mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-29 20:10:22 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*  anf.c
 | |
| 
 | |
| This file is part of a program that implements a Software-Defined Radio.
 | |
| 
 | |
| Copyright (C) 2012, 2013 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 "amd.hpp"
 | |
| #include "snb.hpp"
 | |
| #include "emnr.hpp"
 | |
| #include "anr.hpp"
 | |
| #include "anf.hpp"
 | |
| #include "bandpass.hpp"
 | |
| #include "RXA.hpp"
 | |
| 
 | |
| namespace WDSP {
 | |
| 
 | |
| ANF* ANF::create_anf(
 | |
|     int run,
 | |
|     int position,
 | |
|     int buff_size,
 | |
|     double *in_buff,
 | |
|     double *out_buff,
 | |
|     int dline_size,
 | |
|     int n_taps,
 | |
|     int delay,
 | |
|     double two_mu,
 | |
|     double gamma,
 | |
|     double lidx,
 | |
|     double lidx_min,
 | |
|     double lidx_max,
 | |
|     double ngamma,
 | |
|     double den_mult,
 | |
|     double lincr,
 | |
|     double ldecr
 | |
| )
 | |
| {
 | |
|     ANF *a = new ANF;
 | |
|     a->run = run;
 | |
|     a->position = position;
 | |
|     a->buff_size = buff_size;
 | |
|     a->in_buff = in_buff;
 | |
|     a->out_buff = out_buff;
 | |
|     a->dline_size = dline_size;
 | |
|     a->mask = dline_size - 1;
 | |
|     a->n_taps = n_taps;
 | |
|     a->delay = delay;
 | |
|     a->two_mu = two_mu;
 | |
|     a->gamma = gamma;
 | |
|     a->in_idx = 0;
 | |
|     a->lidx = lidx;
 | |
|     a->lidx_min = lidx_min;
 | |
|     a->lidx_max = lidx_max;
 | |
|     a->ngamma = ngamma;
 | |
|     a->den_mult = den_mult;
 | |
|     a->lincr = lincr;
 | |
|     a->ldecr = ldecr;
 | |
| 
 | |
|     memset (a->d, 0, sizeof(double) * ANF_DLINE_SIZE);
 | |
|     memset (a->w, 0, sizeof(double) * ANF_DLINE_SIZE);
 | |
| 
 | |
|     return a;
 | |
| }
 | |
| 
 | |
| void ANF::destroy_anf (ANF *a)
 | |
| {
 | |
|     delete a;
 | |
| }
 | |
| 
 | |
| void ANF::xanf(ANF *a, int position)
 | |
| {
 | |
|     int i, j, idx;
 | |
|     double c0, c1;
 | |
|     double y, error, sigma, inv_sigp;
 | |
|     double nel, nev;
 | |
|     if (a->run && (a->position == position))
 | |
|     {
 | |
|         for (i = 0; i < a->buff_size; i++)
 | |
|         {
 | |
|             a->d[a->in_idx] = a->in_buff[2 * i + 0];
 | |
| 
 | |
|             y = 0;
 | |
|             sigma = 0;
 | |
| 
 | |
|             for (j = 0; j < a->n_taps; j++)
 | |
|             {
 | |
|                 idx = (a->in_idx + j + a->delay) & a->mask;
 | |
|                 y += a->w[j] * a->d[idx];
 | |
|                 sigma += a->d[idx] * a->d[idx];
 | |
|             }
 | |
|             inv_sigp = 1.0 / (sigma + 1e-10);
 | |
|             error = a->d[a->in_idx] - y;
 | |
| 
 | |
|             a->out_buff[2 * i + 0] = error;
 | |
|             a->out_buff[2 * i + 1] = 0.0;
 | |
| 
 | |
|             if((nel = error * (1.0 - a->two_mu * sigma * inv_sigp)) < 0.0) nel = -nel;
 | |
|             if((nev = a->d[a->in_idx] - (1.0 - a->two_mu * a->ngamma) * y - a->two_mu * error * sigma * inv_sigp) < 0.0) nev = -nev;
 | |
|             if (nev < nel)
 | |
|             {
 | |
|                 if ((a->lidx += a->lincr) > a->lidx_max) a->lidx = a->lidx_max;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if ((a->lidx -= a->ldecr) < a->lidx_min) a->lidx = a->lidx_min;
 | |
|             }
 | |
|             a->ngamma = a->gamma * (a->lidx * a->lidx) * (a->lidx * a->lidx) * a->den_mult;
 | |
| 
 | |
|             c0 = 1.0 - a->two_mu * a->ngamma;
 | |
|             c1 = a->two_mu * error * inv_sigp;
 | |
| 
 | |
|             for (j = 0; j < a->n_taps; j++)
 | |
|             {
 | |
|                 idx = (a->in_idx + j + a->delay) & a->mask;
 | |
|                 a->w[j] = c0 * a->w[j] + c1 * a->d[idx];
 | |
|             }
 | |
|             a->in_idx = (a->in_idx + a->mask) & a->mask;
 | |
|         }
 | |
|     }
 | |
|     else if (a->in_buff != a->out_buff)
 | |
|         memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof (dcomplex));
 | |
| }
 | |
