ampl parser

This commit is contained in:
awe
2026-04-15 19:09:11 +03:00
parent 3cb3d1c31a
commit c40df97085
10 changed files with 371 additions and 27 deletions

View File

@ -10,7 +10,15 @@ from typing import 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 ParserEvent, PointEvent, StartEvent, SweepAuxCurves, SweepInfo, SweepPacket
from rfg_adc_plotter.types import (
ParserEvent,
PointEvent,
SignalKind,
StartEvent,
SweepAuxCurves,
SweepInfo,
SweepPacket,
)
def u32_to_i32(value: int) -> int:
@ -153,6 +161,7 @@ class LegacyBinaryParser:
self._last_step: Optional[int] = None
self._seen_points = False
self._mode: Optional[str] = None
self._current_signal_kind: Optional[SignalKind] = None
@staticmethod
def _u16_at(buf: bytearray, offset: int) -> int:
@ -162,16 +171,22 @@ class LegacyBinaryParser:
self._mode = "legacy"
self._last_step = None
self._seen_points = False
self._current_signal_kind = None
events.append(StartEvent(ch=int(ch)))
def _emit_tty_start(self, events: List[ParserEvent]) -> None:
self._mode = "tty"
def _emit_bin_start(self, events: List[ParserEvent], signal_kind: SignalKind) -> None:
self._mode = "bin"
self._last_step = None
self._seen_points = False
events.append(StartEvent(ch=0))
self._current_signal_kind = signal_kind
events.append(StartEvent(ch=0, signal_kind=signal_kind))
def _emit_tty_start(self, events: List[ParserEvent]) -> None:
self._emit_bin_start(events, signal_kind="bin_iq")
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
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
@ -179,12 +194,23 @@ 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 _emit_tty_point(self, events: List[ParserEvent], step: int, ch_1_word: int, ch_2_word: int) -> None:
self._mode = "tty"
def _prepare_bin_point(self, events: List[ParserEvent], step: int, signal_kind: SignalKind) -> None:
self._mode = "bin"
if self._current_signal_kind != signal_kind:
if self._seen_points:
events.append(StartEvent(ch=0, signal_kind=signal_kind))
self._last_step = None
self._seen_points = False
self._current_signal_kind = signal_kind
if self._seen_points and self._last_step is not None and step <= self._last_step:
events.append(StartEvent(ch=0))
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)
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")
ch_1 = u16_to_i16(int(ch_1_word))
ch_2 = u16_to_i16(int(ch_2_word))
events.append(
@ -193,6 +219,19 @@ class LegacyBinaryParser:
x=int(step),
y=tty_ch_pair_to_sweep(ch_1, ch_2),
aux=(float(ch_1), float(ch_2)),
signal_kind="bin_iq",
)
)
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))
events.append(
PointEvent(
ch=0,
x=int(step),
y=float(value),
signal_kind="bin_logdet",
)
)
@ -210,6 +249,7 @@ 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_logdet_point = (w0 == 0x001A and w3 == 0x0000)
if is_legacy_start:
self._emit_legacy_start(events, ch=int(self._buf[7]))
@ -221,19 +261,44 @@ class LegacyBinaryParser:
del self._buf[:8]
continue
if is_logdet_point:
self._emit_logdet_point(events, step=int(w1), value_word=int(w2))
del self._buf[:8]
continue
if self._mode == "legacy":
if is_legacy_point:
self._emit_legacy_point(events, step=int(w0), value_word_hi=int(w1), value_word_lo=int(w2), ch=int(self._buf[7]))
self._emit_legacy_point(
events,
step=int(w0),
value_word_hi=int(w1),
value_word_lo=int(w2),
ch=int(self._buf[7]),
)
del self._buf[:8]
continue
if is_tty_point and (not is_legacy_point):
self._emit_tty_point(events, step=int(w1), ch_1_word=int(w2), ch_2_word=int(w3))
del self._buf[:8]
continue
del self._buf[:1]
continue
if self._mode == "tty":
if self._mode == "bin":
if is_tty_point:
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_legacy_point and (not is_tty_point):
self._emit_legacy_point(
events,
step=int(w0),
value_word_hi=int(w1),
value_word_lo=int(w2),
ch=int(self._buf[7]),
)
del self._buf[:8]
continue
del self._buf[:1]
continue
@ -245,7 +310,13 @@ class LegacyBinaryParser:
continue
if is_legacy_point and (not is_tty_point):
self._emit_legacy_point(events, step=int(w0), value_word_hi=int(w1), value_word_lo=int(w2), ch=int(self._buf[7]))
self._emit_legacy_point(
events,
step=int(w0),
value_word_hi=int(w1),
value_word_lo=int(w2),
ch=int(self._buf[7]),
)
del self._buf[:8]
continue
@ -454,6 +525,7 @@ class SweepAssembler:
self._aux_1: list[float] = []
self._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_current(self) -> None:
@ -462,6 +534,7 @@ class SweepAssembler:
self._aux_1.clear()
self._aux_2.clear()
self._cur_channel = None
self._cur_signal_kind = None
self._cur_channels.clear()
def _scatter(self, xs: Sequence[int], values: Sequence[float], width: int) -> np.ndarray:
@ -500,9 +573,11 @@ class SweepAssembler:
self._reset_current()
if event.ch is not None:
self._cur_channel = int(event.ch)
self._cur_signal_kind = event.signal_kind
return packet
point_ch = int(event.ch)
point_signal_kind = event.signal_kind
packet: Optional[SweepPacket] = None
if self._cur_channel is None:
self._cur_channel = point_ch
@ -513,6 +588,12 @@ class SweepAssembler:
packet = self.finalize_current()
self._reset_current()
self._cur_channel = point_ch
if self._cur_signal_kind != point_signal_kind:
if self._xs:
packet = self.finalize_current()
self._reset_current()
self._cur_channel = point_ch
self._cur_signal_kind = point_signal_kind
self._cur_channels.add(point_ch)
self._xs.append(int(event.x))
@ -581,6 +662,7 @@ class SweepAssembler:
"sweep": self._sweep_idx,
"ch": ch_primary,
"chs": ch_list,
"signal_kind": self._cur_signal_kind,
"n_valid": n_valid,
"min": vmin,
"max": vmax,

