wired up squelch, added slow SNR option, works OK on Linux, need to test on Win32
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 23 Nov 2012 10:41:31 +0000 (10:41 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 23 Nov 2012 10:41:31 +0000 (10:41 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1048 01035d8c-6547-0410-b346-abe4f91aad63

fdmdv2/src/fdmdv2_defines.h
fdmdv2/src/fdmdv2_main.cpp
fdmdv2/src/fdmdv2_main.h
fdmdv2/src/fdmdv2_plot_spectrum.cpp
fdmdv2/src/fdmdv2_plot_spectrum.h
fdmdv2/src/fdmdv2_plot_waterfall_linux.cpp
fdmdv2/src/fdmdv2_plot_waterfall_linux.h
fdmdv2/src/topFrame.cpp
fdmdv2/src/topFrame.h

index b74966d0c0e6f7057ab7b6d01a729a994e8d5177..6224d78c43d0f80a6bf839e045d9749174980723 100644 (file)
 #define MIN_MAG_DB        -40.0     // min of spectrogram/waterfall magnitude axis
 #define MAX_MAG_DB          0.0     // max of spectrogram/waterfall magnitude axis
 #define STEP_MAG_DB         5.0     // magnitude axis step
-#define BETA                0.1     // constant for time averaging spectrum data
+#define BETA                0.9     // constant for time averaging spectrum data
 #define MIN_F_HZ            0       // min freq on Waterfall and Spectrum
 #define MAX_F_HZ            4000    // max freq on Waterfall and Spectrum
 #define STEP_F_HZ           500     // freq step on Waterfall and Spectrum graticule
 #define WATERFALL_SECS_Y    5       // number of seconds respresented by y axis of waterfall
+#define WATERFALL_SECS_STEP 5       // graticule y axis steps of waterfall
 #define DT                  0.1     // time between real time graphing updates
 #define FS                  8000    // FDMDV modem sample rate
 
@@ -70,6 +71,8 @@
 // Squelch
 #define SQ_DEFAULT_SNR      4.0
 
+#define SNRSLOW_BETA        0.5                           // time constant for slow SNR for display
+
 enum
 {
     ID_ROTATE_LEFT = wxID_HIGHEST + 1,
index db379e5946b6ade05c8a67440108567c89660ebd..6fe7e604f1a930060c9b22bda852dd0611714d5a 100644 (file)
@@ -47,6 +47,7 @@ float g_SquelchLevel;
 int   g_analog;
 int   g_split;
 int   g_tx;
+float g_snr;
 
 // tx/rx processing states
 int                 g_nRxIn = FDMDV_NOM_SAMPLES_PER_FRAME;
@@ -236,8 +237,8 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent)
         // Add Demod Input window
 
         m_panelDemodIn = new PlotScalar((wxFrame*) m_auiNbookCtrl, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
-       m_auiNbookCtrl->AddPage(m_panelDemodIn, _("Demod In"), true, wxNullBitmap);
-       g_plotDemodInFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
+        m_auiNbookCtrl->AddPage(m_panelDemodIn, _("Frm Radio"), true, wxNullBitmap);
+        g_plotDemodInFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
     }
 
     if(wxGetApp().m_show_speech_in)
@@ -245,8 +246,8 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent)
         // Add Speech Input window
 
         m_panelSpeechIn = new PlotScalar((wxFrame*) m_auiNbookCtrl, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
-       m_auiNbookCtrl->AddPage(m_panelSpeechIn, _("Speech In"), true, wxNullBitmap);
-       g_plotSpeechInFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
+        m_auiNbookCtrl->AddPage(m_panelSpeechIn, _("Frm Mic"), true, wxNullBitmap);
+        g_plotSpeechInFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
     }
 
     if(wxGetApp().m_show_speech_out)
@@ -254,7 +255,7 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent)
         // Add Speech Output window
 
         m_panelSpeechOut = new PlotScalar((wxFrame*) m_auiNbookCtrl, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
-       m_auiNbookCtrl->AddPage(m_panelSpeechOut, _("Speech Out"), true, wxNullBitmap);
+       m_auiNbookCtrl->AddPage(m_panelSpeechOut, _("To Spkr/Hdphns"), true, wxNullBitmap);
        g_plotSpeechOutFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
     }
 
@@ -298,6 +299,10 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent)
     wxGetApp().m_recFileFromRadioPath = pConfig->Read("/File/recFileFromRadioPath", wxT(""));
     wxGetApp().m_recFileFromRadioSecs = pConfig->Read("/File/recFileFromRadioSecs", 30);
 
+    bool slow = false;
+    wxGetApp().m_snrSlow = pConfig->Read("/Audio/snrSlow", slow);
+    //printf("wxGetApp().m_snrSlow %d\n", (int)wxGetApp().m_snrSlow);
+
     pConfig->SetPath(wxT("/"));
 
 //    this->Connect(m_menuItemHelpUpdates->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnHelpCheckUpdatesUI));
