Signal Quality Indices (vital_sqi.sqi)

The SQI catalogue. Each submodule groups SQIs by the domain in which they are computed (statistical, frequency, heart-rate, template-matching, etc.).

Standard statistical SQIs

Signal Quality Index (SQI) calculations for photoplethysmogram (PPG) signals.

These SQIs are based on the paper by Elgendi, Mohamed: “Optimal Signal Quality Index for Photoplethysmogram Signals”, Bioengineering.

vital_sqi.sqi.standard_sqi.baseline_wander_sqi(signal, sampling_rate=100)[source]

Quantify low-frequency baseline drift relative to total signal energy.

Baseline wander (< 0.5 Hz) is caused by respiration, motion, and electrode movement. High baseline wander indicates a noisy recording. The metric is the ratio of LF STFT energy to total STFT energy.

Parameters:
  • signal (array_like) – Input signal.

  • sampling_rate (int, optional) – Sampling frequency in Hz (default 100).

Returns:

Ratio of energy below 0.5 Hz to total energy, in [0, 1]. Returns np.nan if total energy is zero or the signal is too short.

Return type:

float

vital_sqi.sqi.standard_sqi.clipping_sqi(signal, eps_pct=0.001)[source]

Estimate the fraction of samples at or near the signal’s amplitude rail.

Clipped or saturated sensors produce runs of samples stuck at the minimum or maximum value. A clean signal should have fewer than ~1% clipped samples; heavily saturated signals can exceed 5-10%.

Parameters:
  • signal (array_like) – Input signal.

  • eps_pct (float, optional) – Tolerance as a fraction of the peak-to-peak range used to define “near the rail” (default 0.001, i.e. 0.1% of range).

Returns:

Fraction of samples in [0, 1] that are within eps_pct of the minimum or maximum value. Returns 0.0 for constant signals and np.nan for empty input.

Return type:

float

vital_sqi.sqi.standard_sqi.entropy_sqi(x, qk=None, base=None, axis=0)[source]

Calculates the entropy of the signal, representing the randomness in the data distribution.

Parameters:
  • x (array_like) – Input signal.

  • qk (array_like, optional) – Array against which relative entropy is calculated (default is None).

  • base (float, optional) – Logarithmic base to use for entropy (default is None).

  • axis (int, optional) – Axis along which entropy is calculated (default is 0).

Returns:

Entropy value(s) of the signal.

Return type:

float or ndarray

vital_sqi.sqi.standard_sqi.kurtosis_sqi(x, axis=0, fisher=True, bias=True, nan_policy='propagate')[source]

Calculates the kurtosis of the signal, a measure of tail heaviness in a distribution.

Parameters:
  • x (array_like) – Input signal.

  • axis (int, optional) – Axis along which kurtosis is calculated (default is 0).

  • fisher (bool, optional) – If True, Fisher’s definition is used (default is True).

  • bias (bool, optional) – If False, the calculations are corrected for statistical bias (default is True).

  • nan_policy ({'propagate', 'omit', 'raise'}, optional) – Defines how to handle NaNs (default is ‘propagate’).

Returns:

Kurtosis value(s) of the signal.

Return type:

float or ndarray

vital_sqi.sqi.standard_sqi.mean_crossing_rate_sqi(y, threshold=1e-10, ref_magnitude=None, pad=True, axis=-1)[source]

Calculates the mean-crossing rate, the rate at which the signal crosses its mean value.

Parameters:
  • y (array_like) – Input signal.

  • threshold (float, optional) – Threshold for clipping values close to zero (default is 1e-10).

  • ref_magnitude (float, optional) – Reference magnitude for scaling threshold (default is None).

  • pad (bool, optional) – If True, y[0] is considered a valid crossing (default is True).

  • axis (int, optional) – Axis along which mean-crossing rate is calculated (default is -1).

Returns:

Mean-crossing rate of the signal.

Return type:

float

vital_sqi.sqi.standard_sqi.perfusion_sqi(x, y)[source]

Calculates the perfusion index, a measure of pulsatile blood flow relative to static blood flow.

Parameters:
  • x (array_like) – Raw PPG signal.

  • y (array_like) – Filtered PPG signal.

