use crate::error::{FFTError, FFTResult};
use crate::fft::ifft;
use scirs2_core::numeric::Complex64;
use std::f64::consts::PI;
use super::algorithms::SparseFFTResult;
#[allow(dead_code)]
pub fn reconstruct_spectrum(
sparse_result: &SparseFFTResult,
n: usize,
) -> FFTResult<Vec<Complex64>> {
let mut spectrum = vec![Complex64::new(0.0, 0.0); n];
for (value, &index) in sparse_result
.values
.iter()
.zip(sparse_result.indices.iter())
{
spectrum[index] = *value;
}
Ok(spectrum)
}
#[allow(dead_code)]
pub fn reconstruct_time_domain(
sparse_result: &SparseFFTResult,
n: usize,
) -> FFTResult<Vec<Complex64>> {
let mut spectrum = vec![Complex64::new(0.0, 0.0); n];
for (value, &index) in sparse_result
.values
.iter()
.zip(sparse_result.indices.iter())
{
spectrum[index] = *value;
}
ifft(&spectrum, None)
}
#[allow(dead_code)]
pub fn reconstruct_high_resolution(
sparse_result: &SparseFFTResult,
original_length: usize,
target_length: usize,
) -> FFTResult<Vec<Complex64>> {
if target_length < original_length {
return Err(FFTError::DimensionError(format!(
"Target _length {target_length} must be greater than or equal to original _length {original_length}"
)));
}
let mut spectrum = vec![Complex64::new(0.0, 0.0); original_length];
for (value, &index) in sparse_result
.values
.iter()
.zip(sparse_result.indices.iter())
{
spectrum[index] = *value;
}
let mut high_res_spectrum = vec![Complex64::new(0.0, 0.0); target_length];
let original_nyquist = original_length / 2;
let target_nyquist = target_length / 2;
high_res_spectrum[0] = spectrum[0];
#[allow(clippy::needless_range_loop)]
for i in 1..=original_nyquist {
let new_idx =
((i as f64) * (target_nyquist as f64) / (original_nyquist as f64)).round() as usize;
if new_idx < target_length {
high_res_spectrum[new_idx] = spectrum[i];
}
}
if original_length.is_multiple_of(2) {
#[allow(clippy::needless_range_loop)]
for i in (original_nyquist + 1)..original_length {
let rel_pos = original_length - i;
let new_idx = target_length - rel_pos;
if new_idx < target_length {
high_res_spectrum[new_idx] = spectrum[i];
}
}
if original_length.is_multiple_of(2) && target_length.is_multiple_of(2) {
high_res_spectrum[target_nyquist] = spectrum[original_nyquist];
}
} else {
#[allow(clippy::needless_range_loop)]
for i in (original_nyquist + 1)..original_length {
let rel_pos = original_length - i;
let new_idx = target_length - rel_pos;
if new_idx < target_length {
high_res_spectrum[new_idx] = spectrum[i];
}
}
}
ifft(&high_res_spectrum, None)
}
#[allow(dead_code)]
pub fn reconstruct_filtered<F>(
sparse_result: &SparseFFTResult,
n: usize,
filter_fn: F,
) -> FFTResult<Vec<Complex64>>
where
F: Fn(usize, usize) -> f64,
{
let mut spectrum = vec![Complex64::new(0.0, 0.0); n];
for (value, &index) in sparse_result
.values
.iter()
.zip(sparse_result.indices.iter())
{
let scale = filter_fn(index, n);
spectrum[index] = *value * scale;
}
ifft(&spectrum, None)
}
#[cfg(test)]
mod tests {
use super::super::algorithms::sparse_fft;
use super::*;
fn create_test_signal(n: usize) -> Vec<f64> {
let mut signal = vec![0.0; n];
for i in 0..n {
let t = 2.0 * PI * (i as f64) / (n as f64);
signal[i] = 1.0 * (3.0 * t).sin() + 0.5 * (7.0 * t).sin();
}
signal
}
#[test]
fn test_reconstruct_spectrum() {
let signal = create_test_signal(64);
let sparse_result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
let spectrum = reconstruct_spectrum(&sparse_result, 64).expect("Operation failed");
assert_eq!(spectrum.len(), 64);
let non_zero_count = spectrum.iter().filter(|&c| c.norm() > 1e-10).count();
assert_eq!(non_zero_count, sparse_result.values.len());
for (&index, &value) in sparse_result
.indices
.iter()
.zip(sparse_result.values.iter())
{
assert!(index < spectrum.len());
assert!(
spectrum[index].norm() > 1e-10,
"Expected non-zero value at index {index}"
);
}
}
#[test]
fn test_reconstruct_time_domain() {
let signal = create_test_signal(64);
let sparse_result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
let reconstructed = reconstruct_time_domain(&sparse_result, 64).expect("Operation failed");
assert_eq!(reconstructed.len(), 64);
}
#[test]
fn test_reconstruct_high_resolution() {
let signal = create_test_signal(32);
let sparse_result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
let high_res =
reconstruct_high_resolution(&sparse_result, 32, 64).expect("Operation failed");
assert_eq!(high_res.len(), 64);
}
#[test]
fn test_reconstruct_high_resolution_invalid_length() {
let signal = create_test_signal(32);
let sparse_result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
let result = reconstruct_high_resolution(&sparse_result, 32, 16);
assert!(result.is_err());
}
#[test]
fn test_reconstruct_filtered() {
let signal = create_test_signal(64);
let sparse_result = sparse_fft(&signal, 6, None, None).expect("Operation failed");
let filter = |freq_index: usize, n: usize| -> f64 {
if freq_index <= n / 8 || freq_index >= 7 * n / 8 {
1.0
} else {
0.0
}
};
let filtered = reconstruct_filtered(&sparse_result, 64, filter).expect("Operation failed");
assert_eq!(filtered.len(), 64);
}
}