Thread overview
[std.numeric.fft] Arbitrary sized FFT
Nov 05, 2022
RIG_
Nov 05, 2022
max haughton
Nov 05, 2022
Imperatorn
Nov 05, 2022
bachmeier
Nov 07, 2022
Commander Zot
Nov 07, 2022
jmh530
Nov 07, 2022
Imperatorn
Nov 08, 2022
Commander Zot
Nov 08, 2022
jmh530
November 05, 2022

Hi,

I want to use D for scientific programming (I work at a University). It's fast, it's readable, and it's so nice to use, but I'm probably going to be forced to use Python / MATLAB unless I can easily do a Fast Fourier Transform.

The current FFT implementation only allows for performing a one-dimensional Fourier transform across a one-dimensional Range.

I need to be able to do a Fourier Transform of an arbitrary-sized complex-values Slice with as many axes as I need.
I had thought about some kind of DFT Matrix as a Vandermonde matrix approach, but the slow-down that I'd see using D would not be worth it.

I would be happy to implement it myself, but I don't know enough about D, nor the FFT algorithms to do so.

I have thought about using fftw, but it feels like doing ffts should in the standard library.

I'd say a wishlist is something on parity with NumPy, where I can take a fft of arbitrary-sized Range across an arbitrary axis. As it stands, the current fft implementation isn't particularly useful without some inbuilt helper methods such as fftshift, ifftshift, fftfreq, etc.

November 05, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

Hi,

I want to use D for scientific programming (I work at a University). It's fast, it's readable, and it's so nice to use, but I'm probably going to be forced to use Python / MATLAB unless I can easily do a Fast Fourier Transform.

[...]
Re numpy: have you seen mir

November 05, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

Hi,

I want to use D for scientific programming (I work at a University). It's fast, it's readable, and it's so nice to use, but I'm probably going to be forced to use Python / MATLAB unless I can easily do a Fast Fourier Transform.

[...]

Remember that D can use anything from C, so if you find a lib you can just use it.

But have you tried Mir?

I also found this in dub:
https://code.dlang.org/packages/pfft

November 05, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

I have thought about using fftw, but it feels like doing ffts should in the standard library.

I don't think so. D is a general purpose programming language. Note that you are talking about Python as an option, but you're actually referring to numpy, which is a Python library the user has to install.

One of the selling points of D is its interoperability with other languages. If for whatever reason you don't want to call C, you can call Python to do that part of the analysis.

November 07, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

Hi,

I want to use D for scientific programming (I work at a University). It's fast, it's readable, and it's so nice to use, but I'm probably going to be forced to use Python / MATLAB unless I can easily do a Fast Fourier Transform.

[...]

i use liquiddsp. i even ported it to D. but it's probably outdated.
i'd be happy to have it in the std lib though.

November 07, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

[snip]

I have thought about using fftw, but it feels like doing ffts should in the standard library.

[snip]

I would guess that whatever python does is written in C and then called from python. For some things, it doesn't make sense to reinvent the wheel, and I think fft probably fits. D has the ability to call C code. Now, it might be that the API for fftw is very C-like. A D wrapper that is more convenient to use might be worthwhile as a dub project (not knowing anything about fftw).

With respect to whether it should be in the standard library, it might make sense to get it solid as a dub library and then propose that for phobos inclusion. This is how sumtype was added. It can be difficult to work on the same schedule as phobos.

It would be nice if there were a way to use this with importC, but taking a brief look at the fftw github page (with the big warnings that you shouldn't check it out unless you know what you're doing) suggests that might not be so easy.

November 07, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

Hi,

I want to use D for scientific programming (I work at a University). It's fast, it's readable, and it's so nice to use, but I'm probably going to be forced to use Python / MATLAB unless I can easily do a Fast Fourier Transform.

The current FFT implementation only allows for performing a one-dimensional Fourier transform across a one-dimensional Range.

I need to be able to do a Fourier Transform of an arbitrary-sized complex-values Slice with as many axes as I need.
I had thought about some kind of DFT Matrix as a Vandermonde matrix approach, but the slow-down that I'd see using D would not be worth it.

I would be happy to implement it myself, but I don't know enough about D, nor the FFT algorithms to do so.