Returns:

Perfusion SQI, calculated as [(max(y) - min(y)) / abs(mean(x))] * 100.

Return type:

float

vital_sqi.sqi.standard_sqi.signal_to_noise_sqi(a, axis=0, ddof=0)[source]

Calculates the Signal-to-Noise Ratio (SNR) SQI, comparing signal level to noise level.

Parameters:
  • a (array_like) – Input signal.

  • axis (int, optional) – Axis along which SNR is calculated (default is 0).

  • ddof (int, optional) – Delta degrees of freedom for standard deviation (default is 0).

Returns:

SNR value(s) of the signal.

Return type:

float or ndarray

vital_sqi.sqi.standard_sqi.skewness_sqi(x, axis=0, bias=True, nan_policy='propagate')[source]

Calculates the skewness of the signal, a measure of asymmetry in a distribution.

Parameters:
  • x (array_like) – Input signal.

  • axis (int, optional) – Axis along which skewness is calculated (default is 0).

  • bias (bool, optional) – If False, calculations are corrected for statistical bias (default is True).

  • nan_policy ({'propagate', 'omit', 'raise'}, optional) – Defines how to handle NaNs (default is ‘propagate’).

Returns:

Skewness value(s) of the signal.

Return type:

float or ndarray

vital_sqi.sqi.standard_sqi.spectral_snr_sqi(signal, sampling_rate=100, signal_band=None)[source]

Estimate signal-to-noise ratio as in-band power over out-of-band power.

Uses the STFT to separate physiological-band energy from noise-band energy. Defaults assume a PPG signal (0.5-4 Hz physiological band). For ECG use signal_band=[0.5, 40].

Parameters:
  • signal (array_like) – Input signal.

  • sampling_rate (int, optional) – Sampling frequency in Hz (default 100).

  • signal_band (list of float, optional) – [low_hz, high_hz] of the physiological frequency band. Defaults to [0.5, 4.0] (PPG heart rate band).

Returns:

SNR in dB (10 * log10(in_band / out_of_band)). Returns np.nan if out-of-band power is zero or signal is too short.

Return type:

float

vital_sqi.sqi.standard_sqi.zero_crossings_rate_sqi(y, threshold=1e-10, ref_magnitude=None, axis=-1)[source]

Calculates the zero-crossing rate, the rate of sign changes in the signal.

Note

This counts crossings of the absolute zero level. For signals with a non-zero DC baseline (e.g. raw PPG/ECG), the signal may never cross zero, making this metric meaningless. Use mean_crossing_rate_sqi() instead, which subtracts the mean first.

Parameters:
  • y (array_like) – Input signal. Should be mean-centred before calling this function for physiologically meaningful results.

  • threshold (float, optional) – Threshold for clipping values close to zero (default is 1e-10).

  • ref_magnitude (float, optional) – Reference magnitude for scaling threshold (default is None).

  • axis (int, optional) – Axis along which zero-crossings are calculated (default is -1).

Returns:

Zero-crossing rate of the signal.

Return type:

float

Waveform / spectral SQIs

Implementation of waveform-based SQIs (Signal Quality Indices): - For ECG based on DiMarco2012. - For PPG (to be extended).

vital_sqi.sqi.waveform_sqi.band_energy_sqi(signal, sampling_rate=100, band=None, nperseg=2048)[source]

Compute the peak value of the time marginal of the energy distribution in a frequency band.

Parameters:
  • signal (array-like) – The input signal.

  • sampling_rate (int, optional) – Sampling rate of the signal. Default is 100 Hz.

  • band (list, optional) – Frequency band [low, high]. If None, the entire spectrum is used. Default is None.

  • nperseg (int, optional) – Length of each segment for the Short-Time Fourier Transform. Default is 2048.

Returns:

Maximum time marginal power in the specified frequency band.

Return type:

float

Raises:

AssertionError – If the band is not a valid list or has invalid values.

Example

>>> import numpy as np
>>> from vital_sqi.sqi.waveform_sqi import band_energy_sqi
>>> signal = np.sin(2 * np.pi * 0.01 * np.arange(1000))
>>> band_energy_sqi(signal, sampling_rate=100, band=[0.1, 0.5])
0.3141592653589793
vital_sqi.sqi.waveform_sqi.hf_energy_sqi(signal, sampling_rate, band=None)[source]

