Bump to version 1.6

pull/81/head v1.6
kosme 2023-03-09 22:28:40 -06:00
rodzic 11b7937333
commit 94453e54ac
5 zmienionych plików z 579 dodań i 500 usunięć

Wyświetl plik

@ -1,3 +1,6 @@
03/09/23 v1.6
Include some functionality from development branch.
01/27/20 v1.5.5 01/27/20 v1.5.5
Lookup table for constants c1 and c2 used during FFT comupting. This increases the FFT computing speed in around 5%. Lookup table for constants c1 and c2 used during FFT comupting. This increases the FFT computing speed in around 5%.

Wyświetl plik

@ -20,7 +20,7 @@
"email": "contact@arduinoos.com" "email": "contact@arduinoos.com"
} }
], ],
"version": "1.5.6", "version": "1.6",
"frameworks": ["arduino","mbed","espidf"], "frameworks": ["arduino","mbed","espidf"],
"platforms": "*", "platforms": "*",
"headers": "arduinoFFT.h" "headers": "arduinoFFT.h"

Wyświetl plik

@ -1,5 +1,5 @@
name=arduinoFFT name=arduinoFFT
version=1.5.6 version=1.6
author=Enrique Condes <enrique@shapeoko.com> author=Enrique Condes <enrique@shapeoko.com>
maintainer=Enrique Condes <enrique@shapeoko.com> maintainer=Enrique Condes <enrique@shapeoko.com>
sentence=A library for implementing floating point Fast Fourier Transform calculations on Arduino. sentence=A library for implementing floating point Fast Fourier Transform calculations on Arduino.

Wyświetl plik

