fourier arduino

Download Fourier Arduino

If you can't read please download the document

Upload: guibur

Post on 30-Nov-2015

300 views

Category:

Documents


2 download

TRANSCRIPT

Conceptualmente hablando FFT es bastante simple. En la prctica, la FFT es difcil! As que no voy a entrar en todos los detalles de este algoritmo y voy a permanecer centrado en su uso y aplicaciones. Esta serie de mensajes va a terminar con una biblioteca con todas las funciones que usted ser capaz de utilizar para todo tipo de aplicaciones, sin preocuparse de las matemticas.

La trama en un osciloscopio muestra una onda que est hecha de muestras que se caracterizan por sus intensidades (ordenadas) y su tiempo de muestreo (abscisa). Estamos en el dominio del tiempo.

Cuanto ms simple sea la seal (por ejemplo, una onda sinusoidal simple), el ms simple es la caracterizacin. La transformada de Fourier propone para descomponer cualquier seal en una suma de seno y coseno. Para cada punto de datos del espectro de potencia de FFT corresponde una magnitud (ordenadas) y una frecuencia (abscisa). Ahora estamos en el dominio de la frecuencia.

Cuanto ms compleja es la seal (por ejemplo, la seal + ruido + armnicos + +) ...

..... ms compleja es la caracterizacin.

Y adivinen qu? El algoritmo de la FFT se puede ejecutar en modo inverso, de modo que a partir de una FFT puede reconstruir una seal de la vida real. Podemos estudiar ms adelante cmo esta propiedad puede ser utilizado para la de eliminacin de ruido de las seales.

FFT se aplica a vectores que contienen las muestras n, donde n debe ser una potencia de 2. Ejecutar el algoritmo de estos datos puede conducir a resultados inesperados. La razn es que el vector trunca la informacin de la seal y pueden contener ondas incompletamente descritas (por ejemplo, las ondas de baja frecuencia). Este efecto secundario puede ser corregida por medio de pesaje de la seal, dando menos importancia a los datos principales y colas. Esta es la funcin de ventanas. La funcin de pesaje en la ventanas depende del tipo de seal a analizar:

Transients whose duration is shorter than the length of the window : Rectangular (Box car) Transients whose duration is longer than the length of the window : Exponential, Hann

General-purpose applications : Hann

Spectral analysis (frequency-response measurements) : Hann (for random excitation), Rectangular (for pseudorandom excitation)

Separation of two tones with frequencies very close to each other but with widely differing amplitudes : Kaiser-Bessel

Separation of two tones with frequencies very close to each other but with almost equal amplitudes : Rectangular

Accurate single-tone amplitude measurements : Flat top

Sine wave or combination of sine waves : Hann

Sine wave and amplitude accuracy is important : Flat top

Narrowband random signal (vibration data) : Hann

Broadband random (white noise) : Uniform

Closely spaced sine waves : Uniform, Hamming

Excitation signals (hammer blow) : Force

Response signals : Exponential

Unknown content : Hann

Once the windowing is executed, you can run the FFT. The result of this algorithm lies in to vectors containing the real and imaginary computed values. You need then to apply some math to convert them into a vector of intensities.Window type Rectangle (box car)

Window type Hamming:

Window type Flat top

All plots exported from my DSP tool box Panorama

Here is a recap of the pieces of code that we need in order to convert a wave into a frequency spectrum:Store data in a vector (Double data type)

Weigh this data according to one function (default is Rectangle, also known as box car, in other words, no weighing!)

Execute the FFT algorithm

Convert complex values in usable data

Without knowing too much of the details from the various algorithms, you will very quickly face a dilemma: would you prefer speed or precision? Precision will require large vectors of data, while speed will require multiple vectors: e.g. instead of computing weighed values for each new set of data, we could compute weighing factors once and apply them repeatedly. Same thoughts for the bit reversal at the top of the FFT algorithm.The proposed example do not use pre-processing of data, to the benefit of the number of samples, and to the clarity of the code.Firstly, some constants shall be declared in the header (.h) file

01// Custom constants

02#define FORWARD 0x01

03#define REVERSE 0x00

04// Windowing type

05#define WIN_TYP_RECTANGLE 0x00// rectangle (Box car)

