| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | /*  varsamp.c
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This file is part of a program that implements a Software-Defined Radio. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Copyright (C) 2017 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@wpratt.com | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "comm.hpp"
 | 
					
						
							|  |  |  | #include "fir.hpp"
 | 
					
						
							|  |  |  | #include "varsamp.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace WDSP { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::calc() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     float min_rate; | 
					
						
							|  |  |  |     float max_rate; | 
					
						
							|  |  |  |     float norm_rate; | 
					
						
							|  |  |  |     float fc_norm_high; | 
					
						
							|  |  |  |     float fc_norm_low; | 
					
						
							|  |  |  |     nom_ratio = (float)out_rate / (float)in_rate; | 
					
						
							|  |  |  |     cvar = var * nom_ratio; | 
					
						
							|  |  |  |     inv_cvar = 1.0f / cvar; | 
					
						
							|  |  |  |     old_inv_cvar = inv_cvar; | 
					
						
							|  |  |  |     dicvar = 0.0; | 
					
						
							|  |  |  |     delta = (float) fabs (1.0 / cvar - 1.0); | 
					
						
							|  |  |  |     fc = fcin; | 
					
						
							|  |  |  |     if (out_rate >= in_rate) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         min_rate = (float)in_rate; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         norm_rate = min_rate; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         min_rate = (float)out_rate; | 
					
						
							|  |  |  |         max_rate = (float)in_rate; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         norm_rate = max_rate; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     if (fc == 0.0) fc = 0.95f * 0.45f * min_rate; | 
					
						
							|  |  |  |     fc_norm_high = fc / norm_rate; | 
					
						
							|  |  |  |     if (fc_low < 0.0) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         fc_norm_low = - fc_norm_high; | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         fc_norm_low = fc_low / norm_rate; | 
					
						
							|  |  |  |     rsize = (int)(140.0 * norm_rate / min_rate); | 
					
						
							|  |  |  |     ncoef = rsize + 1; | 
					
						
							|  |  |  |     ncoef += (R - 1) * (ncoef - 1); | 
					
						
							|  |  |  |     FIR::fir_bandpass(h, ncoef, fc_norm_low, fc_norm_high, (float)R, 1, 0, (float)R * gain); | 
					
						
							|  |  |  |     ring.resize(rsize * 2); | 
					
						
							|  |  |  |     idx_in = rsize - 1; | 
					
						
							|  |  |  |     h_offset = 0.0; | 
					
						
							|  |  |  |     hs.resize(rsize); | 
					
						
							|  |  |  |     isamps = 0.0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | VARSAMP::VARSAMP( | 
					
						
							|  |  |  |     int _run, | 
					
						
							|  |  |  |     int _size, | 
					
						
							|  |  |  |     float* _in, | 
					
						
							|  |  |  |     float* _out, | 
					
						
							|  |  |  |     int _in_rate, | 
					
						
							|  |  |  |     int _out_rate, | 
					
						
							|  |  |  |     float _fc, | 
					
						
							|  |  |  |     float _fc_low, | 
					
						
							|  |  |  |     int _R, | 
					
						
							|  |  |  |     float _gain, | 
					
						
							|  |  |  |     float _var, | 
					
						
							|  |  |  |     int _varmode | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     run = _run; | 
					
						
							|  |  |  |     size = _size; | 
					
						
							|  |  |  |     in = _in; | 
					
						
							|  |  |  |     out = _out; | 
					
						
							|  |  |  |     in_rate = _in_rate; | 
					
						
							|  |  |  |     out_rate = _out_rate; | 
					
						
							|  |  |  |     fcin = _fc; | 
					
						
							|  |  |  |     fc_low = _fc_low; | 
					
						
							|  |  |  |     R = _R; | 
					
						
							|  |  |  |     gain = _gain; | 
					
						
							|  |  |  |     var = _var; | 
					
						
							|  |  |  |     varmode = _varmode; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::flush() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     std::fill(ring.begin(), ring.end(), 0); | 
					
						
							|  |  |  |     idx_in = rsize - 1; | 
					
						
							|  |  |  |     h_offset = 0.0; | 
					
						
							|  |  |  |     isamps = 0.0; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::hshift() | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     int j; | 
					
						
							|  |  |  |     int k; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     int hidx; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     float frac; | 
					
						
							|  |  |  |     float pos; | 
					
						
							|  |  |  |     pos = (float)R * h_offset; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     hidx = (int)(pos); | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  |     frac = pos - (float)hidx; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     for (i = rsize - 1, j = hidx, k = hidx + 1; i >= 0; i--, j += R, k += R) | 
					
						
							|  |  |  |         hs[i] = h[j] + frac * (h[k] - h[j]); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | int VARSAMP::execute(float _var) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     int outsamps = 0; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     uint64_t const* picvar; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     uint64_t N; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     var = _var; | 
					
						
							|  |  |  |     old_inv_cvar = inv_cvar; | 
					
						
							|  |  |  |     cvar = var * nom_ratio; | 
					
						
							|  |  |  |     inv_cvar = 1.0f / cvar; | 
					
						
							|  |  |  |     if (varmode) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         dicvar = (inv_cvar - old_inv_cvar) / (float)size; | 
					
						
							|  |  |  |         inv_cvar = old_inv_cvar; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     else            dicvar = 0.0; | 
					
						
							|  |  |  |     if (run) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         int idx_out; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         float I; | 
					
						
							|  |  |  |         float Q; | 
					
						
							|  |  |  |         for (int i = 0; i < size; i++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |             ring[2 * idx_in + 0] = in[2 * i + 0]; | 
					
						
							|  |  |  |             ring[2 * idx_in + 1] = in[2 * i + 1]; | 
					
						
							|  |  |  |             inv_cvar += dicvar; | 
					
						
							|  |  |  |             picvar = (uint64_t*)(&inv_cvar); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             N = *picvar & 0xffffffffffff0000; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |             inv_cvar = static_cast<float>(N); | 
					
						
							|  |  |  |             delta = 1.0f - inv_cvar; | 
					
						
							|  |  |  |             while (isamps < 1.0) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             { | 
					
						
							|  |  |  |                 I = 0.0; | 
					
						
							|  |  |  |                 Q = 0.0; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |                 hshift(); | 
					
						
							|  |  |  |                 h_offset += delta; | 
					
						
							|  |  |  |                 while (h_offset >= 1.0) h_offset -= 1.0f; | 
					
						
							|  |  |  |                 while (h_offset <  0.0) h_offset += 1.0f; | 
					
						
							|  |  |  |                 for (int j = 0; j < rsize; j++) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |                     if ((idx_out = idx_in + j) >= rsize) idx_out -= rsize; | 
					
						
							|  |  |  |                     I += hs[j] * ring[2 * idx_out + 0]; | 
					
						
							|  |  |  |                     Q += hs[j] * ring[2 * idx_out + 1]; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |                 out[2 * outsamps + 0] = I; | 
					
						
							|  |  |  |                 out[2 * outsamps + 1] = Q; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |                 outsamps++; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |                 isamps += inv_cvar; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |             isamps -= 1.0f; | 
					
						
							|  |  |  |             if (--idx_in < 0) idx_in = rsize - 1; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     else if (in != out) | 
					
						
							|  |  |  |         std::copy( in,  in + size * 2, out); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     return outsamps; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setBuffers(float* _in, float* _out) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     in = _in; | 
					
						
							|  |  |  |     out = _out; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setSize(int _size) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     size = _size; | 
					
						
							|  |  |  |     flush(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setInRate(int _rate) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     in_rate = _rate; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setOutRate(int _rate) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     out_rate = _rate; | 
					
						
							|  |  |  |     calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setFCLow(float _fc_low) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     if (_fc_low != fc_low) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         fc_low = _fc_low; | 
					
						
							|  |  |  |         calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void VARSAMP::setBandwidth(float _fc_low, float _fc_high) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     if (_fc_low != fc_low || _fc_high != fcin) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |         fc_low = _fc_low; | 
					
						
							|  |  |  |         fcin = _fc_high; | 
					
						
							|  |  |  |         calc(); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // exported calls
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  | void* VARSAMP::create_varsampV (int _in_rate, int _out_rate, int R) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     return (void *) new VARSAMP(1, 0, nullptr, nullptr, _in_rate, _out_rate, 0.0, -1.0, R, 1.0, 1.0, 1); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 03:50:48 +02:00
										 |  |  | void VARSAMP::xvarsampV (float* input, float* output, int numsamps, float var, int* outsamps, void* ptr) | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     auto *a = (VARSAMP*) ptr; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  |     a->in = input; | 
					
						
							|  |  |  |     a->out = output; | 
					
						
							|  |  |  |     a->size = numsamps; | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     *outsamps = a->execute(var); | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VARSAMP::destroy_varsampV (void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-10 06:40:35 +02:00
										 |  |  |     delete (VARSAMP*) ptr; | 
					
						
							| 
									
										
										
										
											2024-06-16 11:31:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace WDSP
 |