en ja

ctrl API リファレンス

xdm1000_ctrl.py は XDM1000 / XDM1241 を測定器として扱う利用者向け上位制御 API を提供する。SCPI 層は SCPI コマンドの薄いラッパであり、ctrl 層では測定モード、レンジ、オートレンジ、内部測定速度、連続測定条件を上位 API として整理する。

本書は現在の xdm1000_ctrl.py、xdm1000_worker.py、server_fastapi/spec.py に合わせた API リファレンスである。

設計方針

測定条件は meas() / meas_continue() の引数に混ぜない。測定前に set_mode()、set_range()、set_auto_range()、set_integration_speed() で測定器状態を設定する。

単発測定と連続測定は、測定入口で分ける。

result = dmm.meas()
job = dmm.meas_continue()

連続測定だけに必要な周期・終了条件は、set_continue_interval()、set_continue_duration()、set_continue_count() で設定する。

公開 API

現在の Xdm1000Ctrl が利用者向けに持つ主な API は以下である。

close()
disconnect()
get_state()
is_running()
idn()
set_mode(mode)
set_range(value=None, index=None, range_value=None)
set_auto_range(enabled)
set_integration_speed(speed)
set_continue_interval(interval)
set_continue_duration(duration)
set_continue_count(count)
meas(wait=None)
meas_continue(wait=None)
get_result(clear=False)
wait_until_done(poll_interval=0.2)

以下の旧 API は現在の Xdm1000Ctrl には存在しない。

set_meas_mode()
meas_one_shot()
meas_voltage_dc()
meas_current_dc()
start_continuous_meas()
start_statistics_mode()
get_continuous_result()
get_statistics_result()
stop_job()

remote()、local()、query()、write() は ctrl API として公開しない。これらは SCPI 層の責務である。

Xdm1000Ctrl 初期化

Xdm1000Ctrl(
    port=None,
    timeout=2.0,
    baudrate=115200,
    logger=None,
    log_level=None,
    config=None,
    use_process=True,
)

config がある場合は PORT、TIMEOUT、BAUDRATE を優先する。最終的に port がない場合は ValueError である。

use_process=True では worker process が実体の SCPI オブジェクトを持つ。親プロセス側は worker に命令を送り、共有 state / result store から状態と結果を読む。

use_process=False では同一プロセス内で Xdm1000Ctrl 自身が SCPI オブジェクトを直接持つ。

状態・ライフサイクル

close()

接続または worker process を閉じる。

use_process=True では worker に shutdown を送り、終了しない場合は process を terminate する。その後、manager を shutdown する。

use_process=False では local() を試みた後、SCPI 接続を close する。

disconnect()

close() の別名である。

get_state()

現在状態を dict として返す。

use_process=True では共有 state に process_alive を追加して返す。

use_process=False では direct 用状態に process_alive=False を追加して返す。

主なキーは以下である。

{
    "worker_alive": True,
    "process_alive": True,
    "port": "/dev/cu.usbserial-10",
    "baudrate": 115200,
    "running": False,
    "job_id": None,
    "job_type": None,
    "started_at": None,
    "finished_at": None,
    "error": None,
    "traceback": None,
    "message": "worker_ready",
    "args": {},
    "mode": "voltage_dc",
    "range_value": 10,
    "auto_range": False,
    "integration_speed": "F",
    "continue_interval": 0.1,
    "continue_duration": 10.0,
    "continue_count": None,
}

args は running 中の worker が受け取った引数を保持する。

is_running()

長時間測定中なら True を返す。

wait_until_done(poll_interval=0.2)

running が False になるまで待つ。戻り値は終了時点の get_state() 相当の dict である。

Args:

poll_interval: float = 0.2

Returns:

state: dict

装置識別 API

idn()

*IDN? の応答を返す。

running 中は実行できない。running 中に呼ぶと DeviceBusyError である。

Returns:

"OWON,..."

設定 API

set_mode(mode)

測定モードを設定する。単発測定と連続測定で共通である。

Args:

mode: str

利用可能な mode は以下である。

voltage_dc
voltage_ac
current_dc
current_ac
resistance
fresistance
frequency
period
capacitance
temperature_rtd
diode
continuity

SCPI 側では、次の対応で FUNCtion を設定する。

voltage_dc      -> VOLT
voltage_ac      -> VOLT AC
current_dc      -> CURR
current_ac      -> CURR AC
resistance      -> RES
fresistance     -> FRES
frequency       -> FREQ
period          -> PER
capacitance     -> CAP
temperature_rtd -> TEMP
diode           -> DIOD
continuity      -> CONT

