swharden/FftSharp

Input length smaller than 16

arthurits opened this issue · 6 comments

It seems that this library currently doesn't support input signals whose length is smaller that 16 elements.
As far as I can see, this might be due to the use of ArrayPool here:

Complex[] temp = ArrayPool<Complex>.Shared.Rent(input.Length);

which allocates arrays of lengths: 16, 32, 64, 128, 256, 512, 1,024, 2,048, 4,096, 8,192, 16,384, 3,2768, 65,536, 131,072, 262,144, 524,288 and 1,048,576 elements.

Signal inputs for FFT are usually greater than 16 in length, but there might be still some use cases (ie: for testing or educational purposes) where smaller inputs are FFT-ed.

I believe this could be easily incorporated by adding the following line after the previous one:

Span<Complex> buffer = temp.AsSpan(0, input.Length);

Should the above suggestion be considered, it would also be necessary to modify the 16-element-length check here:

public static void FFTmagnitude(Span<double> destination, Span<double> input)
{
if (input.Length < 16)
throw new ArgumentException("This overload requires an input with at least 16 points");

Maybe something like this?

if (input.Length < 2)
    throw new ArgumentException("Input should have 2 points at least");

Would like to hearing your thoughts before attempting any PR, @swharden.

I'd be happy to add support for small FFTs! I'm fine with any implementation you think as best, as long as some tests are added to confirm the FFT output of some sample data matches the numbers generated with Python

I think there are some notes in the existing tests or maybe this repo's top level folder that help generate numbers for those tests.

Thanks for this suggestion! I can review a PR if you make one, or I'll implement this myself eventually

I'll make the PR. However, I can only help with providing input data for the tests, since I don't use/code with Python. Would that help to do the tests? (I've attached two files: a 4-point 1 Hz sinus and an 8-point 1 Hz sinus, which seem to generate logical FFT values).
Sine wave - 1 Hz - 4 pt.txt
Sine wave - 1 Hz - 8 pt.txt

Sure thing! I see the PR (thanks!) and I'll do the Python stuff and add those tests.

I anticipate being able to finish this and release a new package this evening 🚀

Thank you!

Note to self, here's some python:

import numpy as np

values = [0.33, 2.15, 1.44, 1.37, 0.24, 2.6, 3.51, 1.98]

N = len(values)
fft = np.fft.fft(values)
fftReal = np.fft.rfft(values)
fftMag = np.abs(fftReal) * 2 / N
fftMag[0] = np.abs(fftReal[0]) / N  # special case for DC
print(fftMag)
[1.7025     0.70671034 1.14957601 0.33016737 0.645     ]

resolved by #63