@@ -327,6 +332,11 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent)
     m_textSQ->SetLabel(sqsnr_string);
     m_ckboxSQ->SetValue(g_SquelchActive);
 
+    // SNR settings
+
+    m_ckboxSNR->SetValue(wxGetApp().m_snrSlow);
+    setsnrBeta(wxGetApp().m_snrSlow);
+
 #ifdef _USE_TIMER
     Bind(wxEVT_TIMER, &MainFrame::OnTimer, this);       // ID_MY_WINDOW);
     m_plotTimer.SetOwner(this, ID_TIMER_WATERFALL);
@@ -414,6 +424,8 @@ MainFrame::~MainFrame()
         pConfig->Write(wxT("/File/playFileToMicInPath"), wxGetApp().m_playFileToMicInPath);
         pConfig->Write(wxT("/File/recFileFromRadioPath"), wxGetApp().m_recFileFromRadioPath);
         pConfig->Write(wxT("/File/recFileFromRadioSecs"), wxGetApp().m_recFileFromRadioSecs);
+
+        pConfig->Write(wxT("/Audio/snrSlow"), wxGetApp().m_snrSlow);
     }
 
     m_togRxID->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnRxIDUI), NULL, this);
@@ -502,11 +514,22 @@ void MainFrame::OnTimer(wxTimerEvent &evt)
 
     // SNR text box and guage ------------------------------------------------------------
 
-    float snr_limited = g_stats.snr_est;
+    // LP filter g_stats.snr_est some more to stabilise the
+    // display. g_stats.snr_est already has some low pass filtering
+    // but we need it fairly fast to activate squelch.  So we
+    // optionally perform some further filtering for the display
+    // version of SNR.  The "Slow" checkbox controls the amount of
+    // filtering.  The filtered snr also controls the squelch
+
+    g_snr = m_snrBeta*g_snr + (1.0 - m_snrBeta)*g_stats.snr_est;
+    float snr_limited = g_snr;
 
     if (snr_limited < -9.0) snr_limited = -9.0; // stop text box overflow
     char snr[15];
-    sprintf(snr, "%4.1f", snr_limited);
+    if (wxGetApp().m_snrSlow)
+        sprintf(snr, "%4.1f", snr_limited);
+    else
+        sprintf(snr, "%d", (int)(snr_limited+0.5)); // round to nearest dB
     wxString snr_string(snr);
     m_textSNR->SetLabel(snr_string);
 
@@ -641,6 +664,28 @@ void MainFrame::OnCheckSQClick(wxCommandEvent& event)
     }
 }
 
+void MainFrame::setsnrBeta(bool snrSlow)
+{
+    if(snrSlow)
+    {
+        m_snrBeta = 0.9; // make this closer to 1.0 to smooth SNR est further
+    }
+    else
+    {
+        m_snrBeta = 0.0; // no smoothing of SNR estimate from demodulator
+    }
+}
+
+//-------------------------------------------------------------------------
+// OnCheckSQClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnCheckSNRClick(wxCommandEvent& event)
+{
+    wxGetApp().m_snrSlow = m_ckboxSNR->GetValue();
+    setsnrBeta(wxGetApp().m_snrSlow);
+    //printf("m_snrSlow: %d\n", (int)wxGetApp().m_snrSlow);
+}
+
 //-------------------------------------------------------------------------
 // OnTogBtnTXClick()
 //-------------------------------------------------------------------------
@@ -1219,7 +1264,9 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
         g_pFDMDV  = fdmdv_create();
         g_pCodec2 = codec2_create(CODEC2_MODE_1400);
         g_State = 0;
-        printf("g_stats.snr: %f\n", g_stats.snr_est);
+        g_snr = 0.0;
+
+        //printf("g_stats.snr: %f\n", g_stats.snr_est);
 
         // attempt to start sound cards and tx/rx processing
 
@@ -1586,19 +1633,6 @@ void MainFrame::startRxStream()
 }
 
 
-//----------------------------------------------------------------
-// update average of each spectrum point
-//----------------------------------------------------------------
-void MainFrame::averageData(float mag_dB[])
-{
-    int i;
-
-    for(i = 0; i < FDMDV_NSPEC; i++)
-    {
-        g_avmag[i] = (1.0 - BETA) * g_avmag[i] + BETA * mag_dB[i];
-    }
-}
-
 // returns number of output samples generated by resampling
 
 int resample(SRC_STATE *src,
@@ -1735,6 +1769,11 @@ void txRxProcessing()
             memset(out8k_short, 0, sizeof(short)*N8);
             fifo_read(cbData->rxoutfifo, out8k_short, N8);
         }
