XTOS / OPEN SOURCE REAL-TIME SYSTEMOPEN SOURCE · VERSION 0.9.0 · BUILD FROM SOURCE
Docslibxtos-signal

libxtos-signal

Timestamps, DFT power, filter state, and SSVEP/P300 features.

On this page

Inputs and units

The caller supplies and owns inputs, outputs, results, and filter structures. FFT, SSVEP, and P300 leave input unchanged; filters support exact input==output processing, not partial overlap. Use one state per channel, init before continuous process, and extract features from complete windows. The library does not manage devices, scheduling, or units.

Timestamps are uint64 nanoseconds, sample rate is Hz, and amplitude is double. Power scales with the squared amplitude unit; P300 peak_amplitude keeps the input unit. The caller must reject NaN/Inf and unreasonable lengths. Public notch, bandpass, and ssvep implementations do not check isfinite; no error does not prove valid numbers. Except for the timestamp validator’s three returns, int interfaces use 0 or -1/errno; do not use partial results after failure. Link with -lm.

Timestamps

c
int xtos_signal_validate_timestamps(const uint64_t *timestamps_ns,
    size_t count, uint32_t sample_rate_hz, uint64_t tolerance_ns,
    struct xtos_signal_validation *result);

int xtos_signal_correct_timestamps(uint64_t start_timestamp_ns,
    uint32_t sample_rate_hz, uint64_t *timestamps_ns, size_t count);

Both functions require a non-NULL array, count>0, and sample_rate_hz>0; validation also requires a non-NULL result, otherwise -1/EINVAL.

Expected interval is llround(1000000000.0 / sample_rate_hz).

Validation counts interval_anomalies for strictly increasing adjacent timestamps only when interval error exceeds tolerance_ns.

Repeats or decreases count as timestamp_anomalies.

ReturnMeaningResult
0No anomalies.expected_interval_ns and min/max forward interval; both are 0 for count=1.
1Completed with anomalies, not an errno failure.Read both counts; with no forward interval, min=UINT64_MAX and max=0.
-1Invalid arguments, errno=EINVAL.Do not read an uninitialized result.

correct_timestamps writes start + i×rounded_interval, not independently rounded exact fractional times. A fractional-nanosecond period accumulates rounding error, and uint64 multiply/add overflow is unchecked. Keep counts and start safe; maintain a rational clock for long-term accuracy. Preserve original timestamps and anomaly records; correction is for resampling, replay, or missing labels.

DFT power

c
int xtos_signal_fft_power(const double *input, size_t n,
                          double *power, size_t power_count);

/* Caller allocates n input values and at least n/2 + 1 output values. */

n must be a nonzero power of two; input and power must be non-NULL with power_count≥n/2+1, otherwise -1/EINVAL. The radix-2 FFT returns bins 0 through n/2, including Nyquist; extra output is untouched. power[k]=Re(X[k])²+Im(X[k])² for unnormalized X. It does not divide by n or n², window, remove the mean, or double interior positive bins, so it is not a per-Hz PSD. Bin frequency is k×fs/n and resolution is fs/n.

The function allocates two n-element double arrays for an input copy; failure is -1/ENOMEM and temporaries are freed before return. The caller owns power. Preallocating power does not remove internal allocation, so this does not belong in a strictly allocation-free acquisition path. n affects memory, FFT time, frequency resolution, and update latency.

Filters

InterfaceParametersBehavior
notch_initNon-NULL filter; range comparisons fs>0, 0<f0<fs/2, Q>0; no explicit finite check.Second-order IIR notch; Q controls bandwidth; init clears history.
bandpass_initNon-NULL filter; 0<low<high<fs/2; Nyquist is invalid; no explicit finite check.Second-order high-pass then low-pass, Q=1/√2 per stage; fourth-order baseline.
processNon-NULL filter/input/output; arrays hold at least count; count=0 is allowed.0 on success, -1/EINVAL on error; exact in-place processing; no allocation.

