A simple and fast no_std
library to get the frequency spectrum of a digital signal (e.g. audio) using FFT.
It follows the KISS principle and consists of simple building blocks/optional features. In short, this is
a convenient wrapper around several FFT implementations which you can choose from during compilation time
via Cargo features.
I'm not an expert on digital signal processing. Code contributions are highly welcome! 🙂
The MSRV (minimum supported Rust version) is 1.52.1 stable.
Please see file /EDUCATIONAL.md.
no_std
-environments)Most tips and comments are located inside the code, so please check out the repository on Github! Anyway, the most basic usage looks like this:
By default this crate uses the real
-module from the great microfft
-crate. It's the fastest implementation
and as of version v0.5.0
there should be no valid reason why you should ever change this. The multiple features
are there mainly for educational reasons and to support me while programming/testing.
```toml
no_std
-builds!no_std
build problems caused by wrong feature resolution of Cargoresolver = "2"
[dependencies]
spectrum-analyzer = "
[dependencies.spectrum-analyzer]
default-features = false # important! only one feature at a time works!
version = "
```rust use spectrumanalyzer::{samplesffttospectrum, FrequencyLimit}; use spectrumanalyzer::windows::hannwindow; use spectrumanalyzer::scaling::divideby_N;
/// Minimal example. fn main() { // YOU need to implement the samples source; get microphone input for example let samples: &[f32] = &[0.0, 3.14, 2.718, -1.0, -2.0, -4.0, 7.0, 6.0]; // apply hann window for smoothing; length must be a power of 2 for the FFT // 2048 is a good starting point with 44100 kHz let hannwindow = hannwindow(&samples[0..8]); // calc spectrum let spectrumhannwindow = samplesffttospectrum( // (windowed) samples &hannwindow, // sampling rate 44100, // optional frequency limit: e.g. only interested in frequencies 50 <= f <= 150? FrequencyLimit::All, // optional scale Some(÷byN), ).unwrap();
for (fr, fr_val) in spectrum_hann_window.data().iter() {
println!("{}Hz => {}", fr, fr_val)
}
} ```
Measurements taken on i7-1165G7 @ 2.80GHz (Single-threaded) with optimized build
| Operation | Time |
| ------------------------------------------------------ | ------:|
| Hann Window with 4096 samples | ≈68µs |
| Hamming Window with 4096 samples | ≈118µs |
| FFT (rustfft/complex
) to spectrum with 4096 samples | ≈170µs |
| FFT (microfft/real
) to spectrum with 4096 samples | ≈90µs |
| FFT (microfft/complex
) to spectrum with 4096 samples | ≈250µs |
In the following example you can see a basic visualization of frequencies 0 to 4000Hz
for
a layered signal of sine waves of 50
, 1000
, and 3777Hz
@ 44100Hz
sampling rate. The peaks for the
given frequencies are clearly visible. Each calculation was done with 2048
samples, i.e. ≈46ms of audio signal.
The noise (wrong peaks) also comes from clipping of the added sine waves!
Peaks (50, 1000, 3777 Hz) are clearly visible but also some noise.
Peaks (50, 1000, 3777 Hz) are clearly visible and Hann window reduces noise a little bit. Because this example has few noise, you don't see much difference.
Peaks (50, 1000, 3777 Hz) are clearly visible and Hamming window reduces noise a little bit. Because this example has few noise, you don't see much difference.
(This is probably not 100% correct, because I'm not totally convinced by my solution/implementation.)
The function FrequencySpectrum::to_log_spectrum
tries to give you better suited representation for
situations, when you want to analyze music. There you are most probably interested in lows, mids,
and highs, but highs could be combined, i.e. 0-128hz, 128-1000hz, 8-20k. This function tries
to solve this. An example visualization can be found when you execute tests. Look into
./test/out
afterwards and search for the corresponding file name.
Also check out $ cargo run --release --example live-spectrum-visualization
which uses your default
audio input device and draws a graph to the terminal.
To execute tests you need the package libfreetype6-dev
(on Ubuntu/Debian). This is required because
not all tests are "automatic unit tests" but also tests that you need to check visually, by looking at the
generated diagram of the spectrum.
I tested f64 but the additional accuracy doesn't pay out the ~40% calculation overhead (on x86_64).
Apply a window function, like Hann window or Hamming window. But I'm not an expert on this.
Also check out my blog post! https://phip1611.de/2021/03/programmierung-und-skripte/frequency-spectrum-analysis-with-fft-in-rust/