-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfour.cpp
190 lines (180 loc) · 6.27 KB
/
four.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "four.h"
#include <iostream> // std::cout
#include <algorithm> // std::swap
#include <vector> // std::vector
#include "math.h"
#include <complex.h>
// derived from Numerical Recipes in C, Cambridge University Press
#define SWAP(a,b) tempr = (a); (a) = (b); (b) = tempr
// Input: nn is the number of points in the data and in the FFT,
// nn must be a power of 2
// Input: data is sampled voltage v(0),0,v(1),0,v(2),...v(nn-1),0 versus time
// Output: data is complex FFT Re[V(0)],Im[V(0)], Re[V(1)],Im[V(1)],...
// data is an array of 2*nn elements
void FFTUtility::fft(double data[], unsigned long nn)
{
unsigned long n,mmax,m,j,istep,i;
double wtemp,wr,wpr,wpi,wi,theta;
double tempr,tempi;
n = nn<<1; // n is the size of data array (2*nn)
j = 1;
for(i=1; i<n; i+=2){
if(j > i){ // bit reversal section
SWAP(data[j-1],data[i-1]);
SWAP(data[j],data[i]);
}
m = n>>1;
while((m >= 2)&&(j > m)){
j = j-m;
m = m>>1;
}
j = j+m;
}
mmax = 2; // Danielson-Lanczos section
while( n > mmax){ // executed log2(nn) times
istep = mmax<<1;
theta = -6.283185307179586476925286766559/mmax;
// the above line should be + for inverse FFT
wtemp = sin(0.5*theta);
wpr = -2.0*wtemp*wtemp; // real part
wpi = sin(theta); // imaginary part
wr = 1.0;
wi = 0.0;
for(m=1; m<mmax; m+=2){
for(i=m; i<=n; i=i+istep){
j = i+mmax;
tempr = wr*data[j-1]-wi*data[j]; // Danielson-Lanczos formula
tempi = wr*data[j]+wi*data[j-1];
data[j-1] = data[i-1]-tempr;
data[j] = data[i]-tempi;
data[i-1] = data[i-1]+tempr;
data[i] = data[i]+tempi;
}
wtemp = wr;
wr = wr*wpr-wi*wpi+wr;
wi = wi*wpr+wtemp*wpi+wi;
}
mmax = istep;
}
}
//-----------------------------------------------------------
// Calculates the FFT magnitude at a given frequency index.
// Input: data is complex FFT Re[V(0)],Im[V(0)], Re[V(1)],Im[V(1)],...
// Input: nn is the number of points in the data and in the FFT,
// nn must be a power of 2
// Input: k is frequency index 0 to nn/2-1
// E.g., if nn=16384, then k can be 0 to 8191
// Output: Magnitude in volts at this frequency (volts)
// data is an array of 2*nn elements
// returns 0 if k >= nn/2
double FFTUtility::fftMagnitude(double data[], unsigned long nn, unsigned long k)
{
double nr, realPart, imagPart;
nr = (double) nn;
if (k >= nn/2){
return 0.0; // out of range
}
if (k == 0){
return sqrt(data[0] * data[0] + data[1] * data[1]) / nr;
}
realPart = fabs(data[2*k]) + fabs(data[2*nn-2*k]);
imagPart = fabs(data[2*k+1]) + fabs(data[2*nn-2*k+1]);
return sqrt(realPart * realPart + imagPart * imagPart) / nr;
}
//-----------------------------------------------------------
// Calculates the FFT magnitude in db full scale at a given frequency index.
// Input: data is complex FFT Re[V(0)],Im[V(0)], Re[V(1)],Im[V(1)],...
// Input: nn is the number of points in the data and in the FFT,
// nn must be a power of 2
// Input: k is frequency index 0 to nn/2-1
// E.g., if nn=16384, then k can be 0 to 8191
// Input: fullScale is the largest possible component in volts
// Output: Magnitude in db full scale at this frequency
// data is an array of 2*nn elements
// returns -200 if k >= nn/2
double FFTUtility::fftMagdB(double data[], unsigned long nn, unsigned long k, double fullScale)
{
double magnitude = fftMagnitude(data, nn, k);
if (magnitude<0.0000000001)
{ // less than 0.1 nV
return -200; // out of range
}
return 20.0*log10(magnitude/fullScale);
}
//-----------------------------------------------------------
// Calculates the FFT phase at a given frequency index.
// Input: data is complex FFT Re[V(0)],Im[V(0)], Re[V(1)],Im[V(1)],...
// Input: nn is the number of points in the data and in the FFT,
// nn must be a power of 2
// Input: k is frequency index 0 to nn/2-1
// E.g., if nn=16384, then k can be 0 to 8191
// Output: Phase at this frequency
// data is an array of 2*nn elements
// returns 0 if k >= nn/2
double FFTUtility::fftPhase(double data[], unsigned long nn, unsigned long k)
{
if (k >= nn/2)
{
return 0.0; // out of range
}
if (data[2*k+1]==0.0)
{
return 0.0; // imaginary part is zero
}
if (data[2*k]==0.0)
{ // real part is zero
if (data[2*k+1]>0.0)
{ // real part is zero
return 1.5707963267948966192313216916398; // 90 degrees
}
else
{
return -1.5707963267948966192313216916398; // -90 degrees
}
}
return atan2 (data[2*k+1], data[2*k]); // imaginary part over real part
}
//-----------------------------------------------------------
// Calculates equivalent frequency in Hz at a given frequency index.
// Input: fs is sampling rate in Hz
// Input: nn is the number of points in the data and in the FFT,
// nn must be a power of 2
// Input: k is frequency index 0 to nn-1
// E.g., if nn=16384, then k can be 0 to 16383
// Output: Equivalent frequency in Hz
// returns 0 if k >= nn
double FFTUtility::fftFrequency (unsigned long nn, unsigned long k, double fs)
{
if (k >= nn)
{
return 0.0; // out of range
}
if (k <= nn/2)
{
return fs * (double)k / (double)nn;
}
return -fs * (double)(nn-k)/ (double)nn;
}
double FFTUtility::goertzel(unsigned int numSamples, unsigned int frequency, unsigned int sampleRate, double* data)
{
double q0(0.0);
double q1(0.0);
double q2(0.0);
double samples = (double) numSamples;
unsigned int k = (int) (0.5 + ((samples * frequency) / sampleRate));
double omega = (2.0 * M_PI * k) / samples;
double sine = sin(omega);
double cosine = cos(omega);
double coeff = 2.0 * cosine;
int i(0);
while( i < numSamples*2 )
{
q0 = coeff * q1 - q2 + data[i];
q2 = q1;
q1 = q0;
i = i + 2;
}
double real = (q1 - q2 * cosine);
double imag = (q2 * sine);
return real*real + imag*imag;
}