Skip to main content

harmos_signal/
lib.rs

1//! Signal processing over plain `&[f64]`: the transform, the reductions, the
2//! readings, and the one mergeable accumulator.
3//!
4//! Every name here is a kernel. Nothing owns your data, nothing is shared,
5//! nothing is locked, and nothing is cached: a function takes the slices you
6//! already have and answers a value, a `Vec`, or — for anything that *selects*
7//! samples — the indices it selected, so the caller reads its own columns.
8//! That is the whole design rule, and it is what lets two applications with two
9//! different series types share one implementation of the mathematics.
10//!
11//! This crate depends on `rustfft` and `std`, and on nothing else. It does not
12//! depend on `harmos`, and it must not: a runtime's read path stays free of
13//! algorithms, and this crate stays liftable into a repository of its own
14//! unchanged.
15//!
16//! This is measurement math and not a data engine. Everything here computes a
17//! property of a signal — a spectrum, an envelope, a crossing, a reduction, a
18//! calibrated conversion — and nothing here arranges data: tables, joins,
19//! group-by, lazy pipelines, generic aggregation frameworks, and columnar
20//! containers are a DataFrame's work, which meti left behind to arrive at
21//! exactly this content. An application that needs relational row manipulation
22//! reaches for a DataFrame of its own, above the runtime's algorithm-free
23//! reads.
24//!
25//! ```
26//! use harmos_signal::{Summary, Taper, transform};
27//!
28//! let rate = 1_000.0;
29//! let samples: Vec<f64> = (0..1_000)
30//!     .map(|i| (std::f64::consts::TAU * 50.0 * f64::from(i) / rate).sin())
31//!     .collect();
32//!
33//! // The RMS of a unit sine is one over root two, whichever way it is measured.
34//! let summary = Summary::of(&samples);
35//! assert!((summary.rms().unwrap() - 1.0 / 2.0_f64.sqrt()).abs() < 1e-3);
36//!
37//! // And the tone reads its own amplitude off the bin it lands on.
38//! let spectrum = transform(&samples, rate, Taper::Rectangular);
39//! let magnitude = harmos_signal::magnitude(&spectrum.real, &spectrum.imag);
40//! assert!((magnitude[50] - 1.0).abs() < 1e-9);
41//! ```
42
43mod spectrum;
44mod waveform;
45
46pub use spectrum::{
47    Band, Decibel, Estimate, Scale, Spectrum, Taper, Welch, band_energy, band_rms, bins, centroid,
48    fundamental, harmonics, magnitude, occupied_bandwidth, papr, peaks, phase, reconstruct,
49    rolloff, thd, transform,
50};
51pub use waveform::{
52    Edge, Summary, above_floor, crossing, decimate, derivative, edges, extrema, integral, lttb,
53    lttb_log, nearest, resample, resample_count, resample_uniform, value_at,
54};