Nyquist=fs/2. At fs=250 Hz, a 50 Hz notch and 5–40 Hz band-pass are valid; a 125 Hz cutoff is not. Choose 50/60 Hz for the actual mains environment; there is no auto-detection. Recompute coefficients after a rate change. Filters are stateful causal IIR, not zero-phase; startup and re-init have transients, and phase delay affects ERP timing. Preserve state across blocks, use one state per channel, and do not reset per window or share concurrently.

SSVEP

c
int xtos_signal_ssvep_feature(const double *input, size_t n,
    uint32_t sample_rate_hz, double target_frequency_hz,
    size_t harmonic_count, size_t neighbor_bins,
    struct xtos_ssvep_feature *result);

Requires non-NULL input/result, nonzero power-of-two n, fs>0, 0<target<fs/2, harmonic_count>0, and neighbor_bins>0. The implementation uses ordinary comparisons, not isfinite; reject NaN/Inf in target_frequency_hz first. target_bin=llround(target×n/fs) must be nonzero and ≤n/2, and every target_bin×h must also be ≤n/2, otherwise -1/EINVAL. A valid fundamental does not keep all harmonics in range.

signal_power sums target-harmonic bin power. noise_power averages valid neighbors on both sides, excluding DC and target bins; overlapping neighborhoods may count a bin more than once.

snr=signal_power/noise_power and snr_db=10×log10(snr).

No valid neighbor or nonpositive noise gives -1/EDOM; allocation failure gives ENOMEM.

It does not perform CCA, stimulus identification, artifact rejection, or subject calibration; this is a research feature, not a diagnosis or safety signal.

P300

c
int xtos_signal_p300_feature(const double *input, size_t n,
    uint32_t sample_rate_hz, size_t baseline_samples,
    uint32_t window_start_ms, uint32_t window_end_ms,
    double detection_z_threshold, struct xtos_p300_feature *result);

int xtos_signal_p300_quality_gate(const struct xtos_p300_feature *trials,
    size_t trial_count, size_t min_valid_trials,
    double min_detection_rate, double min_mean_z_score,
    double max_latency_stddev_ms, struct xtos_p300_quality *result);

input[0..baseline_samples) is the prestimulus baseline and stimulus onset is baseline_samples.

Require fs>0, 2≤baseline_samples<n, start_ms<end_ms, and a finite positive z threshold.

Convert milliseconds with (ms×fs+500)/1000. The analysis interval is [baseline+start_offset, baseline+end_offset), excluding the end; the rounded window must be nonempty and inside n.

n need not be a power of two.

Baseline mean and population standard deviation provide centering and z scores.

The window selects the greatest positive centered amplitude, keeping the earliest index on a tie. peak_latency_ms is relative to stimulus onset; window_energy is the sum of squared centered samples; detected means only peak_z_score≥threshold.

Invalid parameters or checked nonfinite baseline/window values give EINVAL; zero or nonfinite baseline deviation gives EDOM.

quality_gate requires trial_count>0, min_valid_trials>0, finite detection_rate in [0,1], finite mean-z, a finite nonnegative latency standard-deviation limit, and non-NULL trials/result.

It checks trial fields and summarizes detection rate, mean z, and population latency deviation among valid trials.

Any rejected trial, too few valid trials, unmet threshold, or no valid trial sets passed=0; completed statistics still return 0.

Validation and sources

Public tests/test_signal.c covers fixed timestamps, an impulse, integer-bin sinusoids, settled filters, and a synthetic P300 epoch. Applications should also test unit conversion, missing samples, NaN/Inf, short output, Nyquist boundaries, cross-block state, and stimulus onset. Thresholds depend on amplitude, preprocessing, and window; do not copy them into human experiments.

Sources: sdk/libxtos-signal/include/xtos/signal.h defines result fields; sdk/libxtos-signal/src/signal.c defines rounding, normalization, filter coefficients, and quality gates. Record input, sample rate, window, and version to interpret and replay results.