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

449 lines
10 KiB
C

/* nob.c
This file is part of a program that implements a Software-Defined Radio.
Copyright (C) 2013, 2014 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"
#define MAX_TAU (0.002) // maximum transition time, signal<->zero
#define MAX_ADVTIME (0.002) // maximum deadtime (zero output) in advance of detected noise
#define MAX_SAMPLERATE (1536000)
void initBlanker(ANB a)
{
int i;
a->trans_count = (int)(a->tau * a->samplerate);
if (a->trans_count < 2) a->trans_count = 2;
a->hang_count = (int)(a->hangtime * a->samplerate);
a->adv_count = (int)(a->advtime * a->samplerate);
a->count = 0;
a->in_idx = a->trans_count + a->adv_count;
a->out_idx = 0;
a->coef = PI / a->trans_count;
a->state = 0;
a->avg = 1.0;
a->power = 1.0;
a->backmult = exp(-1.0 / (a->samplerate * a->backtau));
a->ombackmult = 1.0 - a->backmult;
for (i = 0; i <= a->trans_count; i++)
a->wave[i] = 0.5 * cos(i * a->coef);
memset(a->dline, 0, a->dline_size * sizeof(complex));
}
PORT
ANB create_anb (
int run,
int buffsize,
double* in,
double* out,
double samplerate,
double tau,
double hangtime,
double advtime,
double backtau,
double threshold
)
{
ANB a;
a = (ANB) malloc0 (sizeof(anb));
a->run = run;
a->buffsize = buffsize;
a->in = in;
a->out = out;
a->samplerate = samplerate;
a->tau = tau;
a->hangtime = hangtime;
a->advtime = advtime;
a->backtau = backtau;
a->threshold = threshold;
a->wave = (double *) malloc0 (((int)(MAX_SAMPLERATE * MAX_TAU) + 1) * sizeof(double));
a->dline_size = (int)((MAX_TAU + MAX_ADVTIME) * MAX_SAMPLERATE) + 1;
a->dline = (double *) malloc0 (a->dline_size * sizeof(complex));
InitializeCriticalSectionAndSpinCount (&a->cs_update, 2500);
initBlanker(a);
a->legacy = (double *) malloc0 (2048 * sizeof (complex)); /////////////// legacy interface - remove
return a;
}
PORT
void destroy_anb (ANB a)
{
DeleteCriticalSection (&a->cs_update);
_aligned_free (a->legacy); /////////////// legacy interface - remove
_aligned_free (a->dline);
_aligned_free (a->wave);
_aligned_free (a);
}
PORT
void flush_anb (ANB a)
{
EnterCriticalSection (&a->cs_update);
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void xanb (ANB a)
{
double scale;
double mag;
int i;
if (a->run)
{
EnterCriticalSection (&a->cs_update);
for (i = 0; i < a->buffsize; i++)
{
mag = sqrt(a->in[2 * i + 0] * a->in[2 * i + 0] + a->in[2 * i + 1] * a->in[2 * i + 1]);
a->avg = a->backmult * a->avg + a->ombackmult * mag;
a->dline[2 * a->in_idx + 0] = a->in[2 * i + 0];
a->dline[2 * a->in_idx + 1] = a->in[2 * i + 1];
if (mag > (a->avg * a->threshold))
a->count = a->trans_count + a->adv_count;
switch (a->state)
{
case 0:
a->out[2 * i + 0] = a->dline[2 * a->out_idx + 0];
a->out[2 * i + 1] = a->dline[2 * a->out_idx + 1];
if (a->count > 0)
{
a->state = 1;
a->dtime = 0;
a->power = 1.0;
}
break;
case 1:
scale = a->power * (0.5 + a->wave[a->dtime]);
a->out[2 * i + 0] = a->dline[2 * a->out_idx + 0] * scale;
a->out[2 * i + 1] = a->dline[2 * a->out_idx + 1] * scale;
if (++a->dtime > a->trans_count)
{
a->state = 2;
a->atime = 0;
}
break;
case 2:
a->out[2 * i + 0] = 0.0;
a->out[2 * i + 1] = 0.0;
if (++a->atime > a->adv_count)
a->state = 3;
break;
case 3:
if (a->count > 0)
a->htime = -a->count;
a->out[2 * i + 0] = 0.0;
a->out[2 * i + 1] = 0.0;
if (++a->htime > a->hang_count)
{
a->state = 4;
a->itime = 0;
}
break;
case 4:
scale = 0.5 - a->wave[a->itime];
a->out[2 * i + 0] = a->dline[2 * a->out_idx + 0] * scale;
a->out[2 * i + 1] = a->dline[2 * a->out_idx + 1] * scale;
if (a->count > 0)
{
a->state = 1;
a->dtime = 0;
a->power = scale;
}
else if (++a->itime > a->trans_count)
a->state = 0;
break;
}
if (a->count > 0) a->count--;
if (++a->in_idx == a->dline_size) a->in_idx = 0;
if (++a->out_idx == a->dline_size) a->out_idx = 0;
}
LeaveCriticalSection (&a->cs_update);
}
else if (a->in != a->out)
memcpy (a->out, a->in, a->buffsize * sizeof (complex));
}
void setBuffers_anb (ANB a, double* in, double* out)
{
a->in = in;
a->out = out;
}
void setSamplerate_anb (ANB a, int rate)
{
a->samplerate = rate;
initBlanker (a);
}
void setSize_anb (ANB a, int size)
{
a->buffsize = size;
initBlanker (a);
}
/********************************************************************************************************
* *
* RXA PROPERTIES *
* *
********************************************************************************************************/
// The following is an example to follow for properties in the event that this function is used inside
// a channel.
// PORT
// void SetRXAANBRun (int channel, int run)
// {
// ANB a = rxa[channel].anb.p;
// EnterCriticalSection (&a->cs_update);
// a->run = run;
// LeaveCriticalSection (&a->cs_update);
// }
/********************************************************************************************************
* *
* POINTER-BASED PROPERTIES *
* *
********************************************************************************************************/
PORT
void pSetRCVRANBRun (ANB a, int run)
{
EnterCriticalSection (&a->cs_update);
a->run = run;
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBBuffsize (ANB a, int size)
{
EnterCriticalSection (&a->cs_update);
a->buffsize = size;
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBSamplerate (ANB a, int rate)
{
EnterCriticalSection (&a->cs_update);
a->samplerate = (double) rate;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBTau (ANB a, double tau)
{
EnterCriticalSection (&a->cs_update);
a->tau = tau;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBHangtime (ANB a, double time)
{
EnterCriticalSection (&a->cs_update);
a->hangtime = time;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBAdvtime (ANB a, double time)
{
EnterCriticalSection (&a->cs_update);
a->advtime = time;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBBacktau (ANB a, double tau)
{
EnterCriticalSection (&a->cs_update);
a->backtau = tau;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void pSetRCVRANBThreshold (ANB a, double thresh)
{
EnterCriticalSection (&a->cs_update);
a->threshold = thresh;
LeaveCriticalSection (&a->cs_update);
}
/********************************************************************************************************
* *
* CALLS FOR EXTERNAL USE *
* *
********************************************************************************************************/
#define MAX_EXT_ANBS (32) // maximum number of NOBs called from outside wdsp
__declspec (align (16)) ANB panb[MAX_EXT_ANBS]; // array of pointers for NOBs used EXTERNAL to wdsp
PORT
void create_anbEXT (
int id,
int run,
int buffsize,
double samplerate,
double tau,
double hangtime,
double advtime,
double backtau,
double threshold
)
{
panb[id] = create_anb (run, buffsize, 0, 0,samplerate, tau, hangtime, advtime, backtau, threshold);
}
PORT
void destroy_anbEXT (int id)
{
destroy_anb (panb[id]);
}
PORT
void flush_anbEXT (int id)
{
flush_anb (panb[id]);
}
PORT
void xanbEXT (int id, double* in, double* out)
{
ANB a = panb[id];
a->in = in;
a->out = out;
xanb (a);
}
PORT
void SetEXTANBRun (int id, int run)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->run = run;
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBBuffsize (int id, int size)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->buffsize = size;
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBSamplerate (int id, int rate)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->samplerate = (double) rate;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBTau (int id, double tau)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->tau = tau;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBHangtime (int id, double time)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->hangtime = time;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBAdvtime (int id, double time)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->advtime = time;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBBacktau (int id, double tau)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->backtau = tau;
initBlanker (a);
LeaveCriticalSection (&a->cs_update);
}
PORT
void SetEXTANBThreshold (int id, double thresh)
{
ANB a = panb[id];
EnterCriticalSection (&a->cs_update);
a->threshold = thresh;
LeaveCriticalSection (&a->cs_update);
}
/********************************************************************************************************
* *
* LEGACY INTERFACE *
* *
********************************************************************************************************/
PORT
void xanbEXTF (int id, float *I, float *Q)
{
int i;
ANB a = panb[id];
a->in = a->legacy;
a->out = a->legacy;
for (i = 0; i < a->buffsize; i++)
{
a->legacy[2 * i + 0] = (double)I[i];
a->legacy[2 * i + 1] = (double)Q[i];
}
xanb (a);
for (i = 0; i < a->buffsize; i++)
{
I[i] = (float)a->legacy[2 * i + 0];
Q[i] = (float)a->legacy[2 * i + 1];
}
}