result of FFT

Matthew monkeytonk115 at gmail.com
Wed Jul 9 19:39:43 UTC 2025


On Tuesday, 8 July 2025 at 19:39:37 UTC, Dennis wrote:

> The magnitude of each element (computed with `std.complex.abs`) 
> corresponds to the amplitude of each frequency component, the 
> angle in the complex plane represents the phase (computed with 
> `std.complex.arg` in radians).

This is what I picked up from wikipedia.

> The frequencies are all relative to the FFT window. `res[0]` is 
> 0 Hz, `res[1]` corresponds to a sine wave that fits 1 cycle 
> inside your window, res[2] is 2 cycles etc. The frequency in Hz 
> depends on your sample rate. If it's 44100, 44100 / 4096 = ~10 
> so your window fits 10 times in 1 second. That means res[1] is 
> around 10 hz, res[2] 20 hz etc. up to res[4095] which is 40950 
> hz. Although everything from res[2048] onwards is just a 
> mirrored copy since 44100 samples/s can only capture 
> frequencies up to 22 Khz (for more info search 'Nyquist 
> frequency' and 'aliasing').

This was the key bit of information I didn't know.

> The closest bucket to 1209Hz is 1209 * (4096 / 44100) = 112.3, 
> which is not an exact match so it will leak frequencies in all 
> other bins, but it will still mostly contribute to bins 112 and 
> 113 so it's probably good enough to just check those.

Checking the closest bins to each frequency seems to work well, 
at least with clean sound from a wav file. It remains to be seen 
how it fares against noisy real life signals. I'll likely need a 
window function or interpolation but this is a good start.

```D
void decode_sound(float[] samples)
{
	import std.numeric;
	import std.math;
	import std.complex;
	import std.algorithm;

	size_t fft_size = 4096;
	auto f = new Fft(fft_size);

	foreach(ch; samples.chunks(fft_size))
	{
		auto res = f.fft(ch);
		double[] magnitudes = res.map!(x => x.abs).array;

		auto high = [magnitudes[112], magnitudes[124], magnitudes[137], 
magnitudes[151]].maxIndex;
		auto low  = [magnitudes[65], magnitudes[72], magnitudes[78], 
magnitudes[87]].maxIndex;

		// high and low are 0,1,2,3 depending on which DTMF tone pair 
was detected
	}
}
```

Thanks,
Matthew



More information about the Digitalmars-d-learn mailing list