if(wxGetApp().m_show_timing)
{
// Add Timing Offset window
- m_panelTimeOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl);
+ m_panelTimeOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl, 5.0, DT, -0.5, 0.5, 1, 0.1, "%2.1f");
m_auiNbookCtrl->AddPage(m_panelTimeOffset, L"Timing \u0394", true, wxNullBitmap);
}
if(wxGetApp().m_show_freq)
{
// Add Frequency Offset window
- m_panelFreqOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl);
+ m_panelFreqOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl, 5.0, DT, -200, 200, 1, 50, "%3fHz");
m_auiNbookCtrl->AddPage(m_panelFreqOffset, L"Frequency \u0394", true, wxNullBitmap);
}
wxGetApp().m_strRxInAudio = pConfig->Read(wxT("/Audio/RxIn"), wxT("<m_strRxInAudio>"));
m_panelSpectrum->Refresh();
m_panelScatter->add_new_samples(g_stats.rx_symbols);
- m_panelScatter->m_newdata = true;
m_panelScatter->Refresh();
+
+ m_panelTimeOffset->add_new_sample((float)g_stats.rx_timing/FDMDV_NOM_SAMPLES_PER_FRAME);
+ m_panelTimeOffset->Refresh();
+
+ m_panelFreqOffset->add_new_sample(g_stats.foff);
+ m_panelFreqOffset->Refresh();
}
#endif
m_rxUserdata->infifo2 = fifo_create(4*N48);
- m_rxUserdata->rxinfifo = fifo_create(2 * FDMDV_NOM_SAMPLES_PER_FRAME);
+ m_rxUserdata->rxinfifo = fifo_create(3 * FDMDV_NOM_SAMPLES_PER_FRAME);
m_rxUserdata->rxoutfifo = fifo_create(2 * codec2_samples_per_frame(g_pCodec2));
// Start sound card 1 ----------------------------------------------------------
//==========================================================================
// Name: fdmdv2_plot_scalar.cpp
-// Purpose: Implements a waterfall plot derivative of fdmdv2_plot.
+// Purpose: Plots scalar amplitude against time
// Created: June 22, 2012
// Initial author: David Witten
// Derived from: code written by David Rowe
//----------------------------------------------------------------
// PlotScalar()
//----------------------------------------------------------------
-//PlotScalar::PlotScalar(wxFrame* parent, int x_max_, int y_max_): PlotPanel(parent)
-PlotScalar::PlotScalar(wxFrame* parent): PlotPanel(parent)
+PlotScalar::PlotScalar(wxFrame* parent,
+ float t_secs, // time covered by entire x axis in seconds
+ float sample_period_secs, // tiem between each sample in seconds
+ float a_min, // min ampltude of samples being plotted
+ float a_max, // max ampltude of samples being plotted
+ float graticule_t_step, // time step of x (time) axis graticule in seconds
+ float graticule_a_step, // step of amplitude axis graticule
+ const char a_fmt[] // printf format string for amlitude axis labels
+ ): PlotPanel(parent)
{
int i;
- //align(FL_ALIGN_TOP);
- //labelsize(10);
+ m_t_secs = t_secs;
+ m_sample_period_secs = sample_period_secs;
+ m_a_min = a_min;
+ m_a_max = a_max;
+ m_graticule_t_step = graticule_t_step;
+ m_graticule_a_step = graticule_a_step;
+ assert(strlen(a_fmt) < 15);
+ strcpy(m_a_fmt, a_fmt);
- m_mem = new float[m_x_max];
+ // work out number of samples we will store and allocate storage
- for(i = 0; i < m_x_max; i++)
+ m_samples = m_t_secs/m_sample_period_secs;
+ m_mem = new float[m_samples];
+
+ for(i = 0; i < m_samples; i++)
{
m_mem[i] = 0.0;
}
- m_prev_w = 0;
- m_prev_h = 0;
- m_prev_x = 0;
- m_prev_y = 0;
- m_index = 0;
}
//----------------------------------------------------------------
//----------------------------------------------------------------
void PlotScalar::add_new_sample(float sample)
{
- m_new_sample = sample;
-}
+ int i;
-//----------------------------------------------------------------
-// clip()
-//----------------------------------------------------------------
-int PlotScalar::clip(int y1)
-{
- if(y1 > (m_rCtrl.GetHeight()/2 - 10))
- {
- y1 = m_rCtrl.GetHeight()/2 - 10;
- }
- if(y1 < -(m_rCtrl.GetHeight()/2 - 10))
+ for(i = 0; i < m_samples-1; i++)
{
- y1 = -(m_rCtrl.GetHeight()/2 - 10);
+ m_mem[i] = m_mem[i+1];
}
- return y1;
+ m_mem[m_samples-1] = sample;
}
//----------------------------------------------------------------
//----------------------------------------------------------------
void PlotScalar::draw(wxAutoBufferedPaintDC& dc)
{
- float x_scale;
- float y_scale;
+ float index_to_px;
+ float a_to_py;
int i;
- int x1;
- int y1;
- int x2;
- int y2;
- char label[100];
- wxPen pen;
+ int x, y;
+ int prev_x, prev_y;
+ float a;
- /* detect resizing of window */
- if((m_rCtrl.GetHeight() != m_prev_h) || (m_rCtrl.GetWidth() != m_prev_w) || (m_x != m_prev_x) || (m_y != m_prev_y))
- {
- dc.SetPen(BLACK_COLOR);
- dc.DrawRectangle(m_x, m_y, m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
- m_prev_h = m_rCtrl.GetHeight();
- m_prev_w = m_rCtrl.GetWidth();
- m_prev_x = m_x;
- m_prev_y = m_y;
- }
+ m_rCtrl = GetClientRect();
+ m_rGrid = m_rCtrl;
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
- //fl_push_clip(m_x, m_y, m_w, m_h);
- x_scale = (float)m_x_max;
- y_scale = (float)m_rCtrl.GetHeight() /(2.0 * m_y_max);
-
- // erase last sample
- dc.SetPen(BLACK_COLOR);
- x1 = x_scale * m_index + m_x;
- y1 = y_scale * m_mem[m_index];
- y1 = clip(y1);
- y1 = m_y + m_rCtrl.GetHeight()/2 - y1;
- dc.DrawPoint(x1, y1);
-
- // draw new sample
- dc.SetPen(GREEN_COLOR);
- x1 = x_scale * m_index + m_x;
- y1 = y_scale * m_new_sample;
- y1 = clip(y1);
- y1 = m_y + m_rCtrl.GetHeight()/2 - y1;
- dc.DrawPoint(x1, y1);
- m_mem[m_index] = m_new_sample;
- m_index++;
- if(m_index >= m_x_max)
- {
- m_index = 0;
- }
+ // black background
- // y axis graticule
- m_step = 10;
- while((2.0 * m_y_max/m_step) > 10)
- {
- m_step *= 2.0;
- }
- while((2.0 * m_y_max/m_step) < 4)
- {
- m_step /= 2.0;
- }
- pen = dc.GetPen();
+ dc.Clear();
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ wxBrush ltGraphBkgBrush = wxBrush(BLACK_COLOR);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 0));
+ dc.DrawRectangle(m_rPlot);
+
+ index_to_px = (float)m_rGrid.GetWidth()/m_samples;
+ a_to_py = (float)m_rGrid.GetHeight()/(m_a_max - m_a_min);
+
+ wxPen pen;
pen.SetColour(DARK_GREEN_COLOR);
- pen.SetStyle(wxPENSTYLE_DOT);
+ pen.SetWidth(1);
dc.SetPen(pen);
- for(i =- m_y_max; i < m_y_max; i += m_step)
+
+ // draw all samples
+
+ prev_x = prev_y = 0; // stop warning
+
+ for(i = 0; i < m_samples; i++)
{
- x1 = m_x;
- y1 = m_y + m_rCtrl.GetHeight()/2 - i * y_scale;
- x2 = m_x + m_rCtrl.GetWidth();
- y2 = y1;
- dc.DrawLine(x1, y1, x2, y2);
+ x = index_to_px * i;
+ a = m_mem[i];
+ if (a < m_a_min) a = m_a_min;
+ if (a > m_a_max) a = m_a_max;
+
+ // invert y axis and offset by minimum
+
+ y = m_rGrid.GetHeight() - a_to_py * a + m_a_min*a_to_py;
+
+ // put inside plot window
+
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ y += PLOT_BORDER;
+
+ if (i)
+ dc.DrawLine(x, y, prev_x, prev_y);
+ prev_x = x; prev_y = y;
}
- // y axis graticule labels
- pen = dc.GetPen();
- pen.SetColour(GREEN_COLOR);
- pen.SetStyle(wxPENSTYLE_DOT);
- dc.SetPen(pen);
- for(i =- m_y_max; i < m_y_max; i += m_step)
- {
- x1 = m_x;
- y1 = m_y + m_rCtrl.GetHeight()/2 - i * y_scale;
- sprintf(label, "%d", i);
- wxSize sz = dc.GetTextExtent(label);
- dc.DrawLabel(label, wxRect(x1, y1, sz.GetWidth(), sz.GetHeight()), wxALIGN_LEFT);
+ drawGraticule(dc);
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotScalar::drawGraticule(wxAutoBufferedPaintDC& dc)
+{
+ float t, a;
+ int x, y, text_w, text_h;
+ char buf[15];
+ wxString s;
+ float sec_to_px;
+ float a_to_py;
+
+ wxBrush ltGraphBkgBrush;
+ ltGraphBkgBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+ ltGraphBkgBrush.SetColour(*wxBLACK);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+
+ sec_to_px = (float)m_rGrid.GetWidth()/m_t_secs;
+ a_to_py = (float)m_rGrid.GetHeight()/(m_a_max - m_a_min);
+
+ // upper LH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER)
+ // lower RH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET + m_rGrid.GetWidth(),
+ // PLOT_BORDER + m_rGrid.GetHeight())
+
+ // Vertical gridlines
+
+ dc.SetPen(m_penShortDash);
+ for(t=0; t<=m_t_secs; t+=m_graticule_t_step) {
+ x = t*sec_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, PLOT_BORDER);
+ sprintf(buf, "%2.1fs", t);
+ GetTextExtent(buf, &text_w, &text_h);
+ dc.DrawText(buf, x - text_w/2, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
}
- //fl_pop_clip();
+
+ // Horizontal gridlines
+
+ dc.SetPen(m_penDotDash);
+ for(a=m_a_min; a<m_a_max; a+=m_graticule_a_step) {
+ y = m_rGrid.GetHeight() - a*a_to_py + m_a_min*a_to_py;
+ y += PLOT_BORDER;
+ dc.DrawLine(PLOT_BORDER + XLEFT_OFFSET, y,
+ (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), y);
+ sprintf(buf, m_a_fmt, a);
+ GetTextExtent(buf, &text_w, &text_h);
+ dc.DrawText(buf, PLOT_BORDER + XLEFT_OFFSET - text_w - XLEFT_TEXT_OFFSET, y-text_h/2);
+ }
+
+
}
//----------------------------------------------------------------