| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | /*  fir.c
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This file is part of a program that implements a Software-Defined Radio. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Copyright (C) 2013, 2016, 2022 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 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define _CRT_SECURE_NO_WARNINGS
 | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <limits>
 | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | #include "fftw3.h"
 | 
					
						
							|  |  |  | #include "comm.hpp"
 | 
					
						
							|  |  |  | #include "fir.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace WDSP { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void FIR::fftcv_mults (std::vector<float>& mults, int NM, const float* c_impulse) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-09 06:33:00 +02:00
										 |  |  |     mults.resize(NM * 2); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     std::vector<float> cfft_impulse(NM * 2); | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |     fftwf_plan ptmp = fftwf_plan_dft_1d( | 
					
						
							|  |  |  |         NM, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *) cfft_impulse.data(), | 
					
						
							| 
									
										
										
										
											2024-08-09 06:33:00 +02:00
										 |  |  |         (fftwf_complex *) mults.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         FFTW_FORWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     std::fill(cfft_impulse.begin(), cfft_impulse.end(), 0); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     // store complex coefs right-justified in the buffer
 | 
					
						
							| 
									
										
										
										
											2024-07-16 23:15:13 +02:00
										 |  |  |     std::copy(c_impulse, c_impulse + (NM / 2 + 1) * 2, &(cfft_impulse[NM - 2])); | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_execute (ptmp); | 
					
						
							|  |  |  |     fftwf_destroy_plan (ptmp); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  | void FIR::get_fsamp_window(std::vector<float>& window, int N, int wintype) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     double arg0; | 
					
						
							|  |  |  |     double arg1; | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |     window.resize(N); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     switch (wintype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |         arg0 = 2.0 * PI / ((double)N - 1.0); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |             arg1 = cos(arg0 * (double)i); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             double val =   +0.21747 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 + arg1 *  (-0.45325 | 
					
						
							|  |  |  |                 + arg1 *  (+0.28256 | 
					
						
							|  |  |  |                 + arg1 *  (-0.04672))); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             window[i] = (float) val; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |         arg0 = 2.0 * PI / ((double)N - 1.0); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; ++i) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |             arg1 = cos(arg0 * (double)i); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             double val =   +6.3964424114390378e-02 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 + arg1 *  (-2.3993864599352804e-01 | 
					
						
							|  |  |  |                 + arg1 *  (+3.5015956323820469e-01 | 
					
						
							|  |  |  |                 + arg1 *  (-2.4774111897080783e-01 | 
					
						
							|  |  |  |                 + arg1 *  (+8.5438256055858031e-02 | 
					
						
							|  |  |  |                 + arg1 *  (-1.2320203369293225e-02 | 
					
						
							|  |  |  |                 + arg1 *  (+4.3778825791773474e-04)))))); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             window[i] = (float) val; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             window[i] = 1.0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-08 09:09:40 +02:00
										 |  |  | void FIR::fir_fsamp_odd (std::vector<float>& c_impulse, int N, const float* A, int rtype, double scale, int wintype) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     int mid = (N - 1) / 2; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     double mag; | 
					
						
							|  |  |  |     double phs; | 
					
						
							|  |  |  |     std::vector<float> fcoef(N * 2); | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |     fftwf_plan ptmp = fftwf_plan_dft_1d( | 
					
						
							|  |  |  |         N, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *)fcoef.data(), | 
					
						
							| 
									
										
										
										
											2024-08-08 09:09:40 +02:00
										 |  |  |         (fftwf_complex *)c_impulse.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         FFTW_BACKWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |     double local_scale = 1.0 / (double) N; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     for (int i = 0; i <= mid; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         mag = A[i] * local_scale; | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |         phs = - (double)mid * TWOPI * (double)i / (double)N; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         fcoef[2 * i + 0] = (float) (mag * cos (phs)); | 
					
						
							|  |  |  |         fcoef[2 * i + 1] = (float) (mag * sin (phs)); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     for (int i = mid + 1, j = 0; i < N; i++, j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         fcoef[2 * i + 0] = + fcoef[2 * (mid - j) + 0]; | 
					
						
							|  |  |  |         fcoef[2 * i + 1] = - fcoef[2 * (mid - j) + 1]; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_execute (ptmp); | 
					
						
							|  |  |  |     fftwf_destroy_plan (ptmp); | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |     std::vector<float> window; | 
					
						
							|  |  |  |     get_fsamp_window(window, N, wintype); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     switch (rtype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							|  |  |  |             c_impulse[i] = (float) (scale * c_impulse[2 * i] * window[i]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[2 * i + 0] *= (float) (scale * window[i]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             c_impulse[2 * i + 1] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-08 09:09:40 +02:00
										 |  |  | void FIR::fir_fsamp (std::vector<float>& c_impulse, int N, const float* A, int rtype, double scale, int wintype) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |     double sum; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (N & 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int M = (N - 1) / 2; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int n = 0; n < M + 1; n++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             sum = 0.0; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             for (int k = 1; k < M + 1; k++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 sum += 2.0 * A[k] * cos(TWOPI * (n - M) * k / N); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[2 * n + 0] = (float) ((1.0 / N) * (A[0] + sum)); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             c_impulse[2 * n + 1] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int n = M + 1, j = 1; n < N; n++, j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             c_impulse[2 * n + 0] = c_impulse[2 * (M - j) + 0]; | 
					
						
							|  |  |  |             c_impulse[2 * n + 1] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |         double M = (double)(N - 1) / 2.0; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int n = 0; n < N / 2; n++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             sum = 0.0; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             for (int k = 1; k < N / 2; k++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 sum += 2.0 * A[k] * cos(TWOPI * (n - M) * k / N); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[2 * n + 0] = (float) ((1.0 / N) * (A[0] + sum)); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             c_impulse[2 * n + 1] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int n = N / 2, j = 1; n < N; n++, j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             c_impulse[2 * n + 0] = c_impulse[2 * (N / 2 - j) + 0]; | 
					
						
							|  |  |  |             c_impulse[2 * n + 1] = 0.0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |     std::vector<float> window; | 
					
						
							|  |  |  |     get_fsamp_window (window, N, wintype); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     switch (rtype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							|  |  |  |             c_impulse[i] = (float) (scale * c_impulse[2 * i] * window[i]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         for (int i = 0; i < N; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |                 c_impulse[2 * i + 0] *= (float) (scale * window[i]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 c_impulse[2 * i + 1] = 0.0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void FIR::fir_bandpass (std::vector<float>& c_impulse, int N, double f_low, double f_high, double samplerate, int wintype, int rtype, double scale) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     c_impulse.resize(N * 2); | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |     double ft = (f_high - f_low) / (2.0 * samplerate); | 
					
						
							|  |  |  |     double ft_rad = TWOPI * ft; | 
					
						
							|  |  |  |     double w_osc = PI * (f_high + f_low) / samplerate; | 
					
						
							|  |  |  |     double m = 0.5 * (double)(N - 1); | 
					
						
							|  |  |  |     double delta = PI / m; | 
					
						
							|  |  |  |     double cosphi; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     double posi; | 
					
						
							|  |  |  |     double posj; | 
					
						
							|  |  |  |     double sinc; | 
					
						
							|  |  |  |     double window; | 
					
						
							|  |  |  |     double coef; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (N & 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (rtype) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[N >> 1] = (float) (scale * 2.0 * ft); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  |         case 1: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[N - 1] = (float) (scale * 2.0 * ft); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             c_impulse[  N  ] = 0.0; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     for (int i = (N + 1) / 2, j = N / 2 - 1; i < N; i++, j--) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |         posi = (double)i - m; | 
					
						
							|  |  |  |         posj = (double)j - m; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         sinc = sin (ft_rad * posi) / (PI * posi); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (wintype == 1) // Blackman-Harris 7-term
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             cosphi = cos (delta * i); | 
					
						
							|  |  |  |             window  =             + 6.3964424114390378e-02 | 
					
						
							|  |  |  |                     + cosphi *  ( - 2.3993864599352804e-01 | 
					
						
							|  |  |  |                     + cosphi *  ( + 3.5015956323820469e-01 | 
					
						
							|  |  |  |                     + cosphi *  ( - 2.4774111897080783e-01 | 
					
						
							|  |  |  |                     + cosphi *  ( + 8.5438256055858031e-02 | 
					
						
							|  |  |  |                     + cosphi *  ( - 1.2320203369293225e-02 | 
					
						
							|  |  |  |                     + cosphi *  ( + 4.3778825791773474e-04 )))))); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         else // Blackman-Harris 4-term
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             cosphi = cos (delta * i); | 
					
						
							|  |  |  |             window  =             + 0.21747 | 
					
						
							|  |  |  |                     + cosphi *  ( - 0.45325 | 
					
						
							|  |  |  |                     + cosphi *  ( + 0.28256 | 
					
						
							|  |  |  |                     + cosphi *  ( - 0.04672 ))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         coef = scale * sinc * window; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         switch (rtype) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[i] = (float) (+ coef * cos (posi * w_osc)); | 
					
						
							|  |  |  |             c_impulse[j] = (float) (+ coef * cos (posj * w_osc)); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  |         case 1: | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             c_impulse[2 * i + 0] = (float) (+ coef * cos (posi * w_osc)); | 
					
						
							|  |  |  |             c_impulse[2 * i + 1] = (float) (- coef * sin (posi * w_osc)); | 
					
						
							|  |  |  |             c_impulse[2 * j + 0] = (float) (+ coef * cos (posj * w_osc)); | 
					
						
							|  |  |  |             c_impulse[2 * j + 1] = (float) (- coef * sin (posj * w_osc)); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  | void FIR::fir_read (std::vector<float>& c_impulse, int N, const char *filename, int rtype, float scale) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     // N = number of real or complex coefficients (see rtype)
 | 
					
						
							|  |  |  |     // *filename = filename
 | 
					
						
							|  |  |  |     // rtype = 0:  real coefficients
 | 
					
						
							|  |  |  |     // rtype = 1:  complex coefficients
 | 
					
						
							|  |  |  |     // scale = a scale factor that will be applied to the returned coefficients;
 | 
					
						
							|  |  |  |     //      if this is not needed, set it to 1.0
 | 
					
						
							|  |  |  |     // NOTE:  The number of values in the file must NOT exceed those implied by N and rtype
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FILE *file; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     float I; | 
					
						
							|  |  |  |     float Q; | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |     c_impulse.resize(N * 2); | 
					
						
							|  |  |  |     std::fill(c_impulse.begin(), c_impulse.end(), 0); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     file = fopen (filename, "r"); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!file) { | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < N; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         // read in the complex impulse response
 | 
					
						
							|  |  |  |         // NOTE:  IF the freq response is symmetrical about 0, the imag coeffs will all be zero.
 | 
					
						
							|  |  |  |         switch (rtype) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |             int r = fscanf (file, "%e", &I); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             fprintf(stderr, "^%d parameters read\n", r); | 
					
						
							|  |  |  |             c_impulse[i] = + scale * I; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case 1: | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |             int r = fscanf (file, "%e", &I); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             fprintf(stderr, "%d parameters read\n", r); | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |             r = fscanf (file, "%e", &Q); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             fprintf(stderr, "%d parameters read\n", r); | 
					
						
							|  |  |  |             c_impulse[2 * i + 0] = + scale * I; | 
					
						
							|  |  |  |             c_impulse[2 * i + 1] = - scale * Q; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fclose (file); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  | void FIR::analytic (int N, float* in, float* out) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     if (N < 2) { | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-19 08:10:54 +02:00
										 |  |  |     double inv_N = 1.0 / (double) N; | 
					
						
							|  |  |  |     double two_inv_N = 2.0 * inv_N; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     std::vector<float> x(N * 2); | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |     fftwf_plan pfor = fftwf_plan_dft_1d ( | 
					
						
							|  |  |  |         N, | 
					
						
							|  |  |  |         (fftwf_complex *) in, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *) x.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         FFTW_FORWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |     fftwf_plan prev = fftwf_plan_dft_1d ( | 
					
						
							|  |  |  |         N, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *) x.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         (fftwf_complex *) out, | 
					
						
							|  |  |  |         FFTW_BACKWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_execute (pfor); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     x[0] *= (float) inv_N; | 
					
						
							|  |  |  |     x[1] *= (float) inv_N; | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     for (int i = 1; i < N / 2; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         x[2 * i + 0] *= (float) two_inv_N; | 
					
						
							|  |  |  |         x[2 * i + 1] *= (float) two_inv_N; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-07-21 14:20:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     x[N + 0] *= (float) inv_N; | 
					
						
							|  |  |  |     x[N + 1] *= (float) inv_N; | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     memset (&x[N + 2], 0, (N - 2) * sizeof (float)); | 
					
						
							|  |  |  |     fftwf_execute (prev); | 
					
						
							|  |  |  |     fftwf_destroy_plan (prev); | 
					
						
							|  |  |  |     fftwf_destroy_plan (pfor); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-06 06:26:53 +02:00
										 |  |  | void FIR::mp_imp (int N, std::vector<float>& fir, std::vector<float>& mpfir, int pfactor, int polarity) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     int size = N * pfactor; | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     double inv_PN = 1.0 / (double)size; | 
					
						
							|  |  |  |     std::vector<float> firpad(size * 2); | 
					
						
							|  |  |  |     std::vector<float> firfreq(size * 2); | 
					
						
							|  |  |  |     std::vector<double> mag(size); | 
					
						
							|  |  |  |     std::vector<float> ana(size * 2); | 
					
						
							|  |  |  |     std::vector<float> impulse(size * 2); | 
					
						
							|  |  |  |     std::vector<float> newfreq(size * 2); | 
					
						
							| 
									
										
										
										
											2024-08-06 06:26:53 +02:00
										 |  |  |     std::copy(fir.begin(), fir.begin() + N * 2, firpad.begin()); | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |     fftwf_plan pfor = fftwf_plan_dft_1d ( | 
					
						
							|  |  |  |         size, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *) firpad.data(), | 
					
						
							|  |  |  |         (fftwf_complex *) firfreq.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         FFTW_FORWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT); | 
					
						
							|  |  |  |     fftwf_plan prev = fftwf_plan_dft_1d ( | 
					
						
							|  |  |  |         size, | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         (fftwf_complex *) newfreq.data(), | 
					
						
							|  |  |  |         (fftwf_complex *) impulse.data(), | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         FFTW_BACKWARD, | 
					
						
							|  |  |  |         FFTW_PATIENT | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_execute (pfor); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     for (i = 0; i < size; i++) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-17 01:58:47 +02:00
										 |  |  |         double xr = firfreq[2 * i + 0]; | 
					
						
							|  |  |  |         double xi = firfreq[2 * i + 1]; | 
					
						
							|  |  |  |         mag[i] = sqrt (xr*xr + xi*xi) * inv_PN; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         if (mag[i] > 0.0) | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             ana[2 * i + 0] = (float) log (mag[i]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2024-07-17 03:04:47 +02:00
										 |  |  |             ana[2 * i + 0] = log (std::numeric_limits<float>::min()); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     analytic (size, ana.data(), ana.data()); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     for (i = 0; i < size; i++) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |         newfreq[2 * i + 0] = (float) (+ mag[i] * cos (ana[2 * i + 1])); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         if (polarity) | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             newfreq[2 * i + 1] = (float) (+ mag[i] * sin (ana[2 * i + 1])); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |             newfreq[2 * i + 1] = (float) (- mag[i] * sin (ana[2 * i + 1])); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_execute (prev); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     if (polarity) | 
					
						
							| 
									
										
										
										
											2024-08-06 06:26:53 +02:00
										 |  |  |         std::copy(&impulse[2 * (pfactor - 1) * N], &impulse[2 * (pfactor - 1) * N] + N * 2, mpfir.begin()); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2024-08-06 06:26:53 +02:00
										 |  |  |         std::copy(impulse.begin(), impulse.end(), mpfir.begin()); | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     fftwf_destroy_plan (prev); | 
					
						
							|  |  |  |     fftwf_destroy_plan (pfor); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // impulse response of a zero frequency filter comprising a cascade of two resonators,
 | 
					
						
							|  |  |  | //    each followed by a detrending filter
 | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  | void FIR::zff_impulse(std::vector<float>& c_dresdet, int nc, float scale) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     // nc = number of coefficients (power of two)
 | 
					
						
							|  |  |  |     int n_resdet = nc / 2 - 1;          // size of single zero-frequency resonator with detrender
 | 
					
						
							|  |  |  |     int n_dresdet = 2 * n_resdet - 1;   // size of two cascaded units; when we convolve these we get 2 * n - 1 length
 | 
					
						
							|  |  |  |     // allocate the single and make the values
 | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     std::vector<float> resdet(n_resdet); // (float*)malloc0 (n_resdet * sizeof(float));
 | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     for (int i = 1, j = 0, k = n_resdet - 1; i < nc / 4; i++, j++, k--) | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |         resdet[j] = resdet[k] = (float)(i * (i + 1) / 2); | 
					
						
							|  |  |  |     resdet[nc / 4 - 1] = (float)(nc / 4 * (nc / 4 + 1) / 2); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     // print_impulse ("resdet", n_resdet, resdet, 0, 0);
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     // allocate the float and complex versions and make the values
 | 
					
						
							| 
									
										
										
										
											2024-08-02 08:01:46 +02:00
										 |  |  |     std::vector<float> dresdet(n_dresdet); | 
					
						
							|  |  |  |     auto div = (float) ((nc / 2 + 1) * (nc / 2 + 1));                 // calculate divisor
 | 
					
						
							| 
									
										
										
										
											2024-08-10 02:06:19 +02:00
										 |  |  |     c_dresdet.resize(nc * 2); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     for (int n = 0; n < n_dresdet; n++) // convolve to make the cascade
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (int k = 0; k < n_resdet; k++) | 
					
						
							|  |  |  |             if ((n - k) >= 0 && (n - k) < n_resdet) | 
					
						
							|  |  |  |                 dresdet[n] += resdet[k] * resdet[n - k]; | 
					
						
							|  |  |  |         dresdet[n] /= div; | 
					
						
							|  |  |  |         c_dresdet[2 * n + 0] = dresdet[n] * scale; | 
					
						
							|  |  |  |         c_dresdet[2 * n + 1] = 0.0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace WDSP
 |