mne_rt.protocols.LinearTrendProtocol#

class mne_rt.protocols.LinearTrendProtocol(direction: str = 'up', window: int = 20, slope_threshold: float = 0.0, min_r2: float = 0.0, warmup_windows: int | None = None, smoothing: float = 0.0)#

Bases: object

Reward protocol that detects a statistically significant NF trend.

Instead of rewarding for exceeding a fixed threshold at a single time point, this protocol fits an ordinary least-squares (OLS) line through the last window NF values and issues a reward when:

  1. The fitted slope is in the target direction and exceeds slope_threshold in absolute value, and

  2. The regression goodness-of-fit R² ≥ min_r2 (optional quality gate — set to 0.0 to disable).

This is particularly useful in clinical neurofeedback where participants may not reach a threshold in every window but should be encouraged for sustained directional change across multiple windows.

Parameters:
direction{“up”, “down”}

“up” -> reward when the slope is positive (signal trending upward). “down” -> reward when the slope is negative (signal trending downward). Default is "up".

windowint

Number of most-recent NF values used for each regression. Must be ≥ 3. Larger values give more stable estimates but react more slowly. Default is 20.

slope_thresholdfloat

Minimum absolute slope (in NF-signal units per sample) required to issue a reward. Set to 0.0 to reward any trend in the right direction. Default is 0.0.

min_r2float

Minimum coefficient of determination (R²) of the OLS fit required before a reward is issued. Values in [0.0, 1.0]. Set to 0.0 to disable the quality gate. Default is 0.0.

warmup_windowsint

Evaluations needed to fill the history buffer before rewards can be issued. Must be ≥ window. Defaults to window.

smoothingfloat

EMA smoothing coefficient applied to the raw input before adding to history. 0.0 disables smoothing. Default is 0.0.

Raises:
ValueError

If any parameter is outside its valid range.

Notes

The OLS slope and R² are computed analytically (no external libraries needed) in O(window) time per evaluation.

magnitude returned by evaluate() is the absolute slope divided by the running standard deviation of the history buffer, giving a dimensionless measure of trend strength.

Examples

Reward sustained alpha-power increase over the last 20 windows:

proto = LinearTrendProtocol(direction="up", window=20)
for value in nf_stream:
    crossed, magnitude = proto.evaluate(value)
    if crossed:
        send_reward(magnitude)

Require a clear trend (R² ≥ 0.5) with a non-trivial slope:

proto = LinearTrendProtocol(
    direction="up",
    window=15,
    slope_threshold=0.01,
    min_r2=0.5,
)

Added in version 1.0.0.

__init__(direction: str = 'up', window: int = 20, slope_threshold: float = 0.0, min_r2: float = 0.0, warmup_windows: int | None = None, smoothing: float = 0.0) None[source]#

Methods

__init__([direction, window, ...])

evaluate(value)

Evaluate one NF value and return (crossed, magnitude).

reset()

Clear history and counters, preserving all constructor parameters.

Attributes

n_evaluated

Total number of values evaluated since init or last reset().

r2

R² from the most recent evaluate() call (0.0 before warmup).

slope

OLS slope from the most recent evaluate() call (0.0 before warmup).

evaluate(value: float) tuple[bool, float][source]#

Evaluate one NF value and return (crossed, magnitude).

Parameters:
valuefloat

Current NF feature value.

Returns:
crossedbool

True when all of the following hold: * warmup is complete, * the OLS slope is in the target direction and ≥ slope_threshold, * R² ≥ min_r2.

magnitudefloat

Absolute slope normalised by the history standard deviation (dimensionless trend strength). 0.0 when not crossed.

property n_evaluated: int#

Total number of values evaluated since init or last reset().

property r2: float#

R² from the most recent evaluate() call (0.0 before warmup).

reset() None[source]#

Clear history and counters, preserving all constructor parameters.

property slope: float#

OLS slope from the most recent evaluate() call (0.0 before warmup).