High-Frequency Energy SQI.

Parameters:
  • signal (array-like) – The input signal.

  • sampling_rate (int) – Sampling rate of the signal.

  • band (list, optional) – Frequency band [low_hz, high_hz]. Defaults to [100, np.inf]. For signals sampled at 100 Hz (Nyquist = 50 Hz) this band is above Nyquist and will always return 0; pass an appropriate band for the actual sampling rate (e.g. [20, 50] for 100 Hz data).

Returns:

High-frequency energy SQI.

Return type:

float

vital_sqi.sqi.waveform_sqi.lf_energy_sqi(signal, sampling_rate, band=[0, 0.5])[source]

Low-Frequency Energy SQI.

Parameters:
  • signal (array-like) – The input signal.

  • sampling_rate (int) – Sampling rate of the signal.

  • band (list, optional) – Frequency band. Default is [0, 0.5].

Returns:

Low-frequency energy SQI.

Return type:

float

vital_sqi.sqi.waveform_sqi.qrs_a_sqi(signal, sampling_rate)[source]

QRS Amplitude SQI.

Parameters:
  • signal (array-like) – The input ECG signal.

  • sampling_rate (int) – Sampling rate of the signal.

Returns:

Median peak-to-nadir amplitude difference of QRS complexes.

Return type:

float

Example

>>> signal = np.random.randn(1000)
>>> qrs_a_sqi(signal, sampling_rate=100)
0.75
vital_sqi.sqi.waveform_sqi.qrs_energy_sqi(signal, sampling_rate, band=[5, 25])[source]

QRS Energy SQI.

Parameters:
  • signal (array-like) – The input signal.

  • sampling_rate (int) – Sampling rate of the signal.

  • band (list, optional) – Frequency band. Default is [5, 25].

Returns:

QRS energy SQI.

Return type:

float

vital_sqi.sqi.waveform_sqi.vhf_norm_power_sqi(signal, sampling_rate, band=None, nperseg=2048)[source]

Very High-Frequency Normalized Power SQI.

Parameters:
  • signal (array-like) – The input signal.

  • sampling_rate (int) – Sampling rate of the signal.

  • band (list, optional) – Frequency band [low_hz, high_hz]. Defaults to [150, np.inf]. For signals sampled at 100 Hz (Nyquist = 50 Hz) this band is above Nyquist and will return NaN; pass a band within the Nyquist limit (e.g. [30, 50] for 100 Hz data).

  • nperseg (int, optional) – Length of each segment for the Short-Time Fourier Transform. Default is 2048.

Returns:

Normalized power in the very high-frequency band, or NaN if the band contains no STFT bins.

Return type:

float

R-peak based SQIs

Signal Quality Indexes based on R peak detection. This module includes various R peak detection-based metrics for evaluating ECG and PPG signals. Metrics: - Ratio of ectopic beats - Correlogram - MSQ: Consistency evaluation between two R-peak detectors - Interpolation-based SQI

vital_sqi.sqi.rpeaks_sqi.amplitude_consistency_sqi(s, sample_rate=100, wave_type='PPG', peak_detector=6)[source]

Measure beat-to-beat amplitude variability as a signal quality indicator.

High beat-to-beat variability in peak amplitude indicates motion artifact or poor electrode contact. The metric is the coefficient of variation (std / mean) of detected peak amplitudes. A clean signal has low CV (< 0.1); an artifact-corrupted signal has high CV (> 0.3).

Parameters:
  • s (array_like) – Raw waveform signal (PPG or ECG).

  • sample_rate (int, optional) – Sampling frequency in Hz (default 100).

  • wave_type (str, optional) – 'PPG' or 'ECG' (default 'PPG').

  • peak_detector (int, optional) – Peak detector index (default 6).

Returns:

Coefficient of variation of peak amplitudes, or np.nan if fewer than 2 peaks are detected.

Return type:

float

vital_sqi.sqi.rpeaks_sqi.correlogram_sqi(s, sample_rate=100, wave_type='PPG', time_lag=3, n_selection=3)[source]

