SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
interpolator.h
Go to the documentation of this file.
1 // Copyright (C) 2015 Edouard Griffiths, F4EXB. //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #ifndef INCLUDE_INTERPOLATOR_H
19 #define INCLUDE_INTERPOLATOR_H
20 
21 #ifdef USE_SSE2
22 #include <emmintrin.h>
23 #endif
24 #include "dsp/dsptypes.h"
25 #include "export.h"
26 #include <stdio.h>
27 
29 public:
30  Interpolator();
31  ~Interpolator();
32 
33  void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase = 4.5);
34  void free();
35 
36  // Original code allowed for upsampling, but was never used that way
37  // The decimation factor should always be lower than 2 for proper work
38  bool decimate(Real *distance, const Complex& next, Complex* result)
39  {
40  advanceFilter(next);
41  *distance -= 1.0;
42 
43  if (*distance >= 1.0) {
44  return false;
45  }
46 
47  doInterpolate((int) floor(*distance * (Real)m_phaseSteps), result);
48 
49  return true;
50  }
51 
52  // interpolation simplified from the generalized resampler
53  bool interpolate(Real *distance, const Complex& next, Complex* result)
54  {
55  bool consumed = false;
56 
57  if (*distance >= 1.0)
58  {
59  advanceFilter(next);
60  *distance -= 1.0;
61  consumed = true;
62  }
63 
64  doInterpolate((int)floor(*distance * (Real)m_phaseSteps), result);
65 
66  return consumed;
67  }
68 
69  // original interpolator which is actually an arbitrary rational resampler P/Q for any positive P, Q
70  // sampling frequency must be the highest of the two
71  bool resample(Real* distance, const Complex& next, bool* consumed, Complex* result)
72  {
73  while (*distance >= 1.0)
74  {
75  if (!(*consumed))
76  {
77  advanceFilter(next);
78  *distance -= 1.0;
79  *consumed = true;
80  }
81  else
82  {
83  return false;
84  }
85  }
86 
87  doInterpolate((int)floor(*distance * (Real)m_phaseSteps), result);
88 
89  return true;
90  }
91 
92 private:
93  float* m_taps;
94  float* m_alignedTaps;
95  float* m_taps2;
97  std::vector<Complex> m_samples;
98  int m_ptr;
100  int m_nTaps;
101 
102  static void createPolyphaseLowPass(
103  std::vector<Real>& taps,
104  int phaseSteps,
105  double gain,
106  double sampleRateHz,
107  double cutoffFreqHz,
108  double transitionWidthHz,
109  double oobAttenuationdB);
110 
111  static void createPolyphaseLowPass(
112  std::vector<Real>& taps,
113  int phaseSteps,
114  double gain,
115  double sampleRateHz,
116  double cutoffFreqHz,
117  double nbTapsPerPhase);
118 
119  void createTaps(int nTaps, double sampleRate, double cutoff, std::vector<Real>* taps);
120 
121  void advanceFilter(const Complex& next)
122  {
123  m_ptr--;
124 
125  if (m_ptr < 0) {
126  m_ptr = m_nTaps - 1;
127  }
128 
129  m_samples[m_ptr] = next;
130  }
131 
133  {
134  m_ptr--;
135 
136  if (m_ptr < 0) {
137  m_ptr = m_nTaps - 1;
138  }
139 
140  m_samples[m_ptr].real(0.0);
141  m_samples[m_ptr].imag(0.0);
142  }
143 
144  void doInterpolate(int phase, Complex* result)
145  {
146  if (phase < 0) {
147  phase = 0;
148  }
149 #if USE_SSE2
150  // beware of the ringbuffer
151  if(m_ptr == 0) {
152  // only one straight block
153  const float* src = (const float*)&m_samples[0];
154  const __m128* filter = (const __m128*)&m_alignedTaps[phase * m_nTaps * 2];
155  __m128 sum = _mm_setzero_ps();
156  int todo = m_nTaps / 2;
157 
158  for(int i = 0; i < todo; i++) {
159  sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
160  src += 4;
161  filter += 1;
162  }
163 
164  // add upper half to lower half and store
165  _mm_storel_pi((__m64*)result, _mm_add_ps(sum, _mm_shuffle_ps(sum, _mm_setzero_ps(), _MM_SHUFFLE(1, 0, 3, 2))));
166  } else {
167  // two blocks
168  const float* src = (const float*)&m_samples[m_ptr];
169  const __m128* filter = (const __m128*)&m_alignedTaps[phase * m_nTaps * 2];
170  __m128 sum = _mm_setzero_ps();
171 
172  // first block
173  int block = m_nTaps - m_ptr;
174  int todo = block / 2;
175  if(block & 1)
176  todo++;
177  for(int i = 0; i < todo; i++) {
178  sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
179  src += 4;
180  filter += 1;
181  }
182  if(block & 1) {
183  // one sample beyond the end -> switch coefficient table
184  filter = (const __m128*)&m_alignedTaps2[phase * m_nTaps * 2 + todo * 4 - 4];
185  }
186  // second block
187  src = (const float*)&m_samples[0];
188  block = m_ptr;
189  todo = block / 2;
190  for(int i = 0; i < todo; i++) {
191  sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
192  src += 4;
193  filter += 1;
194  }
195  if(block & 1) {
196  // one sample remaining
197  sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadl_pi(_mm_setzero_ps(), (const __m64*)src), filter[0]));
198  }
199 
200  // add upper half to lower half and store
201  _mm_storel_pi((__m64*)result, _mm_add_ps(sum, _mm_shuffle_ps(sum, _mm_setzero_ps(), _MM_SHUFFLE(1, 0, 3, 2))));
202  }
203 #else
204  int sample = m_ptr;
205  const Real* coeff = &m_alignedTaps[phase * m_nTaps * 2];
206  Real rAcc = 0;
207  Real iAcc = 0;
208 
209  for (int i = 0; i < m_nTaps; i++) {
210  rAcc += *coeff * m_samples[sample].real();
211  iAcc += *coeff * m_samples[sample].imag();
212  sample = (sample + 1) % m_nTaps;
213  coeff += 2;
214  }
215 
216  *result = Complex(rAcc, iAcc);
217 #endif
218 
219  }
220 };
221 
222 #endif // INCLUDE_INTERPOLATOR_H
bool resample(Real *distance, const Complex &next, bool *consumed, Complex *result)
Definition: interpolator.h:71
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
bool interpolate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:53
float * m_taps
Definition: interpolator.h:93
void advanceFilter()
Definition: interpolator.h:132
float * m_alignedTaps
Definition: interpolator.h:94
void advanceFilter(const Complex &next)
Definition: interpolator.h:121
Fixed< IntType, IntBits > floor(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2301
void * create(QString type)
float * m_alignedTaps2
Definition: interpolator.h:96
std::vector< Complex > m_samples
Definition: interpolator.h:97
int32_t i
Definition: decimators.h:244
void doInterpolate(int phase, Complex *result)
Definition: interpolator.h:144
float * m_taps2
Definition: interpolator.h:95
#define SDRBASE_API
Definition: export.h:40
std::complex< Real > Complex
Definition: dsptypes.h:43
float Real
Definition: dsptypes.h:42