449 lines
10 KiB
C
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];
|
|
}
|
|
}
|