221 lines
5.1 KiB
C++
221 lines
5.1 KiB
C++
#pragma once
|
|
|
|
namespace fft {
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.1415926535897932
|
|
#endif
|
|
|
|
|
|
inline bool isPow(const size_t num)
|
|
{
|
|
return num && (!(num & (num - 1)));
|
|
}
|
|
|
|
void rerrange(complex_type* data, const size_t num_elements)
|
|
{
|
|
size_t target_index = 0;
|
|
size_t bit_mask;
|
|
|
|
complex_type buffer;
|
|
for (size_t i = 0; i < num_elements; ++i)
|
|
{
|
|
if (target_index > i)
|
|
{
|
|
buffer = data[target_index];
|
|
data[target_index] = data[i];
|
|
data[i]= buffer;
|
|
}
|
|
|
|
bit_mask = num_elements;
|
|
|
|
while (target_index & (bit_mask >>= 1))
|
|
{
|
|
target_index &= ~bit_mask;
|
|
}
|
|
|
|
target_index |= bit_mask;
|
|
}
|
|
}
|
|
|
|
bool transform(complex_type* data, const size_t count)
|
|
{
|
|
double local_pi = -M_PI;
|
|
|
|
size_t next, match;
|
|
real_type sine;
|
|
real_type delta;
|
|
complex_type mult, factor, product;
|
|
|
|
for (size_t i = 1; i < count; i <<= 1)
|
|
{
|
|
next = i << 1;
|
|
delta = local_pi / i;
|
|
sine = sin(0.5 * delta);
|
|
|
|
mult = complex_type(-2.0 * sine * sine, sin(delta));
|
|
factor = 1.0;
|
|
|
|
for (size_t j = 0; j < i; ++j)
|
|
{
|
|
for (size_t k = j; k < count; k += next)
|
|
{
|
|
match = k + i;
|
|
|
|
product = data[match] * factor;
|
|
data[match] = data[k] - product;
|
|
data[k] += product;
|
|
}
|
|
|
|
factor = mult * factor + factor;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ffti(complex_type* data, const size_t size)
|
|
{
|
|
if(!isPow(size)) {
|
|
return false;
|
|
}
|
|
|
|
rerrange(data, size);
|
|
|
|
return transform(data, size);
|
|
}
|
|
|
|
bool fft_adc_sample(float * w, float ratio, const adcsample_t* data_in, complex_type* data_out, const size_t size)
|
|
{
|
|
for(size_t i = 0; i < size; ++i) {
|
|
float voltage = ratio * data_in[i];
|
|
//float db = 10 * log10(voltage * voltage);
|
|
//db = clampF(-100, db, 100);
|
|
data_out[i] = complex_type(voltage * w[i], 0.0);
|
|
}
|
|
|
|
return ffti(data_out, size);
|
|
}
|
|
|
|
bool fft(const real_type* data_in, complex_type* data_out, const size_t size)
|
|
{
|
|
for(size_t i = 0; i < size; ++i) {
|
|
data_out[i] = complex_type(data_in[i], 0.0);
|
|
}
|
|
|
|
return ffti(data_out, size);
|
|
}
|
|
|
|
void fft_freq(real_type* freq, const size_t size, const size_t sampleFreq)
|
|
{
|
|
for (size_t i = 0; i < size/2; i++)
|
|
{
|
|
freq[i] = ((real_type)i * sampleFreq) / size;
|
|
}
|
|
}
|
|
|
|
void fft_amp(const complex_type* fft_data, real_type* amplitude, const size_t size)
|
|
{
|
|
for (size_t i = 0; i < size/2; ++i)
|
|
{
|
|
amplitude[i] = abs(fft_data[i].imag());
|
|
}
|
|
}
|
|
|
|
void fft_db(real_type* amplitude, const size_t size)
|
|
{
|
|
for (size_t i = 0; i < size/2; ++i)
|
|
{
|
|
amplitude[i] = log10(amplitude[i] * amplitude[i]) * 10;
|
|
}
|
|
}
|
|
|
|
void cosine_window(float * w, unsigned n, const float * coeff, unsigned ncoeff, bool sflag)
|
|
{
|
|
if (n == 1)
|
|
{
|
|
w[0] = 1.0;
|
|
}
|
|
else
|
|
{
|
|
const unsigned wlength = sflag ? (n - 1) : n;
|
|
|
|
for (unsigned i = 0; i < n; ++i)
|
|
{
|
|
float wi = 0.0;
|
|
|
|
for (unsigned j = 0; j < ncoeff; ++j)
|
|
{
|
|
wi += coeff[j] * cos(i * j * 2.0 * M_PI / wlength);
|
|
}
|
|
|
|
w[i] = wi;
|
|
}
|
|
}
|
|
}
|
|
|
|
void rectwin(float * w, unsigned n)
|
|
{
|
|
for (unsigned i = 0; i < n; ++i)
|
|
{
|
|
w[i] = 1.0;
|
|
}
|
|
}
|
|
|
|
void hann(float * w, unsigned n, bool sflag)
|
|
{
|
|
const float coeff[2] = { 0.5, -0.5 };
|
|
|
|
cosine_window(w, n, coeff, sizeof(coeff) / sizeof(float), sflag);
|
|
}
|
|
|
|
void hamming(float * w, unsigned n, bool sflag)
|
|
{
|
|
const float coeff[2] = { 0.54, -0.46 };
|
|
cosine_window(w, n, coeff, sizeof(coeff) / sizeof(float), sflag);
|
|
}
|
|
|
|
void blackman(float * w, unsigned n, bool sflag)
|
|
{
|
|
const float coeff[3] = { 0.42, -0.5, 0.08 };
|
|
cosine_window(w, n, coeff, sizeof(coeff) / sizeof(float), sflag);
|
|
}
|
|
|
|
void blackmanharris(float * w, unsigned n, bool sflag)
|
|
{
|
|
const float coeff[4] = { 0.35875, -0.48829, 0.14128, -0.01168 };
|
|
cosine_window(w, n, coeff, sizeof(coeff) / sizeof(float), sflag);
|
|
}
|
|
|
|
float get_main_freq(float* amplitudes, float* frequencies, size_t size)
|
|
{
|
|
float peaks_amp = -100.f;
|
|
size_t peaks_index = 0;
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
{
|
|
float amp = amplitudes[i];
|
|
if(amp > peaks_amp) {
|
|
peaks_amp = amp;
|
|
peaks_index = i;
|
|
}
|
|
}
|
|
|
|
float sum_amps = amplitudes[peaks_index - 2] +
|
|
amplitudes[peaks_index - 1] +
|
|
amplitudes[peaks_index] +
|
|
amplitudes[peaks_index + 1] +
|
|
amplitudes[peaks_index + 2];
|
|
|
|
float sum_wighted = amplitudes[peaks_index - 2] * frequencies[peaks_index - 2] +
|
|
amplitudes[peaks_index - 1] * frequencies[peaks_index - 1] +
|
|
amplitudes[peaks_index] * frequencies[peaks_index] +
|
|
amplitudes[peaks_index + 1] * frequencies[peaks_index + 1] +
|
|
amplitudes[peaks_index + 2] * frequencies[peaks_index + 2];
|
|
|
|
float mean_freq = sum_wighted / sum_amps;
|
|
return mean_freq;
|
|
}
|
|
|
|
}
|