| 
 | |
| void ANF::flush_anf (ANF *a)
 | |
| {
 | |
|     memset (a->d, 0, sizeof(double) * ANF_DLINE_SIZE);
 | |
|     memset (a->w, 0, sizeof(double) * ANF_DLINE_SIZE);
 | |
|     a->in_idx = 0;
 | |
| }
 | |
| 
 | |
| void ANF::setBuffers_anf (ANF *a, double* in, double* out)
 | |
| {
 | |
|     a->in_buff = in;
 | |
|     a->out_buff = out;
 | |
| }
 | |
| 
 | |
| void ANF::setSamplerate_anf (ANF *a, int)
 | |
| {
 | |
|     flush_anf (a);
 | |
| }
 | |
| 
 | |
| void ANF::setSize_anf (ANF *a, int size)
 | |
| {
 | |
|     a->buff_size = size;
 | |
|     flush_anf (a);
 | |
| }
 | |
| 
 | |
| /********************************************************************************************************
 | |
| *                                                                                                       *
 | |
| *                                           RXA Properties                                              *
 | |
| *                                                                                                       *
 | |
| ********************************************************************************************************/
 | |
| 
 | |
| void ANF::SetANFRun (RXA& rxa, int run)
 | |
| {
 | |
|     ANF *a = rxa.anf.p;
 | |
|     if (a->run != run)
 | |
|     {
 | |
|         RXA::bp1Check (rxa, rxa.amd.p->run, rxa.snba.p->run,
 | |
|             rxa.emnr.p->run, run, rxa.anr.p->run);
 | |
|         rxa.csDSP.lock();
 | |
|         a->run = run;
 | |
|         RXA::bp1Set (rxa);
 | |
|         flush_anf (a);
 | |
|         rxa.csDSP.unlock();
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void ANF::SetANFVals (RXA& rxa, int taps, int delay, double gain, double leakage)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->n_taps = taps;
 | |
|     rxa.anf.p->delay = delay;
 | |
|     rxa.anf.p->two_mu = gain;          //try two_mu = 1e-4
 | |
|     rxa.anf.p->gamma = leakage;        //try gamma = 0.10
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| void ANF::SetANFTaps (RXA& rxa, int taps)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->n_taps = taps;
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| void ANF::SetANFDelay (RXA& rxa, int delay)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->delay = delay;
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| void ANF::SetANFGain (RXA& rxa, double gain)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->two_mu = gain;
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| void ANF::SetANFLeakage (RXA& rxa, double leakage)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->gamma = leakage;
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| void ANF::SetANFPosition (RXA& rxa, int position)
 | |
| {
 | |
|     rxa.csDSP.lock();
 | |
|     rxa.anf.p->position = position;
 | |
|     rxa.bp1.p->position = position;
 | |
|     flush_anf (rxa.anf.p);
 | |
|     rxa.csDSP.unlock();
 | |
| }
 | |
| 
 | |
| } // namespace WDSP
 |