test new variant
This commit is contained in:
@ -5,12 +5,13 @@ from __future__ import annotations
|
||||
import math
|
||||
import time
|
||||
from collections import deque
|
||||
from typing import List, Optional, Sequence, Set
|
||||
from typing import Dict, List, Optional, Sequence, Set
|
||||
|
||||
import numpy as np
|
||||
|
||||
from rfg_adc_plotter.constants import DATA_INVERSION_THRESHOLD, LOG_BASE, LOG_EXP_LIMIT, LOG_POSTSCALER, LOG_SCALER
|
||||
from rfg_adc_plotter.types import (
|
||||
Do1Level,
|
||||
ParserEvent,
|
||||
PointEvent,
|
||||
SignalKind,
|
||||
@ -162,6 +163,14 @@ class LegacyBinaryParser:
|
||||
self._seen_points = False
|
||||
self._mode: Optional[str] = None
|
||||
self._current_signal_kind: Optional[SignalKind] = None
|
||||
self._last_tagged_step_by_level: Dict[Do1Level, Optional[int]] = {
|
||||
"low": None,
|
||||
"high": None,
|
||||
}
|
||||
|
||||
def _reset_tagged_steps(self) -> None:
|
||||
self._last_tagged_step_by_level["low"] = None
|
||||
self._last_tagged_step_by_level["high"] = None
|
||||
|
||||
@staticmethod
|
||||
def _u16_at(buf: bytearray, offset: int) -> int:
|
||||
@ -172,6 +181,7 @@ class LegacyBinaryParser:
|
||||
self._last_step = None
|
||||
self._seen_points = False
|
||||
self._current_signal_kind = None
|
||||
self._reset_tagged_steps()
|
||||
events.append(StartEvent(ch=int(ch)))
|
||||
|
||||
def _emit_bin_start(self, events: List[ParserEvent], signal_kind: SignalKind) -> None:
|
||||
@ -179,6 +189,7 @@ class LegacyBinaryParser:
|
||||
self._last_step = None
|
||||
self._seen_points = False
|
||||
self._current_signal_kind = signal_kind
|
||||
self._reset_tagged_steps()
|
||||
events.append(StartEvent(ch=0, signal_kind=signal_kind))
|
||||
|
||||
def _emit_tty_start(self, events: List[ParserEvent]) -> None:
|
||||
@ -187,6 +198,7 @@ class LegacyBinaryParser:
|
||||
def _emit_legacy_point(self, events: List[ParserEvent], step: int, value_word_hi: int, value_word_lo: int, ch: int) -> None:
|
||||
self._mode = "legacy"
|
||||
self._current_signal_kind = None
|
||||
self._reset_tagged_steps()
|
||||
if self._seen_points and self._last_step is not None and step <= self._last_step:
|
||||
events.append(StartEvent(ch=int(ch)))
|
||||
self._seen_points = True
|
||||
@ -194,7 +206,13 @@ class LegacyBinaryParser:
|
||||
value = u32_to_i32((int(value_word_hi) << 16) | int(value_word_lo))
|
||||
events.append(PointEvent(ch=int(ch), x=int(step), y=float(value)))
|
||||
|
||||
def _prepare_bin_point(self, events: List[ParserEvent], step: int, signal_kind: SignalKind) -> None:
|
||||
def _prepare_bin_point(
|
||||
self,
|
||||
events: List[ParserEvent],
|
||||
step: int,
|
||||
signal_kind: SignalKind,
|
||||
do1_level: Optional[Do1Level] = None,
|
||||
) -> None:
|
||||
self._mode = "bin"
|
||||
if self._current_signal_kind != signal_kind:
|
||||
if self._seen_points:
|
||||
@ -202,12 +220,28 @@ class LegacyBinaryParser:
|
||||
self._last_step = None
|
||||
self._seen_points = False
|
||||
self._current_signal_kind = signal_kind
|
||||
self._reset_tagged_steps()
|
||||
|
||||
if signal_kind == "bin_iq_do1_tagged":
|
||||
level: Do1Level = "high" if do1_level == "high" else "low"
|
||||
last_level_step = self._last_tagged_step_by_level[level]
|
||||
if self._seen_points and last_level_step is not None and step <= last_level_step:
|
||||
events.append(StartEvent(ch=0, signal_kind=signal_kind))
|
||||
self._last_step = None
|
||||
self._seen_points = False
|
||||
self._reset_tagged_steps()
|
||||
self._seen_points = True
|
||||
self._last_tagged_step_by_level[level] = int(step)
|
||||
self._last_step = int(step)
|
||||
return
|
||||
|
||||
if self._seen_points and self._last_step is not None and step <= self._last_step:
|
||||
events.append(StartEvent(ch=0, signal_kind=signal_kind))
|
||||
self._last_step = None
|
||||
self._seen_points = False
|
||||
self._seen_points = True
|
||||
self._last_step = int(step)
|
||||
self._reset_tagged_steps()
|
||||
|
||||
def _emit_tty_point(self, events: List[ParserEvent], step: int, ch_1_word: int, ch_2_word: int) -> None:
|
||||
self._prepare_bin_point(events, step=int(step), signal_kind="bin_iq")
|
||||
@ -223,6 +257,33 @@ class LegacyBinaryParser:
|
||||
)
|
||||
)
|
||||
|
||||
def _emit_tty_tagged_point(
|
||||
self,
|
||||
events: List[ParserEvent],
|
||||
step: int,
|
||||
ch_1_word: int,
|
||||
ch_2_word: int,
|
||||
do1_level: Do1Level,
|
||||
) -> None:
|
||||
self._prepare_bin_point(
|
||||
events,
|
||||
step=int(step),
|
||||
signal_kind="bin_iq_do1_tagged",
|
||||
do1_level=do1_level,
|
||||
)
|
||||
ch_1 = u16_to_i16(int(ch_1_word))
|
||||
ch_2 = u16_to_i16(int(ch_2_word))
|
||||
events.append(
|
||||
PointEvent(
|
||||
ch=0,
|
||||
x=int(step),
|
||||
y=tty_ch_pair_to_sweep(ch_1, ch_2),
|
||||
aux=(float(ch_1), float(ch_2)),
|
||||
signal_kind="bin_iq_do1_tagged",
|
||||
do1_level=do1_level,
|
||||
)
|
||||
)
|
||||
|
||||
def _emit_logdet_point(self, events: List[ParserEvent], step: int, value_word: int) -> None:
|
||||
self._prepare_bin_point(events, step=int(step), signal_kind="bin_logdet")
|
||||
value = u16_to_i16(int(value_word))
|
||||
@ -249,6 +310,8 @@ class LegacyBinaryParser:
|
||||
is_tty_start = (w0 == 0x000A and w1 == 0xFFFF and w2 == 0xFFFF and w3 == 0xFFFF)
|
||||
is_legacy_point = (self._buf[6] == 0x0A and w0 != 0xFFFF)
|
||||
is_tty_point = (w0 == 0x000A and w1 != 0xFFFF)
|
||||
is_tty_tagged_low_point = (w0 == 0x00A3 and w1 != 0xFFFF)
|
||||
is_tty_tagged_high_point = (w0 == 0x00A4 and w1 != 0xFFFF)
|
||||
is_logdet_point = (w0 == 0x001A and w3 == 0x0000)
|
||||
|
||||
if is_legacy_start:
|
||||
@ -281,6 +344,26 @@ class LegacyBinaryParser:
|
||||
self._emit_tty_point(events, step=int(w1), ch_1_word=int(w2), ch_2_word=int(w3))
|
||||
del self._buf[:8]
|
||||
continue
|
||||
if is_tty_tagged_low_point and (not is_legacy_point):
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="low",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
if is_tty_tagged_high_point and (not is_legacy_point):
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="high",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
del self._buf[:1]
|
||||
continue
|
||||
|
||||
@ -289,6 +372,26 @@ class LegacyBinaryParser:
|
||||
self._emit_tty_point(events, step=int(w1), ch_1_word=int(w2), ch_2_word=int(w3))
|
||||
del self._buf[:8]
|
||||
continue
|
||||
if is_tty_tagged_low_point:
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="low",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
if is_tty_tagged_high_point:
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="high",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
if is_legacy_point and (not is_tty_point):
|
||||
self._emit_legacy_point(
|
||||
events,
|
||||
@ -309,6 +412,28 @@ class LegacyBinaryParser:
|
||||
del self._buf[:8]
|
||||
continue
|
||||
|
||||
if is_tty_tagged_low_point and (not is_legacy_point):
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="low",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
|
||||
if is_tty_tagged_high_point and (not is_legacy_point):
|
||||
self._emit_tty_tagged_point(
|
||||
events,
|
||||
step=int(w1),
|
||||
ch_1_word=int(w2),
|
||||
ch_2_word=int(w3),
|
||||
do1_level="high",
|
||||
)
|
||||
del self._buf[:8]
|
||||
continue
|
||||
|
||||
if is_legacy_point and (not is_tty_point):
|
||||
self._emit_legacy_point(
|
||||
events,
|
||||
@ -524,15 +649,34 @@ class SweepAssembler:
|
||||
self._ys: list[float] = []
|
||||
self._aux_1: list[float] = []
|
||||
self._aux_2: list[float] = []
|
||||
self._tagged_low_xs: list[int] = []
|
||||
self._tagged_low_ys: list[float] = []
|
||||
self._tagged_low_aux_1: list[float] = []
|
||||
self._tagged_low_aux_2: list[float] = []
|
||||
self._tagged_high_xs: list[int] = []
|
||||
self._tagged_high_ys: list[float] = []
|
||||
self._tagged_high_aux_1: list[float] = []
|
||||
self._tagged_high_aux_2: list[float] = []
|
||||
self._cur_channel: Optional[int] = None
|
||||
self._cur_signal_kind: Optional[SignalKind] = None
|
||||
self._cur_channels: set[int] = set()
|
||||
|
||||
def _reset_tagged_current(self) -> None:
|
||||
self._tagged_low_xs.clear()
|
||||
self._tagged_low_ys.clear()
|
||||
self._tagged_low_aux_1.clear()
|
||||
self._tagged_low_aux_2.clear()
|
||||
self._tagged_high_xs.clear()
|
||||
self._tagged_high_ys.clear()
|
||||
self._tagged_high_aux_1.clear()
|
||||
self._tagged_high_aux_2.clear()
|
||||
|
||||
def _reset_current(self) -> None:
|
||||
self._xs.clear()
|
||||
self._ys.clear()
|
||||
self._aux_1.clear()
|
||||
self._aux_2.clear()
|
||||
self._reset_tagged_current()
|
||||
self._cur_channel = None
|
||||
self._cur_signal_kind = None
|
||||
self._cur_channels.clear()
|
||||
@ -567,6 +711,24 @@ class SweepAssembler:
|
||||
if last_idx < series.size - 1:
|
||||
series[last_idx + 1 :] = series[last_idx]
|
||||
|
||||
@staticmethod
|
||||
def _nanmean_pair(primary: np.ndarray, secondary: np.ndarray) -> np.ndarray:
|
||||
width = min(primary.size, secondary.size)
|
||||
if width <= 0:
|
||||
return np.zeros((0,), dtype=np.float32)
|
||||
first = np.asarray(primary[:width], dtype=np.float32)
|
||||
second = np.asarray(secondary[:width], dtype=np.float32)
|
||||
out = np.full((width,), np.nan, dtype=np.float32)
|
||||
first_valid = np.isfinite(first)
|
||||
second_valid = np.isfinite(second)
|
||||
both_valid = first_valid & second_valid
|
||||
only_first = first_valid & (~second_valid)
|
||||
only_second = second_valid & (~first_valid)
|
||||
out[only_first] = first[only_first]
|
||||
out[only_second] = second[only_second]
|
||||
out[both_valid] = (first[both_valid] + second[both_valid]) * 0.5
|
||||
return out
|
||||
|
||||
def consume(self, event: ParserEvent) -> Optional[SweepPacket]:
|
||||
if isinstance(event, StartEvent):
|
||||
packet = self.finalize_current()
|
||||
@ -598,7 +760,21 @@ class SweepAssembler:
|
||||
self._cur_channels.add(point_ch)
|
||||
self._xs.append(int(event.x))
|
||||
self._ys.append(float(event.y))
|
||||
if event.aux is not None:
|
||||
if self._cur_signal_kind == "bin_iq_do1_tagged":
|
||||
level = "high" if event.do1_level == "high" else "low"
|
||||
if level == "low":
|
||||
self._tagged_low_xs.append(int(event.x))
|
||||
self._tagged_low_ys.append(float(event.y))
|
||||
if event.aux is not None:
|
||||
self._tagged_low_aux_1.append(float(event.aux[0]))
|
||||
self._tagged_low_aux_2.append(float(event.aux[1]))
|
||||
else:
|
||||
self._tagged_high_xs.append(int(event.x))
|
||||
self._tagged_high_ys.append(float(event.y))
|
||||
if event.aux is not None:
|
||||
self._tagged_high_aux_1.append(float(event.aux[0]))
|
||||
self._tagged_high_aux_2.append(float(event.aux[1]))
|
||||
elif event.aux is not None:
|
||||
self._aux_1.append(float(event.aux[0]))
|
||||
self._aux_2.append(float(event.aux[1]))
|
||||
return packet
|
||||
@ -613,13 +789,37 @@ class SweepAssembler:
|
||||
self._max_width = max(self._max_width, width)
|
||||
target_width = self._max_width if self._fancy else width
|
||||
|
||||
sweep = self._scatter(self._xs, self._ys, target_width)
|
||||
aux_curves: SweepAuxCurves = None
|
||||
if self._aux_1 and self._aux_2 and len(self._aux_1) == len(self._xs):
|
||||
aux_curves = (
|
||||
self._scatter(self._xs, self._aux_1, target_width),
|
||||
self._scatter(self._xs, self._aux_2, target_width),
|
||||
)
|
||||
do1_tagged_payload = None
|
||||
if self._cur_signal_kind == "bin_iq_do1_tagged":
|
||||
raw_low = self._scatter(self._tagged_low_xs, self._tagged_low_ys, target_width)
|
||||
raw_high = self._scatter(self._tagged_high_xs, self._tagged_high_ys, target_width)
|
||||
sweep = self._nanmean_pair(raw_low, raw_high)
|
||||
aux_low = None
|
||||
if self._tagged_low_aux_1 and self._tagged_low_aux_2 and len(self._tagged_low_aux_1) == len(self._tagged_low_xs):
|
||||
aux_low = (
|
||||
self._scatter(self._tagged_low_xs, self._tagged_low_aux_1, target_width),
|
||||
self._scatter(self._tagged_low_xs, self._tagged_low_aux_2, target_width),
|
||||
)
|
||||
aux_high = None
|
||||
if self._tagged_high_aux_1 and self._tagged_high_aux_2 and len(self._tagged_high_aux_1) == len(self._tagged_high_xs):
|
||||
aux_high = (
|
||||
self._scatter(self._tagged_high_xs, self._tagged_high_aux_1, target_width),
|
||||
self._scatter(self._tagged_high_xs, self._tagged_high_aux_2, target_width),
|
||||
)
|
||||
do1_tagged_payload = {
|
||||
"raw_low": raw_low,
|
||||
"raw_high": raw_high,
|
||||
"aux_low": aux_low,
|
||||
"aux_high": aux_high,
|
||||
}
|
||||
else:
|
||||
sweep = self._scatter(self._xs, self._ys, target_width)
|
||||
if self._aux_1 and self._aux_2 and len(self._aux_1) == len(self._xs):
|
||||
aux_curves = (
|
||||
self._scatter(self._xs, self._aux_1, target_width),
|
||||
self._scatter(self._xs, self._aux_2, target_width),
|
||||
)
|
||||
|
||||
n_valid_cur = int(np.count_nonzero(np.isfinite(sweep)))
|
||||
|
||||
@ -670,4 +870,6 @@ class SweepAssembler:
|
||||
"std": std,
|
||||
"dt_ms": dt_ms,
|
||||
}
|
||||
if do1_tagged_payload is not None:
|
||||
info["_do1_tagged_payload"] = do1_tagged_payload
|
||||
return (sweep, info, aux_curves)
|
||||
|
||||
@ -50,7 +50,7 @@ def _looks_like_legacy_8byte_stream(data: bytes) -> bool:
|
||||
w0 = _u16le_at(buf, base)
|
||||
w1 = _u16le_at(buf, base + 2)
|
||||
w3 = _u16le_at(buf, base + 6)
|
||||
if w0 == 0x000A and w1 != 0xFFFF:
|
||||
if w0 in {0x000A, 0x00A3, 0x00A4} and w1 != 0xFFFF:
|
||||
matched_steps_tty.append(w1)
|
||||
elif w0 == 0x001A and w3 == 0x0000:
|
||||
matched_steps_logdet.append(w1)
|
||||
@ -232,7 +232,8 @@ class SweepReader(threading.Thread):
|
||||
)
|
||||
)
|
||||
sys.stderr.write(
|
||||
"[hint] parser_16_bit_x2: if source is 8-byte tty CH1/CH2 stream (0x000A,step,ch1,ch2), try --bin\n"
|
||||
"[hint] parser_16_bit_x2: if source is 8-byte tty CH1/CH2 stream "
|
||||
"(0x000A/0x00A3/0x00A4,step,ch1,ch2), try --bin\n"
|
||||
)
|
||||
assembler = SweepAssembler(fancy=self._fancy, apply_inversion=False)
|
||||
return parser, assembler, []
|
||||
@ -358,7 +359,8 @@ class SweepReader(threading.Thread):
|
||||
and (now_s - self._started_at) >= _NO_PACKET_HINT_AFTER_S
|
||||
):
|
||||
sys.stderr.write(
|
||||
"[hint] parser_16_bit_x2 still has no sweeps; if source is tty CH1/CH2, rerun with --bin\n"
|
||||
"[hint] parser_16_bit_x2 still has no sweeps; "
|
||||
"if source is tty CH1/CH2 (0x000A/0x00A3/0x00A4), rerun with --bin\n"
|
||||
)
|
||||
parser_hint_emitted = True
|
||||
time.sleep(0.0005)
|
||||
|
||||
Reference in New Issue
Block a user