ionique.utils

The utils module provides preprocessing tools, feature extraction, and helper utilities.

Preprocessing:

  • Filter — frequency-domain filtering (lowpass, highpass, bandpass, bandstop)

  • ClockFilter — clock-tone removal via sine-wave subtraction

  • Trimmer — removes edge samples from segments at a given rank

Feature extraction:

  • extract_features() — collects segment statistics into a pandas DataFrame

Helpers:

  • split_voltage_steps() — detects voltage transitions and returns boundaries

  • si_eval() — parses SI-prefixed value strings (e.g. "1.5 mV"0.0015)

  • Singleton — metaclass for singleton pattern

  • ignored() — context manager to suppress specific exceptions

See Signal Preprocessing and Signal Analysis for usage examples.

Signal Processing and Data Extraction Utilities

This module provides a set of utility functions and classes designed for use in signal processing workflows.

These tools are intended for both internal processing and external use cases such as analysis pipelines and API integrations.

class ionique.utils.ClockFilter(clock_frequency: float, section_length: float = 0.5, sampling_frequency: float = None)

Bases: object

Remove a single periodic clock frequency from a signal by sine-wave subtraction.

If the power spectral density of a signal contains a very narrow and sharp peak at one frequency caused by EMF interference from a digital signal, this filter can eliminate its effect. Unlike a notch filter, it subtracts a phase-matching sine wave of the exact frequency from the signal. For multiple clock frequencies or harmonics, apply once per frequency. Can be used before, after, or without low-pass filtering.

Parameters:
  • clock_frequency (float) – Clock frequency to be removed, in Hz.

  • section_length (float, optional) – Length of sections in seconds to use for noise estimation. Each section is filtered independently. Defaults to 0.5.

  • sampling_frequency (float, optional) – Sampling frequency of the signal in Hz.

__init__(clock_frequency: float, section_length: float = 0.5, sampling_frequency: float = None) None
clock_frequency: float
sampling_frequency: float = None
section_length: float = 0.5
class ionique.utils.Filter(cutoff_frequency: float, filter_type: Literal['lowpass', 'highpass', 'bandpass', 'bandstop'], filter_method: Literal['butter', 'bessel'] = 'butter', order: int = 2, bidirectional: bool = True, sampling_frequency: float = None)

Bases: object

Apply low-pass, high-pass, band-pass, or band-stop filters using SOS form.

Filters are implemented using second-order sections (SOS) for numerical stability and can be applied in either forward-only or bidirectional mode.

Parameters:
  • cutoff_frequency (float or list[float]) – The cutoff frequency or frequency band for the filter in Hz. For band filters, provide a list of [low, high] values.

  • filter_type (Literal["lowpass", "highpass", "bandpass", "bandstop"]) – The type of filter to apply.

  • filter_method (Literal["butter", "bessel"], optional) – The filter design method. Supported options: “butter” (Butterworth) and “bessel”. Defaults to “butter”.

  • order (int, optional) – The order of the filter. Must be >= 1. Defaults to 2.

  • bidirectional (bool, optional) – If True, applies filtering forward and backward using sosfiltfilt. If False, uses causal sosfilt. Defaults to True.

  • sampling_frequency (float, optional) – Sampling frequency of the signal in Hz.

sos

Second-order sections representation of the filter, computed after initialization when sampling_frequency is provided.

Type:

numpy.ndarray

__init__(cutoff_frequency: float, filter_type: Literal['lowpass', 'highpass', 'bandpass', 'bandstop'], filter_method: Literal['butter', 'bessel'] = 'butter', order: int = 2, bidirectional: bool = True, sampling_frequency: float = None) None
bidirectional: bool = True
cutoff_frequency: float
filter_method: Literal['butter', 'bessel'] = 'butter'
filter_type: Literal['lowpass', 'highpass', 'bandpass', 'bandstop']
order: int = 2
sampling_frequency: float = None
class ionique.utils.Singleton(*args, **kwargs)

Bases: type

Generic singleton metaclass.

This metaclass ensures the same return every time the class is instanced.

__init__(*args, **kwargs)

Initialize the metaclass and set the singleton instance to None.

Parameters:
  • args (tuple) – Arguments for the class.

  • kwargs (dict) – Keyword arguments for the class.

class ionique.utils.Trimmer(samples_to_remove: int, rank: str = 'vstep', newrank: str = 'vstepgap')

Bases: object

Segment trimming utility for hierarchical signal data.

Traverses segments of a given rank and trims a fixed number of samples from the start of each segment. The resulting trimmed segments are added as new child segments with a specified new rank. Useful when initial samples of each segment contain artifacts that should be excluded from analysis.

