Evoked measure set for auditory paradigms: ERP, induced power, debiased ITC - #1
Merged
Conversation
Four pieces of the evoked work, all measurement primitives with tests rather than wiring, so the modules can adopt them next. There was no ERP amplitude or latency measure anywhere — not in this package and not in the lab's EEGLAB scripts. Everything on both sides was ITC, ERSP or trial-averaged power, all of which discard sign, which is presumably why the absence went unnoticed. Sign is worth having now: under a fixed-orientation inverse a source's time course is its projection onto the cortical normal, so an N1 that inverts between regions means something. The measure takes a polarity argument because a named component is a signed extremum, not the largest excursion. n_cycles now accepts [lo, hi] as a linear ramp alongside a scalar and "adaptive". A fixed 7 cycles cannot resolve the 92-308 ms onset window at low frequencies because the wavelet is longer than the window. The ramp mirrors the lab's EEGLAB cycles [1 30]; EEGLAB's second element is a growth factor rather than an endpoint, so this is an interpretation and is documented as one. D24 already settled that we match conclusions, not values. Measures can now span a union of frequency-by-time tiles. A rectangle cannot express a response that sweeps, so a chirp measured as one box mixes response with background; the test shows the diagonal recovering 1.0 where the enclosing rectangle reads under 0.35. Induced power gets its own function, with the caveat in the docstring that subtracting an average estimated from the same trials removes a 1/n share of the induced power too. Also fixes the R script that has never been able to read its own input: roi_evoked_analysis.R looked for evoked_measures.csv while Python has written roi_evoked_measures.csv since the roi_ rename, which is why autifony's roi_evoked results directories are empty. Six references corrected. No autifony re-run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
roi, electrode and vertex now share one config contract: n_cycles accepts a [lo, hi] ramp, a measure can span a union of tiles instead of one rectangle, and unknown types still warn and skip rather than failing. roi_evoked additionally gains the two measures that need the trials rather than the TF map: ERP amplitude and latency off the averaged waveform, and induced power from trials with the phase-locked average removed. Induced is computed only when a measure asks for it, since it doubles the TFR cost. Existing configs are unaffected — a scalar n_cycles and a band plus time_window behave exactly as before, so autifony's current measure set produces the same numbers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ITC is biased upward at low trial counts: pure noise gives roughly 1/sqrt(n). Measured here, noise-only ITC runs 0.199 at 20 trials against 0.044 at 400, so subjects with different trial counts are not on the same scale and a group difference can be a trial-count difference. Autifony's counts vary by subject and paradigm, and Sentinel is repeated-measures across four timepoints where they will vary by session too. debias_itc works on the squared quantity where the bias is exactly 1/n, and clips at zero rather than going imaginary, which is the honest answer for an ITC at or below chance. Debiased noise reads 0.0000 at every trial count tested. Offered as itc_debiased alongside raw itc rather than replacing it, so existing measure sets are untouched. Also reproduces the lab's Rayleigh rcrit for comparability, with a docstring making clear it answers a different question: it is a significance threshold, not a bias correction, and it is zeroed for mouse MEA in their pipeline in any case. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…empty run as success roi_evoked gated induced power on self._needs_induced(measures). The call site shipped in 5c3e884; the method did not. Every subject of a 26-subject chirp run raised AttributeError. The second half is worse than the first. Per-subject exceptions are caught and logged so one bad recording cannot sink a run, which is right. But with every subject failing, aggregate found nothing to write, logged a single warning, and the CLI printed "Done. Output: ..." and exited 0. The failure was visible only in the log body, and the absent CSV was the first real signal. So a run where every subject failed now raises, on the serial and the parallel path alike. Partial failure stays tolerated — that distinction is the whole point: some subjects failing is data, all of them failing is code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The electrode module implemented ITC, ERSP and STP and warned-and-skipped 'erp' and 'induced', so a config that meant thirteen measures to roi_evoked meant nine to electrode_evoked. Comparing the two arms then compared whatever happened to overlap. Both are ports of the roi implementation against the per-channel trials rather than the per-ROI ones: induced power from trials with the phase-locked average removed, computed only when a measure asks for it, and ERP amplitude and latency off the trial-averaged waveform. _needs_induced moves to BaseAnalysis. It was on ROIEvokedAnalysis alone, which is how the two modules came to read the same config differently in the first place; one copy is one chance to disagree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
5 commits, 9 files, +3,118/−40. 163 tests pass.
What this is for
Ports the 22-column evoked measure set used for the auditory paradigms (40 Hz
ASSR, 80 Hz ASSR, chirp), so
roi_evoked,vertex_evokedandelectrode_evokedall speak the same measure vocabulary and a source arm can becompared against the sensor array on identical definitions.
The measure set is ported verbatim from its MATLAB lineage, with defects
flagged in place rather than repaired — a deliberate decision, so that results
stay comparable to the prior work while the known problems are visible. Two are
documented at their definitions: a chirp offset window that falls outside the
epoch and therefore yields NaN, and gamma band edges that differ between the
source scripts.
What's in it
30c172d)5c3e884) so roi / vertex /electrode share definitions
f7251b9) — ITC is biased upwardat low trial counts, which matters when paradigms differ in trials retained
d4a9126), which is what makesit a fair comparator rather than a spectral-only one
Defects fixed
d0c7909fixes two that travelled together and were found the hard way:roi_evokedcalledself._needs_induced(...), a method that was neverwritten. Every subject of a 26-subject chirp run failed on
AttributeError.one bad recording cannot sink a run, but with every subject failing,
aggregate wrote nothing, logged one warning, and the CLI printed "Done".
The second is the more serious of the two. A run where every subject fails now
raises, on both the serial and parallel paths; partial failure is still
tolerated. Both carry regression tests.
Usage note
These measures are consumed by a sibling method-development workspace that
compares source spaces on auditory evoked responses. Nothing here depends on
that workspace, but the measure definitions are what make its arms comparable,
so changing a definition silently invalidates cross-arm results.
🤖 Generated with Claude Code