@ -21,489 +21,529 @@
#include "arduinoFFT.h" #include "arduinoFFT.h"
arduinoFFT::arduinoFFT(void) arduinoFFT::arduinoFFT(void) { // Constructor
{ // Constructor #warning("This method is deprecated and may be removed on future revisions.")
#warning("This method is deprecated and may be removed on future revisions.")
} }
arduinoFFT::arduinoFFT(double *vReal, double *vImag, uint16_t samples, double samplingFrequency) arduinoFFT::arduinoFFT(double *vReal, double *vImag, uint16_t samples,
{// Constructor double samplingFrequency) { // Constructor
this->_vReal = vReal; this->_vReal = vReal;
this->_vImag = vImag; this->_vImag = vImag;
this->_samples = samples; this->_samples = samples;
this->_samplingFrequency = samplingFrequency; this->_samplingFrequency = samplingFrequency;
this->_power = Exponent(samples); this->_power = Exponent(samples);
} }
arduinoFFT::~arduinoFFT(void) arduinoFFT::~arduinoFFT(void) {
{ // Destructor
// Destructor
} }
uint8_t arduinoFFT::Revision(void) uint8_t arduinoFFT::Revision(void) { return (FFT_LIB_REV); }
{
return(FFT_LIB_REV); void arduinoFFT::Compute(double *vReal, double *vImag, uint16_t samples,
FFTDirection dir) {
#warning("This method is deprecated and may be removed on future revisions.")
Compute(vReal, vImag, samples, Exponent(samples), dir);
} }
void arduinoFFT::Compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir) void arduinoFFT::Compute(FFTDirection dir) {
{ // Computes in-place complex-to-complex FFT /
#warning("This method is deprecated and may be removed on future revisions.") // Reverse bits /
Compute(vReal, vImag, samples, Exponent(samples), dir); uint16_t j = 0;
} for (uint16_t i = 0; i < (this->_samples - 1); i++) {
if (i < j) {
void arduinoFFT::Compute(uint8_t dir) Swap(&this->_vReal[i], &this->_vReal[j]);
{// Computes in-place complex-to-complex FFT / if (dir == FFT_REVERSE)
// Reverse bits / Swap(&this->_vImag[i], &this->_vImag[j]);
uint16_t j = 0; }
for (uint16_t i = 0; i < (this->_samples - 1); i++) { uint16_t k = (this->_samples >> 1);
if (i < j) { while (k <= j) {
Swap(&this->_vReal[i], &this->_vReal[j]); j -= k;
if(dir==FFT_REVERSE) k >>= 1;
Swap(&this->_vImag[i], &this->_vImag[j]); }
} j += k;
uint16_t k = (this->_samples >> 1); }
while (k <= j) { // Compute the FFT
j -= k;
k >>= 1;
}
j += k;
}
// Compute the FFT /
#ifdef __AVR__ #ifdef __AVR__
uint8_t index = 0; uint8_t index = 0;
#endif #endif
double c1 = -1.0; double c1 = -1.0;
double c2 = 0.0; double c2 = 0.0;
uint16_t l2 = 1; uint16_t l2 = 1;
for (uint8_t l = 0; (l < this->_power); l++) { for (uint8_t l = 0; (l < this->_power); l++) {
uint16_t l1 = l2; uint16_t l1 = l2;
l2 <<= 1; l2 <<= 1;
double u1 = 1.0; double u1 = 1.0;
double u2 = 0.0; double u2 = 0.0;
for (j = 0; j < l1; j++) { for (j = 0; j < l1; j++) {
for (uint16_t i = j; i < this->_samples; i += l2) { for (uint16_t i = j; i < this->_samples; i += l2) {
uint16_t i1 = i + l1; uint16_t i1 = i + l1;
double t1 = u1 * this->_vReal[i1] - u2 * this->_vImag[i1]; double t1 = u1 * this->_vReal[i1] - u2 * this->_vImag[i1];
double t2 = u1 * this->_vImag[i1] + u2 * this->_vReal[i1]; double t2 = u1 * this->_vImag[i1] + u2 * this->_vReal[i1];
this->_vReal[i1] = this->_vReal[i] - t1; this->_vReal[i1] = this->_vReal[i] - t1;
this->_vImag[i1] = this->_vImag[i] - t2; this->_vImag[i1] = this->_vImag[i] - t2;
this->_vReal[i] += t1; this->_vReal[i] += t1;
this->_vImag[i] += t2; this->_vImag[i] += t2;
} }
double z = ((u1 * c1) - (u2 * c2)); double z = ((u1 * c1) - (u2 * c2));
u2 = ((u1 * c2) + (u2 * c1)); u2 = ((u1 * c2) + (u2 * c1));
u1 = z; u1 = z;
} }
#ifdef __AVR__ #ifdef __AVR__
c2 = pgm_read_float_near(&(_c2[index])); c2 = pgm_read_float_near(&(_c2[index]));
c1 = pgm_read_float_near(&(_c1[index])); c1 = pgm_read_float_near(&(_c1[index]));
index++; index++;
#else #else
c2 = sqrt((1.0 - c1) / 2.0); c2 = sqrt((1.0 - c1) / 2.0);
c1 = sqrt((1.0 + c1) / 2.0); c1 = sqrt((1.0 + c1) / 2.0);
#endif #endif
if (dir == FFT_FORWARD) { if (dir == FFT_FORWARD) {
c2 = -c2; c2 = -c2;
} }
} }
// Scaling for reverse transform / // Scaling for reverse transform /
if (dir != FFT_FORWARD) { if (dir != FFT_FORWARD) {
for (uint16_t i = 0; i < this->_samples; i++) { for (uint16_t i = 0; i < this->_samples; i++) {
this->_vReal[i] /= this->_samples; this->_vReal[i] /= this->_samples;
this->_vImag[i] /= this->_samples; this->_vImag[i] /= this->_samples;
} }
} }
} }
void arduinoFFT::Compute(double *vReal, double *vImag, uint16_t samples, uint8_t power, uint8_t dir) void arduinoFFT::Compute(double *vReal, double *vImag, uint16_t samples,
{ // Computes in-place complex-to-complex FFT uint8_t power, FFTDirection dir) {
// Reverse bits // Computes in-place complex-to-complex FFT
#warning("This method is deprecated and may be removed on future revisions.") // Reverse bits
uint16_t j = 0; #warning("This method is deprecated and may be removed on future revisions.")
for (uint16_t i = 0; i < (samples - 1); i++) { uint16_t j = 0;
if (i < j) { for (uint16_t i = 0; i < (samples - 1); i++) {
Swap(&vReal[i], &vReal[j]); if (i < j) {
if(dir==FFT_REVERSE) Swap(&vReal[i], &vReal[j]);
Swap(&vImag[i], &vImag[j]); if (dir == FFT_REVERSE)
} Swap(&vImag[i], &vImag[j]);
uint16_t k = (samples >> 1); }
while (k <= j) { uint16_t k = (samples >> 1);
j -= k; while (k <= j) {
k >>= 1; j -= k;
} k >>= 1;
j += k; }
} j += k;
// Compute the FFT }
// Compute the FFT
#ifdef __AVR__ #ifdef __AVR__
uint8_t index = 0; uint8_t index = 0;
#endif #endif
double c1 = -1.0; double c1 = -1.0;
double c2 = 0.0; double c2 = 0.0;
uint16_t l2 = 1; uint16_t l2 = 1;
for (uint8_t l = 0; (l < power); l++) { for (uint8_t l = 0; (l < power); l++) {
uint16_t l1 = l2; uint16_t l1 = l2;
l2 <<= 1; l2 <<= 1;
double u1 = 1.0; double u1 = 1.0;
double u2 = 0.0; double u2 = 0.0;
for (j = 0; j < l1; j++) { for (j = 0; j < l1; j++) {
for (uint16_t i = j; i < samples; i += l2) { for (uint16_t i = j; i < samples; i += l2) {
uint16_t i1 = i + l1; uint16_t i1 = i + l1;
double t1 = u1 * vReal[i1] - u2 * vImag[i1]; double t1 = u1 * vReal[i1] - u2 * vImag[i1];
double t2 = u1 * vImag[i1] + u2 * vReal[i1]; double t2 = u1 * vImag[i1] + u2 * vReal[i1];
vReal[i1] = vReal[i] - t1; vReal[i1] = vReal[i] - t1;
vImag[i1] = vImag[i] - t2; vImag[i1] = vImag[i] - t2;
vReal[i] += t1; vReal[i] += t1;
vImag[i] += t2; vImag[i] += t2;
} }
double z = ((u1 * c1) - (u2 * c2)); double z = ((u1 * c1) - (u2 * c2));
u2 = ((u1 * c2) + (u2 * c1)); u2 = ((u1 * c2) + (u2 * c1));
u1 = z; u1 = z;
} }
#ifdef __AVR__ #ifdef __AVR__
c2 = pgm_read_float_near(&(_c2[index])); c2 = pgm_read_float_near(&(_c2[index]));
c1 = pgm_read_float_near(&(_c1[index])); c1 = pgm_read_float_near(&(_c1[index]));
index++; index++;
#else #else
c2 = sqrt((1.0 - c1) / 2.0); c2 = sqrt((1.0 - c1) / 2.0);
c1 = sqrt((1.0 + c1) / 2.0); c1 = sqrt((1.0 + c1) / 2.0);
#endif #endif
if (dir == FFT_FORWARD) { if (dir == FFT_FORWARD) {
c2 = -c2; c2 = -c2;
} }
} }
// Scaling for reverse transform // Scaling for reverse transform
if (dir != FFT_FORWARD) { if (dir != FFT_FORWARD) {
for (uint16_t i = 0; i < samples; i++) { for (uint16_t i = 0; i < samples; i++) {
vReal[i] /= samples; vReal[i] /= samples;
vImag[i] /= samples; vImag[i] /= samples;
} }
} }
} }
void arduinoFFT::ComplexToMagnitude() void arduinoFFT::ComplexToMagnitude() {
{ // vM is half the size of vReal and vImag // vM is half the size of vReal and vImag
for (uint16_t i = 0; i < this->_samples; i++) { for (uint16_t i = 0; i < this->_samples; i++) {
this->_vReal[i] = sqrt(sq(this->_vReal[i]) + sq(this->_vImag[i])); this->_vReal[i] = sqrt(sq(this->_vReal[i]) + sq(this->_vImag[i]));
} }
} }
void arduinoFFT::ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples) void arduinoFFT::ComplexToMagnitude(double *vReal, double *vImag,
{ // vM is half the size of vReal and vImag uint16_t samples) {
#warning("This method is deprecated and may be removed on future revisions.") // vM is half the size of vReal and vImag
for (uint16_t i = 0; i < samples; i++) { #warning("This method is deprecated and may be removed on future revisions.")
vReal[i] = sqrt(sq(vReal[i]) + sq(vImag[i])); for (uint16_t i = 0; i < samples; i++) {
} vReal[i] = sqrt(sq(vReal[i]) + sq(vImag[i]));
}
} }
void arduinoFFT::DCRemoval() void arduinoFFT::DCRemoval() {
{ // calculate the mean of vData
// calculate the mean of vData double mean = 0;
double mean = 0; for (uint16_t i = 0; i < this->_samples; i++) {
for (uint16_t i = 0; i < this->_samples; i++) mean += this->_vReal[i];
{ }
mean += this->_vReal[i]; mean /= this->_samples;
} // Subtract the mean from vData
mean /= this->_samples; for (uint16_t i = 0; i < this->_samples; i++) {
// Subtract the mean from vData this->_vReal[i] -= mean;
for (uint16_t i = 0; i < this->_samples; i++) }
{
this->_vReal[i] -= mean;
}
} }
void arduinoFFT::DCRemoval(double *vData, uint16_t samples) void arduinoFFT::DCRemoval(double *vData, uint16_t samples) {
{ // calculate the mean of vData
// calculate the mean of vData #warning("This method is deprecated and may be removed on future revisions.")
#warning("This method is deprecated and may be removed on future revisions.") double mean = 0;
double mean = 0; for (uint16_t i = 0; i < samples; i++) {
for (uint16_t i = 0; i < samples; i++) mean += vData[i];
{ }
mean += vData[i]; mean /= samples;
} // Subtract the mean from vData
mean /= samples; for (uint16_t i = 0; i < samples; i++) {
// Subtract the mean from vData vData[i] -= mean;
for (uint16_t i = 0; i < samples; i++) }
{
vData[i] -= mean;
}
} }
void arduinoFFT::Windowing(uint8_t windowType, uint8_t dir) void arduinoFFT::Windowing(FFTWindow windowType, FFTDirection dir) {
{// Weighing factors are computed once before multiple use of FFT // Weighing factors are computed once before multiple use of FFT
// The weighing function is symmetric; half the weighs are recorded // The weighing function is symmetric; half the weighs are recorded
double samplesMinusOne = (double(this->_samples) - 1.0); double samplesMinusOne = (double(this->_samples) - 1.0);
for (uint16_t i = 0; i < (this->_samples >> 1); i++) { for (uint16_t i = 0; i < (this->_samples >> 1); i++) {
double indexMinusOne = double(i); double indexMinusOne = double(i);
double ratio = (indexMinusOne / samplesMinusOne); double ratio = (indexMinusOne / samplesMinusOne);
double weighingFactor = 1.0; double weighingFactor = 1.0;
// Compute and record weighting factor // Compute and record weighting factor
switch (windowType) { switch (windowType) {
case FFT_WIN_TYP_RECTANGLE: // rectangle (box car) case FFT_WIN_TYP_RECTANGLE: // rectangle (box car)
weighingFactor = 1.0; weighingFactor = 1.0;
break; break;
case FFT_WIN_TYP_HAMMING: // hamming case FFT_WIN_TYP_HAMMING: // hamming
weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio)); weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio));
break; break;
case FFT_WIN_TYP_HANN: // hann case FFT_WIN_TYP_HANN: // hann
weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio)); weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio));
break; break;
case FFT_WIN_TYP_TRIANGLE: // triangle (Bartlett) case FFT_WIN_TYP_TRIANGLE: // triangle (Bartlett)
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
weighingFactor = 1.0 - ((2.0 * fabs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne); weighingFactor =
#else 1.0 - ((2.0 * fabs(indexMinusOne - (samplesMinusOne / 2.0))) /
weighingFactor = 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne); samplesMinusOne);
#endif #else
break; weighingFactor =
case FFT_WIN_TYP_NUTTALL: // nuttall 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) /
weighingFactor = 0.355768 - (0.487396 * (cos(twoPi * ratio))) + (0.144232 * (cos(fourPi * ratio))) - (0.012604 * (cos(sixPi * ratio))); samplesMinusOne);
break; #endif
case FFT_WIN_TYP_BLACKMAN: // blackman break;
weighingFactor = 0.42323 - (0.49755 * (cos(twoPi * ratio))) + (0.07922 * (cos(fourPi * ratio))); case FFT_WIN_TYP_NUTTALL: // nuttall
break; weighingFactor = 0.355768 - (0.487396 * (cos(twoPi * ratio))) +
case FFT_WIN_TYP_BLACKMAN_NUTTALL: // blackman nuttall (0.144232 * (cos(fourPi * ratio))) -
weighingFactor = 0.3635819 - (0.4891775 * (cos(twoPi * ratio))) + (0.1365995 * (cos(fourPi * ratio))) - (0.0106411 * (cos(sixPi * ratio))); (0.012604 * (cos(sixPi * ratio)));
break; break;
case FFT_WIN_TYP_BLACKMAN_HARRIS: // blackman harris case FFT_WIN_TYP_BLACKMAN: // blackman
weighingFactor = 0.35875 - (0.48829 * (cos(twoPi * ratio))) + (0.14128 * (cos(fourPi * ratio))) - (0.01168 * (cos(sixPi * ratio))); weighingFactor = 0.42323 - (0.49755 * (cos(twoPi * ratio))) +
break; (0.07922 * (cos(fourPi * ratio)));
case FFT_WIN_TYP_FLT_TOP: // flat top break;
weighingFactor = 0.2810639 - (0.5208972 * cos(twoPi * ratio)) + (0.1980399 * cos(fourPi * ratio)); case FFT_WIN_TYP_BLACKMAN_NUTTALL: // blackman nuttall
break; weighingFactor = 0.3635819 - (0.4891775 * (cos(twoPi * ratio))) +
case FFT_WIN_TYP_WELCH: // welch (0.1365995 * (cos(fourPi * ratio))) -
weighingFactor = 1.0 - sq((indexMinusOne - samplesMinusOne / 2.0) / (samplesMinusOne / 2.0)); (0.0106411 * (cos(sixPi * ratio)));
break; break;
} case FFT_WIN_TYP_BLACKMAN_HARRIS: // blackman harris
if (dir == FFT_FORWARD) { weighingFactor = 0.35875 - (0.48829 * (cos(twoPi * ratio))) +
this->_vReal[i] *= weighingFactor; (0.14128 * (cos(fourPi * ratio))) -
this->_vReal[this->_samples - (i + 1)] *= weighingFactor; (0.01168 * (cos(sixPi * ratio)));
} break;
else { case FFT_WIN_TYP_FLT_TOP: // flat top
this->_vReal[i] /= weighingFactor; weighingFactor = 0.2810639 - (0.5208972 * cos(twoPi * ratio)) +
this->_vReal[this->_samples - (i + 1)] /= weighingFactor; (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) {
this->_vReal[i] *= weighingFactor;
this->_vReal[this->_samples - (i + 1)] *= weighingFactor;
} else {
this->_vReal[i] /= weighingFactor;
this->_vReal[this->_samples - (i + 1)] /= weighingFactor;
}
}
} }
void arduinoFFT::Windowing(double *vData, uint16_t samples,
void arduinoFFT::Windowing(double *vData, uint16_t samples, uint8_t windowType, uint8_t dir) FFTWindow windowType, FFTDirection dir) {
{// Weighing factors are computed once before multiple use of FFT // Weighing factors are computed once before multiple use of FFT
// The weighing function is symetric; half the weighs are recorded // The weighing function is symetric; half the weighs are recorded
#warning("This method is deprecated and may be removed on future revisions.") #warning("This method is deprecated and may be removed on future revisions.")
double samplesMinusOne = (double(samples) - 1.0); double samplesMinusOne = (double(samples) - 1.0);
for (uint16_t i = 0; i < (samples >> 1); i++) { for (uint16_t i = 0; i < (samples >> 1); i++) {
double indexMinusOne = double(i); double indexMinusOne = double(i);
double ratio = (indexMinusOne / samplesMinusOne); double ratio = (indexMinusOne / samplesMinusOne);
double weighingFactor = 1.0; double weighingFactor = 1.0;
// Compute and record weighting factor // Compute and record weighting factor
switch (windowType) { switch (windowType) {
case FFT_WIN_TYP_RECTANGLE: // rectangle (box car) case FFT_WIN_TYP_RECTANGLE: // rectangle (box car)
weighingFactor = 1.0; weighingFactor = 1.0;
break; break;
case FFT_WIN_TYP_HAMMING: // hamming case FFT_WIN_TYP_HAMMING: // hamming
weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio)); weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio));
break; break;
case FFT_WIN_TYP_HANN: // hann case FFT_WIN_TYP_HANN: // hann
weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio)); weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio));
break; break;
case FFT_WIN_TYP_TRIANGLE: // triangle (Bartlett) case FFT_WIN_TYP_TRIANGLE: // triangle (Bartlett)
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
weighingFactor = 1.0 - ((2.0 * fabs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne); weighingFactor =
#else 1.0 - ((2.0 * fabs(indexMinusOne - (samplesMinusOne / 2.0))) /
weighingFactor = 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) / samplesMinusOne); samplesMinusOne);
#endif #else
break; weighingFactor =
case FFT_WIN_TYP_NUTTALL: // nuttall 1.0 - ((2.0 * abs(indexMinusOne - (samplesMinusOne / 2.0))) /
weighingFactor = 0.355768 - (0.487396 * (cos(twoPi * ratio))) + (0.144232 * (cos(fourPi * ratio))) - (0.012604 * (cos(sixPi * ratio))); samplesMinusOne);
break; #endif
case FFT_WIN_TYP_BLACKMAN: // blackman break;
weighingFactor = 0.42323 - (0.49755 * (cos(twoPi * ratio))) + (0.07922 * (cos(fourPi * ratio))); case FFT_WIN_TYP_NUTTALL: // nuttall
break; weighingFactor = 0.355768 - (0.487396 * (cos(twoPi * ratio))) +
case FFT_WIN_TYP_BLACKMAN_NUTTALL: // blackman nuttall (0.144232 * (cos(fourPi * ratio))) -
weighingFactor = 0.3635819 - (0.4891775 * (cos(twoPi * ratio))) + (0.1365995 * (cos(fourPi * ratio))) - (0.0106411 * (cos(sixPi * ratio))); (0.012604 * (cos(sixPi * ratio)));
break; break;
case FFT_WIN_TYP_BLACKMAN_HARRIS: // blackman harris case FFT_WIN_TYP_BLACKMAN: // blackman
weighingFactor = 0.35875 - (0.48829 * (cos(twoPi * ratio))) + (0.14128 * (cos(fourPi * ratio))) - (0.01168 * (cos(sixPi * ratio))); weighingFactor = 0.42323 - (0.49755 * (cos(twoPi * ratio))) +
break; (0.07922 * (cos(fourPi * ratio)));
case FFT_WIN_TYP_FLT_TOP: // flat top break;
weighingFactor = 0.2810639 - (0.5208972 * cos(twoPi * ratio)) + (0.1980399 * cos(fourPi * ratio)); case FFT_WIN_TYP_BLACKMAN_NUTTALL: // blackman nuttall
break; weighingFactor = 0.3635819 - (0.4891775 * (cos(twoPi * ratio))) +
case FFT_WIN_TYP_WELCH: // welch (0.1365995 * (cos(fourPi * ratio))) -
weighingFactor = 1.0 - sq((indexMinusOne - samplesMinusOne / 2.0) / (samplesMinusOne / 2.0)); (0.0106411 * (cos(sixPi * ratio)));
break; break;
} case FFT_WIN_TYP_BLACKMAN_HARRIS: // blackman harris
if (dir == FFT_FORWARD) { weighingFactor = 0.35875 - (0.48829 * (cos(twoPi * ratio))) +
vData[i] *= weighingFactor; (0.14128 * (cos(fourPi * ratio))) -
vData[samples - (i + 1)] *= weighingFactor; (0.01168 * (cos(sixPi * ratio)));
} break;
else { case FFT_WIN_TYP_FLT_TOP: // flat top
vData[i] /= weighingFactor; weighingFactor = 0.2810639 - (0.5208972 * cos(twoPi * ratio)) +
vData[samples - (i + 1)] /= weighingFactor; (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 arduinoFFT::MajorPeak() double arduinoFFT::MajorPeak() {
{ double maxY = 0;
double maxY = 0; uint16_t IndexOfMaxY = 0;
uint16_t IndexOfMaxY = 0; // If sampling_frequency = 2 * max_frequency in signal,
//If sampling_frequency = 2 * max_frequency in signal, // value would be stored at position samples/2
//value would be stored at position samples/2 for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) {
for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) { if ((this->_vReal[i - 1] < this->_vReal[i]) &&
if ((this->_vReal[i-1] < this->_vReal[i]) && (this->_vReal[i] > this->_vReal[i+1])) { (this->_vReal[i] > this->_vReal[i + 1])) {
if (this->_vReal[i] > maxY) { if (this->_vReal[i] > maxY) {
maxY = this->_vReal[i]; maxY = this->_vReal[i];
IndexOfMaxY = 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 delta =
double interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples-1); 0.5 *
if(IndexOfMaxY==(this->_samples >> 1)) //To improve calculation on edge values ((this->_vReal[IndexOfMaxY - 1] - this->_vReal[IndexOfMaxY + 1]) /
interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples); (this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) +
// returned value: interpolated frequency peak apex this->_vReal[IndexOfMaxY + 1]));
return(interpolatedX); 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
return (interpolatedX);
} }
void arduinoFFT::MajorPeak(double *f, double *v) void arduinoFFT::MajorPeak(double *f, double *v) {
{ double maxY = 0;
double maxY = 0; uint16_t IndexOfMaxY = 0;
uint16_t IndexOfMaxY = 0; // If sampling_frequency = 2 * max_frequency in signal,
//If sampling_frequency = 2 * max_frequency in signal, // value would be stored at position samples/2
//value would be stored at position samples/2 for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) {
for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) { if ((this->_vReal[i - 1] < this->_vReal[i]) &&
if ((this->_vReal[i - 1] < this->_vReal[i]) && (this->_vReal[i] > this->_vReal[i + 1])) { (this->_vReal[i] > this->_vReal[i + 1])) {
if (this->_vReal[i] > maxY) { if (this->_vReal[i] > maxY) {
maxY = this->_vReal[i]; maxY = this->_vReal[i];
IndexOfMaxY = 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 delta =
double interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples - 1); 0.5 *
if (IndexOfMaxY == (this->_samples >> 1)) //To improve calculation on edge values ((this->_vReal[IndexOfMaxY - 1] - this->_vReal[IndexOfMaxY + 1]) /
interpolatedX = ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples); (this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) +
// returned value: interpolated frequency peak apex this->_vReal[IndexOfMaxY + 1]));
*f = interpolatedX; double interpolatedX =
#if defined(ESP8266) || defined(ESP32) ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples - 1);
*v = fabs(this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) + this->_vReal[IndexOfMaxY + 1]); if (IndexOfMaxY ==
#else (this->_samples >> 1)) // To improve calculation on edge values
*v = abs(this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) + this->_vReal[IndexOfMaxY + 1]); interpolatedX =
#endif ((IndexOfMaxY + delta) * this->_samplingFrequency) / (this->_samples);
// returned value: interpolated frequency peak apex
*f = interpolatedX;
#if defined(ESP8266) || defined(ESP32)
*v = fabs(this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) +
this->_vReal[IndexOfMaxY + 1]);
#else
*v = abs(this->_vReal[IndexOfMaxY - 1] - (2.0 * this->_vReal[IndexOfMaxY]) +
this->_vReal[IndexOfMaxY + 1]);
#endif
} }
double arduinoFFT::MajorPeak(double *vD, uint16_t samples, double samplingFrequency) double arduinoFFT::MajorPeak(double *vD, uint16_t samples,
{ double samplingFrequency) {
#warning("This method is deprecated and may be removed on future revisions.") #warning("This method is deprecated and may be removed on future revisions.")
double maxY = 0; double maxY = 0;
uint16_t IndexOfMaxY = 0; uint16_t IndexOfMaxY = 0;
//If sampling_frequency = 2 * max_frequency in signal, // If sampling_frequency = 2 * max_frequency in signal,
//value would be stored at position samples/2 // value would be stored at position samples/2
for (uint16_t i = 1; i < ((samples >> 1) + 1); i++) { for (uint16_t i = 1; i < ((samples >> 1) + 1); i++) {
if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) { if ((vD[i - 1] < vD[i]) && (vD[i] > vD[i + 1])) {
if (vD[i] > maxY) { if (vD[i] > maxY) {
maxY = vD[i]; maxY = vD[i];
IndexOfMaxY = i; IndexOfMaxY = i;
} }
} }
} }
double delta = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1])); double delta =
double interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples-1); 0.5 *
if(IndexOfMaxY==(samples >> 1)) //To improve calculation on edge values ((vD[IndexOfMaxY - 1] - vD[IndexOfMaxY + 1]) /
interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples); (vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]));
// returned value: interpolated frequency peak apex double interpolatedX =
return(interpolatedX); ((IndexOfMaxY + delta) * samplingFrequency) / (samples - 1);
if (IndexOfMaxY == (samples >> 1)) // To improve calculation on edge values
interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples);
// returned value: interpolated frequency peak apex
return (interpolatedX);
} }
void arduinoFFT::MajorPeak(double *vD, uint16_t samples, double samplingFrequency, double *f, double *v) void arduinoFFT::MajorPeak(double *vD, uint16_t samples,
{ double samplingFrequency, double *f, double *v) {
#warning("This method is deprecated and may be removed on future revisions.") #warning("This method is deprecated and may be removed on future revisions.")
double maxY = 0; double maxY = 0;
uint16_t IndexOfMaxY = 0; uint16_t IndexOfMaxY = 0;
//If sampling_frequency = 2 * max_frequency in signal, // If sampling_frequency = 2 * max_frequency in signal,
//value would be stored at position samples/2 // value would be stored at position samples/2
for (uint16_t i = 1; i < ((samples >> 1) + 1); i++) { for (uint16_t i = 1; i < ((samples >> 1) + 1); i++) {
if ((vD[i - 1] < vD[i]) && (vD[i] > vD[i + 1])) { if ((vD[i - 1] < vD[i]) && (vD[i] > vD[i + 1])) {
if (vD[i] > maxY) { if (vD[i] > maxY) {
maxY = vD[i]; maxY = vD[i];
IndexOfMaxY = i; IndexOfMaxY = i;
} }
} }
} }
double delta = 0.5 * ((vD[IndexOfMaxY - 1] - vD[IndexOfMaxY + 1]) / (vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1])); double delta =
double interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples - 1); 0.5 *
//double popo = ((vD[IndexOfMaxY - 1] - vD[IndexOfMaxY + 1]) /
if (IndexOfMaxY == (samples >> 1)) //To improve calculation on edge values (vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]));
interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples); double interpolatedX =
// returned value: interpolated frequency peak apex ((IndexOfMaxY + delta) * samplingFrequency) / (samples - 1);
*f = interpolatedX; // double popo =
#if defined(ESP8266) || defined(ESP32) if (IndexOfMaxY == (samples >> 1)) // To improve calculation on edge values
*v = fabs(vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]); interpolatedX = ((IndexOfMaxY + delta) * samplingFrequency) / (samples);
#else // returned value: interpolated frequency peak apex
*v = abs(vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]); *f = interpolatedX;
#endif #if defined(ESP8266) || defined(ESP32)
*v =
fabs(vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]);
#else
*v = abs(vD[IndexOfMaxY - 1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY + 1]);
#endif
} }
double arduinoFFT::MajorPeakParabola() double arduinoFFT::MajorPeakParabola() {
{ double maxY = 0;
double maxY = 0; uint16_t IndexOfMaxY = 0;
uint16_t IndexOfMaxY = 0; // If sampling_frequency = 2 * max_frequency in signal,
//If sampling_frequency = 2 * max_frequency in signal, // value would be stored at position samples/2
//value would be stored at position samples/2 for (uint16_t i = 1; i < ((this->_samples >> 1) + 1); i++) {
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-1] < this->_vReal[i]) && (this->_vReal[i] > this->_vReal[i+1])) if (this->_vReal[i] > maxY) {
{ maxY = this->_vReal[i];
if (this->_vReal[i] > maxY) IndexOfMaxY = i;
{ }
maxY = this->_vReal[i]; }
IndexOfMaxY = i; }
}
}
}
double freq = 0; double freq = 0;
if( IndexOfMaxY>0 ) if (IndexOfMaxY > 0) {
{ // Assume the three points to be on a parabola
// Assume the three points to be on a parabola double a, b, c;
double a,b,c; Parabola(IndexOfMaxY - 1, this->_vReal[IndexOfMaxY - 1], IndexOfMaxY,
Parabola(IndexOfMaxY-1, this->_vReal[IndexOfMaxY-1], IndexOfMaxY, this->_vReal[IndexOfMaxY], IndexOfMaxY+1, this->_vReal[IndexOfMaxY+1], &a, &b, &c); this->_vReal[IndexOfMaxY], IndexOfMaxY + 1,
this->_vReal[IndexOfMaxY + 1], &a, &b, &c);
// Peak is at the middle of the parabola // Peak is at the middle of the parabola
double x = -b/(2*a); double x = -b / (2 * a);
// And magnitude is at the extrema of the parabola if you want It... // And magnitude is at the extrema of the parabola if you want It...
// double y = a*x*x+b*x+c; // double y = a*x*x+b*x+c;
// Convert to frequency // Convert to frequency
freq = (x * this->_samplingFrequency) / (this->_samples); freq = (x * this->_samplingFrequency) / (this->_samples);
} }
return freq; return freq;
} }
void arduinoFFT::Parabola(double x1, double y1, double x2, double y2, double x3, double y3, double *a, double *b, double *c) void arduinoFFT::Parabola(double x1, double y1, double x2, double y2, double x3,
{ double y3, double *a, double *b, double *c) {
double reversed_denom = 1/((x1 - x2) * (x1 - x3) * (x2 - x3)); double reversed_denom = 1 / ((x1 - x2) * (x1 - x3) * (x2 - x3));
*a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) * reversed_denom; *a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) * reversed_denom;
*b = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) * reversed_denom; *b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) *
*c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) *reversed_denom; reversed_denom;
*c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 +
x1 * x2 * (x1 - x2) * y3) *
reversed_denom;
} }
uint8_t arduinoFFT::Exponent(uint16_t value) uint8_t arduinoFFT::Exponent(uint16_t value) {
{ #warning("This method may not be accessible on future revisions.")
#warning("This method may not be accessible on future revisions.") // Calculates the base 2 logarithm of a value
// Calculates the base 2 logarithm of a value uint8_t result = 0;
uint8_t result = 0; while (((value >> result) & 1) != 1)
while (((value >> result) & 1) != 1) result++; result++;
return(result); return (result);
} }
// Private functions // Private functions
void arduinoFFT::Swap(double *x, double *y) void arduinoFFT::Swap(double *x, double *y) {
{ double temp = *x;
double temp = *x; *x = *y;
*x = *y; *y = temp;
*y = temp;
} }

