diff --git a/src/dialogs/confdialog.cxx b/src/dialogs/confdialog.cxx index c13acb30..e9984c59 100644 --- a/src/dialogs/confdialog.cxx +++ b/src/dialogs/confdialog.cxx @@ -86,6 +86,20 @@ static void cb_inpMyAntenna(Fl_Input2* o, void*) { progdefaults.changed = true; } +Fl_Group *grpNoise=(Fl_Group *)0; + +Fl_Check_Button *btnNoiseOn=(Fl_Check_Button *)0; + +static void cb_btnNoiseOn(Fl_Check_Button* o, void*) { + progdefaults.noise = o->value(); +} + +Fl_Counter *noiseDB=(Fl_Counter *)0; + +static void cb_noiseDB(Fl_Counter* o, void*) { + progdefaults.s2n = o->value(); +} + Fl_Group *tabUI=(Fl_Group *)0; Fl_Tabs *tabsUI=(Fl_Tabs *)0; @@ -2438,6 +2452,27 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 inpMyAntenna->when(FL_WHEN_RELEASE); inpMyAntenna->labelsize(FL_NORMAL_SIZE); } // Fl_Input2* inpMyAntenna + { grpNoise = new Fl_Group(5, 203, 490, 165, _("Test Signal - Do NOT use with transmitter")); + grpNoise->box(FL_ENGRAVED_FRAME); + grpNoise->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); + grpNoise->hide(); + { Fl_Check_Button* o = btnNoiseOn = new Fl_Check_Button(43, 241, 70, 15, _("Noise on")); + btnNoiseOn->down_box(FL_DOWN_BOX); + btnNoiseOn->callback((Fl_Callback*)cb_btnNoiseOn); + o->value(progdefaults.noise); + } // Fl_Check_Button* btnNoiseOn + { Fl_Counter* o = noiseDB = new Fl_Counter(40, 279, 89, 21, _("dB")); + noiseDB->type(1); + noiseDB->minimum(-18); + noiseDB->maximum(60); + noiseDB->step(1); + noiseDB->value(20); + noiseDB->callback((Fl_Callback*)cb_noiseDB); + noiseDB->align(FL_ALIGN_LEFT); + o->value(progdefaults.s2n); + } // Fl_Counter* noiseDB + grpNoise->end(); + } // Fl_Group* grpNoise tabOperator->end(); } // Fl_Group* tabOperator { tabUI = new Fl_Group(-3, 25, 508, 345, _("UI")); @@ -2757,6 +2792,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 tabsWaterfall->color(FL_LIGHT1); tabsWaterfall->selection_color(FL_LIGHT1); { Fl_Group* o = new Fl_Group(0, 50, 500, 320, _("Display")); + o->hide(); { Fl_Group* o = new Fl_Group(5, 60, 490, 162, _("Colors and cursors")); o->box(FL_ENGRAVED_FRAME); o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); @@ -2897,7 +2933,6 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 o->end(); } // Fl_Group* o { Fl_Group* o = new Fl_Group(0, 50, 500, 320, _("FFT Processing")); - o->hide(); { Fl_Group* o = new Fl_Group(5, 62, 490, 135); o->box(FL_ENGRAVED_FRAME); { Fl_Counter* o = cntLowFreqCutoff = new Fl_Counter(50, 72, 70, 20, _("Lower limit")); @@ -3879,6 +3914,7 @@ an merging")); { tabsRig = new Fl_Tabs(0, 25, 500, 345); tabsRig->selection_color(FL_LIGHT1); { Fl_Group* o = new Fl_Group(0, 50, 500, 320, _("Hardware PTT")); + o->hide(); { grpHWPTT = new Fl_Group(5, 100, 490, 265); grpHWPTT->box(FL_ENGRAVED_FRAME); { inpTTYdev = new Fl_Input_Choice(200, 209, 160, 22, _("Device:")); @@ -4057,7 +4093,6 @@ an merging")); o->end(); } // Fl_Group* o { tabHamlib = new Fl_Group(0, 50, 500, 320, _("Hamlib")); - tabHamlib->hide(); { chkUSEHAMLIB = new Fl_Check_Button(195, 60, 100, 20, _("Use Hamlib")); chkUSEHAMLIB->tooltip(_("Hamlib used for rig control")); chkUSEHAMLIB->down_box(FL_DOWN_BOX); @@ -4267,6 +4302,7 @@ an merging")); { tabsSoundCard = new Fl_Tabs(0, 25, 500, 345); tabsSoundCard->selection_color(FL_LIGHT1); { tabAudio = new Fl_Group(0, 50, 500, 320, _("Devices")); + tabAudio->hide(); { AudioOSS = new Fl_Group(5, 60, 490, 45); AudioOSS->box(FL_ENGRAVED_FRAME); { btnAudioIO[0] = new Fl_Round_Button(15, 70, 53, 25, _("OSS")); @@ -4412,7 +4448,6 @@ ll with your audio device.")); tabAudioOpt->end(); } // Fl_Group* tabAudioOpt { tabMixer = new Fl_Group(0, 50, 500, 320, _("Mixer")); - tabMixer->hide(); { Fl_Group* o = new Fl_Group(5, 60, 490, 145, _("OSS mixer")); o->box(FL_ENGRAVED_FRAME); o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); @@ -4580,6 +4615,7 @@ d frequency")); { tabsMisc = new Fl_Tabs(0, 25, 500, 345); tabsMisc->selection_color(FL_LIGHT1); { tabSweetSpot = new Fl_Group(0, 50, 500, 320, _("Sweet Spot")); + tabSweetSpot->hide(); { Fl_Group* o = new Fl_Group(5, 60, 490, 75); o->box(FL_ENGRAVED_FRAME); o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); @@ -4722,7 +4758,6 @@ d frequency")); tabCPUspeed->end(); } // Fl_Group* tabCPUspeed { tabFileExtraction = new Fl_Group(0, 50, 500, 320, _("Text Capture")); - tabFileExtraction->hide(); { Fl_Group* o = new Fl_Group(5, 60, 490, 119, _("Auto Extract files from rx stream")); o->box(FL_ENGRAVED_FRAME); o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); diff --git a/src/dialogs/confdialog.fl b/src/dialogs/confdialog.fl index 314ba5ea..ae9dfad6 100644 --- a/src/dialogs/confdialog.fl +++ b/src/dialogs/confdialog.fl @@ -89,7 +89,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 } { Fl_Group tabOperator { label Operator - callback {progdefaults.changed = true;} open selected + callback {progdefaults.changed = true;} open xywh {0 25 500 345} when 1 } { Fl_Group {} { @@ -149,6 +149,23 @@ progdefaults.changed = true;} code0 {inpMyAntenna->labelsize(FL_NORMAL_SIZE);} class Fl_Input2 } + Fl_Group grpNoise { + label {Test Signal - Do NOT use with transmitter} open selected + xywh {5 203 490 165} box ENGRAVED_FRAME align 21 hide + } { + Fl_Check_Button btnNoiseOn { + label {Noise on} + callback {progdefaults.noise = o->value();} + xywh {43 241 70 15} down_box DOWN_BOX + code0 {o->value(progdefaults.noise);} + } + Fl_Counter noiseDB { + label dB + callback {progdefaults.s2n = o->value();} + xywh {40 279 89 21} type Simple align 4 minimum -18 maximum 60 step 1 value 20 + code0 {o->value(progdefaults.s2n);} + } + } } Fl_Group tabUI { label UI open @@ -533,7 +550,7 @@ progdefaults.changed = true;} } { Fl_Group {} { label Display open - xywh {0 50 500 320} + xywh {0 50 500 320} hide } { Fl_Group {} { label {Colors and cursors} open @@ -717,7 +734,7 @@ progdefaults.changed = true;} } Fl_Group {} { label {FFT Processing} open - xywh {0 50 500 320} hide + xywh {0 50 500 320} } { Fl_Group {} {open xywh {5 62 490 135} box ENGRAVED_FRAME @@ -1643,7 +1660,7 @@ progdefaults.changed = true;} } { Fl_Group {} { label {Hardware PTT} open - xywh {0 50 500 320} + xywh {0 50 500 320} hide } { Fl_Group grpHWPTT {open xywh {5 100 490 265} box ENGRAVED_FRAME @@ -1922,7 +1939,7 @@ rigCAT_restore_defaults();} } Fl_Group tabHamlib { label Hamlib open - xywh {0 50 500 320} hide + xywh {0 50 500 320} } { Fl_Check_Button chkUSEHAMLIB { label {Use Hamlib} @@ -2203,7 +2220,7 @@ progdefaults.changed = true;} } { Fl_Group tabAudio { label Devices open - xywh {0 50 500 320} + xywh {0 50 500 320} hide } { Fl_Group AudioOSS {open xywh {5 60 490 45} box ENGRAVED_FRAME @@ -2374,7 +2391,7 @@ progdefaults.changed = true;} } Fl_Group tabMixer { label Mixer open - xywh {0 50 500 320} hide + xywh {0 50 500 320} } { Fl_Group {} { label {OSS mixer} open @@ -2575,7 +2592,7 @@ progdefaults.changed = true;} } { Fl_Group tabSweetSpot { label {Sweet Spot} open - xywh {0 50 500 320} + xywh {0 50 500 320} hide } { Fl_Group {} {open xywh {5 60 490 75} box ENGRAVED_FRAME align 21 @@ -2730,7 +2747,7 @@ progdefaults.changed = true;} } Fl_Group tabFileExtraction { label {Text Capture} open - xywh {0 50 500 320} hide + xywh {0 50 500 320} } { Fl_Group {} { label {Auto Extract files from rx stream} open diff --git a/src/dialogs/fl_digi.cxx b/src/dialogs/fl_digi.cxx index b78c962b..27ac30ef 100644 --- a/src/dialogs/fl_digi.cxx +++ b/src/dialogs/fl_digi.cxx @@ -135,6 +135,7 @@ using namespace std; bool bWF_only = false; +bool withnoise = false; Fl_Double_Window *fl_digi_main = (Fl_Double_Window *)0; Fl_Help_Dialog *help_dialog = (Fl_Help_Dialog *)0; @@ -3500,6 +3501,8 @@ void create_fl_digi_main_primary() { wf->UI_select(progStatus.WF_UI); createConfig(); + if (withnoise) + grpNoise->show(); } void cb_mnuAltDockedscope(Fl_Menu_ *w, void *d); @@ -3964,6 +3967,8 @@ void create_fl_digi_main_WF_only() { wf->UI_select(true); createConfig(); + if (withnoise) + grpNoise->show(); altTabs(); } diff --git a/src/dominoex/dominoex.cxx b/src/dominoex/dominoex.cxx index 4eac5efd..95c20864 100644 --- a/src/dominoex/dominoex.cxx +++ b/src/dominoex/dominoex.cxx @@ -510,7 +510,7 @@ void dominoex::synchronize() void dominoex::eval_s2n() { double s = pipe[pipeptr].vector[currsymbol].mag(); - double n = pipe[(pipeptr + symlen) % twosym].vector[currsymbol].mag(); + double n = (NUMTONES - 1 ) * pipe[(pipeptr + symlen) % twosym].vector[currsymbol].mag(); sig = decayavg( sig, s, abs( s - sig) > 4 ? 4 : 32); noise = decayavg( noise, n, 64); @@ -525,7 +525,7 @@ void dominoex::eval_s2n() display_metric(metric); - snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", s2n > 0 ? s2n : 0); + snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", s2n ); put_Status1(dommsg); } diff --git a/src/include/confdialog.h b/src/include/confdialog.h index 8257aee4..aff9806f 100644 --- a/src/include/confdialog.h +++ b/src/include/confdialog.h @@ -20,10 +20,14 @@ extern Fl_Input2 *inpMyName; extern Fl_Input2 *inpMyQth; extern Fl_Input2 *inpMyLocator; extern Fl_Input2 *inpMyAntenna; +extern Fl_Group *grpNoise; +#include +extern Fl_Check_Button *btnNoiseOn; +#include +extern Fl_Counter *noiseDB; extern Fl_Group *tabUI; extern Fl_Tabs *tabsUI; extern Fl_Group *tabUserInterface; -#include extern Fl_Check_Button *btnShowTooltips; extern Fl_Check_Button *chkMenuIcons; #include @@ -90,7 +94,6 @@ extern Fl_Button *btnWaterfallFont; extern Fl_Check_Button *btnViewXmtSignal; #include extern Fl_Value_Slider *valTxMonitorLevel; -#include extern Fl_Counter *cntLowFreqCutoff; extern Fl_Counter *valLatency; extern Fl_Check_Button *btnWFaveraging; diff --git a/src/include/configuration.h b/src/include/configuration.h index df8a05bb..f998cba7 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -38,6 +38,12 @@ #endif #define CONFIG_LIST \ + ELEM_(bool, noise, "NOISETEST", \ + "Noise test on/off", \ + false) \ + ELEM_(double, s2n, "SIGNAL2NOISE", \ + "Signal to Noise ratio for test", \ + +20.0) \ ELEM_(bool, rsidWideSearch, "RSIDWIDESEARCH", \ "RSID detector searches the entire passband", \ false) \ diff --git a/src/include/fl_digi.h b/src/include/fl_digi.h index 90f2b00e..82e12526 100644 --- a/src/include/fl_digi.h +++ b/src/include/fl_digi.h @@ -120,6 +120,7 @@ extern Fl_Button *btnAltMacros; extern Fl_Button *btnMacroTimer; extern bool bWF_only; +extern bool withnoise; extern bool useCheckButtons; extern int altMacros; diff --git a/src/include/modem.h b/src/include/modem.h index 9097b544..c79810a1 100644 --- a/src/include/modem.h +++ b/src/include/modem.h @@ -170,6 +170,11 @@ public: void cwid_sendtext (const std::string& s); void cwid(); +// for noise tests +private: + void add_noise(double *, int); + double sigmaN (double es_ovr_n0); + double gauss(double sigma); }; extern modem *cw_modem; diff --git a/src/main.cxx b/src/main.cxx index fbf425b1..241d9df1 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -475,6 +475,9 @@ void generate_option_help(void) { << " --debug-level LEVEL\n" << " Set the event log verbosity\n\n" + << " --noise\n" + << " unhide controls for noise tests\n\n" + << " --version\n" << " Print version information\n\n" @@ -564,7 +567,7 @@ int parse_args(int argc, char **argv, int& idx) #if USE_PORTAUDIO OPT_FRAMES_PER_BUFFER, #endif - OPT_WO, OPT_DEBUG_LEVEL, + OPT_WO, OPT_NOISE, OPT_DEBUG_LEVEL, OPT_EXIT_AFTER, OPT_DEPRECATED, OPT_HELP, OPT_VERSION, OPT_BUILD_INFO }; @@ -614,6 +617,7 @@ int parse_args(int argc, char **argv, int& idx) { "exit-after", 1, 0, OPT_EXIT_AFTER }, { "wo", 0, 0, OPT_WO }, + { "noise", 0, 0, OPT_NOISE }, { "debug-level", 1, 0, OPT_DEBUG_LEVEL }, { "help", 0, 0, OPT_HELP }, @@ -625,6 +629,8 @@ int parse_args(int argc, char **argv, int& idx) int longindex; optind = idx; int c = getopt_long(argc, argv, shortopts, longopts, &longindex); + + withnoise = false; switch (c) { case -1: @@ -770,6 +776,11 @@ int parse_args(int argc, char **argv, int& idx) case OPT_WO: bWF_only = true; break; + + case OPT_NOISE: + withnoise = true; + break; + case OPT_DEBUG_LEVEL: { int v = strtol(optarg, 0, 10); diff --git a/src/mfsk/mfsk.cxx b/src/mfsk/mfsk.cxx index f5f06256..c24d1d3c 100644 --- a/src/mfsk/mfsk.cxx +++ b/src/mfsk/mfsk.cxx @@ -650,13 +650,10 @@ void mfsk::afc() void mfsk::eval_s2n() { sig = pipe[pipeptr].vector[currsymbol].mag(); - noise = 0.0; - for (int i = 0; i < numtones; i++) { - if (i != currsymbol) - noise += pipe[pipeptr].vector[i].mag(); - } + noise = (numtones -1) * pipe[pipeptr].vector[prev2symbol].mag(); if (noise > 0) s2n = decayavg ( s2n, sig / noise, 64 ); + } int mfsk::rx_process(const double *buf, int len) diff --git a/src/olivia/olivia.cxx b/src/olivia/olivia.cxx index d65fd80c..d672aa17 100755 --- a/src/olivia/olivia.cxx +++ b/src/olivia/olivia.cxx @@ -233,9 +233,9 @@ int olivia::rx_process(const double *buf, int len) { int c; unsigned char ch = 0; - double snr; +// double snr; static char msg1[20]; - static char msg2[20]; +// static char msg2[20]; if (tones != progdefaults.oliviatones || bw != progdefaults.oliviabw || @@ -261,31 +261,38 @@ int olivia::rx_process(const double *buf, int len) Rx->Process(buf, len); - bool gotchar = false; +// bool gotchar = false; while (Rx->GetChar(ch) > 0) { if ((c = unescape(ch)) != -1 && c > 7) { put_rx_char(c); - gotchar = true; +// gotchar = true; } + metric = clamp( 4 * Rx->SignalToNoiseRatio(), 0, 100); + display_metric(metric); + snprintf(msg1, sizeof(msg1), "f/o %+4.1f Hz", Rx->FrequencyOffset()); + put_Status1(msg1, 5, STATUS_CLEAR); } - if (gotchar) { - double noisepwr1 = wf->powerDensity((1.0 * frequency - Rx->Bandwidth / 2.0 - 100.0), 50.0), - noisepwr2 = wf->powerDensity((1.0 * frequency + Rx->Bandwidth / 2.0 + 100.0), 50.0), - noisepwr = 0, - sigpwr = wf->powerDensity(1.0 * frequency, 1.0 * Rx->Bandwidth); - noisepwr = noisepwr1 < noisepwr ? noisepwr1 : noisepwr2; - if (noisepwr == 0) noisepwr = 1.0e-10; - metric = decayavg( metric, sigpwr / noisepwr, 8); - - snprintf(msg1, sizeof(msg1), "s/n %4.1f dB", 10.0 * log10(metric)); - put_Status1(msg1, 5, STATUS_CLEAR); +// if (gotchar) { +// float noisepwr1 = wf->powerDensity((1.0 * frequency - Rx->Bandwidth / 2.0 - 100.0), 1.0*bw/tones), +// noisepwr2 = wf->powerDensity((1.0 * frequency + Rx->Bandwidth / 2.0 + 100.0), 1.0*bw/tones), +// noisepwr = 0, +// sigpwr = wf->powerDensity(1.0 * frequency, 1.0 * Rx->Bandwidth) / tones; - snprintf(msg2, sizeof(msg2), "f/o %+4.1f Hz", Rx->FrequencyOffset()); - put_Status2(msg2, 5, STATUS_CLEAR); +// noisepwr = noisepwr1 < noisepwr2 ? noisepwr1 : noisepwr2; +// if (noisepwr <= 0) noisepwr = 1e-9; +// if (noisepwr > 0) +// metric = decayavg( metric, sigpwr / noisepwr, 16); - snr = 3 * Rx->SignalToNoiseRatio(); - display_metric(snr > 100.0 ? 100.0 : snr ); - } +// snprintf(msg1, sizeof(msg1), "s/n %4.1f dB", 10.0 * log10(metric)); +// put_Status1(msg1, 5, STATUS_CLEAR); + +// snprintf(msg2, sizeof(msg2), "f/o %+4.1f Hz", Rx->FrequencyOffset()); +// put_Status2(msg2, 5, STATUS_CLEAR); + +// snr = 4 * Rx->SignalToNoiseRatio(); +// display_metric(snr > 100.0 ? 100.0 : snr ); +// display_metric(clamp(4*Rx->SignalToNoiseRatio(), 0, 100); +// } return 0; } diff --git a/src/thor/thor.cxx b/src/thor/thor.cxx index c146b1e1..7ad2d9c4 100644 --- a/src/thor/thor.cxx +++ b/src/thor/thor.cxx @@ -473,13 +473,13 @@ void thor::synchronize() void thor::eval_s2n() { double s = pipe[pipeptr].vector[currsymbol].mag(); - double n = pipe[(pipeptr + symlen) % twosym].vector[currsymbol].mag(); + double n = (THORNUMTONES - 1) * pipe[(pipeptr + symlen) % twosym].vector[currsymbol].mag(); sig = decayavg( sig, s, s - sig > 0 ? 4 : 20); noise = decayavg( noise, n, 64); if (noise) - s2n = 20*log10(sig / noise) - 6; + s2n = 20*log10(sig / noise); else s2n = 0; @@ -488,7 +488,7 @@ void thor::eval_s2n() display_metric(metric); - snprintf(thormsg, sizeof(thormsg), "s/n %3.0f dB", s2n > 0 ? s2n : 0); + snprintf(thormsg, sizeof(thormsg), "s/n %3.0f dB", s2n ); put_Status1(thormsg); } diff --git a/src/trx/modem.cxx b/src/trx/modem.cxx index 16180a31..be6bcbce 100644 --- a/src/trx/modem.cxx +++ b/src/trx/modem.cxx @@ -254,6 +254,84 @@ double modem::PTTnco() mbuffer _mdm_scdbl; +double modem::sigmaN (double es_ovr_n0) +{ + double sn_ratio, sigma; + double mode_factor = 0.707; + switch (mode) { + case MODE_CW: + mode_factor /= 0.44; + break; + case MODE_FELDHELL: case MODE_SLOWHELL: + case MODE_HELLX5: case MODE_HELLX9: + mode_factor /= 0.22; + break; + case MODE_MT63_500: case MODE_MT63_1000: case MODE_MT63_2000 : + mode_factor *= 3.0; + break; + case MODE_BPSK31: case MODE_PSK63: case MODE_PSK125: case MODE_PSK250: case MODE_PSK500: + mode_factor *= 16; + break; + case MODE_QPSK31: case MODE_QPSK63: case MODE_QPSK125: case MODE_QPSK250: + mode_factor *= 16; + break; + case MODE_THROB1: case MODE_THROB2: case MODE_THROB4: + case MODE_THROBX1: case MODE_THROBX2: case MODE_THROBX4: + mode_factor *= 6.0; + break; +// case MODE_RTTY: +// case MODE_OLIVIA: +// case MODE_DOMINOEX4: case MODE_DOMINOEX5: case MODE_DOMINOEX8: +// case MODE_DOMINOEX11: case MODE_DOMINOEX16: case MODE_DOMINOEX22: +// case MODE_MFSK4: case MODE_MFSK11: case MODE_MFSK22: case MODE_MFSK31: +// case MODE_MFSK64: case MODE_MFSK8: case MODE_MFSK16: case MODE_MFSK32: +// case MODE_THOR4: case MODE_THOR5: case MODE_THOR8: +// case MODE_THOR11:case MODE_THOR16: case MODE_THOR22: +// case MODE_FSKHELL: case MODE_FSKH105: case MODE_HELL80: + default: break; + } + if (trx_state == STATE_TUNE) mode_factor = 0.707; + + sn_ratio = pow(10, ( es_ovr_n0 / 10) ); + sigma = sqrt ( mode_factor / sn_ratio ); + return sigma; +} + +// A Rayleigh-distributed random variable R, with the probability +// distribution +// F(R) = 0 where R < 0 and +// F(R) = 1 - exp(-R^2/2*sigma^2) where R >= 0, +// is related to a pair of Gaussian variables C and D +// through the transformation +// C = R * cos(theta) and +// D = R * sin(theta), +// where theta is a uniformly distributed variable in the interval +// 0 to 2 * Pi. + +double modem::gauss(double sigma) { + double u, r; + u = 1.0 * rand() / RAND_MAX; + r = sigma * sqrt( 2.0 * log( 1.0 / (1.0 - u) ) ); + u = 1.0 * rand() / RAND_MAX; + return r * cos(2 * M_PI * u); +} + +// given the desired Es/No, calculate the standard deviation of the +// additive white gaussian noise (AWGN). The standard deviation of +// the AWGN will be used to generate Gaussian random variables +// simulating the noise that is added to the signal. +// return signal + noise, limiting value to +/- 1.0 + +void modem::add_noise(double *buffer, int len) +{ + double sigma = sigmaN(progdefaults.s2n); + double sn = 0; + for (int n = 0; n < len; n++) { + sn = (buffer[n] + gauss(sigma)) / (1.0 + 3.0 * sigma); + buffer[n] = clamp(sn, -1.0, 1.0); + } +} + void modem::ModulateXmtr(double *buffer, int len) { if (progdefaults.PTTrightchannel) { @@ -262,6 +340,7 @@ void modem::ModulateXmtr(double *buffer, int len) ModulateStereo( buffer, PTTchannel, len); return; } + if (withnoise && progdefaults.noise) add_noise(buffer, len); try { unsigned n = 4; while (scard->Write(buffer, len) == 0 && --n); @@ -290,6 +369,7 @@ void modem::ModulateXmtr(double *buffer, int len) using namespace std; void modem::ModulateStereo(double *left, double *right, int len) { + if (withnoise && progdefaults.noise) add_noise(left, len); try { unsigned n = 4; while (scard->Write_stereo(left, right, len) == 0 && --n); @@ -312,8 +392,6 @@ void modem::ModulateStereo(double *left, double *right, int len) _mdm_scdbl.next(); // change buffers } } -// for (int i = 0; i < len; i++) -// std::cout << (left[i] + 1.0) << "," << (right[i] - 1.0) << std::endl; }