int g_channel_noise;
float g_sig_pwr_av = 0.0;
struct FIFO *g_error_pattern_fifo;
-short *g_error_hist;
+short *g_error_hist, *g_error_histn;
// time averaged magnitude spectrum used for waterfall and spectrum display
float g_avmag[MODEM_STATS_NSPEC];
if(wxGetApp().m_show_test_frame_errors_hist)
{
- // Add Test Frame Errors window
- m_panelTestFrameErrorsHist = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, 1.0, 1.0/(2*FDMDV_NC_MAX), 0.0, 1.0, 1.0/FDMDV_NC_MAX, 0.1, "%3.2f", 0);
+ // Add Test Frame Historgram window. 1 column for every bit, 2 bits per carrier
+ m_panelTestFrameErrorsHist = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, 1.0, 1.0/(2*FDMDV_NC_MAX), 0.001, 0.1, 1.0/FDMDV_NC_MAX, 0.1, "%0.0E", 0);
m_auiNbookCtrl->AddPage(m_panelTestFrameErrorsHist, L"Test Frame Histogram", true, wxNullBitmap);
m_panelTestFrameErrorsHist->setBarGraph(1);
+ m_panelTestFrameErrorsHist->setLogY(1);
}
wxGetApp().m_framesPerBuffer = pConfig->Read(wxT("/Audio/framesPerBuffer"), PA_FPB);
if (fifo_read(g_error_pattern_fifo, error_pattern, sz_error_pattern) == 0) {
int i,b;
- /* both modes map IQ to alternate bits, but one same carrier */
+ /* both modes map IQ to alternate bits, but on same carrier */
if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600) {
/* FreeDV 1600 mapping from error pattern to two bits on each carrier */
c = i/4;
m_panelTestFrameErrors->add_new_sample(c, c + 0.8*error_pattern[i]);
g_error_hist[c] += error_pattern[i];
+ g_error_histn[c]++;
//printf("i: %d c: %d\n", i, c);
}
- int max_hist = 0;
+ /* calculate BERs and send to plot */
+
+ float ber[2*FDMDV_NC_MAX];
+ for(b=0; b<2*FDMDV_NC_MAX; b++) {
+ ber[b] = 0.0;
+ }
for(b=0; b<g_Nc; b++) {
- if (g_error_hist[b] > max_hist) {
- max_hist = g_error_hist[b];
- }
- //printf("%4d ", g_error_hist[b]);
+ ber[b+1] = (float)g_error_hist[b]/g_error_histn[b];
}
- printf("\n");
- m_panelTestFrameErrorsHist->add_new_short_samples(0, g_error_hist, 2*FDMDV_NC_MAX, max_hist);
+ m_panelTestFrameErrorsHist->add_new_samples(0, ber, 2*FDMDV_NC_MAX);
}
m_panelTestFrameErrors->Refresh();
freedv_set_total_bits(g_pfreedv, 0);
freedv_set_total_bit_errors(g_pfreedv, 0);
int i;
- for(i=0; i<2*g_Nc; i++)
+ for(i=0; i<2*g_Nc; i++) {
g_error_hist[i] = 0;
+ g_error_histn[i] = 0;
+ }
}
freedv_set_callback_error_pattern(g_pfreedv, my_freedv_put_error_pattern, (void*)m_panelTestFrameErrors);
g_error_pattern_fifo = fifo_create(2*freedv_get_sz_error_pattern(g_pfreedv));
g_error_hist = new short[FDMDV_NC_MAX*2];
+ g_error_histn = new short[FDMDV_NC_MAX*2];
int i;
- for(i=0; i<2*FDMDV_NC_MAX; i++)
+ for(i=0; i<2*FDMDV_NC_MAX; i++) {
g_error_hist[i] = 0;
+ g_error_histn[i] = 0;
+ }
assert(g_pfreedv != NULL);
else {
// FreeDV clean up
delete g_error_hist;
+ delete g_error_histn;
fifo_destroy(g_error_pattern_fifo);
freedv_close(g_pfreedv);
speex_preprocess_state_destroy(g_speex_st);
assert(strlen(a_fmt) < 15);
strcpy(m_a_fmt, a_fmt);
m_mini = mini;
- bar_graph = 0;
+ m_bar_graph = 0;
+ m_logy = 0;
// work out number of samples we will store and allocate storage
//----------------------------------------------------------------
// add_new_samples()
//----------------------------------------------------------------
+void PlotScalar::add_new_samples(int channel, float samples[], int length)
+{
+ int i;
+ int offset = channel*m_samples;
+
+ assert(channel < m_channels);
+
+ for(i = 0; i < m_samples-length; i++)
+ m_mem[offset+i] = m_mem[offset+i+length];
+ for(; i < m_samples; i++)
+ m_mem[offset+i] = *samples++;
+}
+
+//----------------------------------------------------------------
+// add_new_short_samples()
+//----------------------------------------------------------------
void PlotScalar::add_new_short_samples(int channel, short samples[], int length, float scale_factor)
{
int i;
y += PLOT_BORDER;
}
- if (bar_graph) {
+ if (m_bar_graph) {
+
+ if (m_logy) {
+
+ // can't take log(0)
+
+ assert(m_a_min > 0.0);
+ assert(m_a_max > 0.0);
+
+ float norm = (log10(a) - log10(m_a_min))/(log10(m_a_max) - log10(m_a_min));
+ y = m_rGrid.GetHeight()*(1.0 - norm);
+ } else {
+ y = m_rGrid.GetHeight() - a_to_py * a + m_a_min*a_to_py;
+ }
+
// use points to make a bar graph
int x1, x2, y1;
// 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;
+ for(a=m_a_min; a<m_a_max; ) {
+ if (m_logy) {
+ float norm = (log10(a) - log10(m_a_min))/(log10(m_a_max) - log10(m_a_min));
+ y = m_rGrid.GetHeight()*(1.0 - norm);
+ }
+ else {
+ y = m_rGrid.GetHeight() - a*a_to_py + m_a_min*a_to_py;
+ }
if (m_mini) {
dc.DrawLine(0, y, m_rGrid.GetWidth(), y);
}
GetTextExtent(buf, &text_w, &text_h);
dc.DrawText(buf, PLOT_BORDER + XLEFT_OFFSET - text_w - XLEFT_TEXT_OFFSET, y-text_h/2);
}
+
+ if (m_logy) {
+ // m_graticule_a_step == 0.1 means 10 steps/decade
+ float log10_step_size = floor(log10(a));
+ a += pow(10,log10_step_size);
+ }
+ else {
+ a += m_graticule_a_step;
+ }
}
);
~PlotScalar();
void add_new_sample(int channel, float sample);
+ void add_new_samples(int channel, float samples[], int length);
void add_new_short_samples(int channel, short samples[], int length, float scale_factor);
- void setBarGraph(int abar_graph) { bar_graph = abar_graph; }
+ void setBarGraph(int bar_graph) { m_bar_graph = bar_graph; }
+ void setLogY(int logy) { m_logy = logy; }
protected:
int m_mini;
int m_samples;
float *m_mem;
- int bar_graph; // non zero to plot bar graphs
+ int m_bar_graph; // non zero to plot bar graphs
+ int m_logy; // plot graph on log scale
void draw(wxAutoBufferedPaintDC& dc);
void drawGraticule(wxAutoBufferedPaintDC& dc);