Compute the Correlogram SQI from the autocorrelation function (ACF).

The ACF is computed up to time_lag seconds. The top n_selection ACF peaks are selected and their mean is returned as a single quality score. A high score (close to 1) indicates a highly periodic signal; a low score indicates poor periodicity or noise.

Parameters:
  • s (array-like) – Raw waveform signal (PPG or ECG).

  • sample_rate (int, optional) – Sampling frequency in Hz (default 100).

  • wave_type (str, optional) – 'PPG' or 'ECG' (default 'PPG'). Currently unused but retained for API consistency with other SQI functions.

  • time_lag (int, optional) – Duration in seconds over which ACF is computed (default 3). The signal must be at least time_lag * sample_rate samples long.

  • n_selection (int, optional) – Number of top ACF peaks to average (default 3).

Returns:

Mean ACF value of the top n_selection peaks, in [-1, 1]. Returns np.nan if the signal is too short, no peaks are found, or an error occurs.

Return type:

float

vital_sqi.sqi.rpeaks_sqi.ectopic_sqi(s, rule_index=1, sample_rate=100, rpeak_detector=6, wave_type='PPG', low_rri=300, high_rri=2000)[source]

Compute the ratio of ectopic (invalid) beats in a signal.

The function first removes out-of-range RR intervals (outliers), then applies an interpolation-based ectopic detection method to the remaining intervals.

Parameters:
  • s (array-like) – Raw waveform signal (PPG or ECG).

  • rule_index (int, optional) –

    Controls which step of ectopic analysis to perform:

    • 0 — return the outlier ratio only (no ectopic removal)

    • 1 — apply adaptive ectopic removal after outlier filtering

    • 2 — apply linear ectopic removal after outlier filtering

    • 3 — apply spline ectopic removal after outlier filtering

    Default is 1.

  • sample_rate (int, optional) – Sampling frequency in Hz (default 100).

  • rpeak_detector (int, optional) – Peak detector index used by RRTransformation (default 6). This parameter is passed through but the actual detector is managed internally by vitalDSP.

  • wave_type (str, optional) – 'PPG' or 'ECG' (default 'PPG').

  • low_rri (int, optional) – Minimum acceptable RR interval in milliseconds (default 300).

  • high_rri (int, optional) – Maximum acceptable RR interval in milliseconds (default 2000).

Returns:

A ratio in [0, 1] where 0 means no ectopic/outlier beats and 1 means all beats are invalid. Returns np.nan on error.

Return type:

float

vital_sqi.sqi.rpeaks_sqi.interpolation_sqi(s)[source]

Interpolation-based SQI to assess consistency in R-R intervals.

Parameters:

s (array-like) – Input signal.

Returns:

Interpolation SQI value.

Return type:

float

vital_sqi.sqi.rpeaks_sqi.msq_sqi(s, peak_detector_1=7, peak_detector_2=6, wave_type='PPG')[source]

Computes the Modified Signal Quality (MSQ) SQI based on agreement between two R-peak detectors. This SQI is used to evaluate the consistency of peaks detected by different algorithms.

Parameters:
  • s (array-like) – Input signal.

  • peak_detector_1 (int, optional) – Type of the primary peak detection algorithm. Default is 7 (Billauer).

  • peak_detector_2 (int, optional) – Type of the secondary peak detection algorithm. Default is 6 (Scipy).

  • wave_type (str, optional) – Type of signal, either ‘PPG’ or ‘ECG’. Default is ‘PPG’.

Returns:

MSQ SQI value indicating consistency between detectors.

Return type:

float

vital_sqi.sqi.rpeaks_sqi.remove_ectopic_beats(rr_intervals, method='adaptive')[source]

Mark ectopic beats in an RR-interval array as NaN.

Parameters:
  • rr_intervals (np.ndarray) – RR intervals in seconds, possibly containing NaN values from a prior outlier-removal step.

  • method (str, optional) –

    Detection algorithm. One of:

    • 'adaptive' — compares each interval to a 5-point running mean; deviations > 20 % are flagged.

    • 'linear' — fits a linear trend to valid intervals; deviations > 15 % are flagged.

    • 'spline' — fits a smoothing spline; deviations > 10 % are flagged.

    Default is 'adaptive'.