set_mode() を呼ぶと、以前の range_value と auto_range のキャッシュは無効化される。レンジは測定モードに依存するためである。

Returns:

{"mode": mode}

set_range(value=None, index=None, range_value=None)

現在の測定モードに対する手動レンジを設定する。単発測定と連続測定で共通である。

Args:

value: str | int | float | None
index: int | None
range_value: str | int | float | None

value は物理量指定である。数値で指定した場合、単位は現在の測定モードの基本単位である。

voltage_dc, voltage_ac       -> V
current_dc, current_ac       -> A
resistance, fresistance      -> Ohm
capacitance                  -> F
temperature_rtd              -> KITS90 または PT100

単位付き文字列は、空白あり・空白なしの両方を受け付ける。

dmm.set_mode("voltage_dc")
dmm.set_range(value=5.0)        # 5 V レンジ
dmm.set_range(value="500 mV")  # 500 mV レンジ
dmm.set_range(value="500mV")   # 500 mV レンジ

index は XDM1000 Programming Manual の SCPI RANGE 離散番号を直接指定する。

dmm.set_mode("voltage_dc")
dmm.set_range(index=3)          # DCV 5 V レンジ

value、index、range_value は同時に指定しない。range_value は旧 API 互換用であり、value と同じ意味で扱う。

ctrl 層は現在の測定モードと指定値を照合し、許可された離散レンジだけを SCPI RANGE <index> へ変換する。呼び出し後、auto_range キャッシュは False になる。

set_range() の前に set_mode() が必要である。

Returns:

{
    "range_value": value | None,
    "range_index": index,
    "range_label": "5 V",
}

set_auto_range(enabled)

オートレンジを設定する。単発測定と連続測定で共通である。

Args:

enabled: bool

enabled=True の場合、SCPI 側では AUTO を発行する。

enabled=False の場合、XDM1000 の SCPI には汎用の AUTO OFF を送らず、直近の set_range() で決定した range_index を RANGE <index> で再設定する。したがって enabled=False にするには、先に set_range() が必要である。

set_auto_range() の前に set_mode() が必要である。

Returns:

{"auto_range": True | False}

set_integration_speed(speed)

内部測定速度を設定する。単発測定と連続測定で共通である。

Args:

speed: str

指定値は以下である。小文字を渡した場合も大文字化して扱う。

F: high speed
M: middle speed
S: low speed

SCPI コマンド名は RATE だが、ctrl API では測定点間隔と誤解しないように integration_speed と呼ぶ。これは連続測定の周期ではない。連続測定の周期は set_continue_interval() で設定する。

Returns:

{"integration_speed": speed}

連続測定条件 API

set_continue_interval(interval)

連続測定時の測定開始間隔を設定する。

Args:

interval: float

単位は秒である。0 以上の値を指定する。0.0 の場合は可能な限り連続して読む。

実装上は、各サンプルの測定開始時刻から次の測定開始目標時刻までの最低間隔として扱う。

Returns:

{"continue_interval": interval}

set_continue_duration(duration)

連続測定の最大測定時間を設定する。

Args:

duration: float | None

単位は秒である。None で時間制限を無効化する。duration に数値を指定する場合は正の値でなければならない。

duration と continue_count が両方設定されている場合は、先に到達した条件で終了する。

Returns:

{"continue_duration": duration}

set_continue_count(count)

連続測定の最大測定回数を設定する。

Args:

count: int | None

None で回数制限を無効化する。count に数値を指定する場合は正の整数でなければならない。

duration と count が両方 None の場合、meas_continue() は ValueError である。

Returns:

{"continue_count": count}

測定 API

meas(wait=None)

現在設定で 1 回測定する。

Args:

wait: float | None = None

wait は SCPI 機能ではない。Python 側で測定直前に待つ秒数である。None の場合は待たない。

mode、range_value、integration_speed は引数に持たせない。必要なら測定前に設定 API を呼ぶ。

meas() の前に set_mode() が必要である。

Returns:

{
    "type": "single",
    "mode": "voltage_dc",
    "range_value": 10,
    "auto_range": False,
    "integration_speed": "F",
    "value": 1.234,
    "host_time_start": 1710000000.0,
    "host_time_end": 1710000000.02,
    "read_elapsed": 0.02,
}

戻り値は get_result() でも取得できるように保存される。

meas_continue(wait=None)

現在設定で連続測定を開始または実行する。

Args:

wait: float | None = None

wait は SCPI 機能ではない。Python 側で連続測定開始前に待つ秒数である。None の場合は待たない。

