Add real switch support for multi-device matrix radar
MultiDeviceLibreVnaService only exposes the 2x4 virtual combo matrix on its own USB transport. When a physical GPIO switch sits on the master stimulus and/or slave receiver path, the effective matrix is wider than that. SwitchedMatrixRadarService wraps the inner service and drives the extra switch(es) between acquire_collection calls, widening the combo matrix by the physical position counts (matrix_output_switch_positions / matrix_input_switch_positions in RunConfigModel). Combo-matrix construction was centralized into RunConfigModel.build_runtime_combos() so the GUI, workflows, and codec all derive the same widened matrix instead of each computing its own version of the virtual 2x4 layout.
This commit is contained in:
+1
-1
@@ -226,4 +226,4 @@ python_app/runtime
|
|||||||
SHARE_INTERNET_TO_PI.md
|
SHARE_INTERNET_TO_PI.md
|
||||||
|
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
./docs
|
docs/
|
||||||
@@ -61,7 +61,7 @@ class AppWindowConfigProfileIOMixin:
|
|||||||
"""Return the canonical virtual combo matrix shown for matrix-mode radars."""
|
"""Return the canonical virtual combo matrix shown for matrix-mode radars."""
|
||||||
return ",".join(
|
return ",".join(
|
||||||
f"{int(combo.input)}:{int(combo.output)}"
|
f"{int(combo.input)}:{int(combo.output)}"
|
||||||
for combo in RunConfigModel.build_matrix_radar_virtual_combos()
|
for combo in self._defaults_config.build_runtime_combos()
|
||||||
)
|
)
|
||||||
|
|
||||||
def _sync_pass_through_y_controls(self) -> None:
|
def _sync_pass_through_y_controls(self) -> None:
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class AppWindowConfigStateBuildersMixin:
|
|||||||
if config.is_matrix_radar:
|
if config.is_matrix_radar:
|
||||||
return ",".join(
|
return ",".join(
|
||||||
f"{int(combo.input)}:{int(combo.output)}"
|
f"{int(combo.input)}:{int(combo.output)}"
|
||||||
for combo in RunConfigModel.build_matrix_radar_virtual_combos()
|
for combo in config.build_runtime_combos()
|
||||||
)
|
)
|
||||||
combos = list(config.combos)
|
combos = list(config.combos)
|
||||||
full_combos = config.build_full_combos(config.input_switch.positions, config.output_switch.positions)
|
full_combos = config.build_full_combos(config.input_switch.positions, config.output_switch.positions)
|
||||||
|
|||||||
@@ -46,13 +46,31 @@ def create_matrix_radar_service(config: RunConfigModel) -> MatrixRadarService:
|
|||||||
if model == RunConfigModel.LIBREVNA_MULTI_MODEL:
|
if model == RunConfigModel.LIBREVNA_MULTI_MODEL:
|
||||||
from python_app.hardware_full.multi_device_service import MultiDeviceLibreVnaService
|
from python_app.hardware_full.multi_device_service import MultiDeviceLibreVnaService
|
||||||
|
|
||||||
return MultiDeviceLibreVnaService(
|
inner = MultiDeviceLibreVnaService(
|
||||||
master_serial=config.radar.serial,
|
master_serial=config.radar.serial,
|
||||||
slave_serials=list(config.radar.multi_device.slave_serials),
|
slave_serials=list(config.radar.multi_device.slave_serials),
|
||||||
force_external_reference=config.radar.multi_device.force_external_reference,
|
force_external_reference=config.radar.multi_device.force_external_reference,
|
||||||
recovery_attempts=config.radar.multi_device.recovery_attempts,
|
recovery_attempts=config.radar.multi_device.recovery_attempts,
|
||||||
backend_mode=config.radar.driver_mode,
|
backend_mode=config.radar.driver_mode,
|
||||||
)
|
)
|
||||||
|
out_physical = config.matrix_output_switch_positions
|
||||||
|
in_physical = config.matrix_input_switch_positions
|
||||||
|
if out_physical <= 1 and in_physical <= 1:
|
||||||
|
return inner
|
||||||
|
|
||||||
|
from python_app.hardware_full.switched_matrix_radar_service import (
|
||||||
|
SwitchedMatrixRadarService,
|
||||||
|
build_physical_switch,
|
||||||
|
)
|
||||||
|
|
||||||
|
return SwitchedMatrixRadarService(
|
||||||
|
inner=inner,
|
||||||
|
output_switch=build_physical_switch(config.output_switch, out_physical, config.radar.driver_mode),
|
||||||
|
input_switch=build_physical_switch(config.input_switch, in_physical, config.radar.driver_mode),
|
||||||
|
inner_output_positions=RunConfigModel.MULTI_DEVICE_OUTPUT_POSITIONS,
|
||||||
|
inner_input_positions=RunConfigModel.MULTI_DEVICE_INPUT_POSITIONS,
|
||||||
|
settling_ms=config.runtime.settling_ms,
|
||||||
|
)
|
||||||
|
|
||||||
if model == RunConfigModel.SN9000_MODEL:
|
if model == RunConfigModel.SN9000_MODEL:
|
||||||
if config.radar.driver_mode != "native":
|
if config.radar.driver_mode != "native":
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ class SwitchService:
|
|||||||
"""Switch to requested position."""
|
"""Switch to requested position."""
|
||||||
self._driver.switch_to(position)
|
self._driver.switch_to(position)
|
||||||
|
|
||||||
|
def position_count(self) -> int:
|
||||||
|
"""Return number of positions supported by the backend driver."""
|
||||||
|
return self._driver.position_count()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_position(self) -> int:
|
def current_position(self) -> int:
|
||||||
"""Return current switch position reported by backend driver."""
|
"""Return current switch position reported by backend driver."""
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
"""Matrix radar behind real GPIO switches on the stimulus and/or receiver path."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, replace
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
from python_app.hardware_full.matrix_radar_service import MatrixRadarService
|
||||||
|
from python_app.hardware_full.switch_service import SwitchService
|
||||||
|
from python_app.models.dataset_model import ComboKey, SweepCollection, TraceData
|
||||||
|
from python_app.models.run_config_model import RadarSweepModel, SwitchModel
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
class SwitchedMatrixRadarService:
|
||||||
|
"""Widen a matrix radar's combo matrix with real switch positions.
|
||||||
|
|
||||||
|
Implements the ``MatrixRadarService`` protocol, so the producer and the
|
||||||
|
capture workflows treat it as an ordinary matrix radar that simply reports
|
||||||
|
more positions. The hardware sweep is never stopped: switches are only ever
|
||||||
|
driven BETWEEN ``acquire_collection`` calls, and the inner service's
|
||||||
|
free-running collection discards any partially swept cycle.
|
||||||
|
"""
|
||||||
|
|
||||||
|
inner: MatrixRadarService
|
||||||
|
output_switch: SwitchService | None
|
||||||
|
input_switch: SwitchService | None
|
||||||
|
inner_output_positions: int
|
||||||
|
inner_input_positions: int
|
||||||
|
settling_ms: int = 0
|
||||||
|
|
||||||
|
def open(self) -> None:
|
||||||
|
"""Open the inner radar and both switches."""
|
||||||
|
self.inner.open()
|
||||||
|
if self.output_switch is not None:
|
||||||
|
self.output_switch.open()
|
||||||
|
if self.input_switch is not None:
|
||||||
|
self.input_switch.open()
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Close switches first, then the inner radar; never raises."""
|
||||||
|
for switch in (self.input_switch, self.output_switch):
|
||||||
|
if switch is not None:
|
||||||
|
try:
|
||||||
|
switch.close()
|
||||||
|
except Exception as exc: # noqa: BLE001 — shutdown path
|
||||||
|
logger.warning("Switch close ignored error: %s", exc)
|
||||||
|
self.inner.close()
|
||||||
|
|
||||||
|
def configure(self, sweep: RadarSweepModel) -> None:
|
||||||
|
"""Apply sweep settings to the inner radar."""
|
||||||
|
self.inner.configure(sweep)
|
||||||
|
|
||||||
|
def recover(self) -> None:
|
||||||
|
"""Reconnect the inner radar; switches are not on the USB transport."""
|
||||||
|
self.inner.recover()
|
||||||
|
|
||||||
|
def acquire_collection(self, collection_id: int = 1) -> SweepCollection:
|
||||||
|
"""Acquire the full widened matrix, one inner collection per switch step.
|
||||||
|
|
||||||
|
A partial failure raises instead of returning a short collection: the
|
||||||
|
preprocessor requires every runtime combo to be present, so half a matrix
|
||||||
|
is worse than a dropped frame.
|
||||||
|
"""
|
||||||
|
capture_start_ns = time.monotonic_ns()
|
||||||
|
out_steps = self.output_switch.position_count() if self.output_switch is not None else 1
|
||||||
|
in_steps = self.input_switch.position_count() if self.input_switch is not None else 1
|
||||||
|
total_inputs = in_steps * self.inner_input_positions
|
||||||
|
total_outputs = out_steps * self.inner_output_positions
|
||||||
|
|
||||||
|
# Place each trace at its canonical index rather than appending. The GPR stage
|
||||||
|
# rejects a collection whose trace order differs from run.combos, and run.combos
|
||||||
|
# is built output-major (`build_full_combos`) while these loops run switch-major.
|
||||||
|
# Appending happens to agree for an output switch and to disagree for an input one.
|
||||||
|
slots: list[TraceData | None] = [None] * (total_inputs * total_outputs)
|
||||||
|
|
||||||
|
for out_k in range(out_steps):
|
||||||
|
if self.output_switch is not None:
|
||||||
|
self.output_switch.switch_to(out_k)
|
||||||
|
for in_k in range(in_steps):
|
||||||
|
if self.input_switch is not None:
|
||||||
|
self.input_switch.switch_to(in_k)
|
||||||
|
# Settle AFTER the last switch change and BEFORE collecting, so the
|
||||||
|
# cycle we anchor on starts with the RF path already stable.
|
||||||
|
if self.settling_ms > 0:
|
||||||
|
time.sleep(self.settling_ms / 1000.0)
|
||||||
|
|
||||||
|
sub = self.inner.acquire_collection(collection_id)
|
||||||
|
for trace in sub.traces:
|
||||||
|
input_pos = in_k * self.inner_input_positions + int(trace.combo.input)
|
||||||
|
output_pos = out_k * self.inner_output_positions + int(trace.combo.output)
|
||||||
|
slots[output_pos * total_inputs + input_pos] = replace(
|
||||||
|
trace, combo=ComboKey(input=input_pos, output=output_pos)
|
||||||
|
)
|
||||||
|
|
||||||
|
if any(trace is None for trace in slots):
|
||||||
|
missing = sum(1 for trace in slots if trace is None)
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Switched matrix collection is incomplete: {missing} of {len(slots)} combos missing"
|
||||||
|
)
|
||||||
|
|
||||||
|
return SweepCollection(
|
||||||
|
collection_id=int(collection_id),
|
||||||
|
monotonic_ns=time.monotonic_ns(),
|
||||||
|
traces=[trace for trace in slots if trace is not None],
|
||||||
|
capture_start_ns=capture_start_ns,
|
||||||
|
capture_end_ns=time.monotonic_ns(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def build_physical_switch(
|
||||||
|
model: SwitchModel,
|
||||||
|
physical_positions: int,
|
||||||
|
radar_driver_mode: str,
|
||||||
|
) -> SwitchService | None:
|
||||||
|
"""Build the driver for a real switch described by a virtual switch section.
|
||||||
|
|
||||||
|
The config section carries the LOGICAL axis size and a forced "mock" mode so
|
||||||
|
the C++ loader accepts it; the real driver needs the PHYSICAL position count
|
||||||
|
and native mode. Mock radar runs keep mock switches so the whole path can be
|
||||||
|
exercised without GPIO.
|
||||||
|
"""
|
||||||
|
if physical_positions <= 1:
|
||||||
|
return None
|
||||||
|
driver_mode = "mock" if radar_driver_mode.strip().lower() == "mock" else "native"
|
||||||
|
return SwitchService.from_model(
|
||||||
|
replace(model, positions=physical_positions, driver_mode=driver_mode)
|
||||||
|
)
|
||||||
@@ -219,6 +219,16 @@ def run_config_from_dict(payload: dict[str, Any]) -> RunConfigModel:
|
|||||||
"recovery_attempts",
|
"recovery_attempts",
|
||||||
model.radar.multi_device.recovery_attempts,
|
model.radar.multi_device.recovery_attempts,
|
||||||
)
|
)
|
||||||
|
model.radar.multi_device.output_switch_positions = _read_int(
|
||||||
|
multi_device_payload,
|
||||||
|
"output_switch_positions",
|
||||||
|
model.radar.multi_device.output_switch_positions,
|
||||||
|
)
|
||||||
|
model.radar.multi_device.input_switch_positions = _read_int(
|
||||||
|
multi_device_payload,
|
||||||
|
"input_switch_positions",
|
||||||
|
model.radar.multi_device.input_switch_positions,
|
||||||
|
)
|
||||||
model.radar.kamil_adc.project_dir = _read_str(
|
model.radar.kamil_adc.project_dir = _read_str(
|
||||||
kamil_adc_payload, "project_dir", model.radar.kamil_adc.project_dir
|
kamil_adc_payload, "project_dir", model.radar.kamil_adc.project_dir
|
||||||
)
|
)
|
||||||
@@ -493,6 +503,8 @@ def run_config_to_dict(model: RunConfigModel) -> dict[str, Any]:
|
|||||||
"slave_serials": list(model.radar.multi_device.slave_serials),
|
"slave_serials": list(model.radar.multi_device.slave_serials),
|
||||||
"force_external_reference": model.radar.multi_device.force_external_reference,
|
"force_external_reference": model.radar.multi_device.force_external_reference,
|
||||||
"recovery_attempts": model.radar.multi_device.recovery_attempts,
|
"recovery_attempts": model.radar.multi_device.recovery_attempts,
|
||||||
|
"output_switch_positions": model.radar.multi_device.output_switch_positions,
|
||||||
|
"input_switch_positions": model.radar.multi_device.input_switch_positions
|
||||||
},
|
},
|
||||||
"kamil_adc": {
|
"kamil_adc": {
|
||||||
"project_dir": model.radar.kamil_adc.project_dir,
|
"project_dir": model.radar.kamil_adc.project_dir,
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ class RadarMultiDeviceModel:
|
|||||||
slave_serials: list[str] = field(default_factory=list)
|
slave_serials: list[str] = field(default_factory=list)
|
||||||
force_external_reference: bool = True
|
force_external_reference: bool = True
|
||||||
recovery_attempts: int = 3
|
recovery_attempts: int = 3
|
||||||
|
output_switch_positions: int = 1 # 1 = свитча нет
|
||||||
|
input_switch_positions: int = 1 # 1 = свитча нет
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
@@ -387,6 +389,24 @@ class RunConfigModel:
|
|||||||
"""Return whether this config acquires the full virtual switch matrix per sweep."""
|
"""Return whether this config acquires the full virtual switch matrix per sweep."""
|
||||||
return self.is_multi_device or self.is_sn9000
|
return self.is_multi_device or self.is_sn9000
|
||||||
|
|
||||||
|
@property
|
||||||
|
def matrix_output_switch_positions(self) -> int:
|
||||||
|
"""Physical positions of the real switch on the master stimulus path."""
|
||||||
|
if not self.is_multi_device:
|
||||||
|
return 1
|
||||||
|
return max(1, int(self.radar.multi_device.output_switch_positions))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def matrix_input_switch_positions(self) -> int:
|
||||||
|
"""Physical positions of the real switch on the slave receiver path."""
|
||||||
|
if not self.is_multi_device:
|
||||||
|
return 1
|
||||||
|
return max(1, int(self.radar.multi_device.input_switch_positions))
|
||||||
|
|
||||||
|
def build_runtime_combos(self) -> list[ComboModel]:
|
||||||
|
"""Build the combo matrix from the effective switch axis sizes."""
|
||||||
|
return self.build_full_combos(self.input_switch.positions, self.output_switch.positions)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_kamil_adc(self) -> bool:
|
def is_kamil_adc(self) -> bool:
|
||||||
"""Return whether this config targets the external Kamil ADC acquisition path."""
|
"""Return whether this config targets the external Kamil ADC acquisition path."""
|
||||||
@@ -443,22 +463,25 @@ class RunConfigModel:
|
|||||||
if not self.is_matrix_radar:
|
if not self.is_matrix_radar:
|
||||||
return
|
return
|
||||||
self._apply_matrix_virtual_switches()
|
self._apply_matrix_virtual_switches()
|
||||||
self.combos = self.build_matrix_radar_virtual_combos()
|
self.combos = self.build_runtime_combos()
|
||||||
|
|
||||||
def _apply_matrix_virtual_switches(self) -> None:
|
def _apply_matrix_virtual_switches(self) -> None:
|
||||||
"""Pin the canonical 2x4 virtual switch matrix used by all matrix-mode radars."""
|
"""Pin the virtual switch matrix, widened by any real switch on the path."""
|
||||||
|
out_physical = self.matrix_output_switch_positions
|
||||||
|
in_physical = self.matrix_input_switch_positions
|
||||||
|
|
||||||
self.output_switch.name = self.output_switch.name or "virtual_output"
|
self.output_switch.name = self.output_switch.name or "virtual_output"
|
||||||
self.output_switch.driver_mode = "mock"
|
self.output_switch.driver_mode = "mock"
|
||||||
self.output_switch.driver = self.output_switch.driver or "h7992"
|
self.output_switch.driver = self.output_switch.driver or "h7992"
|
||||||
self.output_switch.radar_port = 1
|
self.output_switch.radar_port = 1
|
||||||
self.output_switch.positions = self.MULTI_DEVICE_OUTPUT_POSITIONS
|
self.output_switch.positions = out_physical * self.MULTI_DEVICE_OUTPUT_POSITIONS
|
||||||
self.output_switch.default_position = 0
|
self.output_switch.default_position = 0
|
||||||
|
|
||||||
self.input_switch.name = self.input_switch.name or "virtual_input"
|
self.input_switch.name = self.input_switch.name or "virtual_input"
|
||||||
self.input_switch.driver_mode = "mock"
|
self.input_switch.driver_mode = "mock"
|
||||||
self.input_switch.driver = self.input_switch.driver or "h7992"
|
self.input_switch.driver = self.input_switch.driver or "h7992"
|
||||||
self.input_switch.radar_port = 2
|
self.input_switch.radar_port = 2
|
||||||
self.input_switch.positions = self.MULTI_DEVICE_INPUT_POSITIONS
|
self.input_switch.positions = in_physical * self.MULTI_DEVICE_INPUT_POSITIONS
|
||||||
self.input_switch.default_position = 0
|
self.input_switch.default_position = 0
|
||||||
|
|
||||||
def ensure_combos(self) -> None:
|
def ensure_combos(self) -> None:
|
||||||
|
|||||||
@@ -81,14 +81,7 @@ class MultiRadarSequentialCaptureSession:
|
|||||||
self._manual_matrix_radar_capture = (
|
self._manual_matrix_radar_capture = (
|
||||||
self._is_matrix_radar and kind in MATRIX_RADAR_MANUAL_CAPTURE_KINDS
|
self._is_matrix_radar and kind in MATRIX_RADAR_MANUAL_CAPTURE_KINDS
|
||||||
)
|
)
|
||||||
self._combos = (
|
self._combos = base_config.build_runtime_combos()
|
||||||
RunConfigModel.build_matrix_radar_virtual_combos()
|
|
||||||
if self._is_matrix_radar
|
|
||||||
else RunConfigModel.build_full_combos(
|
|
||||||
base_config.input_switch.positions,
|
|
||||||
base_config.output_switch.positions,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not self._combos:
|
if not self._combos:
|
||||||
raise RuntimeError("No switch combinations available for capture")
|
raise RuntimeError("No switch combinations available for capture")
|
||||||
|
|
||||||
|
|||||||
@@ -64,11 +64,7 @@ class SequentialCaptureSession:
|
|||||||
self._manual_matrix_radar_capture = (
|
self._manual_matrix_radar_capture = (
|
||||||
self._is_matrix_radar and kind in MATRIX_RADAR_MANUAL_CAPTURE_KINDS
|
self._is_matrix_radar and kind in MATRIX_RADAR_MANUAL_CAPTURE_KINDS
|
||||||
)
|
)
|
||||||
self._combos = (
|
self._combos = config.build_runtime_combos()
|
||||||
RunConfigModel.build_matrix_radar_virtual_combos()
|
|
||||||
if self._is_matrix_radar
|
|
||||||
else RunConfigModel.build_full_combos(config.input_switch.positions, config.output_switch.positions)
|
|
||||||
)
|
|
||||||
if not self._combos:
|
if not self._combos:
|
||||||
raise RuntimeError("No switch combinations available for capture")
|
raise RuntimeError("No switch combinations available for capture")
|
||||||
|
|
||||||
|
|||||||
+144
-11
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"radar": {
|
"radar": {
|
||||||
"model": "librevna",
|
"model": "librevna_multi",
|
||||||
"serial": "",
|
"serial": "",
|
||||||
"remote_host": "127.0.0.1",
|
"remote_host": "127.0.0.1",
|
||||||
"remote_port": 50209,
|
"remote_port": 50209,
|
||||||
@@ -8,9 +8,14 @@
|
|||||||
"mock_signal_hz": 5000000.0,
|
"mock_signal_hz": 5000000.0,
|
||||||
"visa_library": "",
|
"visa_library": "",
|
||||||
"multi_device": {
|
"multi_device": {
|
||||||
"slave_serials": [],
|
"slave_serials": [
|
||||||
|
"20A1307D5532",
|
||||||
|
"2072306C5532"
|
||||||
|
],
|
||||||
"force_external_reference": false,
|
"force_external_reference": false,
|
||||||
"recovery_attempts": 3
|
"recovery_attempts": 3,
|
||||||
|
"output_switch_positions": 1,
|
||||||
|
"input_switch_positions": 3
|
||||||
},
|
},
|
||||||
"kamil_adc": {
|
"kamil_adc": {
|
||||||
"project_dir": "",
|
"project_dir": "",
|
||||||
@@ -20,7 +25,18 @@
|
|||||||
"env": {},
|
"env": {},
|
||||||
"startup_timeout_s": 5.0,
|
"startup_timeout_s": 5.0,
|
||||||
"sweep_timeout_s": 5.0,
|
"sweep_timeout_s": 5.0,
|
||||||
"stop_timeout_s": 2.0
|
"stop_timeout_s": 2.0,
|
||||||
|
"phase_calibration": {
|
||||||
|
"phase0_rad": 0.0,
|
||||||
|
"freq0_hz": 2046000000.0,
|
||||||
|
"phase1_rad": 300.0,
|
||||||
|
"freq1_hz": 5612000000.0
|
||||||
|
},
|
||||||
|
"band": {
|
||||||
|
"start_hz": 2100000000.0,
|
||||||
|
"stop_hz": 5500000000.0,
|
||||||
|
"points": 2048
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"laser_control": {
|
"laser_control": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
@@ -75,7 +91,7 @@
|
|||||||
"driver_mode": "mock",
|
"driver_mode": "mock",
|
||||||
"driver": "h7992",
|
"driver": "h7992",
|
||||||
"radar_port": 2,
|
"radar_port": 2,
|
||||||
"positions": 4,
|
"positions": 12,
|
||||||
"default_position": 0,
|
"default_position": 0,
|
||||||
"gpio_chip": "/dev/gpiochip0",
|
"gpio_chip": "/dev/gpiochip0",
|
||||||
"pin_a": 22,
|
"pin_a": 22,
|
||||||
@@ -92,11 +108,14 @@
|
|||||||
"debounce_ms": 50,
|
"debounce_ms": 50,
|
||||||
"action": "capture_tmp_reference"
|
"action": "capture_tmp_reference"
|
||||||
},
|
},
|
||||||
|
"logging": {
|
||||||
|
"level": "info"
|
||||||
|
},
|
||||||
"run": {
|
"run": {
|
||||||
"settling_ms": 0,
|
"settling_ms": 0,
|
||||||
"idle_sleep_ms": 2,
|
"idle_sleep_ms": 2,
|
||||||
"continuous": true,
|
"continuous": true,
|
||||||
"processing_live_config_path": "python_app/runtime/processing_live.json",
|
"processing_live_config_path": "/home/guriy/Documents/radar_system/python_app/runtime/processing_live.json",
|
||||||
"locator_server": {
|
"locator_server": {
|
||||||
"device_id": 3,
|
"device_id": 3,
|
||||||
"protocol_version": 1,
|
"protocol_version": 1,
|
||||||
@@ -123,6 +142,38 @@
|
|||||||
"input": 3,
|
"input": 3,
|
||||||
"output": 0
|
"output": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"input": 4,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 5,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 6,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 7,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 8,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 9,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 10,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 11,
|
||||||
|
"output": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"input": 0,
|
"input": 0,
|
||||||
"output": 1
|
"output": 1
|
||||||
@@ -138,17 +189,49 @@
|
|||||||
{
|
{
|
||||||
"input": 3,
|
"input": 3,
|
||||||
"output": 1
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 4,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 5,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 6,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 7,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 8,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 9,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 10,
|
||||||
|
"output": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": 11,
|
||||||
|
"output": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preprocess": {
|
"preprocess": {
|
||||||
"s21": {
|
"s21": {
|
||||||
"calibration": {
|
"calibration": {
|
||||||
"set_name": "smoke_cal",
|
"set_name": "smoke_cal3",
|
||||||
"bundle_path": ""
|
"bundle_path": ""
|
||||||
},
|
},
|
||||||
"reference": {
|
"reference": {
|
||||||
"set_name": "smoke_ref",
|
"set_name": "smoke_cal3",
|
||||||
"bundle_path": ""
|
"bundle_path": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -219,6 +302,54 @@
|
|||||||
"x_m": 0.185,
|
"x_m": 0.185,
|
||||||
"y_m": 0.0,
|
"y_m": 0.0,
|
||||||
"z_m": 0.0
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 4,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 5,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 6,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 7,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 8,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 9,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 10,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input_pos": 11,
|
||||||
|
"x_m": 0.0,
|
||||||
|
"y_m": 0.0,
|
||||||
|
"z_m": 0.0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -253,7 +384,7 @@
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"switches": {
|
"switches": {
|
||||||
"combo_mode": "text",
|
"combo_mode": "text",
|
||||||
"combos_text": "0:0,1:0,2:0,3:0,0:1,1:1,2:1,3:1",
|
"combos_text": "0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,0:1,1:1,2:1,3:1,4:1,5:1,6:1,7:1,8:1,9:1,10:1,11:1",
|
||||||
"single_input": "0",
|
"single_input": "0",
|
||||||
"single_output": "0"
|
"single_output": "0"
|
||||||
},
|
},
|
||||||
@@ -262,6 +393,7 @@
|
|||||||
"pass_through": {
|
"pass_through": {
|
||||||
"show_magnitude": true,
|
"show_magnitude": true,
|
||||||
"show_phase": false,
|
"show_phase": false,
|
||||||
|
"unwrap_phase": false,
|
||||||
"combo_filter": "",
|
"combo_filter": "",
|
||||||
"fixed_y_enabled": false,
|
"fixed_y_enabled": false,
|
||||||
"y_min_db": -100.0,
|
"y_min_db": -100.0,
|
||||||
@@ -333,7 +465,8 @@
|
|||||||
"data_actions": {
|
"data_actions": {
|
||||||
"save_count": 10,
|
"save_count": 10,
|
||||||
"save_path": "python_app/data/snapshots",
|
"save_path": "python_app/data/snapshots",
|
||||||
"save_name": "snapshot_simulator"
|
"save_name": "snapshot_simulator",
|
||||||
|
"record_count": 100
|
||||||
},
|
},
|
||||||
"preprocess_dialog": {
|
"preprocess_dialog": {
|
||||||
"set_name": "smoke_cal",
|
"set_name": "smoke_cal",
|
||||||
@@ -342,4 +475,4 @@
|
|||||||
"median_sweep_count": 5
|
"median_sweep_count": 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user