Files
templates/c/set-protocol/docs/GUI_SPECTRUM.md

2.6 KiB
Raw Blame History

Shared GUI spectrum

include/set_spectrum.h / src/set_spectrum.c implement the same numerical pipeline for desktop and Android. CMake, tools/build_host.py, and the Android NDK build include it. The wire protocol is unchanged. The host-only analyzer allocates at most two FFT arrays (2×N doubles), releasing them before return.

The last N samples are used: the largest power of two within available data and max_size, 16…16384. Timestamps are seconds; inputs are immutable. Fs is measured from the selected endpoints. Non-monotonic/duplicate times and interval deviations over 50% of the mean are rejected. Lesser jitter is linearly interpolated onto an even grid (this can affect high-frequency amplitude; inspect returned jitter).

Processing order: interpolation, optional mean subtraction, filter, periodic window, forward FFT, one-sided peak amplitude. Windows: rectangular, Hann, Hamming, Blackman, Flat Top. Amplitudes are divided by window sum, doubled except DC and Nyquist. Output is not RMS/PSD/dB. Coherent gain correction is exact for bin-centered tones away from DC/Nyquist; off-bin tones still have scalloping.

Filters run before the window, on the unmodified sample copy. LP/HP are second order Butterworth; band pass cascades HP and LP; notch uses Q=30. Coefficients: W3C Audio EQ Cookbook. Initial state is the first sample's steady state, not a carried streaming state; block-start transients may occur. Cutoffs must be strictly within (0, Fs/2).

Python

from protocan.spectrum import NativeSpectrum, Window, Filter

# lib = an existing ctypes.CDLL from protocan.native.NativeProtocol
spectrum = NativeSpectrum(lib).analyze(times_seconds, values,
    window=Window.HANN, filter=Filter.LOW_PASS, high_hz=100,
    max_size=4096, remove_mean=True)
plot(spectrum.frequencies, spectrum.amplitudes)

Adapter errors are ValueError, not empty/misleading arrays. No NumPy/Qt dependency.

Android

SpectrumAnalyzer.analyze(List<TrendPoint>, SpectrumOptions) calls JNI using relative seconds from millisecond timestamps. TrendSpectrum contains N, Fs, maximum relative jitter, amplitudes or a displayable error. Call on a worker dispatcher. PlotViewport provides axis-independent zoom/pan, focus anchoring, 128× limit and bounds clamping without any Compose dependency.

Checks

Build CMake with tests and run CTest in Debug (assertions enabled). Python tests/test_spectrum.py runs against an explicitly supplied SETPROTOCOL_LIBRARY: independent direct DFT, amplitude correction, DC/Nyquist, off-bin leakage, filter bands, timing rejection/interpolation, bounded tail selection and immutable inputs.