I have thought about using fftw, but it feels like doing ffts should in the standard library.

I'd say a wishlist is something on parity with NumPy, where I can take a fft of arbitrary-sized Range across an arbitrary axis. As it stands, the current fft implementation isn't particularly useful without some inbuilt helper methods such as fftshift, ifftshift, fftfreq, etc.

What about using something like this?

https://github.com/d1vanov/Simple-FFT

Some extra reading:
https://github.com/atilaneves/dpp
https://github.com/Superbelko/ohmygentool
https://github.com/dkorpel/ctod
https://github.com/jacob-carlborg/dstep
http://rainers.github.io/visuald/visuald/CppConversion.html

November 08, 2022

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

here's a binding to liquiddsp fft algorithms, just for anyone interested.

extern(C) {
enum LIQUID_VERSION = "1.3.1";
enum LIQUID_VERSION_NUMBER = 1003001;
extern const(char)* liquid_version;
const(char) * liquid_libversion();
int liquid_libversion_number();

/// Change Log: 2.096.0 Added __c_complex_float, __c_complex_double, and __c_complex_real types#
//alias liquid_float_complex = cfloat;
//alias liquid_double_complex = cdouble;
public import core.stdc.config;
alias liquid_float_complex = __c_complex_float;
alias liquid_double_complex = __c_complex_double;

}

