test(e2e-chain): orchestrator + end-to-end fixes (Task 7)
Full-chain orchestrator (run_chain_e2e.sh) now runs the starter set green (3 pass). Fixes found bringing the chain up end-to-end: - client: gorilla/websocket cannot survive a read deadline (next ReadMessage panics "repeated read on failed connection"); replace the poll-with-deadline loop with a background reader goroutine + mutex-guarded state. - orchestrator: guard env.sh's unbound LD_LIBRARY_PATH under set -u. - scenarios/gen_data: centralize NUM_ROWS/ROW_DT and enforce sine freq to be a multiple of the buffer fundamental (LOOP_HZ=5 Hz) so the looped FileReader buffer is a seamless waveform; align starter freqs (5/5/10 Hz). - gen_cfg: FileReader allows exactly one consuming Function, so route tapped (oracle=fed/both) sources through the DDB (ReaderGAM->DDB, then StreamGAM and TapGAM both read DDB) instead of a second FileReader consumer. - validate_waveform: fidelity gates correctness (bit-exact / within one quant level); sine shape becomes a gross frequency-sanity gate (corr>=0.5) plus a tracked corr/nRMSE quality metric, since per-sample wall-clock calibration (Phase-A) and FULL_ARRAY packed timestamps (Phase-A4) are still pending. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,16 @@ QUANT_TYPES = {"none", "uint8", "int8", "uint16", "int16"}
|
||||
QUANT_LEVELS = {"uint8": 255, "int8": 254, "uint16": 65535, "int16": 65534}
|
||||
TIME_MODES = {"PacketTime", "FullArray", "FirstSample", "LastSample"}
|
||||
|
||||
# Producer buffer geometry — the single source of truth shared with gen_data.py.
|
||||
# The MARTe FileReader loops this finite buffer (EOF=Rewind), so the streamed
|
||||
# signal is only a continuous waveform if the buffer holds an integer number of
|
||||
# periods. The buffer fundamental LOOP_HZ = 1/(NUM_ROWS*ROW_DT) is therefore the
|
||||
# smallest sine frequency that loops seamlessly; every sine freq must be a
|
||||
# positive integer multiple of it or the analytic shape oracle is invalid.
|
||||
NUM_ROWS = 200 # producer cycles written to the FileReader input
|
||||
ROW_DT = 1.0e-3 # seconds per producer cycle (row); 1 kHz producer
|
||||
LOOP_HZ = 1.0 / (NUM_ROWS * ROW_DT) # 5.0 Hz buffer fundamental
|
||||
|
||||
|
||||
def _sig(name, type, elements=1, time_mode="PacketTime", time_signal=None,
|
||||
sampling_rate=None, quant="none", range_min=None, range_max=None,
|
||||
@@ -135,6 +145,11 @@ def validate_scenario(s):
|
||||
if sig["time_mode"] in ("FirstSample", "LastSample"):
|
||||
if not sig["sampling_rate"] or sig["sampling_rate"] <= 0:
|
||||
errs.append(f"{sig['name']}: First/LastSample needs sampling_rate>0")
|
||||
if sig["formula"] == "sine" and sig.get("freq"):
|
||||
ratio = sig["freq"] / LOOP_HZ
|
||||
if abs(ratio - round(ratio)) > 1e-9 or round(ratio) < 1:
|
||||
errs.append(f"{sig['name']}: sine freq {sig['freq']} must be a "
|
||||
f"positive multiple of LOOP_HZ={LOOP_HZ} (seamless loop)")
|
||||
return errs
|
||||
|
||||
|
||||
@@ -151,7 +166,7 @@ SCENARIOS = [
|
||||
"multicast_group": None,
|
||||
"signals": [
|
||||
_sig("Counter", "uint32", 1, formula="counter"),
|
||||
_sig("Sine", "float32", 1, formula="sine", freq=2.0, unit="V"),
|
||||
_sig("Sine", "float32", 1, formula="sine", freq=5.0, unit="V"),
|
||||
],
|
||||
}],
|
||||
"oracle": "analytic",
|
||||
@@ -190,7 +205,7 @@ SCENARIOS = [
|
||||
"signals": [
|
||||
_sig("Sine", "float32", 1, quant="uint16",
|
||||
range_min=-5.0, range_max=5.0, formula="sine",
|
||||
freq=3.0, unit="V"),
|
||||
freq=10.0, unit="V"),
|
||||
],
|
||||
}],
|
||||
"oracle": "analytic",
|
||||
|
||||
Reference in New Issue
Block a user