| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | /*  icfir.c
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This file is part of a program that implements a Software-Defined Radio. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Copyright (C) 2018 Warren Pratt, NR0V | 
					
						
							|  |  |  | Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | of the License, or (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The author can be reached by email at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | warren@pratt.one | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | #include "comm.hpp"
 | 
					
						
							| 
									
										
										
										
											2024-07-13 03:20:26 +02:00
										 |  |  | #include "fircore.hpp"
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | #include "fir.hpp"
 | 
					
						
							|  |  |  | #include "icfir.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace WDSP { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::calc() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-08 09:09:40 +02:00
										 |  |  |     std::vector<float> impulse; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     scale = 1.0f / (float)(2 * size); | 
					
						
							|  |  |  |     icfir_impulse (impulse, nc, DD, R, Pairs, (float) runrate, (float) cicrate, cutoff, xtype, xbw, 1, scale, wintype); | 
					
						
							|  |  |  |     p = new FIRCORE(size, in, out, mp, impulse); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::decalc() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     delete p; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | ICFIR::ICFIR( | 
					
						
							|  |  |  |     int _run, | 
					
						
							|  |  |  |     int _size, | 
					
						
							|  |  |  |     int _nc, | 
					
						
							|  |  |  |     int _mp, | 
					
						
							|  |  |  |     float* _in, | 
					
						
							|  |  |  |     float* _out, | 
					
						
							|  |  |  |     int _runrate, | 
					
						
							|  |  |  |     int _cicrate, | 
					
						
							|  |  |  |     int _DD, | 
					
						
							|  |  |  |     int _R, | 
					
						
							|  |  |  |     int _Pairs, | 
					
						
							|  |  |  |     float _cutoff, | 
					
						
							|  |  |  |     int _xtype, | 
					
						
							|  |  |  |     float _xbw, | 
					
						
							|  |  |  |     int _wintype | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | //  run:  0 - no action; 1 - operate
 | 
					
						
							|  |  |  | //  size:  number of complex samples in an input buffer to the CFIR filter
 | 
					
						
							|  |  |  | //  nc:  number of filter coefficients
 | 
					
						
							|  |  |  | //  mp:  minimum phase flag
 | 
					
						
							|  |  |  | //  in:  pointer to the input buffer
 | 
					
						
							|  |  |  | //  out:  pointer to the output buffer
 | 
					
						
							|  |  |  | //  rate:  samplerate
 | 
					
						
							|  |  |  | //  DD:  differential delay of the CIC to be compensated (usually 1 or 2)
 | 
					
						
							|  |  |  | //  R:  interpolation factor of CIC
 | 
					
						
							|  |  |  | //  Pairs:  number of comb-integrator pairs in the CIC
 | 
					
						
							|  |  |  | //  cutoff:  cutoff frequency
 | 
					
						
							|  |  |  | //  xtype:  0 - fourth power transition; 1 - raised cosine transition
 | 
					
						
							|  |  |  | //  xbw:  width of raised cosine transition
 | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     run = _run; | 
					
						
							|  |  |  |     size = _size; | 
					
						
							|  |  |  |     nc = _nc; | 
					
						
							|  |  |  |     mp = _mp; | 
					
						
							|  |  |  |     in = _in; | 
					
						
							|  |  |  |     out = _out; | 
					
						
							|  |  |  |     runrate = _runrate; | 
					
						
							|  |  |  |     cicrate = _cicrate; | 
					
						
							|  |  |  |     DD = _DD; | 
					
						
							|  |  |  |     R = _R; | 
					
						
							|  |  |  |     Pairs = _Pairs; | 
					
						
							|  |  |  |     cutoff = _cutoff; | 
					
						
							|  |  |  |     xtype = _xtype; | 
					
						
							|  |  |  |     xbw = _xbw; | 
					
						
							|  |  |  |     wintype = _wintype; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | ICFIR::~ICFIR() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     decalc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::flush() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     p->flush(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::execute() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     if (run) | 
					
						
							|  |  |  |         p->execute(); | 
					
						
							|  |  |  |     else if (in != out) | 
					
						
							|  |  |  |         std::copy( in,  in + size * 2, out); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::setBuffers(float* _in, float* _out) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     decalc(); | 
					
						
							|  |  |  |     in = _in; | 
					
						
							|  |  |  |     out = _out; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::setSamplerate(int _rate) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     decalc(); | 
					
						
							|  |  |  |     runrate = _rate; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::setSize(int _size) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     decalc(); | 
					
						
							|  |  |  |     size = _size; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  | void ICFIR::setOutRate(int _rate) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     decalc(); | 
					
						
							|  |  |  |     cicrate = _rate; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-08 09:09:40 +02:00
										 |  |  | void ICFIR::icfir_impulse ( | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     std::vector<float>& _impulse, | 
					
						
							|  |  |  |     int _N, | 
					
						
							|  |  |  |     int _DD, | 
					
						
							|  |  |  |     int _R, | 
					
						
							|  |  |  |     int _Pairs, | 
					
						
							|  |  |  |     float _runrate, | 
					
						
							|  |  |  |     float _cicrate, | 
					
						
							|  |  |  |     float _cutoff, | 
					
						
							|  |  |  |     int _xtype, | 
					
						
							|  |  |  |     float _xbw, | 
					
						
							|  |  |  |     int _rtype, | 
					
						
							|  |  |  |     float _scale, | 
					
						
							|  |  |  |     int _wintype | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // N:       number of impulse response samples
 | 
					
						
							|  |  |  |     // DD:      differential delay used in the CIC filter
 | 
					
						
							|  |  |  |     // R:       interpolation / decimation factor of the CIC
 | 
					
						
							|  |  |  |     // Pairs:   number of comb-integrator pairs in the CIC
 | 
					
						
							|  |  |  |     // runrate: sample rate at which this filter is to run (assumes there may be flat interp. between this filter and the CIC)
 | 
					
						
							|  |  |  |     // cicrate: sample rate at interface to CIC
 | 
					
						
							|  |  |  |     // cutoff:  cutoff frequency
 | 
					
						
							|  |  |  |     // xtype:   transition type, 0 for 4th-power rolloff, 1 for raised cosine
 | 
					
						
							|  |  |  |     // xbw:     transition bandwidth for raised cosine
 | 
					
						
							|  |  |  |     // rtype:   0 for real output, 1 for complex output
 | 
					
						
							|  |  |  |     // scale:   scale factor to be applied to the output
 | 
					
						
							| 
									
										
										
										
											2024-08-06 06:26:53 +02:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     int j; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     double tmp; | 
					
						
							|  |  |  |     double local_scale; | 
					
						
							|  |  |  |     double ri; | 
					
						
							|  |  |  |     double mag = 0; | 
					
						
							|  |  |  |     double fn; | 
					
						
							|  |  |  |     std::vector<float> A(_N); | 
					
						
							|  |  |  |     double ft = _cutoff / _cicrate;                                       // normalized cutoff frequency
 | 
					
						
							|  |  |  |     int u_samps = (_N + 1) / 2;                                          // number of unique samples,  OK for odd or even N
 | 
					
						
							|  |  |  |     int c_samps = (int)(_cutoff / _runrate * _N) + (_N + 1) / 2 - _N / 2;    // number of unique samples within bandpass, OK for odd or even N
 | 
					
						
							|  |  |  |     auto x_samps = (int)(_xbw / _runrate * _N);                             // number of unique samples in transition region, OK for odd or even N
 | 
					
						
							|  |  |  |     double offset = 0.5f - 0.5f * (float)((_N + 1) / 2 - _N / 2);          // sample offset from center, OK for odd or even N
 | 
					
						
							|  |  |  |     std::vector<double> xistion(x_samps + 1); | 
					
						
							|  |  |  |     double delta = PI / (float)x_samps; | 
					
						
							|  |  |  |     double L = _cicrate / _runrate; | 
					
						
							|  |  |  |     double phs = 0.0; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     for (i = 0; i <= x_samps; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         xistion[i] = 0.5 * (cos (phs) + 1.0); | 
					
						
							|  |  |  |         phs += delta; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     if ((tmp = _DD * _R * sin (PI * ft / _R) / sin (PI * _DD * ft)) < 0.0)  //normalize by peak gain
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         tmp = -tmp; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     local_scale = _scale / pow (tmp, _Pairs); | 
					
						
							|  |  |  |     if (_xtype == 0) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |             fn = ri / (L * (float)_N); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             if (fn <= ft) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (fn == 0.0) tmp = 1.0; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |                 else if ((tmp = sin (PI * _DD * fn) / (_DD * _R * sin (PI * fn / _R))) < 0.0) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                     tmp = -tmp; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |                 mag = pow (tmp, _Pairs) * local_scale; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 mag *= (ft * ft * ft * ft) / (fn * fn * fn * fn); | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |             A[i] = (float) mag; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     else if (_xtype == 1) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |             fn = ri / (L *(float)_N); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             if (i < c_samps) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (fn == 0.0) tmp = 1.0; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |                 else if ((tmp = sin (PI * _DD * fn) / (_DD * _R * sin (PI * fn / _R))) < 0.0) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                     tmp = -tmp; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |                 mag = pow (tmp, _Pairs) * local_scale; | 
					
						
							|  |  |  |                 A[i] = (float) mag; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             else if ( i >= c_samps && i <= c_samps + x_samps) | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |                 A[i] = (float) (mag * xistion[i - c_samps]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             else | 
					
						
							|  |  |  |                 A[i] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     if (_N & 1) | 
					
						
							|  |  |  |         for (i = u_samps, j = 2; i < _N; i++, j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             A[i] = A[u_samps - j]; | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |         for (i = u_samps, j = 1; i < _N; i++, j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             A[i] = A[u_samps - j]; | 
					
						
							| 
									
										
										
										
											2024-08-10 23:46:47 +02:00
										 |  |  |     _impulse.resize(2 * _N); | 
					
						
							|  |  |  |     FIR::fir_fsamp (_impulse, _N, A.data(), _rtype, 1.0, _wintype); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace WDSP
 |