/* 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]; } }