SpeedyStatSplit

SpeedyStatSplit is a variance-based recursive segmentation algorithm optimized in Cython. It finds boundaries where the signal’s statistical properties change — making it ideal for resolving multi-level current sub-states within already-detected events.

Note

SpeedyStatSplit is not an event detector. Use an event detector (AutoSquareParser, SpikeParser, or lambda_event_parser) first to find translocation events, then apply SpeedyStatSplit to segment current levels within those events.

The algorithm recursively splits a signal at the point that maximizes the reduction in total variance, stopping when segments are too narrow or the gain is below a threshold.

Typical two-stage workflow:

from ionique.parsers import AutoSquareParser, SpeedyStatSplit

# Stage 1: detect blockade events
detector = AutoSquareParser(threshold_baseline=0.7, expected_conductance=1.9)
trace.parse(detector, newrank="event", at_child_rank="vstep")

# Stage 2: segment sub-states within each event
splitter = SpeedyStatSplit(
    sampling_freq=100000,
    min_width=100,
    window_width=10000,
)
trace.parse(splitter, newrank="state", at_child_rank="event")

Parameters

Parameter

Default

Description

sampling_freq

(required)

Sampling frequency in Hz.

min_width

100

Minimum segment width in samples. Segments shorter than this will not be split further. Controls over-segmentation.

max_width

1000000

Maximum segment width in samples.

window_width

10000

Sliding window width for split-point search. Larger values detect broader features; smaller values detect finer changes.

min_gain_per_sample

None

Legacy threshold: minimum log-likelihood gain per sample to accept a split. Set this or false_positive_rate, not both.

false_positive_rate

None

Expected false positive splits per second. Automatically calculates the gain threshold.

prior_segments_per_second

None

Prior expected segment rate for Bayesian threshold calculation.

cutoff_freq

None

Apply a lowpass filter at this frequency before splitting.

Parameter sensitivity

min_width

Controls the minimum size of detected segments. Small values allow fine-grained splitting but risk over-segmentation on noise. Large values merge adjacent states.

SpeedyStatSplit min_width parameter comparison
# Fine-grained: resolve brief sub-states within events
parser = SpeedyStatSplit(sampling_freq=100000, min_width=50)

# Coarse: only detect major current-level changes
parser = SpeedyStatSplit(sampling_freq=100000, min_width=3000)

window_width

The window within which split candidates are evaluated. Affects the scale of detectable transitions.

SpeedyStatSplit window_width parameter comparison

Sensitivity tuning

The overall sensitivity depends on the interaction between min_width and the gain threshold (set via false_positive_rate or min_gain_per_sample).

SpeedyStatSplit sensitivity comparison
# High sensitivity — resolve small, brief sub-states
splitter = SpeedyStatSplit(
    sampling_freq=100000,
    min_width=50,
    false_positive_rate=10.0,
)

# Low sensitivity — only split on large, clear level changes
splitter = SpeedyStatSplit(
    sampling_freq=100000,
    min_width=1500,
    false_positive_rate=0.01,
)

Full example

SpeedyStatSplit full segmentation example
from ionique.parsers import AutoSquareParser, SpeedyStatSplit

# First detect events
detector = AutoSquareParser(threshold_baseline=0.7, expected_conductance=1.9)
trace.parse(detector, newrank="event", at_child_rank="vstep")

# Then segment sub-states within each event
splitter = SpeedyStatSplit(
    sampling_freq=100000,
    min_width=200,
    window_width=10000,
)
trace.parse(splitter, newrank="state", at_child_rank="event")

states = trace.traverse_to_rank("state")
print(f"Resolved {len(states)} sub-states across all events")

for st in states[:5]:
    print(f"  [{st.start}:{st.end}] mean={st.mean:.3f}, std={st.std:.4f}")

Additional methods

SpeedyStatSplit exposes lower-level methods through its Cython backend:

# Get MetaSegment objects directly (more memory-efficient)
segments = parser.parse_meta(current_array)

# Find the single best split point
best_index = parser.best_single_split(current_array)

Tip

SpeedyStatSplit works best on segments that already contain a single blockade event with multi-level structure. Running it directly on a full voltage step will segment the entire signal (baseline + events together), which is usually not what you want. Detect events first, then split within them.