### Cargo.toml Setup for RustFFT with Feature Flags Source: https://context7.com/ejmahler/rustfft/llms.txt Shows how to add RustFFT to your project's `Cargo.toml` and control SIMD compilation and binary size using feature flags. ```toml [dependencies] # Default: avx, sse, neon enabled; wasm_simd disabled rustfft = "6.4" # Minimal binary (scalar only, fastest compile) # rustfft = { version = "6.4", default-features = false } # WASM with SIMD acceleration # rustfft = { version = "6.4", default-features = false, features = ["wasm_simd"] } # x86_64 with only SSE (no AVX) ``` -------------------------------- ### FftPlanner::plan_fft_forward and FftPlanner::plan_fft_inverse Source: https://context7.com/ejmahler/rustfft/llms.txt Demonstrates how to use `FftPlanner` to plan and execute forward and inverse FFTs. The planner automatically selects the most efficient algorithm based on CPU features. FFT instances are thread-safe and cheap to clone. ```APIDOC ## FftPlanner::plan_fft_forward and FftPlanner::plan_fft_inverse ### Description Use `FftPlanner` to create FFT instances for forward and inverse transforms. The planner optimizes for available CPU SIMD extensions. FFT instances are thread-safe and can be cloned efficiently. ### Method `FftPlanner::::new()` creates a new planner. `planner.plan_fft_forward(len)` plans a forward FFT of the specified length. `planner.plan_fft_inverse(len)` plans an inverse FFT of the specified length. `fft_instance.process(buffer)` computes the FFT in-place on the provided buffer. ### Parameters #### `plan_fft_forward` and `plan_fft_inverse` - **len** (usize) - The size of the FFT to plan. #### `process` - **buffer** (&mut [Complex]) - A mutable slice of complex numbers to transform in-place. ### Request Example ```rust use rustfft::{FftPlanner, num_complex::Complex}; use std::sync::Arc; let mut planner = FftPlanner::::new(); let fft_forward = planner.plan_fft_forward(1234); let fft_inverse = planner.plan_fft_inverse(1234); let mut signal: Vec> = (0..1234) .map(|i| Complex { re: (i as f32).sin(), im: 0.0 }) .collect(); fft_forward.process(&mut signal); fft_inverse.process(&mut signal); ``` ### Response #### Success Response - The `process` method modifies the input buffer in-place. #### Response Example (No explicit response body, operation is in-place) ``` -------------------------------- ### Plan and Process FFT with rustfft Source: https://context7.com/ejmahler/rustfft/llms.txt This snippet demonstrates how to plan and process a forward FFT using `FftPlanner`. The planner automatically selects the best available backend, such as AVX, if supported. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(8192); // uses AVX if available let mut buf = vec![Complex { re: 0.0f32, im: 0.0 }; 8192]; fft.process(&mut buf); } ``` -------------------------------- ### FftPlanner: Plan and Compute FFTs Source: https://context7.com/ejmahler/rustfft/llms.txt Use FftPlanner to create FFT instances for forward and inverse transforms. Reuse planners to share internal data. FFT instances are thread-safe and cheap to clone. ```rust use rustfft::{FftPlanner, num_complex::Complex}; use std::sync::Arc; fn main() { let mut planner = FftPlanner::::new(); // Plan a forward FFT of size 1234 (any size works, including primes) let fft_forward = planner.plan_fft_forward(1234); // Plan an inverse FFT of the same size (reuses internal data) let fft_inverse = planner.plan_fft_inverse(1234); // Arc makes FFT instances cheap to clone and share across threads let fft_clone: Arc> = Arc::clone(&fft_forward); // Compute a forward FFT in-place let mut signal: Vec> = (0..1234) .map(|i| Complex { re: (i as f32).sin(), im: 0.0 }) .collect(); fft_forward.process(&mut signal); // signal now contains frequency-domain data // Normalize and invert fft_inverse.process(&mut signal); let norm = 1.0 / 1234.0_f32; for s in &mut signal { *s *= norm; } // signal is back to the original time-domain values } ``` -------------------------------- ### Naive O(n^2) DFT Implementation Source: https://context7.com/ejmahler/rustfft/llms.txt A reference DFT implementation suitable for testing and validation. Its quadratic complexity makes it unsuitable for large inputs. ```rust use rustfft::{Fft, FftDirection, num_complex::Complex, algorithm::Dft}; fn main() { let dft = Dft::::new(8, FftDirection::Forward); let mut buffer = vec![ Complex { re: 1.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, Complex { re: 0.0, im: 0.0 }, ]; dft.process(&mut buffer); // All bins have magnitude 1.0 for a unit impulse input for bin in &buffer { println!("magnitude: {:.4}", bin.norm()); } } ``` -------------------------------- ### FftPlannerSse: SSE4.1 FFT Planner Source: https://context7.com/ejmahler/rustfft/llms.txt Uses SSE4.1 instructions for FFT computation on x86_64. Falls back to a general planner if SSE4.1 is unavailable or the 'sse' feature is disabled. ```rust use rustfft::{FftPlannerSse, FftPlanner, num_complex::Complex}; fn main() { let mut buffer: Vec> = vec![Complex { re: 1.0, im: 0.0 }; 256]; match FftPlannerSse::::new() { Ok(mut planner) => { let fft = planner.plan_fft_forward(256); fft.process(&mut buffer); println!("SSE4.1 path used"); } Err(_) => { let mut planner = FftPlanner::::new(); planner.plan_fft_forward(256).process(&mut buffer); println!("Fallback path used"); } } } ``` -------------------------------- ### RustFFT 4.0 vs 5.0: In-place FFT Processing Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md Compares the `process` method signature for in-place FFT computation between RustFFT 4.0 and 5.0. RustFFT 5.0 simplifies this by using a single buffer for in-place operations. ```rust // RustFFT 4.0 let fft = Radix4::new(4096, false); let mut input : Vec> = get_my_input_data(); let mut output = vec![Complex::zero(); fft.len()]; ft.process(&mut input, &mut output); ``` ```rust // RustFFT 5.0 let fft = Radix4::new(4096, FftDirection::Forward); let mut buffer : Vec> = get_my_input_data(); ft.process(&mut buffer); ``` -------------------------------- ### Perform Forward FFT in Rust Source: https://github.com/ejmahler/rustfft/blob/master/README.md Use FftPlanner to plan and execute a forward FFT. Ensure the `rustfft` and `num_complex` crates are included in your project. ```rust use rustfft::{FftPlanner, num_complex::Complex}; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1234); let mut buffer = vec![Complex{ re: 0.0, im: 0.0 }; 1234]; fft.process(&mut buffer); ``` -------------------------------- ### Explicit AVX FFT planner with fallback Source: https://context7.com/ejmahler/rustfft/llms.txt The `FftPlannerAvx` planner attempts to use AVX/FMA instructions for FFT computation on x86_64 systems. It returns an `Err(())` if AVX is unavailable or the `avx` feature flag is disabled, allowing for a graceful fallback to the generic `FftPlanner`. ```rust use rustfft::{FftPlannerAvx, FftPlanner, num_complex::Complex}; fn main() { let mut buffer: Vec> = (0..1024) .map(|i| Complex { re: i as f32, im: 0.0 }) .collect(); // Try AVX; fall back to the generic planner on non-AVX machines if let Ok(mut avx_planner) = FftPlannerAvx::::new() { let fft = avx_planner.plan_fft_forward(1024); fft.process(&mut buffer); println!("Computed with AVX"); } else { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1024); fft.process(&mut buffer); println!("Computed with generic planner"); } } ``` -------------------------------- ### FftPlannerNeon: NEON FFT Planner Source: https://context7.com/ejmahler/rustfft/llms.txt Leverages ARM NEON instructions for FFTs on AArch64 targets. Falls back to the general planner if NEON is not available or the 'neon' feature is disabled. ```rust use rustfft::{FftPlannerNeon, FftPlanner, num_complex::Complex}; fn main() { let size = 2048; let mut buffer: Vec> = (0..size) .map(|i| Complex { re: (i as f32).sin(), im: 0.0 }) .collect(); match FftPlannerNeon::::new() { Ok(mut planner) => { planner.plan_fft_forward(size).process(&mut buffer); println!("NEON acceleration active"); } Err(_) => { FftPlanner::::new() .plan_fft_forward(size) .process(&mut buffer); } } } ``` -------------------------------- ### In-place FFT with scratch buffer Source: https://context7.com/ejmahler/rustfft/llms.txt Use `process_with_scratch` to avoid repeated scratch allocation when computing many FFTs in a tight loop. Ensure the scratch buffer is sized correctly using `fft.get_inplace_scratch_len()`. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(4096); // Pre-allocate scratch once, reuse across all iterations let mut scratch = vec![Complex { re: 0.0f32, im: 0.0 }; fft.get_inplace_scratch_len()]; for _ in 0..1000 { let mut buffer: Vec> = (0..4096) .map(|i| Complex { re: (i as f32 * 0.01).sin(), im: 0.0 }) .collect(); fft.process_with_scratch(&mut buffer, &mut scratch); // scratch contents are garbage after this call — that is expected } } ``` -------------------------------- ### Sharing FFT Instances Across Threads Source: https://context7.com/ejmahler/rustfft/llms.txt Demonstrates how to share FFT instances safely across multiple threads using `Arc`. This allows concurrent processing without synchronization overhead. ```rust use std::sync::Arc; use std::thread; use rustfft::{FftPlanner, num_complex::Complex32}; fn main() { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1024); let handles: Vec<_> = (0..8) .map(|thread_id| { let fft = Arc::clone(&fft); thread::spawn(move || { let mut buffer: Vec = (0..1024) .map(|i| Complex32::new((i as f32 * 0.01).sin(), 0.0)) .collect(); fft.process(&mut buffer); println!("Thread {}: DC = {:?}", thread_id, buffer[0]); }) }) .collect(); for h in handles { h.join().unwrap(); } } ``` -------------------------------- ### FftPlannerWasmSimd: WASM SIMD FFT Planner Source: https://context7.com/ejmahler/rustfft/llms.txt Targets WebAssembly fixed-width SIMD. Requires the 'wasm_simd' crate feature to be enabled at compile time, as CPU features cannot be detected dynamically in WASM. Falls back to the general planner if the feature is not enabled. ```rust use rustfft::{FftPlannerWasmSimd, FftPlanner, num_complex::Complex}; fn compute(size: usize, buffer: &mut Vec>) { match FftPlannerWasmSimd::::new() { Ok(mut planner) => { planner.plan_fft_forward(size).process(buffer); } Err(_) => { // Running outside WASM or wasm_simd feature not enabled FftPlanner::::new() .plan_fft_forward(size) .process(buffer); } } } ``` -------------------------------- ### FftPlannerAvx Source: https://context7.com/ejmahler/rustfft/llms.txt An explicit planner for AVX (Advanced Vector Extensions) instructions, targeting x86_64 architectures. This planner returns an error if AVX/FMA are not available or if the `avx` feature is disabled, allowing for a fallback to a generic planner. All planning methods mirror those of the standard `FftPlanner`. ```APIDOC ## FftPlannerAvx ### Description Explicit AVX planner (x86_64 only). Returns `Err(())` if AVX/FMA are unavailable or the `avx` feature flag is disabled, allowing a graceful custom fallback. All plan calls mirror `FftPlanner`'s API. ### Method `FftPlannerAvx::::new()` to create a planner. `planner.plan_fft_forward(len)` to plan an FFT. `fft.process(&mut buffer)` to compute the FFT. ### Parameters - `T`: The scalar type for the complex numbers (e.g., `f32`, `f64`). - `len`: The size of the FFT. ### Request Example ```rust use rustfft::{FftPlannerAvx, FftPlanner, num_complex::Complex}; let mut buffer: Vec> = (0..1024).map(|i| Complex { re: i as f32, im: 0.0 }).collect(); // Try AVX; fall back to the generic planner on non-AVX machines if let Ok(mut avx_planner) = FftPlannerAvx::::new() { let fft = avx_planner.plan_fft_forward(1024); fft.process(&mut buffer); println!("Computed with AVX"); } else { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1024); fft.process(&mut buffer); println!("Computed with generic planner"); } ``` ### Response - The `buffer` is transformed in-place to contain the FFT result, computed using AVX instructions if available, otherwise using the generic planner. ``` -------------------------------- ### Out-of-place FFT with scratch buffer Source: https://context7.com/ejmahler/rustfft/llms.txt Utilize `process_outofplace_with_scratch` to compute a FFT from `input` into `output`, using both buffers as scratch space. This is efficient when preserving the input is not necessary. The scratch size can be queried with `fft.get_outofplace_scratch_len()`. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1024); let mut input: Vec> = (0..1024) .map(|i| Complex { re: (i as f64 * 0.1).sin(), im: 0.0 }) .collect(); let mut output = vec![Complex { re: 0.0_f64, im: 0.0 }; 1024]; let scratch_len = fft.get_outofplace_scratch_len(); let mut scratch = vec![Complex { re: 0.0_f64, im: 0.0 }; scratch_len]; // input is consumed as scratch space; results land in output fft.process_outofplace_with_scratch(&mut input, &mut output, &mut scratch); println!("Frequency bin 1: {:?}", output[1]); } ``` -------------------------------- ### Update FftPlanner API for FFT Direction Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md The FftPlanner constructor no longer takes a direction. Instead, the direction is specified in the plan_fft method or by using convenience methods like plan_fft_forward and plan_fft_inverse. ```rust ```rust // RustFFT 4.0 let planner_forward = FFTplanner::new(false); let fft_forward = planner.plan_fft(1234); let planner_inverse = FFTplanner::new(true); let fft_inverse = planner.plan_fft(1234); // RustFFT 5.0 let planner = FftPlanner::new(); let fft_forward1 = planner.plan_fft(1234, FftDirection::Forward); let fft_forward2 = planner.plan_fft_forward(1234); let fft_inverse1 = planner.plan_fft(1234, FftDirection::Inverse); let fft_inverse2 = planner.plan_fft_inverse(1234); ``` ``` -------------------------------- ### Prime-size FFT using Rader's Algorithm Source: https://context7.com/ejmahler/rustfft/llms.txt Computes a prime-size FFT by delegating to an inner FFT of a composite size. This is most effective when the prime minus one has small prime factors. Ensure the inner FFT is planned correctly. ```rust use rustfft::{Fft, FftPlanner, num_complex::Complex, algorithm::RadersAlgorithm}; fn main() { let prime = 1201; let mut planner = FftPlanner::::new(); // inner FFT has length prime - 1 = 1200 let inner_fft = planner.plan_fft_forward(prime - 1); let fft = RadersAlgorithm::new(inner_fft); let mut buffer: Vec> = vec![Complex { re: 1.0, im: 0.0 }; prime]; fft.process(&mut buffer); println!("Rader FFT of size {}", fft.len()); } ``` -------------------------------- ### Fft::process: In-place FFT on Packed Windows Source: https://context7.com/ejmahler/rustfft/llms.txt Transforms multiple FFT windows packed within a single buffer. Panics if buffer length is incompatible with FFT length. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let fft_len = 256; let num_windows = 4; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(fft_len); // Pack 4 consecutive windows into one buffer let mut buffer: Vec> = (0..fft_len * num_windows) .map(|i| Complex { re: (i as f32 * 0.05).sin(), im: 0.0 }) .collect(); // All 4 windows are transformed in one call fft.process(&mut buffer); println!("DC component of first window: {:?}", buffer[0]); println!("DC component of second window: {:?}", buffer[fft_len]); } ``` -------------------------------- ### RustFFT 4.0 vs 5.0: Out-of-place FFT Processing Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md Illustrates the change in the out-of-place FFT processing method from RustFFT 4.0 to 5.0. RustFFT 5.0's `process_outofplace_with_scratch` requires explicit scratch space management. ```rust // RustFFT 4.0 let fft = Radix4::new(4096, false); let mut input : Vec> = get_my_input_data(); let mut output = vec![Complex::zero(); fft.len()]; ft.process(&mut input, &mut output); ``` ```rust // RustFFT 5.0 let fft = Radix4::new(4096, FftDirection::Forward); let mut input : Vec> = get_my_input_data(); let mut output = vec![Complex::zero(); fft.len()]; let mut scratch = vec![Complex::zero(); fft.get_outofplace_scratch_len()]; ft.process_outofplace_with_scratch(&mut input, &mut output, &mut scratch); ``` -------------------------------- ### RadersAlgorithm Constructor Change Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md Demonstrates the updated constructor for RadersAlgorithm. RustFFT 5.0 simplifies it by removing the explicit length parameter, deriving it from the inner FFT. ```rust // RustFFT 4.0 let inner_fft : Arc> = ...; let fft = RadersAlgorithm::new(inner_fft.len() + 1, inner_fft); ``` ```rust // RustFFT 5.0 let inner_fft : Arc> = ...; let fft = RadersAlgorithm::new(inner_fft); ``` -------------------------------- ### Fft::process_with_scratch Source: https://context7.com/ejmahler/rustfft/llms.txt Performs an in-place FFT computation using a pre-allocated scratch buffer. This method is optimized for scenarios where multiple FFTs are computed in rapid succession, avoiding repeated scratch allocation overhead. The scratch buffer should be sized using `fft.get_inplace_scratch_len()`. ```APIDOC ## Fft::process_with_scratch ### Description Avoids repeated scratch allocation by accepting a caller-managed scratch buffer. Use `fft.get_inplace_scratch_len()` to size the buffer correctly. Ideal when computing many FFTs in a tight loop. ### Method `process_with_scratch` ### Parameters - `buffer`: A mutable slice of complex numbers to be transformed in-place. - `scratch`: A mutable slice of complex numbers for scratch space, sized by `get_inplace_scratch_len()`. ### Request Example ```rust use rustfft::{FftPlanner, num_complex::Complex}; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(4096); let mut scratch = vec![Complex { re: 0.0f32, im: 0.0 }; fft.get_inplace_scratch_len()]; let mut buffer: Vec> = (0..4096).map(|i| Complex { re: (i as f32 * 0.01).sin(), im: 0.0 }).collect(); fft.process_with_scratch(&mut buffer, &mut scratch); ``` ### Response - The input `buffer` is modified in-place to contain the FFT result. - The contents of `scratch` are considered garbage after the call and can be reused. ``` -------------------------------- ### Fft::process_outofplace_with_scratch Source: https://context7.com/ejmahler/rustfft/llms.txt Computes an out-of-place FFT, transforming data from an input buffer to an output buffer. Both input and output buffers can be utilized as scratch space, which is efficient when the original input data is no longer needed. The required scratch size can be queried using `fft.get_outofplace_scratch_len()`, which is often 0. ```APIDOC ## Fft::process_outofplace_with_scratch ### Description Computes a FFT from `input` into `output`, using both buffers as scratch space. Useful when preserving the input is unnecessary and a copy can be avoided. Query `fft.get_outofplace_scratch_len()` for the scratch size (often 0). ### Method `process_outofplace_with_scratch` ### Parameters - `input`: An immutable slice of complex numbers representing the input data. - `output`: A mutable slice of complex numbers where the FFT result will be stored. - `scratch`: A mutable slice of complex numbers for scratch space. ### Request Example ```rust use rustfft::{FftPlanner, num_complex::Complex}; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(1024); let mut input: Vec> = (0..1024).map(|i| Complex { re: (i as f64 * 0.1).sin(), im: 0.0 }).collect(); let mut output = vec![Complex { re: 0.0_f64, im: 0.0 }; 1024]; let scratch_len = fft.get_outofplace_scratch_len(); let mut scratch = vec![Complex { re: 0.0_f64, im: 0.0 }; scratch_len]; fft.process_outofplace_with_scratch(&mut input, &mut output, &mut scratch); ``` ### Response - The `output` buffer will contain the result of the FFT. - The `input` buffer may be modified as it is used for scratch space. ``` -------------------------------- ### Explicit scalar FFT planner Source: https://context7.com/ejmahler/rustfft/llms.txt The `FftPlannerScalar` forces the use of scalar algorithms, which is useful for reproducible benchmarks or environments where SIMD must be avoided. All plan calls mirror the standard `FftPlanner` API. ```rust use rustfft::{FftPlannerScalar, num_complex::Complex}; fn main() { let mut planner = FftPlannerScalar::::new(); let fft = planner.plan_fft_forward(1024); let mut buffer: Vec> = (0..1024) .map(|i| Complex { re: i as f64, im: 0.0 }) .collect(); fft.process(&mut buffer); println!("FFT len={}, DC={:?}", fft.len(), buffer[0]); } ``` -------------------------------- ### Fft::process_immutable_with_scratch Source: https://context7.com/ejmahler/rustfft/llms.txt Performs an out-of-place FFT computation while preserving the original input data. This method requires a scratch buffer whose size can be determined using `fft.get_immutable_scratch_len()`. The typical size of this scratch buffer ranges from the length of the FFT to twice its length. ```APIDOC ## Fft::process_immutable_with_scratch ### Description Computes a FFT from an immutable `input` slice into `output`, leaving `input` untouched. Requires a scratch buffer sized by `fft.get_immutable_scratch_len()` (typically between `self.len()` and `self.len() * 2`). ### Method `process_immutable_with_scratch` ### Parameters - `input`: An immutable slice of complex numbers representing the input data. - `output`: A mutable slice of complex numbers where the FFT result will be stored. - `scratch`: A mutable slice of complex numbers for scratch space, sized by `get_immutable_scratch_len()`. ### Request Example ```rust use rustfft::{FftPlanner, num_complex::Complex}; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(512); let input: Vec> = (0..512).map(|i| Complex { re: (i as f32 * 0.02).cos(), im: 0.0 }).collect(); let mut output = vec![Complex { re: 0.0f32, im: 0.0 }; 512]; let mut scratch = vec![Complex { re: 0.0f32, im: 0.0 }; fft.get_immutable_scratch_len()]; fft.process_immutable_with_scratch(&input, &mut output, &mut scratch); ``` ### Response - The `output` buffer will contain the result of the FFT. - The `input` buffer remains unchanged. ``` -------------------------------- ### FftPlannerScalar Source: https://context7.com/ejmahler/rustfft/llms.txt Provides an explicit planner for scalar FFT algorithms, bypassing any potential SIMD optimizations. This is useful for ensuring consistent, reproducible results across different platforms or in environments where SIMD instructions should be avoided, such as for benchmarking. ```APIDOC ## FftPlannerScalar ### Description Explicit scalar (non-SIMD) planner. Forces use of scalar algorithms regardless of CPU capabilities. Useful for reproducible cross-platform benchmarks or environments where SIMD must be avoided. ### Method `FftPlannerScalar::::new()` to create a planner. `planner.plan_fft_forward(len)` to plan an FFT. `fft.process(&mut buffer)` to compute the FFT. ### Parameters - `T`: The scalar type for the complex numbers (e.g., `f32`, `f64`). - `len`: The size of the FFT. ### Request Example ```rust use rustfft::{FftPlannerScalar, num_complex::Complex}; let mut planner = FftPlannerScalar::::new(); let fft = planner.plan_fft_forward(1024); let mut buffer: Vec> = (0..1024).map(|i| Complex { re: i as f64, im: 0.0 }).collect(); fft.process(&mut buffer); ``` ### Response - The `buffer` is transformed in-place to contain the FFT result. ``` -------------------------------- ### algorithm::BluesteinsAlgorithm: Arbitrary-Size FFT Source: https://context7.com/ejmahler/rustfft/llms.txt Computes an FFT for any size N using Bluestein's method, which maps the problem to a larger convolution. An inner FFT of a suitable size (M >= 2N - 1) is required, preferably with small prime factors for performance. ```rust use rustfft::{Fft, FftPlanner, num_complex::Complex, algorithm::BluesteinsAlgorithm}; fn main() { let n = 1201; // prime-like size // inner_fft length must be >= 2*1201 - 1 = 2401; 2401 = 7^4 is a fast choice let mut planner = FftPlanner::::new(); let inner_fft = planner.plan_fft_forward(2401); let fft = BluesteinsAlgorithm::new(n, inner_fft); let mut buffer: Vec> = vec![Complex { re: 1.0, im: 0.0 }; n]; fft.process(&mut buffer); println!("Bluestein FFT of size {}", fft.len()); } ``` -------------------------------- ### algorithm::Radix4: Direct Power-of-Two FFT Source: https://context7.com/ejmahler/rustfft/llms.txt Computes FFTs for sizes that are powers of two directly, bypassing the planner. This method avoids planner overhead but does not utilize SIMD acceleration. It will panic if the input length is not a power of two. ```rust use rustfft::{Fft, FftDirection, num_complex::Complex, algorithm::Radix4}; fn main() { let fft = Radix4::::new(4096, FftDirection::Forward); let mut buffer: Vec> = (0..4096) .map(|i| Complex { re: (i as f32 * 0.001).sin(), im: 0.0 }) .collect(); fft.process(&mut buffer); println!("Size: {}, direction: {}", fft.len(), fft.fft_direction()); } ``` -------------------------------- ### Out-of-place FFT preserving input with scratch buffer Source: https://context7.com/ejmahler/rustfft/llms.txt Use `process_immutable_with_scratch` for out-of-place FFT computation where the input must remain untouched. This method requires a scratch buffer sized by `fft.get_immutable_scratch_len()`, which is typically between `self.len()` and `self.len() * 2`. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(512); let input: Vec> = (0..512) .map(|i| Complex { re: (i as f32 * 0.02).cos(), im: 0.0 }) .collect(); let mut output = vec![Complex { re: 0.0f32, im: 0.0 }; 512]; let mut scratch = vec![ Complex { re: 0.0f32, im: 0.0 }; fft.get_immutable_scratch_len() ]; fft.process_immutable_with_scratch(&input, &mut output, &mut scratch); // input is still valid here assert_eq!(input[0], Complex { re: 1.0, im: 0.0 }); println!("DC bin magnitude: {}", output[0].norm()); } ``` -------------------------------- ### Normalizing FFT Output for Round-Trip Fidelity Source: https://context7.com/ejmahler/rustfft/llms.txt Explains that RustFFT does not normalize outputs by default. A forward and inverse FFT pass scales elements by the FFT length. Normalize by multiplying by `1/len` after the inverse pass to recover the original signal. ```rust use rustfft::{FftPlanner, num_complex::Complex}; fn main() { let n = 256; let original: Vec> = (0..n) .map(|i| Complex { re: (i as f64 * 0.1).sin(), im: 0.0 }) .collect(); let mut buffer = original.clone(); let mut planner = FftPlanner::::new(); let fft_fwd = planner.plan_fft_forward(n); let fft_inv = planner.plan_fft_inverse(n); fft_fwd.process(&mut buffer); fft_inv.process(&mut buffer); // Normalize let scale = 1.0 / n as f64; for s in &mut buffer { *s *= scale; } // Verify round-trip fidelity let max_err = buffer.iter().zip(original.iter()) .map(|(a, b)| (a - b).norm()) .fold(0.0_f64, f64::max); println!("Max round-trip error: {:.2e}", max_err); // ~1e-15 } ``` -------------------------------- ### FftPlanner::plan_fft: Direction-Parameterized Planning Source: https://context7.com/ejmahler/rustfft/llms.txt Plan forward or inverse FFTs using the FftDirection enum. The compute_fft function normalizes the output for inverse transforms. ```rust use rustfft::{FftPlanner, FftDirection, num_complex::Complex}; fn compute_fft(samples: &mut Vec>, forward: bool) { let mut planner = FftPlanner::::new(); let direction = if forward { FftDirection::Forward } else { FftDirection::Inverse }; let fft = planner.plan_fft(samples.len(), direction); fft.process(samples); if !forward { let norm = 1.0 / samples.len() as f64; for s in samples.iter_mut() { *s *= norm; } } } fn main() { let mut data: Vec> = (0..512) .map(|i| Complex { re: (i as f64 * 0.1).cos(), im: 0.0 }) .collect(); compute_fft(&mut data, true); // forward compute_fft(&mut data, false); // inverse — data restored after normalization } ``` -------------------------------- ### Update FFT Direction from bool to FftDirection Enum Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md Change the constructor parameters for FFT algorithms from a boolean to the FftDirection enum (Forward or Inverse). ```rust ```rust // RustFFT 4.0 let fft_forward = Radix4::new(4096, false); let fft_inverse = Radix4::new(4096, true); // RustFFT 5.0 let fft_forward = Radix4::new(4096, FftDirection::Forward); let fft_inverse = Radix4::new(4096, FftDirection::Inverse); ``` ``` -------------------------------- ### FFTButterfly Trait Replacement Source: https://github.com/ejmahler/rustfft/blob/master/UpgradeGuide4to5.md Shows the migration from the deleted `FFTButterfly` trait to the `Fft` trait in RustFFT 5.0. Algorithms like `MixedRadixDoubleButterfly` and `GoodThomasAlgorithmDoubleButterfly` are renamed and updated to use `Fft` trait objects. ```rust // RustFFT 4.0 let butterfly8 : Arc> = Arc::new(Butterfly8::new(false)); let butterfly3 : Arc> = Arc::new(Butterfly3::new(false)); let fft1 = MixedRadixDoubleButterfly::new(Arc::clone(&butterfly8), Arc::clone(&butterfly3)); let fft2 = GoodThomasAlgorithmDoubleButterfly::new(Arc::clone(&butterfly8), Arc::clone(&butterfly3)); ``` ```rust // RustFFT 5.0 let butterfly8 : Arc> = Arc::new(Butterfly8::new(FftDirection::Forward)); let butterfly3 : Arc> = Arc::new(Butterfly3::new(FftDirection::Forward)); let fft1 = MixedRadixSmall::new(Arc::clone(&butterfly8), Arc::clone(&butterfly3)); let fft2 = GoodThomasAlgorithmSmall::new(Arc::clone(&butterfly8), Arc::clone(&butterfly3)); ``` -------------------------------- ### algorithm::MixedRadix: Direct Composite-Size FFT Source: https://context7.com/ejmahler/rustfft/llms.txt Computes an FFT of a composite size by decomposing it into two smaller FFTs of the same direction. This method bypasses SIMD acceleration. The inner FFTs must be planned beforehand. ```rust use rustfft::{Fft, FftPlanner, num_complex::Complex, algorithm::MixedRadix}; fn main() { let mut planner = FftPlanner::::new(); // 1200 = 30 * 40 let inner_n1 = planner.plan_fft_forward(30); let inner_n2 = planner.plan_fft_forward(40); let fft = MixedRadix::new(inner_n1, inner_n2); let mut buffer: Vec> = vec![Complex { re: 1.0, im: 0.0 }; 1200]; fft.process(&mut buffer); println!("MixedRadix FFT of size {}", fft.len()); // 1200 } ``` -------------------------------- ### Fft::process Source: https://context7.com/ejmahler/rustfft/llms.txt Performs an in-place FFT computation on a mutable slice of complex numbers. This method can process multiple FFT windows packed within a single buffer. ```APIDOC ## Fft::process ### Description Computes a Fast Fourier Transform in-place on a mutable slice of `Complex`. This method is designed to be efficient, potentially processing multiple FFT windows packed contiguously within the buffer. ### Method `fft_instance.process(buffer)` applies the FFT to the provided buffer. ### Parameters #### `process` - **buffer** (&mut [Complex]) - A mutable slice containing the complex numbers to be transformed. The length of the buffer must be a multiple of the FFT length planned, and each chunk of `self.len()` elements is treated as an independent FFT window. ### Request Example ```rust use rustfft::{FftPlanner, num_complex::Complex}; let fft_len = 256; let num_windows = 4; let mut planner = FftPlanner::::new(); let fft = planner.plan_fft_forward(fft_len); let mut buffer: Vec> = (0..fft_len * num_windows) .map(|i| Complex { re: (i as f32 * 0.05).sin(), im: 0.0 }) .collect(); fft.process(&mut buffer); ``` ### Response #### Success Response - The `process` method modifies the input buffer in-place, transforming each window. #### Response Example (No explicit response body, operation is in-place) ``` -------------------------------- ### FftPlanner::plan_fft Source: https://context7.com/ejmahler/rustfft/llms.txt Plans either a forward or inverse FFT using the `FftDirection` enum. This method is useful when the direction of the transform is determined at runtime. ```APIDOC ## FftPlanner::plan_fft ### Description Plans a forward or inverse FFT using the `FftDirection` enum. This is a convenient way to plan transforms when the direction is not known at compile time. ### Method `planner.plan_fft(len, direction)` plans an FFT of the specified length and direction. `fft_instance.process(buffer)` computes the FFT in-place. ### Parameters #### `plan_fft` - **len** (usize) - The size of the FFT to plan. - **direction** (FftDirection) - The direction of the FFT (`FftDirection::Forward` or `FftDirection::Inverse`). #### `process` - **buffer** (&mut [Complex]) - A mutable slice of complex numbers to transform in-place. ### Request Example ```rust use rustfft::{FftPlanner, FftDirection, num_complex::Complex}; fn compute_fft(samples: &mut Vec>, forward: bool) { let mut planner = FftPlanner::::new(); let direction = if forward { FftDirection::Forward } else { FftDirection::Inverse }; let fft = planner.plan_fft(samples.len(), direction); fft.process(samples); } let mut data: Vec> = (0..512) .map(|i| Complex { re: (i as f64 * 0.1).cos(), im: 0.0 }) .collect(); compute_fft(&mut data, true); ``` ### Response #### Success Response - The `process` method modifies the input buffer in-place. #### Response Example (No explicit response body, operation is in-place) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.