From 4019b12c9bba716826ef95a312a34ce298a510de Mon Sep 17 00:00:00 2001 From: Enrique Condes Date: Thu, 3 Jan 2019 00:32:15 +0800 Subject: [PATCH] New MajorPeak fucntion that returns peak magnitude --- Examples/FFT_05/FFT_05.ino | 119 +++++++++++++++++++++++++++++++++++++ src/arduinoFFT.cpp | 50 +++++++++++++++- src/arduinoFFT.h | 4 ++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 Examples/FFT_05/FFT_05.ino diff --git a/Examples/FFT_05/FFT_05.ino b/Examples/FFT_05/FFT_05.ino new file mode 100644 index 0000000..7abe3b6 --- /dev/null +++ b/Examples/FFT_05/FFT_05.ino @@ -0,0 +1,119 @@ +/* + + Example of use of the FFT libray + Copyright (C) 2014 Enrique Condes + + 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 . + +*/ + +/* + In this example, the Arduino simulates the sampling of a sinusoidal 1000 Hz + signal with an amplitude of 100, sampled at 5000 Hz. Samples are stored + inside the vReal array. The samples are windowed according to Hamming + function. The FFT is computed using the windowed samples. Then the magnitudes + of each of the frequencies that compose the signal are calculated. Finally, + the frequency with the highest peak is obtained, being that the main frequency + present in the signal. This frequency is printed, along with the magnitude of + the peak. +*/ + +#include "arduinoFFT.h" + +arduinoFFT FFT = arduinoFFT(); /* Create FFT object */ +/* +These values can be changed in order to evaluate the functions +*/ +const uint16_t samples = 64; //This value MUST ALWAYS be a power of 2 +const double signalFrequency = 1000; +const double samplingFrequency = 5000; +const uint8_t amplitude = 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 +#define SCL_PLOT 0x03 + +void setup() +{ + Serial.begin(115200); + Serial.println("Ready"); +} + +void loop() +{ + /* Build raw data */ + double cycles = (((samples-1) * signalFrequency) / samplingFrequency); //Number of signal cycles that the sampling will read + for (uint16_t i = 0; i < samples; i++) + { + vReal[i] = int8_t((amplitude * (sin((i * (twoPi * cycles)) / samples))) / 2.0);/* Build data with positive and negative values*/ + //vReal[i] = uint8_t((amplitude * (sin((i * (twoPi * cycles)) / samples) + 1.0)) / 2.0);/* Build data displaced on the Y axis to include only positive values*/ + vImag[i] = 0.0; //Imaginary part must be zeroed in case of looping to avoid wrong calculations and overflows + } + /* Print the results of the simulated sampling according to time */ + Serial.println("Data:"); + PrintVector(vReal, samples, SCL_TIME); + FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */ + Serial.println("Weighed data:"); + PrintVector(vReal, samples, SCL_TIME); + FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */ + Serial.println("Computed Real values:"); + PrintVector(vReal, samples, SCL_INDEX); + Serial.println("Computed Imaginary values:"); + PrintVector(vImag, samples, SCL_INDEX); + FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */ + Serial.println("Computed magnitudes:"); + PrintVector(vReal, (samples >> 1), SCL_FREQUENCY); + double x; + double v; + FFT.MajorPeak(vReal, samples, samplingFrequency, &x, &v); + Serial.print(x, 6); + Serial.print(", "); + Serial.println(v, 6); + while(1); /* Run Once */ + // delay(2000); /* Repeat after delay */ +} + +void PrintVector(double *vData, uint16_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); + if(scaleType==SCL_FREQUENCY) + Serial.print("Hz"); + Serial.print(" "); + Serial.println(vData[i], 4); + } + Serial.println(); +} diff --git a/src/arduinoFFT.cpp b/src/arduinoFFT.cpp index d4b411b..2f10d04 100644 --- a/src/arduinoFFT.cpp +++ b/src/arduinoFFT.cpp @@ -334,10 +334,33 @@ double arduinoFFT::MajorPeak() double interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples-1); if(IndexOfMaxY==(this->_samples >> 1)) //To improve calculation on edge values interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples); - // retuned value: interpolated frequency peak apex + // returned value: interpolated frequency peak apex return(interpolatedX); } +void arduinoFFT::MajorPeak(double *f, double *v) +{ + double maxY = 0; + uint16_t IndexOfMaxY = 0; + //If sampling_frequency = 2 * max_frequency in signal, + //value would be stored at position samples/2 + for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) { + if ((this->_vReal[i - 1] < this->_vReal[i]) && (this->_vReal[i] > this->_vReal[i + 1])) { + if (this->_vReal[i] > maxY) { + maxY = this->_vReal[i]; + IndexOfMaxY = i; + } + } + } + double delta = 0.5 * ((this->_vReal[IndexOfMaxY - 1] - this->_vReal[IndexOfMaxY + 1]) / (this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) + this->_vReal[IndexOfMaxY + 1])); + double interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples - 1); + if (IndexOfMaxY == (this->_samples >> 1)) //To improve calculation on edge values + interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples); + // returned value: interpolated frequency peak apex + *f = interpolatedX; + *v = abs(this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) + this->_vReal[IndexOfMaxY + 1]); +} + double arduinoFFT::MajorPeak(double *vD, uint16_t samples, double samplingFrequency) { #warning("This method is deprecated and will be removed on future revisions.") @@ -361,6 +384,31 @@ double arduinoFFT::MajorPeak(double *vD, uint16_t samples, double samplingFreque return(interpolatedX); } +void arduinoFFT::MajorPeak(double *vD, uint16_t samples, double samplingFrequency, double *f, double *v) +{ + #warning("This method is deprecated and will be removed on future revisions.") + double maxY = 0; + uint16_t IndexOfMaxY = 0; + //If sampling_frequency = 2 * max_frequency in signal, + //value would be stored at position samples/2 + 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); + //double popo = + if (IndexOfMaxY == (samples >> 1)) //To improve calculation on edge values + interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples); + // returned value: interpolated frequency peak apex + *f = interpolatedX; + *v = abs(vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]); +} + uint8_t arduinoFFT::Exponent(uint16_t value) { #warning("This method will not be accessible on future revisions.") diff --git a/src/arduinoFFT.h b/src/arduinoFFT.h index 665dea3..2324e72 100644 --- a/src/arduinoFFT.h +++ b/src/arduinoFFT.h @@ -81,6 +81,10 @@ public: double MajorPeak(); void Windowing(uint8_t windowType, uint8_t dir); + void MajorPeak(double *f, double *v); + void MajorPeak(double *vD, uint16_t samples, double samplingFrequency, double *f, double *v); + + private: /* Variables */ uint16_t _samples;