npc-sync 0.2.7__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {npc_sync-0.2.7/src/npc_sync.egg-info → npc_sync-0.2.8}/PKG-INFO +1 -1
- {npc_sync-0.2.7 → npc_sync-0.2.8}/pyproject.toml +1 -1
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync/sync.py +12 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8/src/npc_sync.egg-info}/PKG-INFO +1 -1
- {npc_sync-0.2.7 → npc_sync-0.2.8}/tests/test_replay.py +10 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/LICENSE +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/README.md +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/setup.cfg +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync/__init__.py +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync/py.typed +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync.egg-info/SOURCES.txt +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync.egg-info/dependency_links.txt +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync.egg-info/entry_points.txt +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync.egg-info/requires.txt +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/src/npc_sync.egg-info/top_level.txt +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/tests/test_core.py +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/tests/test_known_files.py +0 -0
- {npc_sync-0.2.7 → npc_sync-0.2.8}/tests/test_plots.py +0 -0
|
@@ -68,6 +68,11 @@ REPLAY_SLOT_SAMPLES = 10_000
|
|
|
68
68
|
acquisition buffers. Buffer sizes seen so far (50,000 and 10,000 samples) are multiples
|
|
69
69
|
of this. Buffer size is not recorded in the sync file metadata."""
|
|
70
70
|
|
|
71
|
+
REPLAY_MAX_BUFFER_SAMPLES = 50_000
|
|
72
|
+
"""Largest acquisition buffer (0.5 s at 100 kHz) considered when looking for replayed
|
|
73
|
+
buffers. Identical slots separated by more than this are coincidental matches (e.g. quiet
|
|
74
|
+
or periodic stretches of real data) and are ignored."""
|
|
75
|
+
|
|
71
76
|
SUSPICIOUS_INTERVAL_THRESHOLD = 0.3 / FRAME_RATE
|
|
72
77
|
DEFINITE_SHORT_INTERVAL_THRESHOLD = 0.05 / FRAME_RATE
|
|
73
78
|
# at 60 fps we should never have diode-flip intervals this small: consider them anomalous
|
|
@@ -175,6 +180,7 @@ def find_replayed_buffers(
|
|
|
175
180
|
times: npt.ArrayLike,
|
|
176
181
|
bits: npt.ArrayLike,
|
|
177
182
|
slot_samples: int = REPLAY_SLOT_SAMPLES,
|
|
183
|
+
max_buffer_samples: int = REPLAY_MAX_BUFFER_SAMPLES,
|
|
178
184
|
) -> tuple[tuple[tuple[int, int], ...], int | None]:
|
|
179
185
|
"""Find acquisition buffers in a sync event list that are replayed copies of a later
|
|
180
186
|
buffer.
|
|
@@ -197,6 +203,8 @@ def find_replayed_buffers(
|
|
|
197
203
|
Bit state (all lines) of each event.
|
|
198
204
|
slot_samples : int
|
|
199
205
|
Fingerprint slot width in samples. Must divide the buffer size.
|
|
206
|
+
max_buffer_samples : int
|
|
207
|
+
Identical slots further apart than this are not treated as replays.
|
|
200
208
|
|
|
201
209
|
Returns
|
|
202
210
|
-------
|
|
@@ -238,6 +246,10 @@ def find_replayed_buffers(
|
|
|
238
246
|
return (), None
|
|
239
247
|
earlier = slots[:-1][same]
|
|
240
248
|
lags = slots[1:][same] - earlier
|
|
249
|
+
plausible = lags <= max_buffer_samples // slot_samples
|
|
250
|
+
earlier, lags = earlier[plausible], lags[plausible]
|
|
251
|
+
if lags.size == 0:
|
|
252
|
+
return (), None
|
|
241
253
|
values, counts = np.unique(lags, return_counts=True)
|
|
242
254
|
lag = int(values[np.argmax(counts)])
|
|
243
255
|
if len(values) > 1:
|
|
@@ -94,3 +94,13 @@ def test_known_sessions(session: str) -> None:
|
|
|
94
94
|
if not paths:
|
|
95
95
|
pytest.skip(f"local sync file not available for {session}")
|
|
96
96
|
assert npc_sync.SyncDataset(paths[0]).invalid_intervals == KNOWN[session]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_ignores_identical_slots_beyond_max_buffer_size() -> None:
|
|
100
|
+
rng = np.random.default_rng(1)
|
|
101
|
+
rel = np.sort(rng.choice(10_000, 50, replace=False))
|
|
102
|
+
state = rng.integers(0, 2**32, 50)
|
|
103
|
+
# same slot content 31 slots (310,000 samples) apart: not a plausible buffer
|
|
104
|
+
times = np.concatenate([rel, rel + 310_000])
|
|
105
|
+
bits = np.concatenate([state, state])
|
|
106
|
+
assert npc_sync.sync.find_replayed_buffers(times, bits) == ((), None)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|