+        
+        if (g_SquelchActive && (g_SquelchLevel > g_snr)) {
+            //printf("g_SquelchLevel: %f g_snr: %f\n", g_SquelchLevel, g_snr);
+            memset(out8k_short, 0, sizeof(short)*N8);
+        }
 
         resample_for_plot(g_plotSpeechOutFifo, out8k_short, N8);
 
@@ -1960,7 +1999,7 @@ void per_frame_rx_processing(
         // Average rx spectrum data using a simple IIR low pass filter
         for(i = 0; i < FDMDV_NSPEC; i++)
         {
-            g_avmag[i] = (1.0 - BETA) * g_avmag[i] + BETA * rx_spec[i];
+            g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
         }
 
         //
@@ -1984,7 +2023,7 @@ void per_frame_rx_processing(
                     output_buf[i] = 0;
                 fifo_write(output_fifo, output_buf, N8);
 
-                if((g_stats.fest_coarse_fine == 1) && (g_stats.snr_est > 3.0))
+                if(g_stats.fest_coarse_fine == 1)
                 {
                     next_state = 1;
                 }
index 3b0dfb63b7b817fbb9d8fd1244b5872354f22495..2e326e5cd33158542ddde3fb8925ebf143d9fa37 100644 (file)
@@ -126,6 +126,8 @@ class MainApp : public wxApp
         wxString            m_recFileFromRadioPath;
         unsigned int        m_recFileFromRadioSecs;
 
+        bool                m_snrSlow;
+
         int                 m_show_wf;
         int                 m_show_spect;
         int                 m_show_scatter;
@@ -269,12 +271,14 @@ class MainFrame : public TopFrame
                              int soundCard, int sampleRate, int inputChannels);
 
  protected:
+
+        void setsnrBeta(bool snrSlow);
+
         // protected event handlers
         virtual void OnCloseFrame(wxCloseEvent& event);
         virtual void OnExitClick(wxCommandEvent& event);
         //void OnQuit(wxCommandEvent& event);
 
-        void averageData(float mag_dB[]);
         void startTxStream();
         void startRxStream();
         void stopTxStream();
@@ -315,6 +319,7 @@ class MainFrame : public TopFrame
         void OnCmdSliderScrollChanged( wxScrollEvent& event );
         void OnSliderScrollTop( wxScrollEvent& event );
         void OnCheckSQClick( wxCommandEvent& event );
+        void OnCheckSNRClick( wxCommandEvent& event );
 
         // Toggle Buttons
         void OnTogBtnSplitClick(wxCommandEvent& event);
@@ -353,6 +358,8 @@ class MainFrame : public TopFrame
         bool        m_useMemory;
         wxTextCtrl* m_tc;
         int         m_zoom;
+
+        float       m_snrBeta;
 };
 
 void resample_for_plot(struct FIFO *plotFifo, short buf[], int length);
index 61ac9f7708ce509a40a585ad036ead2491884812..8191ea4d4d8c1db3318f24904f6a8a12885b2eb3 100644 (file)
@@ -23,7 +23,8 @@
 
 #include "fdmdv2_main.h"
 
-extern float g_avmag[];
+extern float g_avmag[];                 // average mag data passed to draw() 
+void fdmdv2_clickTune(float frequency); // callback to pass new click freq
 
 BEGIN_EVENT_TABLE(PlotSpectrum, PlotPanel)
     EVT_MOTION          (PlotSpectrum::OnMouseMove)
index 49fce6bf989b60e5666f504719511b63f2d8898e..eb6e6d43732a9939ffe873befb4b388f6f1c3922 100644 (file)
@@ -46,6 +46,4 @@ class PlotSpectrum : public PlotPanel
         DECLARE_EVENT_TABLE()
 };
 
-void fdmdv2_clickTune(float frequency);
-
 #endif //__FDMDV2_PLOT_SPECTRUM__
index eb0fe94c793bfc456b19cd45c400d17d5859d2c5..08ecc4c4c71b161965fa665a40ba46bd7a1ba0e9 100644 (file)
@@ -22,7 +22,8 @@
 #include "wx/wx.h"
 #include "fdmdv2_main.h"
 
-extern float g_avmag[]; // magnitude spectrum passed in to draw() 
+extern float g_avmag[];                 // av mag spec passed in to draw() 
+void fdmdv2_clickTune(float frequency); // callback to pass new click freq
 
 BEGIN_EVENT_TABLE(PlotWaterfall, PlotPanel)
     EVT_PAINT           (PlotWaterfall::OnPaint)
@@ -236,7 +237,7 @@ void PlotWaterfall::drawGraticule(wxAutoBufferedPaintDC& dc)
     // Horizontal gridlines
 
     dc.SetPen(m_penDotDash);
