2.6 KiB
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.