preiter93 / ndrustfft

*n*-dimensional R2R/R2C/C2C FFT and R2R DCT (rustfft + ndarray)
MIT License
21 stars 7 forks source link

`ndfft_r2c` call with seemingly valid input panics. #5

Closed skewballfox closed 2 years ago

skewballfox commented 2 years ago

I'm running into an issue where ndfft_r2c panics when called with parameters that seem valid. the size of the input(frames) in this instance is [6248,512], the size of output(spectrum_vector) is [6248,257]. handler was fed the value 512, and the transformation is happening upon the second axis(1).

here's the code:

fn fft_spectrum(frames: Array2<f64>, fft_points: usize /*=512*/) -> Array2<f64> {
    println!("starting fft points");
    let row_size = frames.shape()[0];
    let col_size = frames.shape()[1];
    let mut handler = R2cFftHandler::<f64>::new(fft_points);
    let frames = if col_size < fft_points {
        concatenate![Axis(1), frames, Array2::<f64>::zeros((row_size,fft_points-col_size)) ] }else{ frames };

    println!("declaring spectrum vector");
    let mut spectrum_vector = Array2::<Complex<f64>>::zeros((row_size, fft_points / 2 + 1));
    println!("starting ndfft_r2c");
    ndfft_r2c(
        &frames.view(),
        &mut spectrum_vector.view_mut(),
        &mut handler,
        1
    );
    println!("finished ndfft");
    spectrum_vector.map(|v: &Complex<f64>| -> f64 { (v.re.powf(2.) + v.im.powf(2.)).sqrt() as f64 })
}

the code throws the following error:

thread 'tests::test_mfcc' panicked at 'called `Option::unwrap()` on a `None` value', /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndrustfft-0.3.0/src/lib.rs:453:1

when running a traceback, this seems to originate from the zip function at line 97 inside lib.rs. The full traceback is attached below

stack backtrace:
   0: rust_begin_unwind
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:142:14
   2: core::panicking::panic
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:48:5
   3: core::option::Option<T>::unwrap
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/option.rs:755:21
   4: ndrustfft::ndfft_r2c::{{closure}}
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndrustfft-0.3.0/src/lib.rs:100:36
   5: ndarray::zip::Zip<(P1,P2),D>::for_each::{{closure}}
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:582:41
   6: ndarray::zip::Zip<P,D>::inner
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:354:31
   7: ndarray::zip::Zip<P,D>::for_each_core_strided_c
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:393:35
   8: ndarray::zip::Zip<P,D>::for_each_core_strided
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:371:13
   9: ndarray::zip::Zip<P,D>::for_each_core
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:319:13
  10: ndarray::zip::Zip<(P1,P2),D>::for_each
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndarray-0.15.4/src/zip/mod.rs:580:17
  11: ndrustfft::ndfft_r2c
             at /home/skewballfox/.cargo/registry/src/github.com-1ecc6299db9ec823/ndrustfft-0.3.0/src/lib.rs:97:17
  12: mfcc_2::processing::fft_spectrum
             at ./src/processing.rs:162:5
  13: mfcc_2::processing::power_spectrum
             at ./src/processing.rs:184:5
  14: mfcc_2::feature::mfe
             at ./src/feature.rs:237:26
  15: mfcc_2::feature::mfcc
             at ./src/feature.rs:127:33
  16: mfcc_2::tests::test_mfcc
             at ./src/lib.rs:85:20
  17: mfcc_2::tests::test_mfcc::{{closure}}
             at ./src/lib.rs:71:5
  18: core::ops::function::FnOnce::call_once
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/ops/function.rs:248:5
  19: core::ops::function::FnOnce::call_once
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/ops/function.rs:248:5
preiter93 commented 2 years ago

Hi,

thanks for the report!

Unfortunately, I can't reproduce the error. The following code runs fine on my machine:

use ndarray::{concatenate, Array2, Axis};
use ndrustfft::{ndfft_r2c, Complex, R2cFftHandler};

fn fft_spectrum(frames: Array2<f64>, fft_points: usize /*=512*/) -> Array2<f64> {
    println!("starting fft points");
    let row_size = frames.shape()[0];
    let col_size = frames.shape()[1];
    let mut handler = R2cFftHandler::<f64>::new(fft_points);
    let frames = if col_size < fft_points {
        concatenate![
            Axis(1),
            frames,
            Array2::<f64>::zeros((row_size, fft_points - col_size))
        ]
    } else {
        frames
    };

    println!("declaring spectrum vector");
    let mut spectrum_vector = Array2::<Complex<f64>>::zeros((row_size, fft_points / 2 + 1));
    println!("starting ndfft_r2c");
    ndfft_r2c(
        &frames.view(),
        &mut spectrum_vector.view_mut(),
        &mut handler,
        1,
    );
    println!("finished ndfft");
    spectrum_vector.map(|v: &Complex<f64>| -> f64 { (v.re.powf(2.) + v.im.powf(2.)).sqrt() as f64 })
}

fn main() {
    let frames: Array2<f64> = Array2::ones((6248, 512));
    fft_spectrum(frames, 512);
}

So I think the reason lies in the frames array. Are there maybe NaN values in frames? Can you give me a full example, where you also call the fft_spectrum function? Then I try to investigate further!

Best regards

skewballfox commented 2 years ago

sure, this is currently being called inside test_mfcc inside mfcc-rust.

A couple of notes:

frames shouldn't have any NaNs, otherwise wouldn't that generate an error somewhere earlier in the call stack as the type is explicitly f64?

preiter93 commented 2 years ago

Thx, the error is probably caused by calling ndfft_r2c with an array that does not conform to the standard layout, i.e. row major (C). In your case, the frames array has a column major layout (F). This should be handled somehow in ndrustfft. I am thinking of a solution, maybe tomorrow or next week.

skewballfox commented 2 years ago

so after checking the method is_standard_layout for frames a few times, concat seems to be changing the order in a way I wasn't expecting, frames was row major before the zero padding, and column major after.

definitely changing that. I'm not sure if I should close this issue or not, if that makes the problem disappear on my end.

preiter93 commented 2 years ago

Lets leave it open and I think about a fix for v0.4. I was planning an update either way, to add the option for different normalizations.

preiter93 commented 2 years ago

Branch v0.4 works with different array layouts. I will update it on crates.io shortly.