Returns:

Copy of rr_intervals with ectopic positions set to NaN. If an error occurs the original array is returned unchanged.

Return type:

np.ndarray

Example

>>> import numpy as np
>>> from vital_sqi.sqi.rpeaks_sqi import remove_ectopic_beats
>>> rr = np.array([0.8, 1.2, 1.0, 2.5, 0.9, 0.85])
>>> clean = remove_ectopic_beats(rr, method="adaptive")

Heart-rate-variability SQIs

Heart rate variability SQIs for time and frequency domain analysis.

vital_sqi.sqi.hrv_sqi.cvnn_sqi(nn_intervals)[source]

Calculates the coefficient of variation for NN intervals.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

Coefficient of variation for NN intervals or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> cvnn_sqi(nn_intervals)
0.015
vital_sqi.sqi.hrv_sqi.cvsd_sqi(nn_intervals)[source]

Calculates the coefficient of variation for successive differences.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

Coefficient of variation for successive differences or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> cvsd_sqi(nn_intervals)
0.0123
vital_sqi.sqi.hrv_sqi.dfa_sqi(nn_intervals, scale_min=4, scale_max=None, n_scales=10)[source]

Detrended Fluctuation Analysis (DFA) short-range scaling exponent (alpha1).

DFA alpha1 quantifies short-range (4-16 beat) fractal correlations in the RR interval series. Healthy sinus rhythm gives alpha1 ~ 1.0-1.2. White noise gives alpha1 ~ 0.5. Values near 0.5 indicate disorganised, noisy intervals (poor signal or AF).

Parameters:
  • nn_intervals (list or np.ndarray) – NN intervals in milliseconds. Requires at least 32 values for a reliable estimate.

  • scale_min (int, optional) – Minimum DFA window size in beats (default 4).

  • scale_max (int, optional) – Maximum DFA window size in beats. Defaults to len(nn) // 4.

  • n_scales (int, optional) – Number of logarithmically spaced window sizes (default 10).

Returns:

DFA alpha1 scaling exponent, or np.nan on insufficient data.

Return type:

float

Notes

The per-block linear detrend is computed in closed form (slope from cov(x, y) / var(x)) instead of calling np.polyfit once per block, so the loop over scales touches each block exactly once via vectorised NumPy operations.

References

Peng C.K. et al. (1995). Chaos 5(1):82-87.

vital_sqi.sqi.hrv_sqi.frequency_sqi(nn_intervals, freq_min=0.04, freq_max=0.15, metric='peak')[source]

Compute a frequency-domain feature in a specified band.

Parameters:
  • nn_intervals (list or np.ndarray) – NN intervals in milliseconds. Requires at least 3 values.

  • freq_min (float, optional) – Lower bound of the frequency band in Hz (default 0.04).

  • freq_max (float, optional) – Upper bound of the frequency band in Hz (default 0.15).

  • metric (str, optional) –

    Feature to extract. One of:

    • 'peak' — frequency of the spectral peak in the band.

    • 'absolute' — sum of power in the band.

    • 'log' — sum of log power in the band.

    • 'normalized' — band power / (total power − VLF power), per HRV Task Force.

    • 'relative' — band power / total power.

    Default is 'peak'.

Returns:

The requested feature, or np.nan on invalid input or error.

Return type:

float

Raises:

ValueError – If metric is not one of the accepted strings.

vital_sqi.sqi.hrv_sqi.get_all_features_hrva(signal, sample_rate=100, rpeak_method=6, wave_type='ECG')[source]

Extract a comprehensive set of HRV features from a raw waveform.

Parameters:
  • signal (array-like) – Raw PPG or ECG signal.

  • sample_rate (int, optional) – Sampling frequency in Hz (default 100).

  • rpeak_method (int, optional) – Peak detector index (0–7) passed to PeakDetector (default 6).

  • wave_type (str, optional) – 'PPG' or 'ECG' (default 'ECG'). Controls which detector branch is used.

Returns:

