Skip to content

Conversation

@possibly-human
Copy link
Contributor

@possibly-human possibly-human commented Nov 4, 2025

Summary

Adds an adaptive normalization utility for real-time signals. The module continuously tracks running mean/variance (either cumulatively or via an EMA time window) and remaps the input to a configurable target mean and target standard deviation. Optional clamping enforces bounded output (± N·stddev). The object also reports raw stats, outlier flags, and coefficient of variation (CV).
Adapted from Sofian Audry’s Plaquette implementation.

Functionality

Inputs are :

  • Signal(int or float)

Parameters are :

  • Target mean (float) — desired output mean
  • Target std dev (float) — desired output standard deviation
  • Time window (s) (float) — EMA window for stats; dt inferred per tick; 0 / toggle → infinite
  • Infinite time window (bool) — cumulative mode (no decay)
  • Clamp output (bool) — enables bounding around target mean
  • Clamp max (N·stddev) (float) — clamp range
  • Outlier threshold (N·stddev) (float) — outlier detection

Outputs are :

  • Normalized signal (float) — remapped normalized signal
  • Mean (float) — current running mean
  • Standard deviation (float) — current stddev
  • Outlier (bool) — true when outside ± N·stddev
  • Coefficient of variation (float) — computed as stddev / mean (only valid for strictly positive signals, returns zero when mean approaches zero)

Implementation notes

Uses a Normalizer custom class stored in 3rdparty/extras (to be reused in Respiration and EDA processes)

@possibly-human
Copy link
Contributor Author

possibly-human commented Nov 4, 2025

Testing

Was tested on Linux (booted on a T2 chip, 2019 MacBook Pro)

Once with an LFO generator :
infinite time window
normalizer_infinite

finite time window (adaptative)
normalizer_finite.webm

Example file : https://drive.google.com/file/d/1ryieEqn7UM2S7t2LLmeQG7Vb0iSdmWcK/view?usp=sharing

And once with live data from Sensors2OSC (device orientation). The live data was then recorded and saved with CSV recorder, and output from the Normalization object was compared to output from processing with similar algorithms in python, with the same parameters.
normalization with live data
normalizer_live-data

Example file : https://drive.google.com/file/d/1a6dN9KJCxtB1KbLclHHTybtI6wkMDIU0/view?usp=sharing

normalization object output
from_file

python output
from_python

(Differences are due to the fact that recording of the csv file doesn't start exactly when the ossia sketch starts running)

Python file
normalizer.py

@possibly-human
Copy link
Contributor Author

possibly-human commented Nov 4, 2025

Questions
-Here, we are using a time window (tau) to affect EMA alpha. Should we have a version that takes “number of samples” or takes an array of data as input? Ongoing discussion about live vs offline data processing – (added to User notes document)
-Should we add a freeze/calibrate toggle? To allow users to capture a stable baseline by locking the current mean and standard deviation. This exists in Plaquette (resumeCalibrating() and pauseCalibrating()).

@jcelerier jcelerier self-requested a review November 5, 2025 20:25
@jcelerier
Copy link
Member

I assume this PR is not necessary anymore since it's in the Rate of Change one?

@possibly-human
Copy link
Contributor Author

I assume this PR is not necessary anymore since it's in the Rate of Change one?

wrote to you in slack (basically, not sure if there are differences in the two versions.. if so, this Normalizer specific PR is the correct version)

@possibly-human possibly-human merged commit 6a2f9be into master Dec 12, 2025
6 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants