wdsp/anr.c
Uladzimir Karpenka 89c8a0e2b5 first commit
2026-06-01 15:58:45 +03:00

240 lines
5.8 KiB
C

/* anr.c
This file is part of a program that implements a Software-Defined Radio.
Copyright (C) 2012, 2013 Warren Pratt, NR0V
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.h"
ANR create_anr (
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
)
{
ANR a = (ANR) malloc0 (sizeof(anr));
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) * ANR_DLINE_SIZE);
memset (a->w, 0, sizeof(double) * ANR_DLINE_SIZE);
return a;
}
void destroy_anr (ANR a)
{
_aligned_free (a);
}
void xanr (ANR 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] = y;
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 (complex));
}
void flush_anr (ANR a)
{
memset (a->d, 0, sizeof(double) * ANR_DLINE_SIZE);
memset (a->w, 0, sizeof(double) * ANR_DLINE_SIZE);
a->in_idx = 0;
}
void setBuffers_anr (ANR a, double* in, double* out)
{
a->in_buff = in;
a->out_buff = out;
}
void setSamplerate_anr (ANR a, int rate)
{
flush_anr(a);
}
void setSize_anr (ANR a, int size)
{
a->buff_size = size;
flush_anr(a);
}
/********************************************************************************************************
* *
* RXA Properties *
* *
********************************************************************************************************/
PORT void
SetRXAANRRun (int channel, int run)
{
ANR a = rxa[channel].anr.p;
if (a->run != run)
{
RXAbp1Check (channel, rxa[channel].amd.p->run, rxa[channel].snba.p->run,
rxa[channel].emnr.p->run, rxa[channel].anf.p->run, run,
rxa[channel].rnnr.p->run, rxa[channel].sbnr.p->run); // NR3 + NR4 support
EnterCriticalSection (&ch[channel].csDSP);
a->run = run;
RXAbp1Set (channel);
flush_anr (a);
LeaveCriticalSection (&ch[channel].csDSP);
}
}
PORT void
SetRXAANRVals (int channel, int taps, int delay, double gain, double leakage)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->n_taps = taps;
rxa[channel].anr.p->delay = delay;
rxa[channel].anr.p->two_mu = gain;
rxa[channel].anr.p->gamma = leakage;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}
PORT void
SetRXAANRTaps (int channel, int taps)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->n_taps = taps;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}
PORT void
SetRXAANRDelay (int channel, int delay)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->delay = delay;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}
PORT void
SetRXAANRGain (int channel, double gain)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->two_mu = gain;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}
PORT void
SetRXAANRLeakage (int channel, double leakage)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->gamma = leakage;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}
PORT void
SetRXAANRPosition (int channel, int position)
{
EnterCriticalSection (&ch[channel].csDSP);
rxa[channel].anr.p->position = position;
rxa[channel].bp1.p->position = position;
flush_anr (rxa[channel].anr.p);
LeaveCriticalSection (&ch[channel].csDSP);
}