HARDT - The Ham Radio DSP Toolkit
hfft.h
1 #ifndef __HFFT_H
2 #define __HFFT_H
3 
4 #include <complex>
5 #include <valarray>
6 #include <complex.h>
7 
8 #include "hwindow.h"
9 
11 template <class T>
12 class HFft {
13 
14  private:
15 
16  HWindow<T>* _window;
17  int _size;
18 
19  T* _fftBuffer;
20  std::complex<double>* _hilbertBuffer;
21  std::complex<T>* _iqComplex;
22  std::complex<double>* _iqSpectrum;
23 
24  void FFT(std::valarray<std::complex<double>>& x)
25  {
26  const size_t N = x.size();
27  if (N <= 1) return;
28 
29  // divide
30  std::valarray<std::complex<double>> even = x[std::slice(0, N/2, 2)];
31  std::valarray<std::complex<double>> odd = x[std::slice(1, N/2, 2)];
32 
33  // conquer
34  FFT(even);
35  FFT(odd);
36 
37  // combine
38  for (size_t k = 0; k < N/2; ++k)
39  {
40  std::complex<double> t = std::polar(1.0, -2 * M_PI * k / N) * odd[k];
41  x[k ] = even[k] + t;
42  x[k+N/2] = even[k] - t;
43  }
44  }
45 
46  public:
47 
55  HFft(int size, HWindow<T>* window = nullptr):
56  _window(window),
57  _size(size) {
58 
59  // Set window size
60  if( _window != nullptr ) {
61  _window->SetSize(_size);
62  }
63 
64  // Allocate a buffer for intermediate results in the fft functions
65  _fftBuffer = new T[_size];
66 
67  // Allocate a buffer for intermediate results in the hilbert function
68  _hilbertBuffer = new std::complex<double>[_size];
69 
70  // Allocate buffers for IQ2REAl operations
71  _iqComplex = new std::complex<T>[_size];
72  _iqSpectrum = new std::complex<double>[_size];
73  }
74 
75  ~HFft() {
76  delete _fftBuffer;
77  delete _hilbertBuffer;
78  delete _iqComplex;
79  delete _iqSpectrum;
80  }
81 
88  void FFT(std::complex<T>* src, std::complex<double>* result) {
89 
90  // Prepare a set of complex values
91  std::valarray<std::complex<double>> x(_size);
92  for( int i = 0; i < _size ; i++ )
93  {
94  x[i] = std::complex<double>(src[i].real(), src[i].imag());
95  }
96 
97  // Calculate the FFT
98  FFT(x);
99 
100  // Convert to simple array with bins for positive AND negative frequencies
101  for( int i = 0; i < _size; i++ )
102  {
103  result[i] = x[i];
104  }
105  }
106 
113  void FFT(T* src, std::complex<double>* result, bool window = true) {
114 
115  // Run the input buffer through a window function, if any is given
116  if( window && _window != nullptr ) {
117  _window->Apply(src, _fftBuffer, _size);
118  } else {
119  memcpy((void*) _fftBuffer, (void*) src, _size * sizeof(T));
120  }
121 
122  // Prepare a set of complex values
123  std::valarray<std::complex<double>> x(_size);
124  for( int i = 0; i < _size ; i++ )
125  {
126  x[i] = std::complex<double>(_fftBuffer[i], 0);
127  }
128 
129  // Calculate the FFT
130  FFT(x);
131 
132  // Convert to simple array with bins for positive AND negative frequencies
133  for( int i = 0; i < _size; i++ )
134  {
135  result[i] = x[i];
136  }
137  }
138 
145  void FFT(T* src, double* spectrum, double* phase = nullptr) {
146 
147  // Allocate a buffer for the complex spectrum results
148  std::complex<double>* result = new std::complex<double>[_size];
149 
150  // Run fft on the input
151  FFT(src, result);
152 
153  // convert to real valued spectrum powers for each bin
154  for( int i = 0; i < _size / 2; i++ )
155  {
156  // Get absolute value at point n
157  spectrum[i] = std::abs(result[i]);
158 
159  if( phase != nullptr )
160  {
161  phase[i] = std::arg(result[i]);
162  }
163  }
164 
165  // Cleanup
166  delete[] result;
167  }
168 
175  void IFFT(std::complex<double>* src, T* result) {
176 
177  // Prepare the input array to the fft function, filled with the complex conjugate of the input values
178  std::valarray<std::complex<double>> x(_size);
179  for( int i = 0; i < _size ; i++ )
180  {
181  x[i] = src[i];
182  }
183  x.apply(std::conj);
184 
185  // Calculate the FFT
186  FFT(x);
187 
188  // Convert to simple array with the realvalued signal samples
189  double factor = 1.0 / _size;
190  x.apply(std::conj);
191  for( int i = 0; i < _size; i++ )
192  {
193  result[i] = x[i].real() * factor;
194  }
195  }
196 
198  void HILBERT(T* src, T* dest) {
199  FFT(src, _hilbertBuffer, false);
200 
201  for(int i = _size / 2; i < _size; i++ ) {
202  _hilbertBuffer[i] = 0;
203  }
204 
205  IFFT(_hilbertBuffer, dest);
206  }
207 
218  void SPECTRUM(T* response, int length, std::complex<double>* spectrum) {
219 
220  // Sanity check
221  if( length > _size / 2 ) {
222  throw new HInitializationException("Length must not exceed fft-size/2 in call to HFft::SPECTRUM");
223  }
224 
225  // Initialize buffer
226  T* buffer = new T[_size];
227  memset((void*) buffer, 0, sizeof(T) * _size);
228 
229  // Copy frequency response into buffer
230  memcpy((void*) buffer, (void*) response, sizeof(T) * length);
231 
232  // Take FFT of the frequency response
233  FFT(buffer, spectrum);
234  }
235 
244  void IQ2REAL(T *multiplexed, T* real) {
245 
246  // Demultiplex into complex signal
247  for( int i = 0; i < _size * 2; i += 2 ) {
248  _iqComplex[i / 2] = {multiplexed[i], multiplexed[i + 1]};
249  }
250 
251  // Convert the complex IQ buffer to real valued samples
252  IQ2REAL(_iqComplex, real);
253  }
254 
256  void IQ2REAL(std::complex<T>* iq, T* real) {
257 
258  // FFT -> symmetrical spectrum with positive and negative frequencies
259  FFT(iq, _iqSpectrum);
260 
261  // Zero negative frequencies
262  for( int i = _size / 2; i < _size; i++ ) {
263  _iqSpectrum[i] = 0;
264  }
265 
266  // IFFT -> real signal with negative frequencies removed
267  IFFT(_iqSpectrum, real);
268  }
269 };
270 
271 #endif
HWindow
Definition: hwindow.h:8
HFft::HILBERT
void HILBERT(T *src, T *dest)
Definition: hfft.h:198
HFft::FFT
void FFT(std::complex< T > *src, std::complex< double > *result)
Definition: hfft.h:88
HFft::HFft
HFft(int size, HWindow< T > *window=nullptr)
Definition: hfft.h:55
HWindow::SetSize
void SetSize(int N)
Definition: hwindow.cpp:20
HWindow::Apply
void Apply(T *src, T *dest, size_t blocksize)
Definition: hwindow.cpp:42
HFft::IFFT
void IFFT(std::complex< double > *src, T *result)
Definition: hfft.h:175
HInitializationException
Definition: hexceptions.h:39
HFft::SPECTRUM
void SPECTRUM(T *response, int length, std::complex< double > *spectrum)
Definition: hfft.h:218
HFft::IQ2REAL
void IQ2REAL(T *multiplexed, T *real)
Definition: hfft.h:244
HFft
Definition: hfft.h:12
HFft::FFT
void FFT(T *src, double *spectrum, double *phase=nullptr)
Definition: hfft.h:145
HFft::FFT
void FFT(T *src, std::complex< double > *result, bool window=true)
Definition: hfft.h:113
HFft::IQ2REAL
void IQ2REAL(std::complex< T > *iq, T *real)
Definition: hfft.h:256