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
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"
}
],
"version": "1.5.6",
"version": "1.6",
"frameworks": ["arduino","mbed","espidf"],
"platforms": "*",
"headers": "arduinoFFT.h"

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -19,97 +19,133 @@
*/
#ifndef arduinoFFT_h /* Prevent loading library twice */
#define arduinoFFT_h
#ifndef ArduinoFFT_h /* Prevent loading library twice */
#define ArduinoFFT_h
#ifdef ARDUINO
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h" /* This is where the standard Arduino code lies */
#endif
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include <stdlib.h>
#include <stdio.h>
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif
#include <math.h>
#include "defs.h"
#include "types.h"
#include "WProgram.h" /* This is where the standard Arduino code lies */
#endif
#else
#include <stdio.h>
#include <stdlib.h>
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif
#include "defs.h"
#include "types.h"
#include <math.h>
#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 */
#define FFT_FORWARD 0x01
#define FFT_REVERSE 0x00
#define FFT_FORWARD FFTDirection::Forward
#define FFT_REVERSE FFTDirection::Reverse
/* 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_NUTTALL 0x04 /* nuttall */
#define FFT_WIN_TYP_BLACKMAN 0x05 /* blackman */
#define FFT_WIN_TYP_BLACKMAN_NUTTALL 0x06 /* blackman nuttall */
#define FFT_WIN_TYP_BLACKMAN_HARRIS 0x07 /* blackman harris*/
#define FFT_WIN_TYP_FLT_TOP 0x08 /* flat top */
#define FFT_WIN_TYP_WELCH 0x09 /* welch */
#define FFT_WIN_TYP_RECTANGLE FFTWindow::Rectangle /* rectangle (Box car) */
#define FFT_WIN_TYP_HAMMING FFTWindow::Hamming /* hamming */
#define FFT_WIN_TYP_HANN FFTWindow::Hann /* hann */
#define FFT_WIN_TYP_TRIANGLE FFTWindow::Triangle /* triangle (Bartlett) */
#define FFT_WIN_TYP_NUTTALL FFTWindow::Nuttall /* nuttall */
#define FFT_WIN_TYP_BLACKMAN FFTWindow::Blackman /* blackman */
#define FFT_WIN_TYP_BLACKMAN_NUTTALL \
FFTWindow::Blackman_Nuttall /* blackman nuttall */
#define FFT_WIN_TYP_BLACKMAN_HARRIS \
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*/
#define twoPi 6.28318531
#define fourPi 12.56637061
#define sixPi 18.84955593
#ifdef __AVR__
static const double _c1[]PROGMEM = {0.0000000000, 0.7071067812, 0.9238795325, 0.9807852804,
0.9951847267, 0.9987954562, 0.9996988187, 0.9999247018,
0.9999811753, 0.9999952938, 0.9999988235, 0.9999997059,
0.9999999265, 0.9999999816, 0.9999999954, 0.9999999989,
0.9999999997};
static const double _c2[]PROGMEM = {1.0000000000, 0.7071067812, 0.3826834324, 0.1950903220,
0.0980171403, 0.0490676743, 0.0245412285, 0.0122715383,
0.0061358846, 0.0030679568, 0.0015339802, 0.0007669903,
0.0003834952, 0.0001917476, 0.0000958738, 0.0000479369,
0.0000239684};
static const double _c1[] PROGMEM = {
0.0000000000, 0.7071067812, 0.9238795325, 0.9807852804, 0.9951847267,
0.9987954562, 0.9996988187, 0.9999247018, 0.9999811753, 0.9999952938,
0.9999988235, 0.9999997059, 0.9999999265, 0.9999999816, 0.9999999954,
0.9999999989, 0.9999999997};
static const double _c2[] PROGMEM = {
1.0000000000, 0.7071067812, 0.3826834324, 0.1950903220, 0.0980171403,
0.0490676743, 0.0245412285, 0.0122715383, 0.0061358846, 0.0030679568,
0.0015339802, 0.0007669903, 0.0003834952, 0.0001917476, 0.0000958738,
0.0000479369, 0.0000239684};
#endif
class arduinoFFT {
public:
/* Constructor */
arduinoFFT(void);
arduinoFFT(double *vReal, double *vImag, uint16_t samples, double samplingFrequency);
/* Destructor */
~arduinoFFT(void);
/* Functions */
uint8_t Revision(void);
uint8_t Exponent(uint16_t value);
/* Constructor */
arduinoFFT(void);
arduinoFFT(double *vReal, double *vImag, uint16_t samples,
double samplingFrequency);
/* Destructor */
~arduinoFFT(void);
/* Functions */
uint8_t Revision(void);
uint8_t Exponent(uint16_t value);
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, uint8_t power, uint8_t dir);
void DCRemoval(double *vData, uint16_t samples);
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, uint8_t windowType, uint8_t dir);
void ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples);
void Compute(double *vReal, double *vImag, uint16_t samples,
FFTDirection dir);
void Compute(double *vReal, double *vImag, uint16_t samples, uint8_t power,
FFTDirection dir);
void DCRemoval(double *vData, uint16_t samples);
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 Compute(uint8_t dir);
void DCRemoval();
double MajorPeak();
void MajorPeak(double *f, double *v);
void Windowing(uint8_t windowType, uint8_t dir);
void ComplexToMagnitude();
void Compute(FFTDirection dir);
void DCRemoval();
double MajorPeak();
void MajorPeak(double *f, double *v);
void Windowing(FFTWindow windowType, FFTDirection dir);
double MajorPeakParabola();
double MajorPeakParabola();
private:
/* Variables */
uint16_t _samples;
double _samplingFrequency;
double *_vReal;
double *_vImag;
uint8_t _power;
/* Functions */
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);
/* Variables */
uint16_t _samples;
double _samplingFrequency;
double *_vReal;
double *_vImag;
uint8_t _power;
/* Functions */
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);
};
#endif