From fe030b55830b5a5d283cd602f275016224a8d934 Mon Sep 17 00:00:00 2001 From: Enrique Condes Date: Sat, 19 Jul 2014 20:08:55 -0500 Subject: [PATCH] Original code --- .gitignore | 1 + Examples/FFT_01/FFT_01.pde | 90 ++++++++++++++++++ PlainFFT.cpp | 181 +++++++++++++++++++++++++++++++++++++ PlainFFT.h | 59 ++++++++++++ README.md | 30 ++++++ keywords.txt | 21 +++++ 6 files changed, 382 insertions(+) create mode 100644 .gitignore create mode 100644 Examples/FFT_01/FFT_01.pde create mode 100644 PlainFFT.cpp create mode 100644 PlainFFT.h create mode 100644 keywords.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8fe4fa --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.project diff --git a/Examples/FFT_01/FFT_01.pde b/Examples/FFT_01/FFT_01.pde new file mode 100644 index 0000000..51404c8 --- /dev/null +++ b/Examples/FFT_01/FFT_01.pde @@ -0,0 +1,90 @@ +/* + + Example of use of the FFT libray + Copyright (C) 2011 Didier Longueville + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "PlainFFT.h" + +PlainFFT FFT = PlainFFT(); /* Create FFT object */ +/* +These values can be changed in order to evaluate the functions +*/ +const uint16_t samples = 64; +double signalFrequency = 1000; +double samplingFrequency = 5000; +uint8_t signalIntensity = 100; +/* +These are the input and output vectors +Input vectors receive computed results from FFT +*/ +double vReal[samples]; +double vImag[samples]; + +#define SCL_INDEX 0x00 +#define SCL_TIME 0x01 +#define SCL_FREQUENCY 0x02 + +void setup(){ + Serial.begin(115200); + Serial.println("Ready"); +} + +void loop() +{ + /* Build raw data */ + double cycles = (((samples-1) * signalFrequency) / samplingFrequency); + for (uint8_t i = 0; i < samples; i++) { + vReal[i] = uint8_t((signalIntensity * (sin((i * (6.2831 * cycles)) / samples) + 1.0)) / 2.0); + } + PrintVector(vReal, samples, SCL_TIME); + FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */ + PrintVector(vReal, samples, SCL_TIME); + FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */ + PrintVector(vReal, samples, SCL_INDEX); + PrintVector(vImag, samples, SCL_INDEX); + FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */ + PrintVector(vReal, (samples >> 1), SCL_FREQUENCY); + double x = FFT.MajorPeak(vReal, samples, samplingFrequency); + Serial.println(x, 6); + while(1); /* Run Once */ + // delay(2000); /* Repeat after delay */ +} + +void PrintVector(double *vData, uint8_t bufferSize, uint8_t scaleType) +{ + for (uint16_t i = 0; i < bufferSize; i++) { + double abscissa; + /* Print abscissa value */ + switch (scaleType) { + case SCL_INDEX: + abscissa = (i * 1.0); + break; + case SCL_TIME: + abscissa = ((i * 1.0) / samplingFrequency); + break; + case SCL_FREQUENCY: + abscissa = ((i * 1.0 * samplingFrequency) / samples); + break; + } + Serial.print(abscissa, 6); + Serial.print(" "); + Serial.print(vData[i], 4); + Serial.println(); + } + Serial.println(); +} \ No newline at end of file diff --git a/PlainFFT.cpp b/PlainFFT.cpp new file mode 100644 index 0000000..4153d3c --- /dev/null +++ b/PlainFFT.cpp @@ -0,0 +1,181 @@ +/* + + FFT libray + Copyright (C) 2010 Didier Longueville + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "PlainFFT.h" + +#define twoPi 6.28318531 +#define fourPi 12.56637061 + +PlainFFT::PlainFFT(void) +{ +/* Constructor */ +} + +PlainFFT::~PlainFFT(void) +{ +/* Destructor */ +} + +uint8_t PlainFFT::Revision(void) +{ + return(FFT_LIB_REV); +} + +void PlainFFT::Compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir) +{ +/* Computes in-place complex-to-complex FFT */ + /* Reverse bits */ + uint16_t j = 0; + for (uint16_t i = 0; i < (samples - 1); i++) { + if (i < j) { + Swap(&vReal[i], &vReal[j]); + Swap(&vImag[i], &vImag[j]); + } + uint16_t k = (samples >> 1); + while (k <= j) { + j -= k; + k >>= 1; + } + j += k; + } + /* Compute the FFT */ + double c1 = -1.0; + double c2 = 0.0; + uint8_t l2 = 1; + for (uint8_t l = 0; (l < Exponent(samples)); l++) { + uint8_t l1 = l2; + l2 <<= 1; + double u1 = 1.0; + double u2 = 0.0; + for (j = 0; j < l1; j++) { + for (uint16_t i = j; i < samples; i += l2) { + uint16_t i1 = i + l1; + double t1 = u1 * vReal[i1] - u2 * vImag[i1]; + double t2 = u1 * vImag[i1] + u2 * vReal[i1]; + vReal[i1] = vReal[i] - t1; + vImag[i1] = vImag[i] - t2; + vReal[i] += t1; + vImag[i] += t2; + } + double z = ((u1 * c1) - (u2 * c2)); + u2 = ((u1 * c2) + (u2 * c1)); + u1 = z; + } + c2 = sqrt((1.0 - c1) / 2.0); + if (dir == FFT_FORWARD) { + c2 = -c2; + } + c1 = sqrt((1.0 + c1) / 2.0); + } + /* Scaling for reverse transform */ + if (dir != FFT_FORWARD) { + for (uint16_t i = 0; i < samples; i++) { + vReal[i] /= samples; + vImag[i] /= samples; + } + } +} + +void PlainFFT::ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples) +{ +/* vM is half the size of vReal and vImag */ + for (uint8_t i = 0; i < samples; i++) { + vReal[i] = sqrt(sq(vReal[i]) + sq(vImag[i])); + } +} + +void PlainFFT::Windowing(double *vData, uint16_t samples, uint8_t windowType, uint8_t dir) +{ +/* Weighing factors are computed once before multiple use of FFT */ +/* The weighing function is symetric; half the weighs are recorded */ + double samplesMinusOne = (double(samples) - 1.0); + for (uint16_t i = 0; i < (samples >> 1); i++) { + double indexMinusOne = double(i); + double ratio = (indexMinusOne / samplesMinusOne); + double weighingFactor = 1.0; + /* Compute and record weighting factor */ + switch (windowType) { + case FFT_WIN_TYP_RECTANGLE: /* rectangle (box car) */ + weighingFactor = 1.0; + break; + case FFT_WIN_TYP_HAMMING: /* hamming */ + weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio)); + break; + case FFT_WIN_TYP_HANN: /* hann */ + weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio)); + break; + case FFT_WIN_TYP_TRIANGLE: /* triangle (Bartlett) */ + weighingFactor = 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne); + break; + case FFT_WIN_TYP_BLACKMAN: /* blackmann */ + weighingFactor = 0.42323 - (0.49755 * (cos(twoPi * ratio))) + (0.07922 * (cos(fourPi * ratio))); + break; + case FFT_WIN_TYP_FLT_TOP: /* flat top */ + weighingFactor = 0.2810639 - (0.5208972 * cos(twoPi * ratio)) + (0.1980399 * cos(fourPi * ratio)); + break; + case FFT_WIN_TYP_WELCH: /* welch */ + weighingFactor = 1.0 - sq((indexMinusOne - samplesMinusOne / 2.0) / (samplesMinusOne / 2.0)); + break; + } + if (dir == FFT_FORWARD) { + vData[i] *= weighingFactor; + vData[samples - (i + 1)] *= weighingFactor; + } + else { + vData[i] /= weighingFactor; + vData[samples - (i + 1)] /= weighingFactor; + } + } +} + +double PlainFFT::MajorPeak(double *vD, uint16_t samples, double samplingFrequency) +{ + double maxY = 0; + uint16_t IndexOfMaxY = 0; + for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) { + if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) { + if (vD[i] > maxY) { + maxY = vD[i]; + IndexOfMaxY = i; + } + } + } + double delta = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1])); + double interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples-1); + /* retuned value: interpolated frequency peak apex */ + return(interpolatedX); +} + +/* Private functions */ + +void PlainFFT::Swap(double *x, double *y) +{ + double temp = *x; + *x = *y; + *y = temp; +} + +uint8_t PlainFFT::Exponent(uint16_t value) +{ + /* Computes the Exponent of a powered 2 value */ + uint8_t result = 0; + while (((value >> result) & 1) != 1) result++; + return(result); +} \ No newline at end of file diff --git a/PlainFFT.h b/PlainFFT.h new file mode 100644 index 0000000..5a49570 --- /dev/null +++ b/PlainFFT.h @@ -0,0 +1,59 @@ +/* + + FFT libray + Copyright (C) 2010 Didier Longueville + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PlainFFT_h /* Prevent loading library twice */ +#define PlainFFT_h + +#include "WProgram.h" /* This is where the standard Arduino code lies */ + +#define FFT_LIB_REV 0x02 +/* Custom constants */ +#define FFT_FORWARD 0x01 +#define FFT_REVERSE 0x00 +/* Windowing type */ +#define FFT_WIN_TYP_RECTANGLE 0x00 /* rectangle (Box car) */ +#define FFT_WIN_TYP_HAMMING 0x01 /* hamming */ +#define FFT_WIN_TYP_HANN 0x02 /* hann */ +#define FFT_WIN_TYP_TRIANGLE 0x03 /* triangle (Bartlett) */ +#define FFT_WIN_TYP_BLACKMAN 0x04 /* blackmann */ +#define FFT_WIN_TYP_FLT_TOP 0x05 /* flat top */ +#define FFT_WIN_TYP_WELCH 0x06 /* welch */ + +class PlainFFT { +public: + /* Constructor */ + PlainFFT(void); + /* Destructor */ + ~PlainFFT(void); + /* Functions */ + void ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples); + void Compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir); + double MajorPeak(double *vD, uint16_t samples, double samplingFrequency); + uint8_t Revision(void); + void Windowing(double *vData, uint16_t samples, uint8_t windowType, uint8_t dir); + +private: + /* Functions */ + uint8_t Exponent(uint16_t value); + void Swap(double *x, double *y); + +}; + +#endif diff --git a/README.md b/README.md index 7251692..cad7c21 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,33 @@ arduinoFFT Fast Fourier Transform for Arduino This is a fork from https://code.google.com/p/makefurt/ which has been abandoned since 2011. + +This is a C++ library for Arduino for computing FFT. +Tested on Arduino 0022 Alpha. + +Installation +-------------------------------------------------------------------------------- + +To install this library, just place this entire folder as a subfolder in your + + +When installed, this library should look like: + +Arduino\libraries\PlainFTT (this library's folder) +Arduino\libraries\PlainFTT\PlainFTT.cpp (the library implementation file, uses 32 bits floats vectors) +Arduino\libraries\PlainFTT\PlainFTT.h (the library description file, uses 32 bits floats vectors) +Arduino\libraries\PlainFTT\PlainFTT_INT.cpp (the library implementation file, experimental signed 16 bits vectors) +Arduino\libraries\PlainFTT\PlainFTT_INT.h (the library description file, experimental signed 16 bits vectors) +Arduino\libraries\PlainFTT\keywords.txt (the syntax coloring file) +Arduino\libraries\PlainFTT\examples (the examples in the "open" menu) +Arduino\libraries\PlainFTT\readme.txt (this file) + +Building +-------------------------------------------------------------------------------- + +After this library is installed, you just have to start the Arduino application. +You may see a few warning messages as it's built. + +To use this library in a sketch, go to the Sketch | Import Library menu and +select PlainFTT. This will add a corresponding line to the top of your sketch: +#include (or #include diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..93e62ae --- /dev/null +++ b/keywords.txt @@ -0,0 +1,21 @@ +####################################### +# Syntax Coloring Map For PlainFFT +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +PlainFFT KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +complexToMagnitude KEYWORD2 +compute KEYWORD2 +windowing KEYWORD2 +exponent KEYWORD2 +swap KEYWORD2 +revision KEYWORD2 +majorPeak KEYWORD2 \ No newline at end of file