sokobo
Loading...
Searching...
No Matches
fourier.cpp
1#include "include/fourier.h"
2#define _USE_MATH_DEFINES
3#include <cmath>
4#include <iostream>
5#include <algorithm>
6#include <numeric>
7#include "include/numerical_methods.h"
8
9#ifndef M_PI
10# define M_PI 3.14159265358979323846
11#endif
12
13#ifndef M_E
14# define M_E 2.71828
15#endif
16
17// Discrete Fourier Transform
18std::vector<ComplexNumber> FourierTransform::DFT(const std::vector<ComplexNumber>& signal) {
19 int N = signal.size();
20 std::vector<ComplexNumber> spectrum(N);
21
22 for (int k = 0; k < N; ++k) {
23 ComplexNumber sum(0, 0);
24 for (int n = 0; n < N; ++n) {
25 double angle = -2.0 * M_PI * k * n / N;
26 ComplexNumber twiddle(cos(angle), sin(angle));
27 sum = sum + signal[n] * twiddle;
28 }
29 spectrum[k] = sum;
30 }
31
32 return spectrum;
33}
34
35std::vector<ComplexNumber> FourierTransform::IDFT(const std::vector<ComplexNumber>& spectrum) {
36 int N = spectrum.size();
37 std::vector<ComplexNumber> signal(N);
38
39 for (int n = 0; n < N; ++n) {
40 ComplexNumber sum(0, 0);
41 for (int k = 0; k < N; ++k) {
42 double angle = 2.0 * M_PI * k * n / N;
43 ComplexNumber twiddle(cos(angle), sin(angle));
44 sum = sum + spectrum[k] * twiddle;
45 }
46 signal[n] = sum / N;
47 }
48
49 return signal;
50}
51
52// Helper function for FFT bit-reversal
53static int reverseBits(int num, int bits) {
54 int result = 0;
55 for (int i = 0; i < bits; ++i) {
56 result = (result << 1) | (num & 1);
57 num >>= 1;
58 }
59 return result;
60}
61
62// Fast Fourier Transform (Cooley-Tukey algorithm)
63std::vector<ComplexNumber> FourierTransform::FFT(const std::vector<ComplexNumber>& signal) {
64 int N = signal.size();
65
66 // Check if N is a power of 2
67 if (N == 0 || (N & (N - 1)) != 0) {
68 // If not power of 2, fall back to DFT
69 return DFT(signal);
70 }
71
72 int bits = 0;
73 int temp = N;
74 while (temp > 1) {
75 temp >>= 1;
76 bits++;
77 }
78
79 std::vector<ComplexNumber> result(signal);
80
81 // Bit-reversal permutation
82 for (int i = 0; i < N; ++i) {
83 int j = reverseBits(i, bits);
84 if (i < j) {
85 std::swap(result[i], result[j]);
86 }
87 }
88
89 // FFT computation
90 for (int len = 2; len <= N; len <<= 1) {
91 double angle = -2.0 * M_PI / len;
92 ComplexNumber wlen(cos(angle), sin(angle));
93
94 for (int i = 0; i < N; i += len) {
95 ComplexNumber w(1, 0);
96 for (int j = 0; j < len / 2; ++j) {
97 ComplexNumber u = result[i + j];
98 ComplexNumber v = result[i + j + len / 2] * w;
99 result[i + j] = u + v;
100 result[i + j + len / 2] = u - v;
101 w = w * wlen;
102 }
103 }
104 }
105
106 return result;
107}
108
109std::vector<ComplexNumber> FourierTransform::IFFT(const std::vector<ComplexNumber>& spectrum) {
110 int N = spectrum.size();
111
112 // Conjugate the input
113 std::vector<ComplexNumber> conjugated(N);
114 for (int i = 0; i < N; ++i) {
115 conjugated[i] = ComplexNumber(spectrum[i].getValue().real(),
116 -spectrum[i].getValue().imag());
117 }
118
119 // Apply FFT
120 std::vector<ComplexNumber> result = FFT(conjugated);
121
122 // Conjugate and normalize
123 for (int i = 0; i < N; ++i) {
124 result[i] = ComplexNumber(result[i].getValue().real() / N,
125 -result[i].getValue().imag() / N);
126 }
127
128 return result;
129}
130
131// Continuous Fourier Transform (numerical integration)
132ComplexNumber FourierTransform::continuousFT(std::function<double(double)> f, double omega, double T) {
133 const int samples = 1000;
134 double dt = 2 * T / samples;
135 ComplexNumber result(0, 0);
136
137 for (int n = 0; n < samples; ++n) {
138 double t = -T + n * dt;
139 double angle = -omega * t;
140 ComplexNumber exponential(cos(angle), sin(angle));
141 result = result + ComplexNumber(f(t), 0) * exponential * dt;
142 }
143
144 return result;
145}
146
147std::function<double(double)> FourierTransform::inverseFT(std::function<ComplexNumber(double)> F, double t_max) {
148 return [F, t_max](double t) -> double {
149 const int samples = 1000;
150 double domega = 2 * t_max / samples;
151 double result = 0.0;
152
153 for (int n = 0; n < samples; ++n) {
154 double omega = -t_max + n * domega;
155 ComplexNumber F_omega = F(omega);
156 double angle = omega * t;
157 ComplexNumber exponential(cos(angle), sin(angle));
158 ComplexNumber integrand = F_omega * exponential;
159 result += integrand.getValue().real() * domega;
160 }
161
162 return result / (2 * M_PI);
163 };
164}
165
166// Fourier Series
167std::vector<ComplexNumber> FourierTransform::fourierSeries(std::function<double(double)> f, double period, int harmonics) {
168 std::vector<ComplexNumber> coefficients(2 * harmonics + 1);
169 double omega0 = 2 * M_PI / period;
170
171 for (int n = -harmonics; n <= harmonics; ++n) {
172 const int samples = 1000;
173 double dt = period / samples;
174 ComplexNumber sum(0, 0);
175
176 for (int k = 0; k < samples; ++k) {
177 double t = k * dt;
178 double angle = -n * omega0 * t;
179 ComplexNumber exponential(cos(angle), sin(angle));
180 sum = sum + ComplexNumber(f(t), 0) * exponential * dt;
181 }
182
183 coefficients[n + harmonics] = sum / period;
184 }
185
186 return coefficients;
187}
188
189// Spectral analysis
190std::vector<double> FourierTransform::powerSpectrum(const std::vector<double>& signal) {
191 // Convert real signal to complex
192 std::vector<ComplexNumber> complexSignal;
193 for (double val : signal) {
194 complexSignal.push_back(ComplexNumber(val, 0));
195 }
196
197 // Compute FFT
198 std::vector<ComplexNumber> spectrum = FFT(complexSignal);
199
200 // Compute power spectrum
201 std::vector<double> power(spectrum.size());
202 for (size_t i = 0; i < spectrum.size(); ++i) {
203 power[i] = spectrum[i].getValue().real() * spectrum[i].getValue().real()
204 +
205 spectrum[i].getValue().imag() * spectrum[i].getValue().imag();
206 }
207
208 return power;
209}
210
211std::vector<double> FourierTransform::magnitude(const std::vector<ComplexNumber>& spectrum) {
212 std::vector<double> mag(spectrum.size());
213 for (size_t i = 0; i < spectrum.size(); ++i) {
214 mag[i] =
215 sqrt(spectrum[i].getValue().real() * spectrum[i].getValue().real()
216 +
217 spectrum[i].getValue().imag() * spectrum[i].getValue().imag());
218 }
219 return mag;
220}
221
222std::vector<double> FourierTransform::phase(const std::vector<ComplexNumber>& spectrum) {
223 std::vector<double> ph(spectrum.size());
224 for (size_t i = 0; i < spectrum.size(); ++i) {
225 ph[i] =
226 atan2(spectrum[i].getValue().imag(), spectrum[i].getValue().real());
227 }
228 return ph;
229}
230
231// Window functions
232std::vector<double> FourierTransform::hammingWindow(int N) {
233 std::vector<double> window(N);
234 for (int n = 0; n < N; ++n) {
235 window[n] = 0.54 - 0.46 * cos(2 * M_PI * n / (N - 1));
236 }
237 return window;
238}
239
240std::vector<double> FourierTransform::hanningWindow(int N) {
241 std::vector<double> window(N);
242 for (int n = 0; n < N; ++n) {
243 window[n] = 0.5 * (1 - cos(2 * M_PI * n / (N - 1)));
244 }
245 return window;
246}
247
248std::vector<double> FourierTransform::blackmanWindow(int N) {
249 std::vector<double> window(N);
250 for (int n = 0; n < N; ++n) {
251 double factor = 2 * M_PI * n / (N - 1);
252 window[n] = 0.42 - 0.5 * cos(factor) + 0.08 * cos(2 * factor);
253 }
254 return window;
255}