Wyświetl plik

@ -19,97 +19,133 @@
*/ */
#ifndef arduinoFFT_h /* Prevent loading library twice */ #ifndef ArduinoFFT_h /* Prevent loading library twice */
#define arduinoFFT_h #define ArduinoFFT_h
#ifdef ARDUINO #ifdef ARDUINO
#if ARDUINO >= 100 #if ARDUINO >= 100
#include "Arduino.h" #include "Arduino.h"
#else
#include "WProgram.h" /* This is where the standard Arduino code lies */
#endif
#else #else
#include <stdlib.h> #include "WProgram.h" /* This is where the standard Arduino code lies */
#include <stdio.h> #endif
#ifdef __AVR__ #else
#include <avr/io.h> #include <stdio.h>
#include <avr/pgmspace.h> #include <stdlib.h>
#endif
#include <math.h> #ifdef __AVR__
#include "defs.h" #include <avr/io.h>
#include "types.h" #include <avr/pgmspace.h>
#endif
#include "defs.h"
#include "types.h"
#include <math.h>
#endif #endif
#define FFT_LIB_REV 0x14 // Define this to use a low-precision square root approximation instead of the
// regular sqrt() call
// This might only work for specific use cases, but is significantly faster.
// Only works for ArduinoFFT<float>.
// #define FFT_SQRT_APPROXIMATION
#ifdef FFT_SQRT_APPROXIMATION
#include <type_traits>
#else
#define sqrt_internal sqrt
#endif
enum class FFTDirection { Reverse, Forward };
enum class FFTWindow {
Rectangle, // rectangle (Box car)
Hamming, // hamming
Hann, // hann
Triangle, // triangle (Bartlett)
Nuttall, // nuttall
Blackman, // blackman
Blackman_Nuttall, // blackman nuttall
Blackman_Harris, // blackman harris
Flat_top, // flat top
Welch // welch
};
#define FFT_LIB_REV 0x15
/* Custom constants */ /* Custom constants */
#define FFT_FORWARD 0x01 #define FFT_FORWARD FFTDirection::Forward
#define FFT_REVERSE 0x00 #define FFT_REVERSE FFTDirection::Reverse
/* Windowing type */ /* Windowing type */
#define FFT_WIN_TYP_RECTANGLE 0x00 /* rectangle (Box car) */ #define FFT_WIN_TYP_RECTANGLE FFTWindow::Rectangle /* rectangle (Box car) */
#define FFT_WIN_TYP_HAMMING 0x01 /* hamming */ #define FFT_WIN_TYP_HAMMING FFTWindow::Hamming /* hamming */
#define FFT_WIN_TYP_HANN 0x02 /* hann */ #define FFT_WIN_TYP_HANN FFTWindow::Hann /* hann */
#define FFT_WIN_TYP_TRIANGLE 0x03 /* triangle (Bartlett) */ #define FFT_WIN_TYP_TRIANGLE FFTWindow::Triangle /* triangle (Bartlett) */
#define FFT_WIN_TYP_NUTTALL 0x04 /* nuttall */ #define FFT_WIN_TYP_NUTTALL FFTWindow::Nuttall /* nuttall */
#define FFT_WIN_TYP_BLACKMAN 0x05 /* blackman */ #define FFT_WIN_TYP_BLACKMAN FFTWindow::Blackman /* blackman */
#define FFT_WIN_TYP_BLACKMAN_NUTTALL 0x06 /* blackman nuttall */ #define FFT_WIN_TYP_BLACKMAN_NUTTALL \
#define FFT_WIN_TYP_BLACKMAN_HARRIS 0x07 /* blackman harris*/ FFTWindow::Blackman_Nuttall /* blackman nuttall */
#define FFT_WIN_TYP_FLT_TOP 0x08 /* flat top */ #define FFT_WIN_TYP_BLACKMAN_HARRIS \
#define FFT_WIN_TYP_WELCH 0x09 /* welch */ FFTWindow::Blackman_Harris /* blackman harris*/
#define FFT_WIN_TYP_FLT_TOP FFTWindow::Flat_top /* flat top */
#define FFT_WIN_TYP_WELCH FFTWindow::Welch /* welch */
/*Mathematial constants*/ /*Mathematial constants*/
#define twoPi 6.28318531 #define twoPi 6.28318531
#define fourPi 12.56637061 #define fourPi 12.56637061
#define sixPi 18.84955593 #define sixPi 18.84955593
#ifdef __AVR__ #ifdef __AVR__
static const double _c1[]PROGMEM = {0.0000000000, 0.7071067812, 0.9238795325, 0.9807852804, static const double _c1[] PROGMEM = {
0.9951847267, 0.9987954562, 0.9996988187, 0.9999247018, 0.0000000000, 0.7071067812, 0.9238795325, 0.9807852804, 0.9951847267,
0.9999811753, 0.9999952938, 0.9999988235, 0.9999997059, 0.9987954562, 0.9996988187, 0.9999247018, 0.9999811753, 0.9999952938,
0.9999999265, 0.9999999816, 0.9999999954, 0.9999999989, 0.9999988235, 0.9999997059, 0.9999999265, 0.9999999816, 0.9999999954,
0.9999999997}; 0.9999999989, 0.9999999997};
static const double _c2[]PROGMEM = {1.0000000000, 0.7071067812, 0.3826834324, 0.1950903220, static const double _c2[] PROGMEM = {
0.0980171403, 0.0490676743, 0.0245412285, 0.0122715383, 1.0000000000, 0.7071067812, 0.3826834324, 0.1950903220, 0.0980171403,
0.0061358846, 0.0030679568, 0.0015339802, 0.0007669903, 0.0490676743, 0.0245412285, 0.0122715383, 0.0061358846, 0.0030679568,
0.0003834952, 0.0001917476, 0.0000958738, 0.0000479369, 0.0015339802, 0.0007669903, 0.0003834952, 0.0001917476, 0.0000958738,
0.0000239684}; 0.0000479369, 0.0000239684};
#endif #endif
class arduinoFFT { class arduinoFFT {
public: public:
/* Constructor */ /* Constructor */
arduinoFFT(void); arduinoFFT(void);
arduinoFFT(double *vReal, double *vImag, uint16_t samples, double samplingFrequency); arduinoFFT(double *vReal, double *vImag, uint16_t samples,
/* Destructor */ double samplingFrequency);
~arduinoFFT(void); /* Destructor */
/* Functions */ ~arduinoFFT(void);
uint8_t Revision(void); /* Functions */
uint8_t Exponent(uint16_t value); uint8_t Revision(void);
uint8_t Exponent(uint16_t value);
void ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples); void ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples);
void Compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir); void Compute(double *vReal, double *vImag, uint16_t samples,
void Compute(double *vReal, double *vImag, uint16_t samples, uint8_t power, uint8_t dir); FFTDirection dir);
void DCRemoval(double *vData, uint16_t samples); void Compute(double *vReal, double *vImag, uint16_t samples, uint8_t power,
double MajorPeak(double *vD, uint16_t samples, double samplingFrequency); FFTDirection dir);
void MajorPeak(double *vD, uint16_t samples, double samplingFrequency, double *f, double *v); void DCRemoval(double *vData, uint16_t samples);
void Windowing(double *vData, uint16_t samples, uint8_t windowType, uint8_t dir); double MajorPeak(double *vD, uint16_t samples, double samplingFrequency);
void MajorPeak(double *vD, uint16_t samples, double samplingFrequency,
double *f, double *v);
void Windowing(double *vData, uint16_t samples, FFTWindow windowType,
FFTDirection dir);
void ComplexToMagnitude(); void ComplexToMagnitude();
void Compute(uint8_t dir); void Compute(FFTDirection dir);
void DCRemoval(); void DCRemoval();
double MajorPeak(); double MajorPeak();
void MajorPeak(double *f, double *v); void MajorPeak(double *f, double *v);
void Windowing(uint8_t windowType, uint8_t dir); void Windowing(FFTWindow windowType, FFTDirection dir);
double MajorPeakParabola(); double MajorPeakParabola();
private: private:
/* Variables */ /* Variables */
uint16_t _samples; uint16_t _samples;
double _samplingFrequency; double _samplingFrequency;
double *_vReal; double *_vReal;
double *_vImag; double *_vImag;
uint8_t _power; uint8_t _power;
/* Functions */ /* Functions */
void Swap(double *x, double *y); void Swap(double *x, double *y);
void Parabola(double x1, double y1, double x2, double y2, double x3, double y3, double *a, double *b, double *c); void Parabola(double x1, double y1, double x2, double y2, double x3,
double y3, double *a, double *b, double *c);
}; };
#endif #endif