06#define WIN_TYP_HAMMING 0x01// hamming

07#define WIN_TYP_HANN 0x02// hann

08#define WIN_TYP_TRIANGLE 0x03// triangle (Bartlett)

09#define WIN_TYP_BLACKMAN 0x04// blackmann

10#define WIN_TYP_FLT_TOP 0x05// flat top

11#define WIN_TYP_WELCH 0x06// welch

Then data shall be stored in one of the two fixed size vectors

1const uint8_t samples = 64;

2double vReal[samples];

3double vImag[samples];

And this is the weighing routine

01void PlainFFT::windowing(double *vData, uint8_t samples, uint8_t windowType, uint8_t dir) {

02// The weighing function is symetric; half the weighs are recorded

03double samplesMinusOne = (double(samples) - 1.0);

04for (uint8_t i = 0; i < (samples >> 1); i++) {

05double indexMinusOne = double(i);

06double ratio = (indexMinusOne / samplesMinusOne);

07double weighingFactor = 1.0;

08// compute and record weighting factor

09switch (windowType) {

10case WIN_TYP_RECTANGLE: // rectangle (box car)

11weighingFactor = 1.0;

12break;

13case WIN_TYP_HAMMING: // hamming

14weighingFactor = 0.54 - (0.46 * cos(2.0 * pi * ratio));

15break;

16case WIN_TYP_HANN: // hann

17weighingFactor = 0.54 * (1.0 - cos(2.0 * pi * ratio));

18break;

19case WIN_TYP_TRIANGLE: // triangle (Bartlett)

20weighingFactor = 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne);

21break;

22case WIN_TYP_BLACKMAN: // blackmann

23weighingFactor = 0.42323 - (0.49755 * (cos(2.0 * pi * ratio))) + (0.07922 * (cos(4.0 * pi * ratio)));

24break;

25case WIN_TYP_FLT_TOP: // flat top

26weighingFactor = 0.2810639 - (0.5208972 * cos(2.0 * pi * ratio)) + (0.1980399 * cos(4.0 * pi * ratio));

27break;

28case WIN_TYP_WELCH: // welch

29weighingFactor = 1.0 - sq((indexMinusOne - samplesMinusOne / 2.0) / (samplesMinusOne / 2.0));

30break;

31}

32if (dir == FORWARD) {

33vData[i] *= weighingFactor;

34vData[samples - (i + 1)] *= weighingFactor;

35}

36else {

37vData[i] /= weighingFactor;

38vData[samples - (i + 1)] /= weighingFactor;

39}

40}

41}

Notes:There is a little trick here. As the weighing function is symetrical, why bother computing them all? Half of them are computed and applied symetrically to the vector of data

The dir parameter stands for direction: remember, FFT is reversible, so that we can apply it in FORWARD or REVERSE mode

FFT stands for fast Fourier Transform. The DFT (Direct Fourier Transform) applies to vectors containing any number of signal samples. But it is sssssssssllllllllllllllllllllllloooooooooooooowwwwwwww due to the repeated number of operation. Computing a DFT of n points takes n^2 arithmetical operations, while an FFT can compute the same result in only n log2(n) operations. The implemented algorithm is the CooleyTukey algorithm which the far most popular. The only limitation is that the number of samples in the signal must be a power of two. However, if the number of samples is less than that, it is possible to replace missing data with 0 values without affecting the final result: this is the zero padding.01void PlainFFT::compute(double *vR, double *vI, uint8_t samples, uint8_t dir) {

02// This computes an in-place complex-to-complex FFT

03// dir = 1 gives forward transform, dir = 0 gives reverse transform

04// Reverse bits

05uint8_t j = 0;

06for (uint8_t i = 0; i < (samples - 1); i++) {

07if (i < j) {

08swap(&vR[i], &vR[j]);

09swap(&vI[i], &vI[j]);

10}

11uint8_t k = (samples >> 1);

12while (k >= 1;

15}

16j += k;

17}

18// Compute the FFT

19double c1 = -1.0;

20double c2 = 0.0;

21uint8_t l2 = 1;

22for (uint8_t l = 0; l < exponent(samples); l++) {

23uint8_t l1 = l2;

24l2