HRV features as returned by vitalDSP.physiological_features.hrv_analysis.HRVFeatures.compute_all_features(). Returns an empty dict on detection failure or insufficient peaks.

Return type:

dict

vital_sqi.sqi.hrv_sqi.hr_range_sqi(nn_intervals, range_min=40, range_max=200)[source]

Calculates the percentage of HR values falling outside a specified range.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

range_minfloat

Minimum acceptable HR value (default is 40).

range_maxfloat

Maximum acceptable HR value (default is 200).

Returns:

float

Percentage of HR values outside the specified range or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> hr_range_sqi(nn_intervals, range_min=50, range_max=150)
0.0
vital_sqi.sqi.hrv_sqi.hr_sqi(nn_intervals, stat='mean')[source]

Generalized function to calculate heart rate (HR) statistics.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

statstr

The statistic to compute: ‘mean’, ‘median’, ‘min’, ‘max’, ‘std’.

Returns:

float

The computed HR statistic or NaN if input is invalid.

Raises:

ValueError

If the stat parameter is not one of the allowed values.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> hr_sqi(nn_intervals, stat="mean")
74.07
>>> hr_sqi(nn_intervals, stat="min")
72.29
>>> hr_sqi(nn_intervals, stat="std")
0.86
vital_sqi.sqi.hrv_sqi.hurst_sqi(nn_intervals)[source]

Estimate the Hurst exponent of the NN interval series via R/S analysis.

The Hurst exponent (H) quantifies long-range correlations:

  • H > 0.5 — persistent, structured series (healthy sinus rhythm)

  • H ~ 0.5 — uncorrelated (white noise, artifact)

  • H < 0.5 — anti-persistent series

Parameters:

nn_intervals (list or np.ndarray) – NN intervals in milliseconds. Requires at least 20 values.

Returns:

Hurst exponent estimate in [0, 1], or np.nan on error.

Return type:

float

vital_sqi.sqi.hrv_sqi.lf_hf_ratio_sqi(nn_intervals, lf_range=(0.04, 0.15), hf_range=(0.15, 0.4))[source]

Compute the LF/HF power ratio from NN intervals.

Parameters:
  • nn_intervals (list or np.ndarray) – NN intervals in milliseconds. Requires at least 3 values.

  • lf_range (tuple of float, optional) – Low-frequency band (min_Hz, max_Hz) (default (0.04, 0.15)).

  • hf_range (tuple of float, optional) – High-frequency band (min_Hz, max_Hz) (default (0.15, 0.4)).

Returns:

LF power divided by HF power, or np.nan if HF power is zero or insufficient data are provided.

Return type:

float

vital_sqi.sqi.hrv_sqi.mean_nn_sqi(nn_intervals)[source]

Calculates the mean of NN intervals.

vital_sqi.sqi.hrv_sqi.median_nn_sqi(nn_intervals)[source]

Calculates the median of NN intervals.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

The median of NN intervals or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> median_nn_sqi(nn_intervals)
815.0
vital_sqi.sqi.hrv_sqi.nn_mean_sqi(nn_intervals)[source]

Calculates the mean of NN intervals.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

The mean of NN intervals or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> nn_mean_sqi(nn_intervals)
815.0
vital_sqi.sqi.hrv_sqi.pnn_sqi(nn_intervals, threshold=50)[source]

Calculates the percentage of NN intervals that exceed a given threshold (e.g., pNN50).

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

thresholdfloat

Threshold in milliseconds (default is 50ms).

Returns:

float

Percentage of NN intervals exceeding the threshold or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> pnn_sqi(nn_intervals, threshold=50)
0.0
vital_sqi.sqi.hrv_sqi.poincare_features_sqi(nn_intervals)[source]

Calculates Poincare features: SD1, SD2, area, and SD1/SD2 ratio.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

dict

A dictionary containing the following keys: - “sd1”: Standard deviation perpendicular to the line of identity. - “sd2”: Standard deviation along the line of identity. - “area”: Area of the ellipse formed by SD1 and SD2. - “ratio”: Ratio of SD1 to SD2.

Example:

>>> nn_intervals = [800, 810, 820, 830, 800, 790]
>>> poincare_features_sqi(nn_intervals)
{'sd1': 7.07, 'sd2': 14.14, 'area': 312.21, 'ratio': 0.5}

Notes:

  • SD1 and SD2 are derived from the Poincare plot of NN intervals.

  • Area represents the ellipse formed by SD1 and SD2.

  • Ratio is SD1 divided by SD2 and provides insights into heart rate variability.

Warnings:

Insufficient NN intervals will result in NaN values for all metrics.

vital_sqi.sqi.hrv_sqi.rmssd_sqi(nn_intervals)[source]

Calculates the root mean square of successive NN interval differences.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

The RMSSD value or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> rmssd_sqi(nn_intervals)
10.0
vital_sqi.sqi.hrv_sqi.rr_irregularity_sqi(nn_intervals)[source]

Measure beat-to-beat RR interval irregularity.

Computes the mean absolute deviation of successive RR differences normalised by the median RR interval. More sensitive to ectopic beats and atrial fibrillation than plain SDNN. A clean, regular signal has a value close to 0; a highly irregular signal approaches or exceeds 1.

Parameters:

nn_intervals (list or np.ndarray) – NN intervals in milliseconds.

Returns:

mean(|diff(nn)|) / median(nn), or np.nan on invalid input.

Return type:

float

vital_sqi.sqi.hrv_sqi.sample_entropy_sqi(nn_intervals, m=2, r=None)[source]

Compute Sample Entropy (SampEn) of the NN interval series.

Sample entropy measures the regularity and complexity of a time series. Lower values indicate a more regular, predictable signal (good quality). Higher values indicate more randomness or noise.

Parameters:
  • nn_intervals (list or np.ndarray) – NN intervals in milliseconds. Requires at least 2*m + 2 values.

  • m (int, optional) – Template length (embedding dimension), default 2.

  • r (float, optional) – Tolerance (similarity threshold). Defaults to 0.2 * std(nn_intervals) per Richman & Moorman (2000).

Returns:

Sample entropy value >= 0, or np.nan on invalid input, when the m-length match count is zero, or when no longer (m+1) matches are found (avoids -log(0/B) producing +inf).

Return type:

float

Notes

The internal template-match counter is vectorised with np.lib.stride_tricks.sliding_window_view and broadcasting, so the NumPy-level cost is O(n²) but the Python overhead is constant.

References

Richman J.S. & Moorman J.R. (2000). Am J Physiol Heart Circ Physiol.

vital_sqi.sqi.hrv_sqi.sdnn_sqi(nn_intervals)[source]

Calculates the standard deviation of NN intervals.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

The standard deviation of NN intervals or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> sdnn_sqi(nn_intervals)
12.47
vital_sqi.sqi.hrv_sqi.sdsd_sqi(nn_intervals)[source]

Calculates the standard deviation of successive NN interval differences.

Parameters:

nn_intervalslist or np.ndarray

List of NN intervals in milliseconds.

Returns:

float

The standard deviation of successive NN differences or NaN if input is invalid.

Example:

>>> nn_intervals = [800, 810, 820, 830]
>>> sdsd_sqi(nn_intervals)
10.0

Dynamic time warping SQI

Signal quality indexes based on dynamic template matching

vital_sqi.sqi.dtw_sqi.dtw_distance(seq1, seq2)[source]

Compute the Dynamic Time Warping (DTW) distance between two sequences in a vectorized manner.

Parameters:
  • seq1 (array_like) – The first sequence (e.g., the signal)

  • seq2 (array_like) – The second sequence (e.g., the template)

Returns:

The DTW distance between the sequences

Return type:

float

vital_sqi.sqi.dtw_sqi.dtw_sqi(s, template_type, template_size=100, simple_mode=False)[source]

Euclidean distance between signal and its template using DTW

Parameters:
  • s (array_like) – Signal containing int or float values.

  • template_type (int) – Template type identifier (0-3 for different template types)

  • template_size (int, optional) – Size of the template to resample the signal and template (default is 100)

  • simple_mode (bool, optional) – If True, uses a simpler Euclidean distance instead of DTW

Returns:

Calculated DTW or Euclidean distance between the signal and the template.

Return type:

float