View File

@ -43,13 +43,17 @@ def _looks_like_legacy_8byte_stream(data: bytes) -> bool:
min_matches = max(_LEGACY_STREAM_MIN_RECORDS, int(blocks * _LEGACY_STREAM_MIN_MATCH_RATIO))
matched_steps_legacy: list[int] = []
matched_steps_tty: list[int] = []
matched_steps_logdet: list[int] = []
for block_idx in range(blocks):
base = offset + (block_idx * 8)
if (_u16le_at(buf, base + 6) & 0x00FF) != 0x000A:
w0 = _u16le_at(buf, base)
w1 = _u16le_at(buf, base + 2)
w3 = _u16le_at(buf, base + 6)
if w0 == 0x000A and w1 != 0xFFFF:
matched_steps_tty.append(w1)
elif w0 == 0x001A and w3 == 0x0000:
matched_steps_logdet.append(w1)
continue
matched_steps_legacy.append(_u16le_at(buf, base))
@ -70,6 +74,14 @@ def _looks_like_legacy_8byte_stream(data: bytes) -> bool:
if monotonic_or_reset >= max(4, len(matched_steps_tty) - 4):
return True
if len(matched_steps_logdet) >= tty_min_matches:
monotonic_or_reset = 0
for prev_step, next_step in zip(matched_steps_logdet, matched_steps_logdet[1:]):
if next_step == (prev_step + 1) or next_step <= 2:
monotonic_or_reset += 1
if monotonic_or_reset >= max(4, len(matched_steps_logdet) - 4):
return True
return False