This version of DFT algorithm has been tested with success on a various microcontrollers (AVR – including ATtiny13, STM32 and ESP8266). The code is relatively simple and short what makes it easy to port to other programming languages / microcontrollers. In this tutorial I will open the black-box and show you some practical information about how this algorithm works and how to use it in your projects. I really recommend to make an experiments with different signal frequencies, sampling frequencies and number of N-points.
What You Need
To make it easier to understand and reproduce on your desktop I have created an example codes in Python. So, you need a computer and Python (version >= 2.7) with matplotlib package installed.
Generating Signal Samples
At first, we need to produce some example data. Bellow is the function that helps to generate a signal samples. You can pass signal frequency and sampling frequency as an argument.
#!/usr/bin/env python
import math
from matplotlib import pyplot
def signal(signal_frequency, sampling_frequency, volume=1.0, duration=1.0):
samples = []
samples_per_cycle = int(sampling_frequency/signal_frequency)
samples_number = int(sampling_frequency * duration)
for i in range(samples_number):
sample = 255 * volume
sample *= math.sin(math.pi * 2.0 * (i % samples_per_cycle) / samples_per_cycle)
samples.append(int(sample))
return samples
signal_frequency = 8000
sampling_frequency = 44100
duration = 100. / sampling_frequency
samples = signal(signal_frequency, sampling_frequency, 1.0, duration)
pyplot.plot(samples)
pyplot.ylabel('Amplitude')
pyplot.xlabel('Signal')
pyplot.show()
Computing Twiddle Factors
Bellow is an implementation of Euler’s Formula for Twiddle Factors.
#!/usr/bin/env python
import math
from matplotlib import pyplot
def twiddle_factors(N):
return [math.cos(n*2*math.pi/N) for n in range(N)]
N = 100 # N-points
factors = twiddle_factors(N)
pyplot.plot(factors)
pyplot.xlabel('Twiddle Factors')
pyplot.show()
Optimized DFT Algorithm
Finally, the DFT algorithm do samples processing. The output result is a power spectrum of the signal.
#!/usr/bin/env python
import math
from matplotlib import pyplot
def twiddle_factors(N):
return [math.cos(n*2*math.pi/N) for n in range(N)]
def signal(signal_frequency, sampling_frequency, volume=1.0, duration=1.0):
samples = []
samples_per_cycle = int(sampling_frequency/signal_frequency)
samples_number = int(sampling_frequency * duration)
for i in range(samples_number):
sample = 255 * volume
sample *= math.sin(math.pi * 2.0 * (i % samples_per_cycle) / samples_per_cycle)
samples.append(int(sample))
return samples
def dft(samples, N):
twiddle = twiddle_factors(N) # prepare factors for N-points
offset = 3 * N / 4 # index offset for sin (const for N-points)
re = [0.0] * N
im = [0.0] * N
power = [0.0] * N # power spectrum
for k in range(N/2 + 1):
a, b = 0, offset;
for n in range(N):
re[k] += samples[n] * twiddle[a % N]
im[k] -= samples[n] * twiddle[b % N]
a += k
b += k
power[k] = (re[k]*re[k] + im[k]*im[k]) / (N*N);
return power
N = 100 # N-points
signal_frequency = 8000
sampling_frequency = 44100
duration = N * 1. / sampling_frequency
samples = signal(signal_frequency, sampling_frequency, 1.0, duration)
power_spectrum = dft(samples, N)
pyplot.plot(power_spectrum)
pyplot.xlabel('Power Spectrum')
pyplot.show()

Calculating Frequency Bands
for index in range(N/2):
print("frequency(%d)=%d[Hz]" % (index, sampling_frequency * index/N))
...
[0] freqency=0[Hz], power=0
[1] freqency=441[Hz], power=0
[2] freqency=882[Hz], power=0
[3] freqency=1323[Hz], power=0
[4] freqency=1764[Hz], power=0
[5] freqency=2205[Hz], power=0
[6] freqency=2646[Hz], power=0
[7] freqency=3087[Hz], power=0
[8] freqency=3528[Hz], power=0
[9] freqency=3969[Hz], power=0
[10] freqency=4410[Hz], power=0
[11] freqency=4851[Hz], power=0
[12] freqency=5292[Hz], power=0
[13] freqency=5733[Hz], power=0
[14] freqency=6174[Hz], power=0
[15] freqency=6615[Hz], power=0
[16] freqency=7056[Hz], power=0
[17] freqency=7497[Hz], power=0
[18] freqency=7938[Hz], power=0
[19] freqency=8379[Hz], power=0
[20] freqency=8820[Hz], power=161529539
...
Finding Maximum Value In Power Spectrum
value = max(power_spectrum)
index = power_spectrum.index(value)
print("Maximum value=%d for frequency=%d" % (value, sampling_frequency * index/N))
...
Maximum value=161529539 for frequency=8820
...


Hi Łukasz Podkalicki.
I see the signal generated at 8Khz frequency. However, the FFT algorithm shows that this signal is 8.8Kz. Has there been a mistake here?
Thanks !
Hi! Thank you for this question. Yes, indeed. It happens because example function which generates signal is not so accurate (I’m using floor on real numbers). Anyway, good eyes! 🙂
/L