Skip to content

Conversation

@possibly-human
Copy link
Contributor

Summary

Adds a flexible rate-of-change (derivative) calculator for real-time signals. The module supports two windowing strategies—fixed sample count or fixed time window—and provides multiple output unit options. In time window mode, the last known value is held constant when no new data arrives, ensuring continuous output. Diagnostic outputs expose the internal window state for debugging and analysis.

Functionality

Input is:

  • Signal (int or float) — input signal to analyze

Parameters are:

  • Window mode (enum) — SampleCount (fixed number of samples) or TimeWindow (fixed duration)
  • Sample count (int) — number of most recent samples to use (visible in SampleCount mode, minimum 2)
  • Time window (float) — duration in seconds to use (visible in TimeWindow mode, 0.001–3600s)
  • Output units (enum) — per millisecond, per second, per minute, or per hour

Outputs are:

  • Rate (float) — computed rate of change in selected units
  • Samples in window (int) — current number of samples in analysis window
  • Window time span (float) — actual time span covered by window

Implementation notes

  • Sample count mode: Uses ring buffer to store N most recent samples
  • Time window mode: Automatically adjusts window to requested time span; holds last value when data is sparse
  • Rate calculation: Derivative computed as (newest − oldest) / sum(dt) with unit conversion
  • Performance: O(1) operations with configurable buffer capacity (1M samples max)

@possibly-human
Copy link
Contributor Author

Testing

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

Once with an expression value generator :
stable rate of change
stable_rate_of_change

changing rate of change
changing_rate_of_change.webm

Example file : https://drive.google.com/file/d/1m3JYEtMVVxy1xB6bwtAg25Uz6f__wSGL/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 Rate of change object was compared to output from processing with similar algorithms in python, with the same parameters.
rate of change with live data
rate_of_change_livedata

Example file : https://drive.google.com/file/d/14Kgu6Ltq5tnpljXwV_a8uOMfd2DTg--3/view?usp=sharing

output
rate_comparison

Python file
roc.py

@jcelerier jcelerier self-requested a review December 9, 2025 02:42
Copy link
Member

@jcelerier jcelerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great work thanks!
I have a couple comments but those can be addressed without issue in later PRs

};

// ring buffer storage
std::vector<Sample> _buf;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's already an unholy amount of different ring buffer implementations in ossia :p
What do you think about reusing the boost one? https://www.boost.org/doc/libs/latest/doc/html/circular_buffer.html

void update_window_from_params();

// parameter watchers
halp::ParameterWatcher<int> sample_count_watcher;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to think about a way to do parameter watching without requiring you to make your own class. What are the features you need from it ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically just to indicate when the parameter's value has changed

@jcelerier jcelerier force-pushed the feature/RateOfChange branch from 5894273 to 222c877 Compare December 12, 2025 17:56
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