Add pulse/cycle segmentation, audio–motion alignment, QoM cores, and audio event features#351
Merged
Merged
Conversation
…ulse) Add two plain-numpy signal modules following the _analysis.py convention (standalone functions, explicit __init__ exports, lazy scipy imports): - _peaks.pick_peaks: the ONE canonical adaptive peak-picker (moving-average smoothing, relative/absolute threshold, minimum inter-peak interval, optional prominence gate) shared by all sound-motion modules in this series. Reimplemented from the cymbal-comparison paper's method prose; its default constants are documented as provisional because the paper and its deposited JSON summaries disagree on some values. - _pulse: DP-based grouping of stroke onsets into per-cycle groups (group_strokes, ported faithfully from the ro study, including the honest caveat that the carried EMA estimate is not part of the DP state), segment_cycles/Cycle/cycle_table, exponential accelerando fitting (fit_accelerando, array-based), and motion_onsets (steepest sustained rises of a motion signal), which routes through pick_peaks. Tests use synthetic ground truth only, adapting the ro study's make_ro generator (tests/_synth.py); the deep-accelerando case (25 cycles, shrinking stroke gap) requires >=95% double-group recovery. Source studies: ro; cymbal comparison (Jensenius). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
One QoM surface unifying the band-limited QoM cores that were duplicated across the stillstanding and Westney-comparisons studies (mocap markers, MediaPipe landmarks, slow postural sway): - band_limited_qom: zero-phase band-pass + speed, with an automatic decimate+SOS regime for very low bands (the "slow sway" case) where a direct high-order band-pass is numerically fragile - accel_to_speed: high-pass, integrate, high-pass accelerometer-to-speed (the stillstanding "corpus method"), with optional gravity normalisation - group_qom / pose_qom: per-body-part QoM over marker/landmark groups - body_scale / normalized_qom: median torso length and framing-invariant, dimensionless QoM (body-lengths/s) - grid_qom: spatial grid QoM heatmap + per-cell series - envelope / bin_series: smoothed z-scored envelopes and binned means Tests use synthetic trajectories with analytically known speeds and band content, including a 2x zoom simulation that must leave normalized_qom invariant, and a decimation-regime check for the low band. Source studies: stillstanding; Westney comparisons (Jensenius). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
Stream-to-stream alignment methods for signals and event lists: - xcorr_lag: canonical vectorized lead/lag estimate (scipy.signal.correlate/correlation_lags), normalized, preferring the smallest-|lag| candidate among near-ties so periodic envelopes do not alias; envelope_lag is kept as a thin wrapper preserving the ro study's interface, unifying the two studies' implementations - per_cycle_motion_delta: nearest-to-start motion-onset assignment with descending-order dedup over overlapping lookback windows (ported faithfully from the ro study, semantics documented in the docstring) - anchor_and_match + offset_stats: per-take relative event alignment for streams with independent clocks (anchor the strongest events at t=0, match the rest within a window; no absolute sync claim); the 0.15 s window is a provisional default reimplemented from the cymbal paper - sliding_correlation: windowed local coupling profile - envelope_agreement: N-source envelope correlation matrix (cross-view agreement), built on _qom.envelope Tests: known 0.3 s envelope shift recovery, periodic smallest-lag preference, synthetic offset events for anchor_and_match, and a built-in coupling change profiled by sliding_correlation. Source studies: ro; cymbal comparison; Westney comparisons (Jensenius). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
Plain-numpy audio descriptors complementing the librosa-based, figure-producing MgAudio methods with lightweight numeric outputs (a new module rather than MgAudio methods, following the grain of the _analysis.py plain-function convention; MgAudio methods return MgFigures, these return arrays/floats): - rms_envelope: windowed RMS energy envelope - spectral_flux / spectral_flux_onsets: positive-STFT-difference onset detection function, peak-picked with the canonical pick_peaks at an adaptive mean+std threshold - energy_onsets: RMS-envelope half-wave-rectified-difference onsets (0.15 x peak / 0.06 s provisional defaults from the cymbal paper) - t60_backward_decay: ISO-3382-style backward-decay reverberation time (-5..-35 dB span, -5..-25 fallback, 6 dB re-rise stop; provisional defaults reimplemented from the cymbal paper's prose) - attack_spectral_centroid: energy-weighted STFT centroid over the first 120 ms after the envelope peak Tests: click trains with known onset times, synthetic exponential decays with exact T60 (including the T20-fallback path), and bright-vs-dark attack ordering. Source studies: cymbal comparison; Westney comparisons (Jensenius). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
Add a numpy-level motiongram core to _motionanalysis with a selectable orientation: the "vertical" (per-row mean, image row vs time) variant renders vertical trajectories -- e.g. a mallet's approach-and-rebound path -- directly, as used in the cymbal-comparison study; "horizontal" gives the per-column collapse. The existing image-producing pipelines (MgVideo.motiongrams and the ffmpeg videograms) already render both collapses as PNGs; what they do not offer is the motiongram as data on a chosen axis for further analysis, which is what the source study needed, so the orientation option is exposed here at the array level (with the mapping to the _mgh/_mgv outputs documented). A frame_diff=False mode yields the corresponding videogram. Tests: a synthetic falling-bar frame stack whose vertical motiongram ridge must descend monotonically, while its horizontal motiongram is uniform across columns. Source study: cymbal comparison (Jensenius). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
…ng accuracy) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
alexarje
added a commit
that referenced
this pull request
Jul 16, 2026
Add a README section and a new user-guide page for the newly merged _peaks/_pulse/_alignment/_qom/_audiofeatures/_posture/_physio/_mocap/ _posetools modules (pulse/cycle segmentation, cross-modal alignment, body-scale-normalized QoM, posturography, physiology features, mocap I/O, and pose-landmark trajectory extraction), with runnable code snippets and provenance notes (ro / stillstanding / Westney / cymbal studies) and the new [pose] extra. Regenerate the handsdown API-reference stubs (docs/musicalgestures/*.md, docs/MODULES.md) to add pages for the nine new modules and pick up docstring drift already present at HEAD (motiongram_data orientation option, motiondescriptors fmin/fmax). Add a short runnable example to docs/examples.md and a matching CHANGELOG entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0147io2kMk8M6jcNFNt1G96m
This was referenced Jul 17, 2026
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.
This PR adds a family of scipy-only analysis modules developed across several sound–motion studies (the "ro" World Cup supporter-ritual study, the Westney performance comparisons, the stillstanding project, and a cymbal-strike comparison):
_peaks.py— one canonical adaptive peak-picker (pick_peaks) used by every onset/event detector in this PR (de-duplicating what were previously several near-identical pickers across studies)._pulse.py— drum-stroke/cycle segmentation via dynamic programming over group boundaries (robust to accelerating pulse trains where EMA-threshold groupers fail), accelerando fitting (IOI(t) = IOI₀·2^(−t/T)), and motion-onset detection._alignment.py— lead/lag estimation (xcorr_lag,envelope_lag), per-cycle motion–onset assignment with one-to-one claim semantics, anchor-and-match cross-modal event alignment, sliding-window coupling profiles, and N-source envelope agreement matrices._qom.py— unified quantity-of-motion cores: band-limited QoM (with an automatic decimate+SOS regime for very low bands), acceleration→speed, pose-landmark QoM, body-scale normalization (framing-invariant motion), spatial grid QoM, envelopes and binning._audiofeatures.py— spectral-flux and energy onsets, ISO-3382-inspired backward-decay reverberation estimate, attack spectral centroid.motiongram_datagains a vertical/horizontal orientation option.66+ new tests, all synthetic-ground-truth (no media fixtures); full suite has no new failures. Some defaults ported from a study without archived source code are parameterized and flagged provisional in the docstrings. Each public function carries a
Source:note naming its study of origin. All ported code is the author's own (self-port; no third-party code).Companion paper: "Ro! Rhythmic entrainment in a Norwegian World Cup supporter ritual" (arXiv link to follow).
🤖 Generated with Claude Code