Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "realfft"
version = "3.4.0"
version = "3.5.0"
authors = ["HEnquist <henrik.enquist@gmail.com>"]
edition = "2018"
description = "Real-to-complex forward FFT and complex-to-real inverse FFT for Rust"
Expand All @@ -22,11 +22,11 @@ neon = ["rustfft/neon"]
wasm_simd = ["rustfft/wasm_simd"]

[dependencies]
rustfft = { version = "6.2.0", default-features = false }
rustfft = { version = "6.4.0", default-features = false }

[dev-dependencies]
criterion = "0.3"
rand = "0.8.5"
criterion = "0.6"
rand = "0.9"

[[bench]]
name = "realfft"
Expand Down
90 changes: 55 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# realfft

## RealFFT: Real-to-complex forward FFT and complex-to-real inverse FFT based on RustFFT
# RealFFT: Real-to-complex forward FFT and complex-to-real inverse FFT based on RustFFT

This library is a wrapper for [RustFFT](https://crates.io/crates/rustfft)
that enables fast and convenient FFT of real-valued data.
The API is designed to be as similar as possible to RustFFT. Also, the feature flags are passed
on to RustFFT, allowing selection of its features – they do not affect RealFFT itself.
The API is designed to be as similar as possible to RustFFT.
Also, the [feature flags](#cargo-features) are passed on to RustFFT, allowing
selection of its features – they do not affect RealFFT itself.

Using this library instead of RustFFT directly avoids the need of converting
real-valued data to complex before performing a FFT.
Expand All @@ -25,29 +24,29 @@ there is an improvement of about a factor 2.
The difference shrinks for shorter lengths,
and around 30 elements there is no longer any difference.

### Why use real-to-complex FFT?
#### Using a complex-to-complex FFT
## Why use real-to-complex FFT?
### Using a complex-to-complex FFT
A simple way to transform a real valued signal is to convert it to complex,
and then use a complex-to-complex FFT.

Let's assume `x` is a 6 element long real vector:
```
```text
x = [x0r, x1r, x2r, x3r, x4r, x5r]
```

We now convert `x` to complex by adding an imaginary part with value zero.
Using the notation `(xNr, xNi)` for the complex value `xN`, this becomes:
```
```text
x_c = [(x0r, 0), (x1r, 0), (x2r, 0), (x3r, 0), (x4r, 0), (x5r, 0)]
```

Performing a normal complex FFT, the result of `FFT(x_c)` is:
```
```text
FFT(x_c) = [(X0r, X0i), (X1r, X1i), (X2r, X2i), (X3r, X3i), (X4r, X4i), (X5r, X5i)]
```

But because our `x_c` is real-valued (all imaginary parts are zero), some of this becomes redundant:
```
```text
FFT(x_c) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, 0), (X2r, -X2i), (X1r, -X1i)]
```

Expand All @@ -57,54 +56,54 @@ But it still takes time for the FFT to calculate the redundant values.
Converting the input data to complex also takes a little bit of time.

If the length of `x` instead had been 7, result would have been:
```
```text
FFT(x_c) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, X3i), (X3r, -X3i), (X2r, -X2i), (X1r, -X1i)]
```

The result is similar, but this time there is no zero at `X3i`.
Also in this case we got the same number of independent values as we started with.

#### Real-to-complex
### Real-to-complex
Using a real-to-complex FFT removes the need for converting the input data to complex.
It also avoids calculating the redundant output values.

The result for 6 elements is:
```
```text
RealFFT(x) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, 0)]
```

The result for 7 elements is:
```
```text
RealFFT(x) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, X3i)]
```

This is the data layout output by the real-to-complex FFT,
and the one expected as input to the complex-to-real inverse FFT.

### Scaling
## Scaling
RealFFT matches the behaviour of RustFFT and does not normalize the output of either forward or inverse FFT.
To get normalized results, each element must be scaled by `1/sqrt(length)`,
where `length` is the length of the real-valued signal.
If the processing involves both an FFT and an iFFT step,
it is advisable to merge the two normalization steps to a single, by scaling by `1/length`.

### Documentation
## Documentation

The full documentation can be generated by rustdoc. To generate and view it run:
```
```sh
cargo doc --open
```

### Benchmarks
## Benchmarks

To run a set of benchmarks comparing real-to-complex FFT with standard complex-to-complex, type:
```
```sh
cargo bench
```
The results are printed while running, and are compiled into an html report containing much more details.
To view, open `target/criterion/report/index.html` in a browser.

### Example
## Example
Transform a signal, and then inverse transform the result.
```rust
use realfft::RealFftPlanner;
Expand Down Expand Up @@ -141,20 +140,41 @@ assert_eq!(outdata.len(), length);
c2r.process(&mut spectrum, &mut outdata).unwrap();
```

#### Versions
- 3.4.0: Fix undefined behavior reported by Miri.
Update to latest RustFFT.
- 3.3.0: Add method for getting the length of the complex input/output.
Bugfix: clean up numerical noise in the zero imaginary components.
- 3.2.0: Allow scratch buffer to be larger than needed.
- 3.1.0: Update to RustFFT 6.1 with Neon support.
- 3.0.2: Fix confusing typos in errors about scratch length.
- 3.0.1: More helpful error messages, fix confusing typos.
- 3.0.0: Improved error reporting.
- 2.0.1: Minor bugfix.
- 2.0.0: Update RustFFT to 6.0.0 and num-complex to 0.4.0.
- 1.1.0: Add missing Sync+Send.
- 1.0.0: First version with new api.
## Cargo features
RealFFT has the same set of cargo feature flags as RustFFT.
These features are used to control the features of RustFFT
and they do not affect RealFFT itself.
The default is to enable the default features of RustFFT.
See the [RustFFT documentation](https://docs.rs/rustfft/latest/rustfft/#feature-flags)
for more details.

## Versions
- 3.5.0
- Add cargo features to set the corresponding RustFFT features.
- 3.4.0
- Fix undefined behavior reported by Miri.
- Update to latest RustFFT.
- 3.3.0
- Add method for getting the length of the complex input/output.
- Bugfix: clean up numerical noise in the zero imaginary components.
- 3.2.0
- Allow scratch buffer to be larger than needed.
- 3.1.0
- Update to RustFFT 6.1 with Neon support.
- 3.0.2
- Fix confusing typos in errors about scratch length.
- 3.0.1
- More helpful error messages, fix confusing typos.
- 3.0.0
- Improved error reporting.
- 2.0.1
- Minor bugfix.
- 2.0.0
- Update RustFFT to 6.0.0 and num-complex to 0.4.0.
- 1.1.0
- Add missing Sync+Send.
- 1.0.0
- First version with new api.

#### Compatibility

Expand Down
Loading