ar1st0crat / NWaves

.NET DSP library with a lot of audio processing functions
MIT License
453 stars 71 forks source link

Maximum size of FFT depending on the sampling rate #44

Closed andrasfuchs closed 3 years ago

andrasfuchs commented 3 years ago

I use NWaves on a Raspberry Pi that has an external A/D to calculate FFTs. As I tested different sampling rates and FFT sizes I got IndexOutOfRangeExceptions with certain settings.

To reproduce the problem, you can use a DiscreteSignal with RealFft's MagnitudeSpectrum method. It normally works just fine, but if I increase the FFT size or lower my sampling rate, there is always a point where I got an exception.

I don't know enough about FFT to know if it's a theoretical limit or an intentional limit, but either way it would be great to have a more detailed Exception to explain the reason.

The sampling rate, and FFT size settings that I used and got the exception: 200kHz sampling rate, 1024k or higher 250kHz - 400kHz sampling rate, 2048k or higher 500kHz sampling rate, 4096k or higher

I had 5 seconds of data in my DiscreteSignal in all cases.

The exact stack trace of the IndexOutOfRangeException exception is:

   at NWaves.Transforms.RealFft.Direct(Single[] input, Single[] re, Single[] im)
   at NWaves.Transforms.RealFft.MagnitudeSpectrum(Single[] samples, Single[] spectrum, Boolean normalize)
   at NWaves.Transforms.RealFft.MagnitudeSpectrum(DiscreteSignal signal, Boolean normalize)
   at SleepLogger.Program.<>c__DisplayClass10_1.<Main>b__3() in C:\Work\BioBalanceDetector\Measurements\WaveForms\Experiments\SleepLogging\csharp\SleepLogger\Program.cs:line 256

Could you have a look?

ar1st0crat commented 3 years ago

FFT transformers don't depend on sampling rate. Could you show some of your code? I guess you do FFTs in a loop? If the size of input array is less than FFT size then you'll get IndexOutOfRange. Perhaps, this happens with the last frame (it should be zero-padded to fft size). Anyway, it's only my first guess, and more code will be helpful.

andrasfuchs commented 3 years ago

You can see the whole source code at my repo: https://github.com/andrasfuchs/BioBalanceDetector/tree/master/Measurements/WaveForms/Experiments/SleepLogging/csharp/SleepLogger

The relevant code starts at this line I think. At this point I have the samples as an array of floats in the samples variable.

I create a DiscreteSignal and I do the FFT later on in a separate thread here using RealFft. As you can see I have the exception handler just after this point.

andrasfuchs commented 3 years ago

If the size of input array is less than FFT size then you'll get IndexOutOfRange. Perhaps, this happens with the last frame (it should be zero-padded to fft size).

I think your guess is right. :) I tried the zero-padding, and it works, thank you!

Would you consider adding the zero-padding to the MagnitudeSpectrum method or make a custom Exception with some explanation instead of this general IndexOutOfRangeException?

ar1st0crat commented 3 years ago

This is one of the cases where I wanted to squeeze out as much performance as possible. Writing a library both fast and OOP-friendly / user-friendly is not an easy endeavor ))). These FFT-based methods are often used extensively in loops, so I'd prefer not to add any checks/pre-conditions and leave it to user (at this relatively low level of processing, similar to good old C++). I suppose, making better documentation / samples / video tutorials would be more useful now, and I hope I'll find some time soon for this (and adding new functionality, of course ))).

ToGoOrNotToGo commented 3 years ago

I hope I'll find some time soon for this (and adding new functionality, of course ))).

Good news! :-)