extern(C) {
enum liquid_fft_type {
LIQUID_FFT_UNKNOWN = 0, // unknown transform type

	// regular complex one-dimensional transforms
	LIQUID_FFT_FORWARD  =  +1,  // complex one-dimensional FFT
	LIQUID_FFT_BACKWARD =  -1,  // complex one-dimensional inverse FFT

	// discrete cosine transforms
	LIQUID_FFT_REDFT00  =  10,  // real one-dimensional DCT-I
	LIQUID_FFT_REDFT10  =  11,  // real one-dimensional DCT-II
	LIQUID_FFT_REDFT01  =  12,  // real one-dimensional DCT-III
	LIQUID_FFT_REDFT11  =  13,  // real one-dimensional DCT-IV

	// discrete sine transforms
	LIQUID_FFT_RODFT00  =  20,  // real one-dimensional DST-I
	LIQUID_FFT_RODFT10  =  21,  // real one-dimensional DST-II
	LIQUID_FFT_RODFT01  =  22,  // real one-dimensional DST-III
	LIQUID_FFT_RODFT11  =  23,  // real one-dimensional DST-IV

	// modified discrete cosine transform
	LIQUID_FFT_MDCT     =  30,  // MDCT
	LIQUID_FFT_IMDCT    =  31,  // IMDCT
}

private enum LIQUID_FFT_DEFINE_API(string PRE, T, TC) = `
	struct %PRE%plan_s;
	alias %PRE%plan = %PRE%plan_s*;
	%PRE%plan %PRE%_create_plan(uint n, %TC%* x, %TC%* y, int dir, int flags);
	%PRE%plan %PRE%_create_plan_r2r_1d(uint n, %T%* x, %T%* y, int type, int flags);
	void %PRE%_destroy_plan(%PRE%plan p);
	void %PRE%_print_plan(%PRE%plan p);
	void %PRE%_execute(%PRE%plan p);
	void %PRE%_run(uint n, %TC%* x, %TC%* y, int dir, int flags);
	void %PRE%_r2r_1d_run(uint n, %T%* x, %T%* y, int type, int flags);
	void %PRE%_shift(%TC%* x, uint n);
`.replace("%PRE%", PRE).replace("%T%", T.stringof).replace("%TC%", TC.stringof);
mixin(LIQUID_FFT_DEFINE_API!("fft", float, liquid_float_complex));

private enum LIQUID_SPGRAM_DEFINE_API(string PRE, T, TC, TI) = `
	struct %PRE%_s;
	alias %PRE% = %PRE%_s*;
	%PRE% %PRE%_create(uint nfft, int wtype, uint window_len, uint delay);
	%PRE% %PRE%_create_default(uint nfft);
	void %PRE%_destroy(%PRE% q);
	void %PRE%_clear(%PRE% q);
	void %PRE%_reset(%PRE% q);
	void %PRE%_print(%PRE% q);
	int %PRE%_set_alpha(%PRE% q, float alpha);
	int %PRE%_set_freq(%PRE% q, float freq);
	int %PRE%_set_rate(%PRE% q, float rate);
	uint %PRE%_get_nfft(%PRE% q);
	uint %PRE%_get_window_len(%PRE% q);
	uint %PRE%_get_delay(%PRE% q);
	ulong %PRE%_get_num_samples(%PRE% q);
	ulong %PRE%_get_num_samples_total(%PRE% q);
	ulong %PRE%_get_num_transforms(%PRE% q);
	ulong %PRE%_get_num_transforms_total(%PRE% q);
	float %PRE%_get_alpha(%PRE% q);
	void %PRE%_push(%PRE% q, %TI% x);
	void %PRE%_write(%PRE% q, %TI%* x, uint n);
	void %PRE%_get_psd(%PRE% q, %T%* X);
	int %PRE%_export_gnuplot(%PRE% q, const(char)* filename);
	void %PRE%_estimate_psd(uint nfft, %TI%* x, uint n, %T%* psd);
`.replace("%PRE%", PRE).replace("%T%", T.stringof).replace("%TC%", TC.stringof).replace("%TI%", TI.stringof);
mixin(LIQUID_SPGRAM_DEFINE_API!("spgramcf", float, liquid_float_complex, liquid_float_complex));
mixin(LIQUID_SPGRAM_DEFINE_API!("spgramf", float, liquid_float_complex, float));

private enum LIQUID_ASGRAM_DEFINE_API(string PRE, T, TC, TI) = `
	struct %PRE%_s;
	alias %PRE% = %PRE%_s*;
	%PRE% %PRE%_create(uint nfft);
	void %PRE%_destroy(%PRE% q);
	void %PRE%_reset(%PRE% q);
	void %PRE%_set_scale(%PRE% q, float ref_lvl, float div);
	void %PRE%_set_display(%PRE% q, const(char)* ascii);
	void %PRE%_push(%PRE% q, %TI% x);
	void %PRE%_write(%PRE% q, %TI%* x, uint n);
	void %PRE%_execute(%PRE% q, char*  ascii, float * peakval, float * peakfreq);
	void %PRE%_print(%PRE% q);
`.replace("%PRE%", PRE).replace("%T%", T.stringof).replace("%TC%", TC.stringof).replace("%TI%", TI.stringof);
mixin(LIQUID_ASGRAM_DEFINE_API!("asgramcf", float, liquid_float_complex, liquid_float_complex));
mixin(LIQUID_ASGRAM_DEFINE_API!("asgramf", float, liquid_float_complex, float));

private enum LIQUID_SPWATERFALL_DEFINE_API(string PRE, T, TC, TI) = `
	struct %PRE%_s;
	alias %PRE% = %PRE%_s*;
	%PRE% %PRE%_create(uint _nfft, int _wtype, uint _window_len, uint _delay, uint _time);
	%PRE% %PRE%_create_default(uint _nfft, uint _time);
	void %PRE%_destroy(%PRE% _q);
	void %PRE%_clear(%PRE% _q);
	void %PRE%_reset(%PRE% _q);
	void %PRE%_print(%PRE% _q);
	void %PRE%_push(%PRE% _q, %TI% _x);
	void %PRE%_write(%PRE% _q, %TI% * _x, uint  _n);
	int %PRE%_export(%PRE% _q, const(char)* _base);
`.replace("%PRE%", PRE).replace("%T%", T.stringof).replace("%TC%", TC.stringof).replace("%TI%", TI.stringof);
mixin(LIQUID_SPWATERFALL_DEFINE_API!("spwaterfallcf", float, liquid_float_complex, liquid_float_complex));
mixin(LIQUID_SPWATERFALL_DEFINE_API!("spwaterfallf", float, liquid_float_complex, float));

}

November 08, 2022

On Tuesday, 8 November 2022 at 10:40:03 UTC, Commander Zot wrote:

>

On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:

>

here's a binding to liquiddsp fft algorithms, just for anyone interested.

[snip]

Hopefully that works for you, but it is more likely that people will use it if you make it a dub package and put it on code.dlang.org.