m_ckboxTestFrame->SetToolTip(_("Send frames of known bits instead of compressed voice"));
sbSizer_testFrames->Add(m_ckboxTestFrame, 0, wxALIGN_LEFT, 0);
- m_ckboxChannelNoise = new wxCheckBox(this, wxID_ANY, _("Channel Noise"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxChannelNoise = new wxCheckBox(this, wxID_ANY, _("Channel Noise SNR (dB):"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
m_ckboxChannelNoise->SetToolTip(_("Add simulated AWGN channel noise to received signal"));
sbSizer_testFrames->Add(m_ckboxChannelNoise, 0, wxALIGN_LEFT, 0);
+ m_txtNoiseSNR = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(50,-1), 0, wxTextValidator(wxFILTER_DIGITS));
+ sbSizer_testFrames->Add(m_txtNoiseSNR, 0, wxALIGN_LEFT, 0);
bSizer30->Add(sbSizer_testFrames,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
//------------------------------
wxStaticBoxSizer* sbSizer_freedv700;
- wxStaticBox *sb_freedv700 = new wxStaticBox(this, wxID_ANY, _("FreeDV 700 Clipping"));
+ wxStaticBox *sb_freedv700 = new wxStaticBox(this, wxID_ANY, _("FreeDV 700 Options"));
sbSizer_freedv700 = new wxStaticBoxSizer(sb_freedv700, wxHORIZONTAL);
- m_ckboxFreeDV700txClip = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxFreeDV700txClip = new wxCheckBox(this, wxID_ANY, _("Clipping"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
m_ckboxFreeDV700txClip->SetToolTip(_("Clip FreeDv 700 tx waveform to reduce Peak to Average Power Ratio (PAPR)"));
sbSizer_freedv700->Add(m_ckboxFreeDV700txClip, 0, wxALIGN_LEFT, 0);
+ m_ckboxFreeDV700scatterCombine = new wxCheckBox(this, wxID_ANY, _("Scatter Combine"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxFreeDV700scatterCombine->SetToolTip(_("Upper and Lower carriers combined for Scatter diagram"));
+ sbSizer_freedv700->Add(m_ckboxFreeDV700scatterCombine, 0, wxALIGN_LEFT, 0);
bSizer30->Add(sbSizer_freedv700,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
m_sdbSizer5Cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnCancel), NULL, this);
m_sdbSizer5Apply->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnApply), NULL, this);
+ m_ckboxTestFrame->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnTestFrame), NULL, this);
+ m_ckboxChannelNoise->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnChannelNoise), NULL, this);
m_ckboxFreeDV700txClip->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700txClip), NULL, this);
+ m_ckboxFreeDV700scatterCombine->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700scatterCombine), NULL, this);
event_in_serial = 0;
event_out_serial = 0;
m_sdbSizer5OK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnOK), NULL, this);
m_sdbSizer5Cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnCancel), NULL, this);
m_sdbSizer5Apply->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnApply), NULL, this);
+
+ m_ckboxTestFrame->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnTestFrame), NULL, this);
+ m_ckboxChannelNoise->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnChannelNoise), NULL, this);
m_ckboxFreeDV700txClip->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700txClip), NULL, this);
+ m_ckboxFreeDV700scatterCombine->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700scatterCombine), NULL, this);
}
m_txtCtrlCallSign->SetValue(wxGetApp().m_callSign);
m_ckboxTestFrame->SetValue(wxGetApp().m_testFrames);
m_ckboxChannelNoise->SetValue(wxGetApp().m_channel_noise);
+ m_txtNoiseSNR->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_noise_snr));
m_ckbox_events->SetValue(wxGetApp().m_events);
m_txt_spam_timer->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_events_spam_timer));
m_ckboxEnableChecksum->SetValue(wxGetApp().m_enable_checksum);
m_ckboxFreeDV700txClip->SetValue(wxGetApp().m_FreeDV700txClip);
+ m_ckboxFreeDV700scatterCombine->SetValue(wxGetApp().m_FreeDV700scatterCombine);
}
if(inout == EXCHANGE_DATA_OUT)
wxGetApp().m_callSign = m_txtCtrlCallSign->GetValue();
wxGetApp().m_testFrames = m_ckboxTestFrame->GetValue();
wxGetApp().m_channel_noise = m_ckboxChannelNoise->GetValue();
+ long noise_snr;
+ m_txtNoiseSNR->GetValue().ToLong(&noise_snr);
+ wxGetApp().m_noise_snr = (int)noise_snr;
wxGetApp().m_events = m_ckbox_events->GetValue();
long spam_timer;
wxGetApp().m_enable_checksum = m_ckboxEnableChecksum->GetValue();
wxGetApp().m_FreeDV700txClip = m_ckboxFreeDV700txClip->GetValue();
+ wxGetApp().m_FreeDV700scatterCombine = m_ckboxFreeDV700scatterCombine->GetValue();
if (storePersistent) {
pConfig->Write(wxT("/Data/CallSign"), wxGetApp().m_callSign);
pConfig->Write(wxT("/UDP/enable"), wxGetApp().m_udp_enable);
pConfig->Write(wxT("/UDP/port"), wxGetApp().m_udp_port);
+ pConfig->Write(wxT("/Events/spam_timer"), wxGetApp().m_events_spam_timer);
+
pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip);
+ pConfig->Write(wxT("/FreeDV700/scatterCombine"), wxGetApp().m_FreeDV700scatterCombine);
+
+ pConfig->Write(wxT("/Noise/noise_snr"), wxGetApp().m_noise_snr);
pConfig->Flush();
}
ExchangeData(EXCHANGE_DATA_IN, false);
}
+void OptionsDlg::OnTestFrame(wxScrollEvent& event) {
+ wxGetApp().m_testFrames = m_ckboxTestFrame->GetValue();
+}
+
// immediately change flags rather using ExchangeData() so we can switch on and off at run time
+void OptionsDlg::OnChannelNoise(wxScrollEvent& event) {
+ wxGetApp().m_channel_noise = m_ckboxChannelNoise->GetValue();
+}
+
void OptionsDlg::OnFreeDV700txClip(wxScrollEvent& event) {
wxGetApp().m_FreeDV700txClip = m_ckboxFreeDV700txClip->GetValue();
}
+void OptionsDlg::OnFreeDV700scatterCombine(wxScrollEvent& event) {
+ wxGetApp().m_FreeDV700scatterCombine = m_ckboxFreeDV700scatterCombine->GetValue();
+}
void OptionsDlg::updateEventLog(wxString event_in, wxString event_out) {
wxString event_in_with_serial, event_out_with_serial;
void OnClose(wxCloseEvent& event);
void OnInitDialog(wxInitDialogEvent& event);
+ void OnTestFrame(wxScrollEvent& event);
+ void OnChannelNoise(wxScrollEvent& event);
void OnFreeDV700txClip(wxScrollEvent& event);
+ void OnFreeDV700scatterCombine(wxScrollEvent& event);
wxTextCtrl *m_txtCtrlCallSign; // TODO: this should be renamed to tx_txtmsg, and rename all related incl persis strge
wxCheckBox *m_ckboxTestFrame;
wxCheckBox *m_ckboxChannelNoise;
+ wxTextCtrl *m_txtNoiseSNR;
wxCheckBox *m_ckboxFreeDV700txClip;
+ wxCheckBox *m_ckboxFreeDV700scatterCombine;
wxRadioButton *m_rb_textEncoding1;
wxRadioButton *m_rb_textEncoding2;
// 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);
m_auiNbookCtrl->AddPage(m_panelTestFrameErrorsHist, L"Test Frame Histogram", true, wxNullBitmap);
+ m_panelTestFrameErrorsHist->setBarGraph(1);
}
wxGetApp().m_framesPerBuffer = pConfig->Read(wxT("/Audio/framesPerBuffer"), PA_FPB);
wxGetApp().m_udp_port = (int)pConfig->Read(wxT("/UDP/port"), 3000);
wxGetApp().m_FreeDV700txClip = (float)pConfig->Read(wxT("/FreeDV700/txClip"), t);
+ wxGetApp().m_FreeDV700scatterCombine = (float)pConfig->Read(wxT("/FreeDV700/scatterCombine"), t);
+ wxGetApp().m_noise_snr = (float)pConfig->Read(wxT("/Noise/noise_snr"), 2);
int mode = pConfig->Read(wxT("/Audio/mode"), (long)0);
if (mode == 0)
pConfig->Write(wxT("/Filter/SpkOutEQEnable"), wxGetApp().m_SpkOutEQEnable);
pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip);
+ pConfig->Write(wxT("/FreeDV700/scatterCombine"), wxGetApp().m_FreeDV700scatterCombine);
+ pConfig->Write(wxT("/Noise/noise_snr"), wxGetApp().m_noise_snr);
int mode;
if (m_rb1600->GetValue())
if ((freedv_get_mode(g_pfreedv) == FREEDV_MODE_700B) || (freedv_get_mode(g_pfreedv) == FREEDV_MODE_700C)) {
- /*
- FreeDV 700 uses diversity, so combine symbols for
- scatter plot, as combined symbols are used for
- demodulation. Note we need to use a copy of the
- symbols, as we are not sure when the stats will be
- updated.
- */
-
- COMP rx_symbols_copy[g_Nc/2];
-
- for(c=0; c<g_Nc/2; c++)
- rx_symbols_copy[c] = cadd(g_stats.rx_symbols[r][c], g_stats.rx_symbols[r][c+g_Nc/2]);
- m_panelScatter->add_new_samples_scatter(rx_symbols_copy);
+ if (wxGetApp().m_FreeDV700scatterCombine) {
+ m_panelScatter->setNc(g_Nc/2); /* m_FreeDV700scatterCombine may have changed at run time */
+
+ /*
+ FreeDV 700 uses diversity, so optionaly combine
+ symbols for scatter plot, as combined symbols are
+ used for demodulation. Note we need to use a copy
+ of the symbols, as we are not sure when the stats
+ will be updated.
+ */
+
+ COMP rx_symbols_copy[g_Nc/2];
+
+ for(c=0; c<g_Nc/2; c++)
+ rx_symbols_copy[c] = fcmult(0.5, cadd(g_stats.rx_symbols[r][c], g_stats.rx_symbols[r][c+g_Nc/2]));
+ m_panelScatter->add_new_samples_scatter(rx_symbols_copy);
+ }
+ else {
+ m_panelScatter->setNc(g_Nc); /* m_FreeDV700scatterCombine may have changed at run time */
+ /*
+ Sometimes useful to plot carriers separately, e.g. to determine if tx carrier power is constant
+ across carriers.
+ */
+ m_panelScatter->add_new_samples_scatter(&g_stats.rx_symbols[r][0]);
+ }
}
}
/* both modes map IQ to alternate bits, but one same carrier */
if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600) {
- /* FreeDV 1600 mapping from error pattern to bit on each carrier */
+ /* FreeDV 1600 mapping from error pattern to two bits on each carrier */
for(b=0; b<g_Nc*2; b++) {
for(i=b; i<sz_error_pattern; i+= 2*g_Nc) {
}
int max_hist = 0;
- for(b=0; b<g_Nc; b++)
- if (g_error_hist[b] > max_hist)
+ for(b=0; b<g_Nc; b++) {
+ if (g_error_hist[b] > max_hist) {
max_hist = g_error_hist[b];
+ }
+ }
m_panelTestFrameErrorsHist->add_new_short_samples(0, g_error_hist, 2*FDMDV_NC_MAX, max_hist);
}
}
int max_hist = 0;
- for(b=0; b<g_Nc; b++)
- if (g_error_hist[b] > max_hist)
+ 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]);
+ }
+ printf("\n");
m_panelTestFrameErrorsHist->add_new_short_samples(0, g_error_hist, 2*FDMDV_NC_MAX, max_hist);
}
if (m_rb1600->GetValue()) {
g_mode = FREEDV_MODE_1600;
g_Nc = 16;
- m_panelScatter->setNc(g_Nc);
+ m_panelScatter->setNc(g_Nc+1); /* +1 for BPSK pilot */
}
if (m_rb700b->GetValue()) {
g_mode = FREEDV_MODE_700B;
g_Nc = 14;
- m_panelScatter->setNc(g_Nc/2-1); /* due to diversity, -1 due to no pilot like FreeDV 1600 */
+ if (wxGetApp().m_FreeDV700scatterCombine) {
+ m_panelScatter->setNc(g_Nc/2); /* diversity combnation */
+ }
+ else {
+ m_panelScatter->setNc(g_Nc);
+ }
}
if (m_rb700c->GetValue()) {
g_mode = FREEDV_MODE_700C;
g_Nc = 14;
- m_panelScatter->setNc(g_Nc/2-1); /* due to diversity, -1 due to no pilot like FreeDV 1600 */
+ if (wxGetApp().m_FreeDV700scatterCombine) {
+ m_panelScatter->setNc(g_Nc/2); /* diversity combnation */
+ }
+ else {
+ m_panelScatter->setNc(g_Nc);
+ }
}
if (m_rb800xa->GetValue()) {
g_mode = FREEDV_MODE_800XA;
}
if (g_channel_noise) {
- float snr;
-
- /* enough noise to get a couple of % errors */
-
- if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600)
- snr = 2.0;
- else
- snr = -1.0;
- fdmdv_simulate_channel(&g_sig_pwr_av, rx_fdm, nin, snr);
+ fdmdv_simulate_channel(&g_sig_pwr_av, rx_fdm, nin, wxGetApp().m_noise_snr);
}
freq_shift_coh(rx_fdm_offset, rx_fdm, g_RxFreqOffsetHz, freedv_get_modem_sample_rate(g_pfreedv), &g_RxFreqOffsetPhaseRect, nin);
nout = freedv_comprx(g_pfreedv, output_buf, rx_fdm_offset);
int FilterEvent(wxEvent& event);
MainFrame *frame;
+ // 700 options
+
bool m_FreeDV700txClip;
+ bool m_FreeDV700scatterCombine;
+
+ // Noise simulation
+
+ int m_noise_snr;
+
protected:
};
assert(strlen(a_fmt) < 15);
strcpy(m_a_fmt, a_fmt);
m_mini = mini;
+ bar_graph = 0;
// work out number of samples we will store and allocate storage
float index_to_px;
float a_to_py;
int i;
- int x, y;
int prev_x, prev_y;
float a;
// plot each channel
- int offset;
+ int offset, x, y;
for(offset=0; offset<m_channels*m_samples; offset+=m_samples) {
for(i = 0; i < m_samples; i++) {
- x = index_to_px * i;
a = m_mem[offset+i];
if (a < m_a_min) a = m_a_min;
if (a > m_a_max) a = m_a_max;
y = m_rGrid.GetHeight() - a_to_py * a + m_a_min*a_to_py;
+ // regular point-point line graph
+
+ x = index_to_px * i;
+
// put inside plot window
if (!m_mini) {
y += PLOT_BORDER;
}
- if (i)
- dc.DrawLine(x, y, prev_x, prev_y);
- prev_x = x; prev_y = y;
+ if (bar_graph) {
+ // use points to make a bar graph
+
+ int x1, x2, y1;
+
+ x1 = index_to_px * ((float)i - 0.5);
+ x2 = index_to_px * ((float)i + 0.5);
+ y1 = m_rGrid.GetHeight();
+ x1 += PLOT_BORDER + XLEFT_OFFSET; x2 += PLOT_BORDER + XLEFT_OFFSET;
+ y1 += PLOT_BORDER;
+ dc.DrawLine(x1, y1, x1, y); dc.DrawLine(x1, y, x2, y); dc.DrawLine(x2, y, x2, y1);
+ }
+ else {
+ if (i)
+ dc.DrawLine(x, y, prev_x, prev_y);
+ prev_x = x; prev_y = y;
+ }
}
}
~PlotScalar();
void add_new_sample(int channel, float sample);
void add_new_short_samples(int channel, short samples[], int length, float scale_factor);
+ void setBarGraph(int abar_graph) { bar_graph = abar_graph; }
protected:
int m_mini;
int m_samples;
float *m_mem;
+ int bar_graph; // non zero to plot bar graphs
- void draw(wxAutoBufferedPaintDC& dc);
- void drawGraticule(wxAutoBufferedPaintDC& dc);
- void OnPaint(wxPaintEvent& event);
- void OnSize(wxSizeEvent& event);
- void OnShow(wxShowEvent& event);
+ void draw(wxAutoBufferedPaintDC& dc);
+ void drawGraticule(wxAutoBufferedPaintDC& dc);
+ void OnPaint(wxPaintEvent& event);
+ void OnSize(wxSizeEvent& event);
+ void OnShow(wxShowEvent& event);
- DECLARE_EVENT_TABLE()
+ DECLARE_EVENT_TABLE()
};
#endif // __FDMDV2_PLOT_SCALAR__
// changing number of carriers changes number of symbols to plot
void PlotScatter::setNc(int Nc) {
- Nsym = Nc+1;
+ Nsym = Nc;
assert(Nsym <= (MODEM_STATS_NC_MAX+1));
scatterMemSyms = ((int)(SCATTER_MEM_SECS*(Nsym/DT)));
assert(scatterMemSyms <= SCATTER_MEM_SYMS_MAX);