fix(lf): detect_clock keys off the shortest well-supported interval, not the min
detect_clock estimated the bit clock from the *minimum* edge interval, so a few stray sub-bit edges (which every real ADC capture carries) collapsed the estimate. On a strongly-coupled, rail-clipping EM4100 the true half-bit of 32 dropped to ~3, snapping the data clock to 8 and turning the ASK demod into all phase-error markers — no config, no credential decoded. Base the symbol on the shortest interval with real support (>=20% of the modal count) instead of the raw minimum. Verified: clean synthetic still reads 32; the hardware capture that broke it now clocks correctly. Live on a T5577 emulating EM4100 00FFFFFFFF: DETECT decodes config 00148040, identify returns the credential. Regression test reproduces the exact failure (sparse stray edges): old estimator 3.67 (dead demod), new 31.99. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -88,6 +88,19 @@ class TestDSP:
|
||||
half = dsp.detect_clock(dsp.binarize(env))
|
||||
assert half is not None and abs(half - 32) < 4 # RF/64 -> 32-sample half-bit
|
||||
|
||||
def test_clock_survives_sparse_stray_edges(self):
|
||||
# hardware regression: a strongly-coupled EM4100 gives a clean RF/64 signal (intervals
|
||||
# dominated by 32/64) with a few sub-bit stray edges from ADC ripple. The old min-based
|
||||
# estimator keyed off the bare shortest interval and collapsed to ~3 (-> data clock 8 ->
|
||||
# dead demod). The dominant interval is still 32, so detect_clock must ride through it.
|
||||
env = bytearray(_em4100_env(0x0102030405, rf=64, high=255, low=0))
|
||||
for i in range(200, len(env), 900): # sparse single-sample spikes
|
||||
env[i] = 0 if env[i] > 128 else 255
|
||||
half = dsp.detect_clock(dsp.binarize(bytes(env)))
|
||||
assert half is not None and abs(half - 32) < 4 # not dragged down to the ~3 outlier
|
||||
r = protocols.decode_em4100(bytes(env))
|
||||
assert r and r["id_hex"] == "0102030405" # end-to-end decode survives
|
||||
|
||||
def test_manchester_roundtrip(self):
|
||||
# (1,0)->1, (0,1)->0 at phase 0
|
||||
assert dsp.manchester_decode([1, 0, 0, 1, 1, 0]) == [1, 0, 1]
|
||||
|
||||
Reference in New Issue
Block a user