mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-11 02:46:12 -05:00
WDSP: added ANB and NOB blocks (noise blanker)
This commit is contained in:
parent
74cc488383
commit
02a73de41b
@ -5,6 +5,7 @@ set(wdsp_SOURCES
|
||||
amd.cpp
|
||||
ammod.cpp
|
||||
amsq.cpp
|
||||
anb.cpp
|
||||
anf.cpp
|
||||
anr.cpp
|
||||
bandpass.cpp
|
||||
@ -34,6 +35,7 @@ set(wdsp_SOURCES
|
||||
meter.cpp
|
||||
meterlog10.cpp
|
||||
nbp.cpp
|
||||
nob.cpp
|
||||
osctrl.cpp
|
||||
patchpanel.cpp
|
||||
resample.cpp
|
||||
@ -54,6 +56,7 @@ set(wdsp_HEADERS
|
||||
amd.hpp
|
||||
ammod.hpp
|
||||
amsq.hpp
|
||||
anb.hpp
|
||||
anf.hpp
|
||||
anr.hpp
|
||||
bandpass.hpp
|
||||
@ -85,6 +88,7 @@ set(wdsp_HEADERS
|
||||
meter.hpp
|
||||
meterlog10.hpp
|
||||
nbp.hpp
|
||||
nob.hpp
|
||||
osctrl.hpp
|
||||
patchpanel.hpp
|
||||
resample.hpp
|
||||
|
58
wdsp/RXA.cpp
58
wdsp/RXA.cpp
@ -52,6 +52,8 @@ warren@wpratt.com
|
||||
#include "iir.hpp"
|
||||
#include "firmin.hpp"
|
||||
#include "wcpAGC.hpp"
|
||||
#include "anb.hpp"
|
||||
#include "nob.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
@ -85,6 +87,36 @@ RXA* RXA::create_rxa (
|
||||
rxa->midbuff = new float[2 * rxa->dsp_size * 2]; // (float *) malloc0 (2 * ch.dsp_size * sizeof (complex));
|
||||
memset(rxa->meter, 0, sizeof(float)*RXA_METERTYPE_LAST);
|
||||
|
||||
// Noise blanker (ANB or "NB")
|
||||
rxa->anb.p = ANB::create_anb(
|
||||
0, // run
|
||||
rxa->dsp_insize, // input buffer size
|
||||
rxa->inbuff, // pointer to input buffer
|
||||
rxa->inbuff, // pointer to output buffer
|
||||
rxa->in_rate, // samplerate
|
||||
0.0001, // tau
|
||||
0.0001, // hang time
|
||||
0.0001, // advance time
|
||||
0.05, // back tau
|
||||
30.0 // thershold
|
||||
);
|
||||
// Noise blanker (NOB or "NB2")
|
||||
rxa->nob.p = NOB::create_nob(
|
||||
0, // run
|
||||
rxa->dsp_insize, // input buffer size
|
||||
rxa->inbuff, // pointer to input buffer
|
||||
rxa->inbuff, // pointer to output buffer
|
||||
rxa->in_rate, // samplerate
|
||||
0, // mode (zero)
|
||||
0.0001, // advance slew time
|
||||
0.0001, // advance time
|
||||
0.0001, // hang slew time
|
||||
0.0001, // hang time
|
||||
0.025, // max_imp_seq_time:
|
||||
0.05, // back tau
|
||||
30
|
||||
);
|
||||
|
||||
// Ftequency shifter - shift to select a slice of spectrum
|
||||
rxa->shift.p = SHIFT::create_shift (
|
||||
1, // run
|
||||
@ -571,6 +603,8 @@ void RXA::destroy_rxa (RXA *rxa)
|
||||
GEN::destroy_gen (rxa->gen0.p);
|
||||
RESAMPLE::destroy_resample (rxa->rsmpin.p);
|
||||
SHIFT::destroy_shift (rxa->shift.p);
|
||||
ANB::destroy_anb(rxa->anb.p);
|
||||
NOB::destroy_nob(rxa->nob.p);
|
||||
delete[] (rxa->midbuff);
|
||||
delete[] (rxa->outbuff);
|
||||
delete[] (rxa->inbuff);
|
||||
@ -609,10 +643,14 @@ void RXA::flush_rxa (RXA *rxa)
|
||||
SSQL::flush_ssql (rxa->ssql.p);
|
||||
PANEL::flush_panel (rxa->panel.p);
|
||||
RESAMPLE::flush_resample (rxa->rsmpout.p);
|
||||
ANB::flush_anb (rxa->anb.p);
|
||||
NOB::flush_nob(rxa->nob.p);
|
||||
}
|
||||
|
||||
void RXA::xrxa (RXA *rxa)
|
||||
{
|
||||
ANB::xanb (rxa->anb.p);
|
||||
NOB::xnob (rxa->nob.p);
|
||||
SHIFT::xshift (rxa->shift.p);
|
||||
RESAMPLE::xresample (rxa->rsmpin.p);
|
||||
GEN::xgen (rxa->gen0.p);
|
||||
@ -661,6 +699,14 @@ void RXA::setInputSamplerate (RXA *rxa, int in_rate)
|
||||
// buffers
|
||||
delete[] (rxa->inbuff);
|
||||
rxa->inbuff = new float[1 * rxa->dsp_insize * 2]; // (float *)malloc0(1 * ch.dsp_insize * sizeof(complex));
|
||||
// anb
|
||||
ANB::setBuffers_anb(rxa->anb.p, rxa->inbuff, rxa->inbuff);
|
||||
ANB::setSize_anb(rxa->anb.p, rxa->dsp_insize);
|
||||
ANB::setSamplerate_anb(rxa->anb.p, rxa->in_rate);
|
||||
// nob
|
||||
NOB::setBuffers_nob(rxa->nob.p, rxa->inbuff, rxa->inbuff);
|
||||
NOB::setSize_nob(rxa->nob.p, rxa->dsp_insize);
|
||||
NOB::setSamplerate_nob(rxa->nob.p, rxa->in_rate);
|
||||
// shift
|
||||
SHIFT::setBuffers_shift (rxa->shift.p, rxa->inbuff, rxa->inbuff);
|
||||
SHIFT::setSize_shift (rxa->shift.p, rxa->dsp_insize);
|
||||
@ -708,6 +754,12 @@ void RXA::setDSPSamplerate (RXA *rxa, int dsp_rate)
|
||||
rxa->inbuff = new float[1 * rxa->dsp_insize * 2]; // (float *)malloc0(1 * rxa->dsp_insize * sizeof(complex));
|
||||
delete[] (rxa->outbuff);
|
||||
rxa->outbuff = new float[1 * rxa->dsp_outsize * 2]; // (float *)malloc0(1 * rxa->dsp_outsize * sizeof(complex));
|
||||
// anb
|
||||
ANB::setBuffers_anb (rxa->anb.p, rxa->inbuff, rxa->inbuff);
|
||||
ANB::setSize_anb(rxa->anb.p, rxa->dsp_insize);
|
||||
// nob
|
||||
NOB::setBuffers_nob(rxa->nob.p, rxa->inbuff, rxa->inbuff);
|
||||
NOB::setSize_nob(rxa->nob.p, rxa->dsp_insize);
|
||||
// shift
|
||||
SHIFT::setBuffers_shift (rxa->shift.p, rxa->inbuff, rxa->inbuff);
|
||||
SHIFT::setSize_shift (rxa->shift.p, rxa->dsp_insize);
|
||||
@ -767,6 +819,12 @@ void RXA::setDSPBuffsize (RXA *rxa, int dsp_size)
|
||||
rxa->midbuff = new float[2 * rxa->dsp_size * 2]; // (float *)malloc0(2 * rxa->dsp_size * sizeof(complex));
|
||||
delete[] (rxa->outbuff);
|
||||
rxa->outbuff = new float[1 * rxa->dsp_outsize * 2]; // (float *)malloc0(1 * rxa->dsp_outsize * sizeof(complex));
|
||||
// anb
|
||||
ANB::setBuffers_anb (rxa->anb.p, rxa->inbuff, rxa->inbuff);
|
||||
ANB::setSize_anb (rxa->anb.p, rxa->dsp_insize);
|
||||
// nob
|
||||
NOB::setBuffers_nob(rxa->nob.p, rxa->inbuff, rxa->inbuff);
|
||||
NOB::setSize_nob(rxa->nob.p, rxa->dsp_insize);
|
||||
// shift
|
||||
SHIFT::setBuffers_shift (rxa->shift.p, rxa->inbuff, rxa->inbuff);
|
||||
SHIFT::setSize_shift (rxa->shift.p, rxa->dsp_insize);
|
||||
|
10
wdsp/RXA.hpp
10
wdsp/RXA.hpp
@ -63,6 +63,8 @@ class PANEL;
|
||||
class SIPHON;
|
||||
class CBL;
|
||||
class SSQL;
|
||||
class ANB;
|
||||
class NOB;
|
||||
class BufferProbe;
|
||||
|
||||
class WDSP_API RXA : public Unit
|
||||
@ -203,6 +205,14 @@ public:
|
||||
{
|
||||
SSQL *p;
|
||||
} ssql;
|
||||
struct
|
||||
{
|
||||
ANB *p;
|
||||
} anb;
|
||||
struct
|
||||
{
|
||||
NOB *p;
|
||||
} nob;
|
||||
|
||||
static RXA* create_rxa (
|
||||
int in_rate, // input samplerate
|
||||
|
282
wdsp/anb.cpp
Normal file
282
wdsp/anb.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/* anb.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2014 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 "anb.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
#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)
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void ANB::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(wcomplex));
|
||||
}
|
||||
|
||||
ANB* ANB::create_anb (
|
||||
int run,
|
||||
int buffsize,
|
||||
float* in,
|
||||
float* out,
|
||||
double samplerate,
|
||||
double tau,
|
||||
double hangtime,
|
||||
double advtime,
|
||||
double backtau,
|
||||
double threshold
|
||||
)
|
||||
{
|
||||
ANB *a;
|
||||
a = new 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 = new float[((int)(MAX_SAMPLERATE * MAX_TAU) + 1)];
|
||||
a->dline_size = (int)((MAX_TAU + MAX_ADVTIME) * MAX_SAMPLERATE) + 1;
|
||||
a->dline = new float[a->dline_size * 2];
|
||||
initBlanker(a);
|
||||
a->legacy = new float[2048 * 2]; /////////////// legacy interface - remove
|
||||
return a;
|
||||
}
|
||||
|
||||
void ANB::destroy_anb (ANB *a)
|
||||
{
|
||||
delete[] (a->legacy); /////////////// legacy interface - remove
|
||||
delete[] (a->dline);
|
||||
delete[] (a->wave);
|
||||
delete (a);
|
||||
}
|
||||
|
||||
void ANB::flush_anb (ANB *a)
|
||||
{
|
||||
a->cs_update.lock();
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::xanb (ANB *a)
|
||||
{
|
||||
double scale;
|
||||
double mag;
|
||||
int i;
|
||||
if (a->run)
|
||||
{
|
||||
a->cs_update.lock();
|
||||
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;
|
||||
}
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
else if (a->in != a->out)
|
||||
memcpy (a->out, a->in, a->buffsize * sizeof (wcomplex));
|
||||
}
|
||||
|
||||
void ANB::setBuffers_anb (ANB *a, float* in, float* out)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
}
|
||||
|
||||
void ANB::setSamplerate_anb (ANB *a, int rate)
|
||||
{
|
||||
a->samplerate = rate;
|
||||
initBlanker (a);
|
||||
}
|
||||
|
||||
void ANB::setSize_anb (ANB *a, int size)
|
||||
{
|
||||
a->buffsize = size;
|
||||
initBlanker (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA PROPERTIES *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void ANB::SetRXAANBRun (RXA& rxa, int run)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->run = run;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBBuffsize (RXA& rxa, int size)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->buffsize = size;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBSamplerate (RXA& rxa, int rate)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->samplerate = (double) rate;
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBTau (RXA& rxa, double tau)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->tau = tau;
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBHangtime (RXA& rxa, double time)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->hangtime = time;
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBAdvtime (RXA& rxa, double time)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->advtime = time;
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBBacktau (RXA& rxa, double tau)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->backtau = tau;
|
||||
initBlanker (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void ANB::SetRXAANBThreshold (RXA& rxa, double thresh)
|
||||
{
|
||||
ANB *a = rxa.anb.p;
|
||||
a->cs_update.lock();
|
||||
a->threshold = thresh;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
109
wdsp/anb.hpp
Normal file
109
wdsp/anb.hpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* anb.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2014 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef wdsp_anb_h
|
||||
#define wdsp_anb_h
|
||||
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class ANB
|
||||
{
|
||||
public:
|
||||
int run;
|
||||
int buffsize; // size of input/output buffer
|
||||
float* in; // input buffer
|
||||
float* out; // output buffer
|
||||
int dline_size; // length of delay line which is 'double dline[length][2]'
|
||||
float *dline; // pointer to delay line
|
||||
double samplerate; // samplerate, used to convert times into sample counts
|
||||
double tau; // transition time, signal<->zero
|
||||
double hangtime; // time to stay at zero after noise is no longer detected
|
||||
double advtime; // deadtime (zero output) in advance of detected noise
|
||||
double backtau; // time constant used in averaging the magnitude of the input signal
|
||||
double threshold; // triggers if (noise > threshold * average_signal_magnitude)
|
||||
float *wave; // pointer to array holding transition waveform
|
||||
int state; // state of the state machine
|
||||
double avg; // average value of the signal magnitude
|
||||
int dtime; // count when decreasing the signal magnitude
|
||||
int htime; // count when hanging
|
||||
int itime; // count when increasing the signal magnitude
|
||||
int atime; // count at zero before the noise burst (advance count)
|
||||
double coef; // parameter in calculating transition waveform
|
||||
int trans_count; // number of samples to equal 'tau' time
|
||||
int hang_count; // number of samples to equal 'hangtime' time
|
||||
int adv_count; // number of samples to equal 'advtime' time
|
||||
int in_idx; // ring buffer position into which new samples are inserted
|
||||
int out_idx; // ring buffer position from which delayed samples are pulled
|
||||
double power; // level at which signal was increasing when a new decrease is started
|
||||
int count; // set each time a noise sample is detected, counts down
|
||||
double backmult; // multiplier for waveform averaging
|
||||
double ombackmult; // multiplier for waveform averaging
|
||||
QRecursiveMutex cs_update;
|
||||
float *legacy;
|
||||
|
||||
static ANB* create_anb (
|
||||
int run,
|
||||
int buffsize,
|
||||
float* in,
|
||||
float* out,
|
||||
double samplerate,
|
||||
double tau,
|
||||
double hangtime,
|
||||
double advtime,
|
||||
double backtau,
|
||||
double threshold
|
||||
);
|
||||
|
||||
static void destroy_anb (ANB *a);
|
||||
static void flush_anb (ANB *a);
|
||||
static void xanb (ANB *a);
|
||||
static void setBuffers_anb (ANB *a, float* in, float* out);
|
||||
static void setSamplerate_anb (ANB *a, int rate);
|
||||
static void setSize_anb (ANB *a, int size);
|
||||
// RXA
|
||||
static void SetRXAANBRun (RXA& rxa, int run);
|
||||
static void SetRXAANBBuffsize (RXA& rxa, int size);
|
||||
static void SetRXAANBSamplerate (RXA& rxa, int rate);
|
||||
static void SetRXAANBTau (RXA& rxa, double tau);
|
||||
static void SetRXAANBHangtime (RXA& rxa, double time);
|
||||
static void SetRXAANBAdvtime (RXA& rxa, double time);
|
||||
static void SetRXAANBBacktau (RXA& rxa, double tau);
|
||||
static void SetRXAANBThreshold (RXA& rxa, double thresh);
|
||||
|
||||
private:
|
||||
static void initBlanker(ANB *a); //////////// legacy interface - remove
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
600
wdsp/nob.cpp
Normal file
600
wdsp/nob.cpp
Normal file
@ -0,0 +1,600 @@
|
||||
/* nobII.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2014 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"
|
||||
|
||||
#define MAX_ADV_SLEW_TIME (0.002)
|
||||
#define MAX_ADV_TIME (0.002)
|
||||
#define MAX_HANG_SLEW_TIME (0.002)
|
||||
#define MAX_HANG_TIME (0.002)
|
||||
#define MAX_SEQ_TIME (0.025)
|
||||
#define MAX_SAMPLERATE (1536000.0)
|
||||
|
||||
#include "nob.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void NOB::init_nob (NOB *a)
|
||||
{
|
||||
int i;
|
||||
double coef;
|
||||
a->adv_slew_count = (int)(a->advslewtime * a->samplerate);
|
||||
a->adv_count = (int)(a->advtime * a->samplerate);
|
||||
a->hang_count = (int)(a->hangtime * a->samplerate);
|
||||
a->hang_slew_count = (int)(a->hangslewtime * a->samplerate);
|
||||
a->max_imp_seq = (int)(a->max_imp_seq_time * a->samplerate);
|
||||
a->backmult = exp (-1.0 / (a->samplerate * a->backtau));
|
||||
a->ombackmult = 1.0 - a->backmult;
|
||||
if (a->adv_slew_count > 0)
|
||||
{
|
||||
coef = PI / (a->adv_slew_count + 1);
|
||||
for (i = 0; i < a->adv_slew_count; i++)
|
||||
a->awave[i] = 0.5 * cos ((i + 1) * coef);
|
||||
}
|
||||
if (a->hang_slew_count > 0)
|
||||
{
|
||||
coef = PI / a->hang_slew_count;
|
||||
for (i = 0; i < a->hang_slew_count; i++)
|
||||
a->hwave[i] = 0.5 * cos (i * coef);
|
||||
}
|
||||
|
||||
flush_nob (a);
|
||||
}
|
||||
|
||||
NOB* NOB::create_nob (
|
||||
int run,
|
||||
int buffsize,
|
||||
float* in,
|
||||
float* out,
|
||||
double samplerate,
|
||||
int mode,
|
||||
double advslewtime,
|
||||
double advtime,
|
||||
double hangslewtime,
|
||||
double hangtime,
|
||||
double max_imp_seq_time,
|
||||
double backtau,
|
||||
double threshold
|
||||
)
|
||||
{
|
||||
NOB *a = new NOB;
|
||||
a->run = run;
|
||||
a->buffsize = buffsize;
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
a->samplerate = samplerate;
|
||||
a->mode = mode;
|
||||
a->advslewtime = advslewtime;
|
||||
a->advtime = advtime;
|
||||
a->hangslewtime = hangslewtime;
|
||||
a->hangtime = hangtime;
|
||||
a->max_imp_seq_time = max_imp_seq_time;
|
||||
a->backtau = backtau;
|
||||
a->threshold = threshold;
|
||||
a->dline_size = (int)(MAX_SAMPLERATE * (MAX_ADV_SLEW_TIME +
|
||||
MAX_ADV_TIME +
|
||||
MAX_HANG_SLEW_TIME +
|
||||
MAX_HANG_TIME +
|
||||
MAX_SEQ_TIME ) + 2);
|
||||
a->dline = new double[a->dline_size * 2];
|
||||
a->imp = new int[a->dline_size];
|
||||
a->awave = new double[(int)(MAX_ADV_SLEW_TIME * MAX_SAMPLERATE + 1)];
|
||||
a->hwave = new double[(int)(MAX_HANG_SLEW_TIME * MAX_SAMPLERATE + 1)];
|
||||
|
||||
a->filterlen = 10;
|
||||
a->bfbuff = new double[a->filterlen * 2];
|
||||
a->ffbuff = new double[a->filterlen * 2];
|
||||
a->fcoefs = new double[a->filterlen];
|
||||
a->fcoefs[0] = 0.308720593;
|
||||
a->fcoefs[1] = 0.216104415;
|
||||
a->fcoefs[2] = 0.151273090;
|
||||
a->fcoefs[3] = 0.105891163;
|
||||
a->fcoefs[4] = 0.074123814;
|
||||
a->fcoefs[5] = 0.051886670;
|
||||
a->fcoefs[6] = 0.036320669;
|
||||
a->fcoefs[7] = 0.025424468;
|
||||
a->fcoefs[8] = 0.017797128;
|
||||
a->fcoefs[9] = 0.012457989;
|
||||
|
||||
init_nob (a);
|
||||
|
||||
a->legacy = new double[2048 * 2]; /////////////// legacy interface - remove
|
||||
return a;
|
||||
}
|
||||
|
||||
void NOB::destroy_nob (NOB *a)
|
||||
{
|
||||
delete[] (a->legacy); /////////////// remove
|
||||
delete[] (a->fcoefs);
|
||||
delete[] (a->ffbuff);
|
||||
delete[] (a->bfbuff);
|
||||
delete[] (a->hwave);
|
||||
delete[] (a->awave);
|
||||
delete[] (a->imp);
|
||||
delete[] (a->dline);
|
||||
delete (a);
|
||||
}
|
||||
|
||||
void NOB::flush_nob (NOB *a)
|
||||
{
|
||||
a->out_idx = 0;
|
||||
a->scan_idx = a->out_idx + a->adv_slew_count + a->adv_count + 1;
|
||||
a->in_idx = a->scan_idx + a->max_imp_seq + a->hang_count + a->hang_slew_count + a->filterlen;
|
||||
a->state = 0;
|
||||
a->overflow = 0;
|
||||
a->avg = 1.0;
|
||||
a->bfb_in_idx = a->filterlen - 1;
|
||||
a->ffb_in_idx = a->filterlen - 1;
|
||||
memset (a->dline, 0, a->dline_size * sizeof (wcomplex));
|
||||
memset (a->imp, 0, a->dline_size * sizeof (int));
|
||||
memset (a->bfbuff, 0, a->filterlen * sizeof (wcomplex));
|
||||
memset (a->ffbuff, 0, a->filterlen * sizeof (wcomplex));
|
||||
}
|
||||
|
||||
void NOB::xnob (NOB *a)
|
||||
{
|
||||
double scale;
|
||||
double mag;
|
||||
int bf_idx;
|
||||
int ff_idx;
|
||||
int lidx, tidx;
|
||||
int i, j, k;
|
||||
int bfboutidx;
|
||||
int ffboutidx;
|
||||
int hcount;
|
||||
int len;
|
||||
int ffcount;
|
||||
int staydown;
|
||||
a->cs_update.lock();
|
||||
if (a->run)
|
||||
{
|
||||
for (i = 0; i < a->buffsize; i++)
|
||||
{
|
||||
a->dline[2 * a->in_idx + 0] = a->in[2 * i + 0];
|
||||
a->dline[2 * a->in_idx + 1] = a->in[2 * i + 1];
|
||||
mag = sqrt(a->dline[2 * a->in_idx + 0] * a->dline[2 * a->in_idx + 0] + a->dline[2 * a->in_idx + 1] * a->dline[2 * a->in_idx + 1]);
|
||||
a->avg = a->backmult * a->avg + a->ombackmult * mag;
|
||||
if (mag > (a->avg * a->threshold))
|
||||
a->imp[a->in_idx] = 1;
|
||||
else
|
||||
a->imp[a->in_idx] = 0;
|
||||
if ((bf_idx = a->out_idx + a->adv_slew_count) >= a->dline_size) bf_idx -= a->dline_size;
|
||||
if (a->imp[bf_idx] == 0)
|
||||
{
|
||||
if (++a->bfb_in_idx == a->filterlen) a->bfb_in_idx -= a->filterlen;
|
||||
a->bfbuff[2 * a->bfb_in_idx + 0] = a->dline[2 * bf_idx + 0];
|
||||
a->bfbuff[2 * a->bfb_in_idx + 1] = a->dline[2 * bf_idx + 1];
|
||||
}
|
||||
|
||||
switch (a->state)
|
||||
{
|
||||
case 0: // normal output & impulse setup
|
||||
{
|
||||
a->out[2 * i + 0] = a->dline[2 * a->out_idx + 0];
|
||||
a->out[2 * i + 1] = a->dline[2 * a->out_idx + 1];
|
||||
a->Ilast = a->dline[2 * a->out_idx + 0];
|
||||
a->Qlast = a->dline[2 * a->out_idx + 1];
|
||||
if (a->imp[a->scan_idx] > 0)
|
||||
{
|
||||
a->time = 0;
|
||||
if (a->adv_slew_count > 0)
|
||||
a->state = 1;
|
||||
else if (a->adv_count > 0)
|
||||
a->state = 2;
|
||||
else
|
||||
a->state = 3;
|
||||
tidx = a->scan_idx;
|
||||
a->blank_count = 0;
|
||||
do
|
||||
{
|
||||
len = 0;
|
||||
hcount = 0;
|
||||
while ((a->imp[tidx] > 0 || hcount > 0) && a->blank_count < a->max_imp_seq)
|
||||
{
|
||||
a->blank_count++;
|
||||
if (hcount > 0) hcount--;
|
||||
if (a->imp[tidx] > 0) hcount = a->hang_count + a->hang_slew_count;
|
||||
if (++tidx >= a->dline_size) tidx -= a->dline_size;
|
||||
}
|
||||
j = 1;
|
||||
len = 0;
|
||||
lidx = tidx;
|
||||
while (j <= a->adv_slew_count + a->adv_count && len == 0)
|
||||
{
|
||||
if (a->imp[lidx] == 1)
|
||||
{
|
||||
len = j;
|
||||
tidx = lidx;
|
||||
}
|
||||
if (++lidx >= a->dline_size) lidx -= a->dline_size;
|
||||
j++;
|
||||
}
|
||||
if((a->blank_count += len) > a->max_imp_seq)
|
||||
{
|
||||
a->blank_count = a->max_imp_seq;
|
||||
a->overflow = 1;
|
||||
break;
|
||||
}
|
||||
} while (len != 0);
|
||||
if (a->overflow == 0)
|
||||
{
|
||||
a->blank_count -= a->hang_slew_count;
|
||||
a->Inext = a->dline[2 * tidx + 0];
|
||||
a->Qnext = a->dline[2 * tidx + 1];
|
||||
|
||||
if (a->mode == 1 || a->mode == 2 || a->mode == 4)
|
||||
{
|
||||
bfboutidx = a->bfb_in_idx;
|
||||
a->I1 = 0.0;
|
||||
a->Q1 = 0.0;
|
||||
for (k = 0; k < a->filterlen; k++)
|
||||
{
|
||||
a->I1 += a->fcoefs[k] * a->bfbuff[2 * bfboutidx + 0];
|
||||
a->Q1 += a->fcoefs[k] * a->bfbuff[2 * bfboutidx + 1];
|
||||
if (--bfboutidx < 0) bfboutidx += a->filterlen;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->mode == 2 || a->mode == 3 || a->mode == 4)
|
||||
{
|
||||
if ((ff_idx = a->scan_idx + a->blank_count) >= a->dline_size) ff_idx -= a->dline_size;
|
||||
ffcount = 0;
|
||||
while (ffcount < a->filterlen)
|
||||
{
|
||||
if (a->imp[ff_idx] == 0)
|
||||
{
|
||||
if (++a->ffb_in_idx == a->filterlen) a->ffb_in_idx -= a->filterlen;
|
||||
a->ffbuff[2 * a->ffb_in_idx + 0] = a->dline[2 * ff_idx + 0];
|
||||
a->ffbuff[2 * a->ffb_in_idx + 1] = a->dline[2 * ff_idx + 1];
|
||||
++ffcount;
|
||||
}
|
||||
if (++ff_idx >= a->dline_size) ff_idx -= a->dline_size;
|
||||
}
|
||||
if ((ffboutidx = a->ffb_in_idx + 1) >= a->filterlen) ffboutidx -= a->filterlen;
|
||||
a->I2 = 0.0;
|
||||
a->Q2 = 0.0;
|
||||
for (k = 0; k < a->filterlen; k++)
|
||||
{
|
||||
a->I2 += a->fcoefs[k] * a->ffbuff[2 * ffboutidx + 0];
|
||||
a->Q2 += a->fcoefs[k] * a->ffbuff[2 * ffboutidx + 1];
|
||||
if (++ffboutidx >= a->filterlen) ffboutidx -= a->filterlen;
|
||||
}
|
||||
}
|
||||
|
||||
switch (a->mode)
|
||||
{
|
||||
case 0: // zero
|
||||
a->deltaI = 0.0;
|
||||
a->deltaQ = 0.0;
|
||||
a->I = 0.0;
|
||||
a->Q = 0.0;
|
||||
break;
|
||||
case 1: // sample-hold
|
||||
a->deltaI = 0.0;
|
||||
a->deltaQ = 0.0;
|
||||
a->I = a->I1;
|
||||
a->Q = a->Q1;
|
||||
break;
|
||||
case 2: // mean-hold
|
||||
a->deltaI = 0.0;
|
||||
a->deltaQ = 0.0;
|
||||
a->I = 0.5 * (a->I1 + a->I2);
|
||||
a->Q = 0.5 * (a->Q1 + a->Q2);
|
||||
break;
|
||||
case 3: // hold-sample
|
||||
a->deltaI = 0.0;
|
||||
a->deltaQ = 0.0;
|
||||
a->I = a->I2;
|
||||
a->Q = a->Q2;
|
||||
break;
|
||||
case 4: // linear interpolation
|
||||
a->deltaI = (a->I2 - a->I1) / (a->adv_count + a->blank_count);
|
||||
a->deltaQ = (a->Q2 - a->Q1) / (a->adv_count + a->blank_count);
|
||||
a->I = a->I1;
|
||||
a->Q = a->Q1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a->adv_slew_count > 0)
|
||||
a->state = 5;
|
||||
else
|
||||
{
|
||||
a->state = 6;
|
||||
a->time = 0;
|
||||
a->blank_count += a->adv_count + a->filterlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // slew output in advance of blanking period
|
||||
{
|
||||
scale = 0.5 + a->awave[a->time];
|
||||
a->out[2 * i + 0] = a->Ilast * scale + (1.0 - scale) * a->I;
|
||||
a->out[2 * i + 1] = a->Qlast * scale + (1.0 - scale) * a->Q;
|
||||
if (++a->time == a->adv_slew_count)
|
||||
{
|
||||
a->time = 0;
|
||||
if (a->adv_count > 0)
|
||||
a->state = 2;
|
||||
else
|
||||
a->state = 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // initial advance period
|
||||
{
|
||||
a->out[2 * i + 0] = a->I;
|
||||
a->out[2 * i + 1] = a->Q;
|
||||
a->I += a->deltaI;
|
||||
a->Q += a->deltaQ;
|
||||
|
||||
if (++a->time == a->adv_count)
|
||||
{
|
||||
a->state = 3;
|
||||
a->time = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: // impulse & hang period
|
||||
{
|
||||
a->out[2 * i + 0] = a->I;
|
||||
a->out[2 * i + 1] = a->Q;
|
||||
a->I += a->deltaI;
|
||||
a->Q += a->deltaQ;
|
||||
|
||||
if (++a->time == a->blank_count)
|
||||
{
|
||||
if (a->hang_slew_count > 0)
|
||||
{
|
||||
a->state = 4;
|
||||
a->time = 0;
|
||||
}
|
||||
else
|
||||
a->state = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: // slew output after blanking period
|
||||
{
|
||||
scale = 0.5 - a->hwave[a->time];
|
||||
a->out[2 * i + 0] = a->Inext * scale + (1.0 - scale) * a->I;
|
||||
a->out[2 * i + 1] = a->Qnext * scale + (1.0 - scale) * a->Q;
|
||||
if (++a->time == a->hang_slew_count)
|
||||
a->state = 0;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
scale = 0.5 + a->awave[a->time];
|
||||
a->out[2 * i + 0] = a->Ilast * scale;
|
||||
a->out[2 * i + 1] = a->Qlast * scale;
|
||||
if (++a->time == a->adv_slew_count)
|
||||
{
|
||||
a->state = 6;
|
||||
a->time = 0;
|
||||
a->blank_count += a->adv_count + a->filterlen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
a->out[2 * i + 0] = 0.0;
|
||||
a->out[2 * i + 1] = 0.0;
|
||||
if (++a->time == a->blank_count)
|
||||
a->state = 7;
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
a->out[2 * i + 0] = 0.0;
|
||||
a->out[2 * i + 1] = 0.0;
|
||||
staydown = 0;
|
||||
a->time = 0;
|
||||
if ((tidx = a->scan_idx + a->hang_slew_count + a->hang_count) >= a->dline_size) tidx -= a->dline_size;
|
||||
while (a->time++ <= a->adv_count + a->adv_slew_count + a->hang_slew_count + a->hang_count) // CHECK EXACT COUNTS!!!!!!!!!!!!!!!!!!!!!!!
|
||||
{
|
||||
if (a->imp[tidx] == 1) staydown = 1;
|
||||
if (--tidx < 0) tidx += a->dline_size;
|
||||
}
|
||||
if (staydown == 0)
|
||||
{
|
||||
if (a->hang_count > 0)
|
||||
{
|
||||
a->state = 8;
|
||||
a->time = 0;
|
||||
}
|
||||
else if (a->hang_slew_count > 0)
|
||||
{
|
||||
a->state = 9;
|
||||
a->time = 0;
|
||||
if ((tidx = a->scan_idx + a->hang_slew_count + a->hang_count - a->adv_count - a->adv_slew_count) >= a->dline_size) tidx -= a->dline_size;
|
||||
if (tidx < 0) tidx += a->dline_size;
|
||||
a->Inext = a->dline[2 * tidx + 0];
|
||||
a->Qnext = a->dline[2 * tidx + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
a->state = 0;
|
||||
a->overflow = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
a->out[2 * i + 0] = 0.0;
|
||||
a->out[2 * i + 1] = 0.0;
|
||||
if (++a->time == a->hang_count)
|
||||
{
|
||||
if (a->hang_slew_count > 0)
|
||||
{
|
||||
a->state = 9;
|
||||
a->time = 0;
|
||||
if ((tidx = a->scan_idx + a->hang_slew_count - a->adv_count - a->adv_slew_count) >= a->dline_size) tidx -= a->dline_size;
|
||||
if (tidx < 0) tidx += a->dline_size;
|
||||
a->Inext = a->dline[2 * tidx + 0];
|
||||
a->Qnext = a->dline[2 * tidx + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
a->state = 0;
|
||||
a->overflow = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
scale = 0.5 - a->hwave[a->time];
|
||||
a->out[2 * i + 0] = a->Inext * scale;
|
||||
a->out[2 * i + 1] = a->Qnext * scale;
|
||||
|
||||
if (++a->time >= a->hang_slew_count)
|
||||
{
|
||||
a->state = 0;
|
||||
a->overflow = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (++a->in_idx == a->dline_size) a->in_idx = 0;
|
||||
if (++a->scan_idx == a->dline_size) a->scan_idx = 0;
|
||||
if (++a->out_idx == a->dline_size) a->out_idx = 0;
|
||||
}
|
||||
}
|
||||
else if (a->in != a->out)
|
||||
memcpy (a->out, a->in, a->buffsize * sizeof (wcomplex));
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::setBuffers_nob (NOB *a, float* in, float* out)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
}
|
||||
|
||||
void NOB::setSamplerate_nob (NOB *a, int rate)
|
||||
{
|
||||
a->samplerate = rate;
|
||||
init_nob (a);
|
||||
}
|
||||
|
||||
void NOB::setSize_nob (NOB *a, int size)
|
||||
{
|
||||
a->buffsize = size;
|
||||
flush_nob (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA PROPERTIES *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void NOB::SetRXANOBRun (RXA& rxa, int run)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->run = run;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBMode (RXA& rxa, int mode)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->mode = mode;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBBuffsize (RXA& rxa, int size)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->buffsize = size;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBSamplerate (RXA& rxa, int rate)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->samplerate = (double) rate;
|
||||
init_nob (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBTau (RXA& rxa, double tau)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->advslewtime = tau;
|
||||
a->hangslewtime = tau;
|
||||
init_nob (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBHangtime (RXA& rxa, double time)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->hangtime = time;
|
||||
init_nob (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBAdvtime (RXA& rxa, double time)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->advtime = time;
|
||||
init_nob (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBBacktau (RXA& rxa, double tau)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->backtau = tau;
|
||||
init_nob (a);
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
void NOB::SetRXANOBThreshold (RXA& rxa, double thresh)
|
||||
{
|
||||
NOB *a = rxa.nob.p;
|
||||
a->cs_update.lock();
|
||||
a->threshold = thresh;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
} // namespace
|
129
wdsp/nob.hpp
Normal file
129
wdsp/nob.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
/* nobII.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2014 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef wdsp_nob_h
|
||||
#define wdsp_nob_h
|
||||
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class NOB
|
||||
{
|
||||
public:
|
||||
int run;
|
||||
int buffsize; // size of input/output buffer
|
||||
float* in; // input buffer
|
||||
float* out; // output buffer
|
||||
int mode;
|
||||
int dline_size; // length of delay line which is 'double dline[length][2]'
|
||||
double *dline; // pointer to delay line
|
||||
int *imp;
|
||||
double samplerate; // samplerate, used to convert times into sample counts
|
||||
double advslewtime; // transition time, signal<->zero
|
||||
double advtime; // deadtime (zero output) in advance of detected noise
|
||||
double hangslewtime;
|
||||
double hangtime; // time to stay at zero after noise is no longer detected
|
||||
double max_imp_seq_time;
|
||||
int filterlen;
|
||||
double *fcoefs;
|
||||
double *bfbuff;
|
||||
int bfb_in_idx;
|
||||
double *ffbuff;
|
||||
int ffb_in_idx;
|
||||
double backtau; // time constant used in averaging the magnitude of the input signal
|
||||
double threshold; // triggers if (noise > threshold * average_signal_magnitude)
|
||||
double *awave; // pointer to array holding transition waveform
|
||||
double *hwave;
|
||||
int state; // state of the state machine
|
||||
double avg; // average value of the signal magnitude
|
||||
int time; // count when decreasing the signal magnitude
|
||||
int adv_slew_count;
|
||||
int adv_count; // number of samples to equal 'tau' time
|
||||
int hang_count; // number of samples to equal 'hangtime' time
|
||||
int hang_slew_count; // number of samples to equal 'advtime' time
|
||||
int max_imp_seq;
|
||||
int blank_count;
|
||||
int in_idx; // ring buffer position into which new samples are inserted
|
||||
int scan_idx;
|
||||
int out_idx; // ring buffer position from which delayed samples are pulled
|
||||
double backmult; // multiplier for waveform averaging
|
||||
double ombackmult; // multiplier for waveform averaging
|
||||
double I1, Q1;
|
||||
double I2, Q2;
|
||||
double I, Q;
|
||||
double Ilast, Qlast;
|
||||
double deltaI, deltaQ;
|
||||
double Inext, Qnext;
|
||||
int overflow;
|
||||
QRecursiveMutex cs_update;
|
||||
double *legacy;
|
||||
|
||||
//////////// legacy interface - remove
|
||||
static NOB* create_nob (
|
||||
int run,
|
||||
int buffsize,
|
||||
float* in,
|
||||
float* out,
|
||||
double samplerate,
|
||||
int mode,
|
||||
double advslewtime,
|
||||
double advtime,
|
||||
double hangslewtime,
|
||||
double hangtime,
|
||||
double max_imp_seq_time,
|
||||
double backtau,
|
||||
double threshold
|
||||
);
|
||||
|
||||
static void destroy_nob (NOB* a);
|
||||
static void flush_nob (NOB* a);
|
||||
static void xnob (NOB* a);
|
||||
static void setBuffers_nob (NOB *a, float* in, float* out);
|
||||
static void setSamplerate_nob (NOB *a, int rate);
|
||||
static void setSize_nob (NOB *a, int size);
|
||||
// RXA
|
||||
static void SetRXANOBRun (RXA& rxa, int run);
|
||||
static void SetRXANOBMode (RXA& rxa, int mode);
|
||||
static void SetRXANOBBuffsize (RXA& rxa, int size);
|
||||
static void SetRXANOBSamplerate (RXA& rxa, int size);
|
||||
static void SetRXANOBTau (RXA& rxa, double tau);
|
||||
static void SetRXANOBHangtime (RXA& rxa, double time);
|
||||
static void SetRXANOBAdvtime (RXA& rxa, double time);
|
||||
static void SetRXANOBBacktau (RXA& rxa, double tau);
|
||||
static void SetRXANOBThreshold (RXA& rxa, double thresh);
|
||||
|
||||
private:
|
||||
static void init_nob (NOB *a);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user