-    for(time=0; time<=WATERFALL_SECS_Y; time++) {
+    for(time=0; time<=WATERFALL_SECS_Y; time+=WATERFALL_SECS_STEP) {
        y = m_rGrid.GetHeight() - time*time_s_to_py;
        y += PLOT_BORDER;
        dc.DrawLine(PLOT_BORDER + XLEFT_OFFSET, y, 
@@ -255,7 +256,7 @@ void PlotWaterfall::plotPixelData()
 {
     float       spec_index_per_px;
     float       intensity_per_dB;
-    int         px_per_sec;
+    float       px_per_sec;
     int         index;
     int         dy;
     int         dy_blocks;
index 5553456031364b0a68b7fd9486b1b52c7980b49a..f7769f4ecc960343fb662eba5a3909f480dd0cfd 100644 (file)
@@ -58,6 +58,4 @@ class PlotWaterfall : public PlotPanel
         DECLARE_EVENT_TABLE()
 };
 
-void fdmdv2_clickTune(float frequency);
-
 #endif //__FDMDV2_PLOT_WATERFALL__
index 79df13a405d4efca3ce58be8058c36aa647125c8..2cf19588271ed258bdbf006f9cae46f0ff6b5b19 100644 (file)
@@ -186,15 +186,18 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
     //------------------------------
     // Box for S/N ratio (Numeric)
     //------------------------------
-    //wxBoxSizer* bSizer29;
-    //bSizer29 = new wxBoxSizer(wxVERTICAL);
+
     m_textSNR = new wxStaticText(this, wxID_ANY, wxT(" 0.0"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
-    //m_textSNR = new wxStaticText(this, wxID_ANY, wxEmptyString, wxPoint(-1,-1), wxSize(35,25), wxTE_READONLY);
-    //m_textSNR->SetToolTip(_("Show SNR ratio numerically."));
-    //m_textSNR->SetMinSize(wxSize(35,25));
-    //bSizer29->Add(m_textSNR, 0, wxALIGN_CENTER|wxALL, 1);
-    //snrSizer->Add(bSizer29, 0, wxEXPAND, 1);
     snrSizer->Add(m_textSNR, 0, wxALIGN_CENTER_HORIZONTAL, 1);
+
+    //------------------------------
+    // S/N ratio slow Checkbox
+    //------------------------------
+
+    m_ckboxSNR = new wxCheckBox(this, wxID_ANY, _("Slow"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+    m_ckboxSNR->SetToolTip(_("Smooth but slow SNR estimation"));
+    snrSizer->Add(m_ckboxSNR, 0, wxALIGN_CENTER_HORIZONTAL, 5);
+
     leftSizer->Add(snrSizer, 2, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxALL, 1);
 
     //------------------------------
@@ -206,6 +209,7 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
     m_gaugeLevel->SetToolTip(_("Display signal level."));
     levelSizer->Add(m_gaugeLevel, 1, wxALIGN_CENTER_HORIZONTAL|wxALL, 10);
     leftSizer->Add(levelSizer, 2, wxALIGN_CENTER|wxALL|wxEXPAND, 1);
+
     bSizer1->Add(leftSizer, 0, wxALL|wxEXPAND, 5);
 
     //=====================================================
@@ -466,6 +470,8 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
     m_sliderSQ->Connect(wxEVT_SCROLL_TOP, wxScrollEventHandler(TopFrame::OnSliderScrollTop), NULL, this);
     m_ckboxSQ->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSQClick), NULL, this);
 
+    m_ckboxSNR->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSNRClick), NULL, this);
+
     m_togBtnOnOff->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
 #ifdef UNIMPLEMENTED
     m_togBtnLoopRx->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnLoopRx), NULL, this);
index b78070e370e9455ce21ebfca3ad0d3db5e275a5a..5f6eb5ecf4748e47c34c6d849726e1d21dca35fd 100644 (file)
@@ -83,6 +83,7 @@ class TopFrame : public wxFrame
         wxMenu* help;
         wxGauge* m_gaugeSNR;
         wxStaticText* m_textSNR;
+        wxCheckBox* m_ckboxSNR;
         wxGauge* m_gaugeLevel;
         wxTextCtrl* m_txtCtrl;
         wxSlider* m_sliderSQ;
@@ -137,6 +138,7 @@ class TopFrame : public wxFrame
         virtual void OnCmdSliderScrollChanged( wxScrollEvent& event ) { event.Skip(); }
         virtual void OnSliderScrollTop( wxScrollEvent& event ) { event.Skip(); }
         virtual void OnCheckSQClick( wxCommandEvent& event ) { event.Skip(); }
+        virtual void OnCheckSNRClick( wxCommandEvent& event ) { event.Skip(); }
 
         virtual void OnTogBtnLoopRx( wxCommandEvent& event ) { event.Skip(); }
         virtual void OnTogBtnLoopTx( wxCommandEvent& event ) { event.Skip(); }