diff --git a/configure.ac b/configure.ac index c4e2da1b..b16c6f93 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_COPYRIGHT([Copyright (C) 2007 Stelios Bounanos, M0GLD (m0gld AT enotty DOT net)]) AC_PREREQ(2.61) -AC_INIT([fldigi], [2.09H], [w1hkj AT w1hkj DOT com]) +AC_INIT([fldigi], [2.09I], [w1hkj AT w1hkj DOT com]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wall foreign std-options 1.9.6]) AM_MAINTAINER_MODE diff --git a/src/dialogs/Viewer.cxx b/src/dialogs/Viewer.cxx index d481532b..95e8038f 100644 --- a/src/dialogs/Viewer.cxx +++ b/src/dialogs/Viewer.cxx @@ -1,3 +1,11 @@ +// special test version of Viewer.cxx +// +// To enable REGULAR EXPRESSION EVALUATION FOR THE FIND STRING +// uncomment the following line + +#define REGEX + + #include #include "Viewer.h" @@ -17,6 +25,10 @@ string bwsrfreq; string bwsrline[MAXCHANNELS]; +#ifndef REGEX +string ucaseline[MAXCHANNELS]; +string tofind; +#endif static int brwsFreq[MAXCHANNELS]; static int freq; @@ -73,6 +85,7 @@ string fline; return fline; } +#ifdef REGEX regex_t* seek_re = 0; void re_comp(const char* needle) { @@ -111,6 +124,8 @@ char* strcasestr(const char* haystack, const char* needle) } #endif // !HAVE_STRCASESTR +#endif // REGEX + void pskBrowser::resize(int x, int y, int w, int h) { unsigned int nuchars = (w - cols[0] - (sbarwidth + border)) / cwidth; string bline; @@ -121,11 +136,20 @@ void pskBrowser::resize(int x, int y, int w, int h) { if (len > nuchars) bwsrline[i] = bwsrline[i].substr(len - nuchars); bline = freqformat(i); +#ifndef REGEX + if (!tofind.empty()) + if (ucaseline[i].find(tofind) != string::npos) + bline.append(dkred); + else if (!progdefaults.myCall.empty()) + if (ucaseline[i].find(progdefaults.myCall) != string::npos) + bline.append(dkgreen); +#else if (re_find(bwsrline[i].c_str())) bline.append(dkred); else if (!progdefaults.myCall.empty() && strcasestr(bwsrline[i].c_str(), progdefaults.myCall.c_str())) bline.append(dkgreen); +#endif bline.append("@.").append(bwsrline[i]); Fl_Hold_Browser::add(bline.c_str()); } @@ -223,6 +247,9 @@ void ClearViewer() { bline = freqformat(i); bwsrline[i].clear(); +#ifndef REGEX + ucaseline[i].clear(); +#endif brwsViewer->add(bline.c_str()); } if (progdefaults.VIEWERshowfreq) @@ -256,7 +283,13 @@ static void cb_brwsViewer(Fl_Hold_Browser*, void*) { static void cb_Seek(Fl_Input *, void *) { +#ifndef REGEX + tofind = inpSeek->value(); + for (size_t i = 0; i < tofind.length(); i++) + tofind[i] = toupper(tofind[i]); +#else re_comp(inpSeek->value()); +#endif } static void cb_Squelch(Fl_Slider *, void *) @@ -360,22 +393,47 @@ void viewaddchr(int ch, int freq, char c) { int index = progdefaults.VIEWERchannels - 1 - ch; if (progdefaults.VIEWERmarquee) { - if (bwsrline[index].length() > progStatus.VIEWERnchars ) + if (bwsrline[index].length() > progStatus.VIEWERnchars ) { bwsrline[index].erase(0,1); - if (c >= ' ' && c <= '~') +#ifndef REGEX + ucaseline[index].erase(0,1); +#endif + } + if (c >= ' ' && c <= '~') { bwsrline[index] += c; - else +#ifndef REGEX + ucaseline[index] += toupper(c); +#endif + } else { bwsrline[index] += ' '; +#ifndef REGEX + ucaseline[index] += ' '; +#endif + } } else { - if (c >= ' ' && c <= '~') + if (c >= ' ' && c <= '~') { bwsrline[index] += c; - else +#ifndef REGEX + ucaseline[index] += toupper(c); +#endif + } else { bwsrline[index] += ' '; +#ifndef REGEX + ucaseline[index] += ' '; +#endif + } if (bwsrline[index].length() > progStatus.VIEWERnchars) bwsrline[index].clear(); } nuline = freqformat(index); - +#ifndef REGEX + if (!tofind.empty()) + if (ucaseline[index].find(tofind) != string::npos) + nuline.append(dkred); + else if (!progdefaults.myCall.empty()) + if (ucaseline[index].find(progdefaults.myCall) != string::npos) + nuline.append(dkgreen); +#else if (re_find(bwsrline[index].c_str())) { nuline.append(dkred); // if (chkBeep->value()) @@ -387,7 +445,7 @@ void viewaddchr(int ch, int freq, char c) { // if (chkBeep->value()) // fl_beep(); } - +#endif nuline.append("@.").append(bwsrline[index]); brwsViewer->text(1 + index, nuline.c_str()); brwsViewer->redraw(); @@ -398,6 +456,9 @@ void viewclearchannel(int ch) int index = progdefaults.VIEWERchannels - 1 - ch; string nuline = freqformat(index); bwsrline[index] = ""; +#ifndef REGEX + ucaseline[index] = ""; +#endif brwsViewer->text( 1 + index, nuline.c_str()); brwsViewer->redraw(); } diff --git a/src/include/viewpsk.h b/src/include/viewpsk.h index fb76aa65..61b985db 100644 --- a/src/include/viewpsk.h +++ b/src/include/viewpsk.h @@ -28,13 +28,14 @@ #include "complex.h" #include "trx.h" #include "filters.h" +#include "fldigi-config.h" //===================================================================== #define VPSKSAMPLERATE (8000) -#define VSNTHRESHOLD 2.0 +#define VSNTHRESHOLD 2.0 // 3 db s/n #define VAFCDECAY 8 #define MAXCHANNELS 30 -#define VSEARCHWIDTH 60 +#define VSEARCHWIDTH 50 #define VSIGSEARCH 5 #define VWAITCOUNT 4 //===================================================================== @@ -58,6 +59,11 @@ private: C_FIR_filter *fir1[MAXCHANNELS]; C_FIR_filter *fir2[MAXCHANNELS]; + + double sigpwr[4000]; + double sigavg; + double sigmin; + Cmovavg *power[MAXCHANNELS]; int bits[MAXCHANNELS]; double bitclk[MAXCHANNELS]; @@ -75,6 +81,8 @@ private: void findsignal(int); void afc(int); + void sigdensity(); + double sigpeak(int &f, int f1, int f2); public: viewpsk(trx_mode mode); diff --git a/src/include/waterfall.h b/src/include/waterfall.h index a9512ae0..55328bd8 100644 --- a/src/include/waterfall.h +++ b/src/include/waterfall.h @@ -30,6 +30,7 @@ #include "fft.h" #include "sound.h" #include "globals.h" +#include "fldigi-config.h" #include #include @@ -271,6 +272,7 @@ private: void drawgrayWF(); void drawspectrum(); void drawsignal(); + protected: public: @@ -280,6 +282,10 @@ public: int newcarrier; int oldcarrier; bool tmp_carrier; + double Pwr(int i) { + if ( i > 0 && i < IMAGE_WIDTH) return pwr[i]; + return 0.0; + } }; class waterfall: public Fl_Group { @@ -354,7 +360,7 @@ public: qsy->deactivate(); wfdisp->useBands(!on); } - + double Pwr(int i) { return wfdisp->Pwr(i); } int handle(int event); /* diff --git a/src/psk/viewpsk.cxx b/src/psk/viewpsk.cxx index 1722cb27..d9e7e05e 100644 --- a/src/psk/viewpsk.cxx +++ b/src/psk/viewpsk.cxx @@ -53,7 +53,14 @@ viewpsk::viewpsk(trx_mode pskmode) for (int i = 0; i < MAXCHANNELS; i++) { fir1[i] = (C_FIR_filter *)0; fir2[i] = (C_FIR_filter *)0; + power[i] = (Cmovavg *)0; } + + for (int i = 0; i < 4000; i++) + sigpwr[i] = 0.0; + sigavg = 0.0; + sigmin = 1e6; + viewmode = MODE_PREV; restart(pskmode); } @@ -63,6 +70,7 @@ viewpsk::~viewpsk() for (int i = 0; i < MAXCHANNELS; i++) { if (fir1[i]) delete fir1[i]; if (fir2[i]) delete fir2[i]; + if (power[i]) delete power[i]; } } @@ -126,6 +134,9 @@ void viewpsk::restart(trx_mode pskmode) if (fir2[i]) delete fir2[i]; fir2[i] = new C_FIR_filter(); fir2[i]->init(FIRLEN, 1, fir2c, fir2c); + + if (power[i]) delete power[i]; + power[i] = new Cmovavg(8); } bandwidth = VPSKSAMPLERATE / symbollen; @@ -133,9 +144,58 @@ void viewpsk::restart(trx_mode pskmode) init(); } +int sigcnt = 0; +//============================================================================= +//========================== viewpsk signal evaluation ======================== +//============================================================================= +void viewpsk::sigdensity() { + sigcnt++; + double sig = 0.0; + double val; + int hbw = (int)(bandwidth / 2); + int twohbw = 2 * hbw; + int flower = progdefaults.VIEWERstart - 50; //nomfreq[0] - 50; + int fupper = flower + 100 * progdefaults.VIEWERchannels + 100; //nomfreq[MAXCHANNELS-1] + 50; + double *vals = new double[twohbw + 1]; + int j = -1; + sigavg = 0.0; +// sigmin = 1e6; + for (int i = flower - hbw; i < fupper + hbw; i++) { + j++; + if (j == twohbw + 1) j = 0; + val = wf->Pwr(i); + if (i >= flower + twohbw) { + sigpwr[i - hbw - 1] = sig; + sig -= vals[j]; + } + vals[j] = val; + sig += val; + sigavg += val; +// if (sig && sig < sigmin) sigmin = sig; + } + + sigavg /= (fupper - flower - 100); +//if (sigcnt == 32) +// for (int i = flower; i <= fupper; i++) +// std::cout << i << ", " << sigpwr[i] / sigavg << std::endl; + +} + +double viewpsk::sigpeak(int &f, int f1, int f2) +{ + double peak = 0; + f = (f1 + f2) / 2; + for (int i = f1; i <= f2; i++) + if (sigpwr[i] > peak) { + peak = sigpwr[i]; + f = i; + } + return peak / sigavg; +// return peak / sigmin; +} //============================================================================= -//=========================== viewpsk receive routines ========================== +//========================= viewpsk receive routines ========================== //============================================================================= void viewpsk::rx_bit(int ch, int bit) @@ -145,7 +205,8 @@ void viewpsk::rx_bit(int ch, int bit) if ((shreg[ch] & 3) == 0) { c = psk_varicode_decode(shreg[ch] >> 2); shreg[ch] = 0; - if (c != -1) { +// if (c != -1) { + if (c >= ' ' && c <= 'z') { REQ(&viewaddchr, ch, (int)frequency[ch], c); timeout[ch] = now + progdefaults.VIEWERtimeout; } @@ -154,23 +215,36 @@ void viewpsk::rx_bit(int ch, int bit) void viewpsk::findsignal(int ch) { - double ftest, sigpwr, noise; - if (sigsearch[ch] > 0) { - sigsearch[ch]--; - ftest = wf->peakFreq((int)(frequency[ch]), VSEARCHWIDTH + (int)(bandwidth / 2)); - sigpwr = wf->powerDensity(ftest, bandwidth); - noise = wf->powerDensity(ftest + 2 * bandwidth, bandwidth / 2) + - wf->powerDensity(ftest - 2 * bandwidth, bandwidth / 2) + 1e-20; - if (sigpwr/noise > VSNTHRESHOLD) { // larger than the search threshold - if (ftest - nomfreq[ch] > VSEARCHWIDTH) ftest = nomfreq[ch] + VSEARCHWIDTH; - if (ftest - nomfreq[ch] < -VSEARCHWIDTH) ftest = nomfreq[ch] - VSEARCHWIDTH; +// double ftest, sigpwr, noise; + if (waitcount[ch] > 0) { + waitcount[ch]--; + return; + } + +// ftest = wf->peakFreq((int)(frequency[ch]), VSEARCHWIDTH + (int)(bandwidth / 2)); +// sigpwr = wf->powerDensity(ftest, bandwidth); +// noise = wf->powerDensity(ftest + 2 * bandwidth, bandwidth / 2) + +// wf->powerDensity(ftest - 2 * bandwidth, bandwidth / 2) + 1e-20; + +// if (sigpwr/noise > VSNTHRESHOLD) { // larger than the search threshold +// if (ftest - nomfreq[ch] > VSEARCHWIDTH) ftest = nomfreq[ch] + VSEARCHWIDTH; +// if (ftest - nomfreq[ch] < -VSEARCHWIDTH) ftest = nomfreq[ch] - VSEARCHWIDTH; +// frequency[ch] = ftest; +// } else { // less than the detection threshold +// frequency[ch] = nomfreq[ch]; +// sigsearch[ch] = VSIGSEARCH; +// } + int ftest; + int f1 = (int)(nomfreq[ch] - VSEARCHWIDTH); + int f2 = (int)(nomfreq[ch] + VSEARCHWIDTH); + if (sigpeak(ftest, f1, f2) > VSNTHRESHOLD) { frequency[ch] = ftest; - } else { // less than the detection threshold - frequency[ch] = nomfreq[ch]; - sigsearch[ch] = VSIGSEARCH; + sigsearch[ch] = 0; } + else + frequency[ch] = nomfreq[ch]; freqerr[ch] = 0.0; - } +// } } void viewpsk::afc(int ch) @@ -225,12 +299,16 @@ void viewpsk::rx_symbol(int ch, complex symbol) default: if (metric[ch] > progdefaults.VIEWERsquelch) dcd[ch] = true; - else + else dcd[ch] = false; } if (dcd[ch] == true) rx_bit(ch, !bits[ch]); + else { + sigsearch[ch] = 1; + waitcount[ch] = VWAITCOUNT; + } } int viewpsk::rx_process(const double *buf, int len) @@ -244,6 +322,7 @@ int viewpsk::rx_process(const double *buf, int len) complex z[MAXCHANNELS]; now = time(NULL); + sigdensity(); while (len-- > 0) { // process all CHANNELS (25) @@ -286,28 +365,38 @@ int viewpsk::rx_process(const double *buf, int len) } for (int channel = 0; channel < progdefaults.VIEWERchannels; channel++) { if (timeout[channel] != -1 && timeout[channel] < now) { + frequency[channel] = nomfreq[channel]; REQ( &viewclearchannel, channel); timeout[channel] = -1; } +// if (sigpwr[(int)(frequency[channel])] / sigmin < VSNTHRESHOLD) + if (sigpwr[(int)(frequency[channel])] / sigavg < VSNTHRESHOLD) + sigsearch[channel] = 1; if (sigsearch[channel]) findsignal(channel); + +/* if (sigsearch[channel]) + findsignal(channel); else { if (waitcount[channel] > 0) { --waitcount[channel]; if (waitcount[channel] == 0) { - sigsearch[channel] = VSIGSEARCH; +// sigsearch[channel] = VSIGSEARCH; + sigsearch[channel] = 1; } } else { - double E1 = wf->powerDensity(frequency[channel], bandwidth); - double E2 = wf->powerDensity(frequency[channel] - 2 * bandwidth, bandwidth/2) + - wf->powerDensity(frequency[channel] + 2 * bandwidth, bandwidth/2); - if ( E1/ E2 <= VSNTHRESHOLD) { +// double E1 = wf->powerDensity(frequency[channel], bandwidth); +// double E2 = wf->powerDensity(frequency[channel] - 2 * bandwidth, bandwidth/2) + +// wf->powerDensity(frequency[channel] + 2 * bandwidth, bandwidth/2); +// if ( E1/ E2 <= VSNTHRESHOLD) { + if (sigpwr[(int)(frequency[channel])] / sigavg < VSNTHRESHOLD) { waitcount[channel] = VWAITCOUNT; sigsearch[channel] = 0; } } } +*/ } return 0; }