www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [std.numeric.fft] Arbitrary sized FFT

reply RIG_ <rustbucket1000 live.co.uk> writes:
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](https://dlang.org/library/std/numeric/fft.html) 
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](https://en.wikipedia.org/wiki/DFT_matrix) as a 
[Vandermonde 
matrix](http://mir-algorithm.libmir.org/mir_ndslice_filling.html) 
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`](https://www.fftw.org/), but 
it feels like doing `fft`s 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.
Nov 05 2022
next sibling parent max haughton <maxhaton gmail.com> writes:
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
Nov 05 2022
prev sibling next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
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
Nov 05 2022
prev sibling next sibling parent bachmeier <no spam.net> writes:
On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:
 I have thought about using [`fftw`](https://www.fftw.org/), but 
 it feels like doing `fft`s 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](https://pyd.dpldocs.info/v0.14.3/source/pyd.embedded.d.html).
Nov 05 2022
prev sibling next sibling parent Commander Zot <no no.no> writes:
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.
Nov 07 2022
prev sibling next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Saturday, 5 November 2022 at 14:47:40 UTC, RIG_ wrote:
 [snip]

 I have thought about using [`fftw`](https://www.fftw.org/), but 
 it feels like doing `fft`s 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.
Nov 07 2022
prev sibling next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
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](https://dlang.org/library/std/numeric/fft.html) 
 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](https://en.wikipedia.org/wiki/DFT_matrix) as a 
 [Vandermonde 
 matrix](http://mir-algorithm.libmir.org/mir_ndslice_filling.html) 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`](https://www.fftw.org/), but 
 it feels like doing `fft`s 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
Nov 07 2022
prev sibling parent reply Commander Zot <no no.no> writes:
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, 

	//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));
}
Nov 08 2022
parent jmh530 <john.michael.hall gmail.com> writes:
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.
Nov 08 2022