Multichannel instrument drivers

Some instruments expose several measurement channels through one physical communication session. mpylab represents every logical channel as a normal graph node while a shared controller owns the connection and device-wide state. This pattern is used by:

  • pm_gt_8542c_multichannel and pm_rs_nrp_multichannel;

  • pm_lumiloop_lspm_multichannel;

  • prb_lumiloop_lsprobe_multichannel.

The generic lifecycle and facade infrastructure lives in mpylab.device.multichannel_common. Power-meter quantity conversion is implemented in mpylab.device.powermeter_multichannel_common, while LUMILOOP protocol and waveform helpers remain in mpylab.device.lumiloop_multichannel_common.

Controller and facade model

Each driver instance is a facade for one [Channel_N] section. Facades for the same physical instrument share one communication session and lock, device-wide frequency and mode settings, and an acquisition generation. The final facade calling Quit() closes the connection. Shared settings must agree; conflicting facade configuration is rejected.

Acquisition modes

acquisition in [Init_Value] has two defined values:

independent

Every channel request performs its own acquisition. This is the default when the option is omitted.

synchronized

One instrument-level acquisition produces a shared snapshot. Facades read their channel from the same generation, independent of call order. A new Trigger() or repeated read requests a new generation.

Synchronized means one grouped instrument cycle. It guarantees exact simultaneous sampling only where the instrument and sensors support it. Unsupported modes raise ValueError. The GT 8542C supports only independent; the R&S NRP groups channels using INIT:ALL.

GetDataNB(retrigger=...) accepts booleans and ON/OFF, TRUE/FALSE, YES/NO, and 1/0. Until hardware reports completion, nonblocking drivers return (-1, None).

Common INI structure

The physical device is configured once in [Init_Value]. Each logical channel has its own section and graph node:

[Init_Value]
nr_of_channels: 2
acquisition: synchronized

[Channel_1]
name: Forward
unit: dBm

[Channel_2]
name: Reflected
unit: dBm

Some drivers use channels as their native count option. During real operation hardware discovery is authoritative and a mismatch is reported. Virtual operation requires an explicit count.

Giga-tronics and R&S power meters

The Giga-tronics 8542C is always a two-channel independent instrument. The R&S NRP supports one or two configured sensors, verifies their presence, and explicitly maps calculation blocks to sensors, for example CALC2 to SENS2.

[Init_Value]
gpib: 22
nr_of_channels: 2
acquisition: synchronized
measurement_timeout: 60
poll_interval: 0.01

[Channel_1]
name: Forward
unit: dBm
swr1: 1.1
swr2: 1.1

LUMILOOP LSPM

meter_serial_number selects one LSPM attached to the TCP server. An optional version suffix makes the selection unambiguous. Without it, the currently selected meter is used. Commands address this meter rather than SCPI scope 0, which would address all enumerated meters.

[Init_Value]
visa: TCPIP::127.0.0.1::10001::SOCKET
channels: 2
meter_serial_number: 12345:2.0
acquisition: synchronized
measurement_duration: 0.1
minimum_samples: 2
ready_timeout: 60
trigger_timeout: 30

LUMILOOP LSProbe

Server enumeration order is not a stable probe identity. Bind each logical channel using serial number and, where needed, version:

[Init_Value]
visa: TCPIP::127.0.0.1::10000::SOCKET
channels: 2
acquisition: synchronized
measurement_duration: 0.1

[Channel_1]
name: Probe1
unit: Voverm
probe_serial_number: 101
probe_version: 2.0

Once one channel specifies probe_serial_number, every configured probe channel must do so. Results are mapped by identity, not response order.

Field-probe interface

On successful GetData(), every concrete field-probe driver returns (status, [probe_x, probe_y, probe_z]). The three components are scuq.quantities.Quantity values in V/m and always use this order in the probe coordinate system. Mapping and rotation into cell coordinates deliberately happen in the measurement class; see Field-probe orientation.

Real acquisition requires a finite positive correction frequency set through SetFreq(). Trigger() consistently returns (status, 0). GetDataNB(retrigger=...) preserves the same result structure and reads the current value before optionally retriggering. Drivers without a genuinely asynchronous instrument interface use the blocking GetData() fallback. GetBatteryState() returns (status, value) with a relative numeric value or None when no battery status is available.

Duration-based LUMILOOP acquisition

A positive measurement_duration selects triggered waveform averaging. The number of samples is max(minimum_samples, ceil(measurement_duration * sample_rate)). The effective sample rate is queried from hardware; virtual_sample_rate is used only in virtual mode. ready_timeout limits mode readiness and trigger_timeout limits waveform completion.

LSPM samples are converted from dBm to watts before calculating mean and type-A uncertainty. LSProbe components are averaged in V/m; their type-A uncertainty is combined with the non-reducible probe specification.

Testing and diagnostics

All concrete modules provide a virtual smoke test:

python -m mpylab.device.pm_gt_8542c_multichannel
python -m mpylab.device.pm_rs_nrp_multichannel
python -m mpylab.device.pm_lumiloop_lspm_multichannel
python -m mpylab.device.prb_lumiloop_lsprobe_multichannel

Power-meter INIs can also be opened with python -m mpylab.device.powermeter_ui path/to/powermeter.ini. Before production use, test channel order, nonblocking polling, timeouts, hardware identity mapping, conflicting facade configuration, and shutdown after the final Quit().

See driver development, the curated driver API, and the complete API.