meas_continue() の前に、少なくとも以下を設定する必要がある。

dmm.set_mode("voltage_dc")
dmm.set_continue_duration(10.0)

または

dmm.set_mode("voltage_dc")
dmm.set_continue_count(100)

Returns:

{"job_id": "..."}

use_process=True では worker process が測定を継続し、呼び出し元には job_id だけ返る。結果は get_result() で取得する。

use_process=False では同一プロセス内で測定ループを実行し、終了後に job_id を返す。したがって呼び出しは連続測定終了までブロックする。

結果取得 API

get_result(clear=False)

直近の単発測定または連続測定結果を返す。

Args:

clear: bool = False

clear=True の場合は、取得後に保存結果を消す。

単発測定後の結果は type="single" である。連続測定後の結果は type="continuous" である。

単発測定結果例:

{
    "type": "single",
    "mode": "voltage_dc",
    "range_value": 10,
    "auto_range": False,
    "integration_speed": "F",
    "value": 1.234,
    "host_time_start": 1710000000.0,
    "host_time_end": 1710000000.02,
    "read_elapsed": 0.02,
}

連続測定結果例:

{
    "type": "continuous",
    "job_id": "...",
    "ok": True,
    "mode": "voltage_dc",
    "range_value": 10,
    "auto_range": False,
    "integration_speed": "F",
    "continue_interval": 0.1,
    "continue_duration": 10.0,
    "continue_count": None,
    "stats": {
        "count": 100,
        "minimum": 1.23,
        "maximum": 1.25,
        "average": 1.24,
        "stdev_population": 0.01
    },
    "started_at": 1710000000.0,
    "finished_at": 1710000010.0,
    "samples": [
        {
            "index": 0,
            "value": 1.234,
            "host_time_start": 1710000000.0,
            "host_time_end": 1710000000.02,
            "read_elapsed": 0.02,
            "t_rel_start": 0.0,
            "t_rel_end": 0.02
        }
    ]
}

use_process=False の連続測定結果では、現在の direct 実装上、stats、started_at、finished_at は含まれず、代わりに count が含まれる。

running 中の制約

次の API は running 中に実行できない。

idn()
set_mode()
set_range()
set_auto_range()
set_integration_speed()
set_continue_interval()
set_continue_duration()
set_continue_count()
meas()
meas_continue()

running 中に呼ぶと DeviceBusyError が送出される。

次の API は running 中でも呼べる。

get_state()
is_running()
get_result()
wait_until_done()

FastAPI 透過 API

server_fastapi/spec.py で公開される API は以下である。

get_state
is_running
idn
set_mode
set_range
set_auto_range
set_integration_speed
set_continue_interval
set_continue_duration
set_continue_count
meas
meas_continue
get_result
wait_until_done

各 API は object_name="xdm1000" として登録され、HTTP method は post である。

request model は以下である。

set_mode                  -> ModeRequest(mode: str)
set_range                 -> RangeRequest(value: str | int | float | None, index: int | None, range_value: str | int | float | None)
set_auto_range            -> AutoRangeRequest(enabled: bool)
set_integration_speed     -> IntegrationSpeedRequest(speed: str)
set_continue_interval     -> ContinueIntervalRequest(interval: float)
set_continue_duration     -> ContinueDurationRequest(duration: float | None)
set_continue_count        -> ContinueCountRequest(count: int | None)
meas                      -> WaitRequest(wait: float | None)
meas_continue             -> WaitRequest(wait: float | None)
get_result                -> ClearRequest(clear: bool = False)
wait_until_done           -> WaitUntilDoneRequest(poll_interval: float = 0.2)

最小使用例

単発測定

from xdm1000.xdm1000_ctrl import Xdm1000Ctrl

dmm = Xdm1000Ctrl(port="/dev/cu.usbserial-10")

try:
    dmm.set_mode("voltage_dc")
    dmm.set_auto_range(True)
    dmm.set_integration_speed("F")
    result = dmm.meas()
    print(result)
finally:
    dmm.close()

連続測定

from xdm1000.xdm1000_ctrl import Xdm1000Ctrl

dmm = Xdm1000Ctrl(port="/dev/cu.usbserial-10")

try:
    dmm.set_mode("voltage_dc")
    dmm.set_auto_range(True)
    dmm.set_integration_speed("F")
    dmm.set_continue_interval(0.1)
    dmm.set_continue_duration(10.0)

    job = dmm.meas_continue()
    print(job)

    dmm.wait_until_done()
    result = dmm.get_result()
    print(result)
finally:
    dmm.close()