Parameters:
  • samples_to_remove (int) – Number of samples to trim from the beginning of each segment.

  • rank (str, optional) – The hierarchical rank of segments to target for trimming. Defaults to “vstep”.

  • newrank (str, optional) – The rank name to assign to newly created trimmed child segments. Defaults to “vstepgap”.

__init__(samples_to_remove: int, rank: str = 'vstep', newrank: str = 'vstepgap') None
newrank: str = 'vstepgap'
rank: str = 'vstep'
samples_to_remove: int
ionique.utils.extract_features(seg, bottom_rank, extractions: list[str], add_ons: dict = {}, lambdas={})

Extract features from hierarchical segments into a DataFrame.

Traverses a hierarchical segment structure down to bottom_rank, then collects feature values from each segment. Static features are retrieved via get_feature(), constants can be added via add_ons, and custom computed features can be provided through lambdas.

This is useful for generating structured datasets from annotated traces for statistical analysis or machine learning.

Parameters:
  • seg (object) – The root segment or trace object containing a hierarchical structure. Must implement traverse_to_rank() and support get_feature().

  • bottom_rank (str) – The rank name of the lowest-level segments from which to extract features.

  • extractions (list[str]) – List of feature names to extract directly using get_feature() on each segment. Common examples include: ‘mean’, ‘frac’, ‘duration’, ‘baseline’, ‘current’, ‘wrap’, ‘start’.

  • add_ons (dict, optional) – A dictionary of fixed key-value pairs to include as constant columns in the resulting DataFrame.

  • lambdas (dict, optional) – A dictionary mapping column names to lambda functions that compute derived values from each segment.

Returns:

A DataFrame where each row corresponds to a bottom-rank segment and columns represent extracted and computed features.

Return type:

pandas.DataFrame

Examples

>>> df = extract_features(
...     seg,
...     bottom_rank='event',
...     extractions=['mean', 'frac', 'duration', 'baseline', 'current', 'wrap', 'start'],
...     add_ons={"sample_type": "MBP_D10"},
...     lambdas={
...         "Voltage": lambda seg: int(1000 * seg.get_feature("voltage")),
...         "start_time": lambda seg: seg.start / seg.get_feature("eff_sampling_freq"),
...     },
... )
ionique.utils.si_eval(value, unit=None, return_unit=False)

Evaluate and convert a value with an SI unit prefix to its numeric base value.

This function handles both string-based and numeric values with SI (International System of Units) prefixes such as “k” (kilo), “M” (mega), “μ” (micro), etc. It multiplies the input value by the appropriate factor based on the SI prefix.

This utility is useful when parsing human-readable measurement strings or standardizing units across data pipelines that mix strings and numeric formats.

Parameters:
  • value (str or float) – The value to be converted. Can be a string like “1.2 kHz” or a numeric value (int or float).

  • unit (str, optional) – The unit string (e.g., “kHz”, “mV”). Required only if value is a numeric type.

  • return_unit (bool, optional) – If True, returns a tuple containing the converted numeric value and the base unit (e.g., ‘Hz’). If False, only the numeric value is returned.

Returns:

The converted value, optionally paired with the base unit.

Return type:

float or tuple[float, str]

Raises:
  • ValueError – If the input format is invalid or the unit is missing for numeric input.

  • TypeError – If the value is neither a string nor a numeric type.

ionique.utils.split_voltage_steps(voltage: ndarray, n_remove=0, as_tuples=False)

Split a voltage signal into segments based on step changes.

This function detects changes in the voltage signal and splits it into individual segments (or steps) wherever a change in value occurs. It is useful in analyzing stepwise voltage protocols.

Optionally, a number of initial samples can be removed from each segment using the n_remove parameter. The output can either be two separate arrays of start and end indices, or a list of tuples representing each segment.

Parameters:
  • voltage (numpy.ndarray) – 1D voltage signal array to be segmented.

  • n_remove (int, optional) – Number of samples to remove from the start of each split. Defaults to 0.

  • as_tuples (bool, optional) – If True, returns a list of (start, end) index tuples. If False, returns two arrays: start_indices and end_indices. Defaults to False.

Returns:

Either a tuple of (start_indices, end_indices) where each is a numpy array of indices, or a list of (start, end) tuples if as_tuples=True.

Return type:

tuple[numpy.ndarray, numpy.ndarray] or list[tuple[int, int]]

Raises:

ValueError – If n_remove is negative or larger than the start of the voltage changes.