From 0e87c974e973b681a84bd8d9c0c28fbbe3c33a0c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 6 Mar 2017 14:34:25 +0000 Subject: [PATCH] Modified behavior of audio level meter and adjacent slider; Tx6 at program startup. 1. Level meter range increased to 0-90 dB. 2. Level meter reading is independent of slider setting. 3. For a trial period: thermometer bar goes red if a 16-bit sample is within 5 dB A/D limit. 4. Slider can be used to adjust levels sent to waterfall. 5. Tx6 message is selected on program startup. Thanks to W9MDB for most of this code. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7596 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- doc/user_guide/en/transceiver-setup.adoc | 5 +---- lib/hspec.f90 | 13 ++++++++++-- lib/symspec.f90 | 10 +++++++-- mainwindow.cpp | 25 ++++++++++++---------- mainwindow.h | 2 ++ mainwindow.ui | 21 +++++++++++++++++- meterwidget.cpp | 27 ++++++++++++++++++------ meterwidget.h | 4 +++- signalmeter.cpp | 13 ++++++++---- signalmeter.h | 2 +- 10 files changed, 90 insertions(+), 32 deletions(-) diff --git a/doc/user_guide/en/transceiver-setup.adoc b/doc/user_guide/en/transceiver-setup.adoc index d819bafd9..d7f282dd5 100644 --- a/doc/user_guide/en/transceiver-setup.adoc +++ b/doc/user_guide/en/transceiver-setup.adoc @@ -10,10 +10,7 @@ button to start normal receive operation. controls to set the background noise level (scale at lower left of main window) to around 30 dB when no signals are present. It is usually best to turn AGC off or reduce the RF gain control to minimize -AGC action. If necessary you can also adjust the slider next to the -dB scale, but note that the overall dynamic range will be best when -the displayed level is near 30 dB with the slider close to its -mid-point. +AGC action. .Bandwidth and Frequency Setting diff --git a/lib/hspec.f90 b/lib/hspec.f90 index 25b7b10bf..ed0541d61 100644 --- a/lib/hspec.f90 +++ b/lib/hspec.f90 @@ -1,5 +1,5 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144,bcontest, & - btrain,pcoeffs,ingain,mycall,hiscall,bshmsg,bswl,datadir,green,s,jh,line1, & + btrain,pcoeffs,ingain,mycall,hiscall,bshmsg,bswl,datadir,green,s,jh,pxmax,rmsNoGain,line1, & mygrid) ! Input: @@ -56,15 +56,24 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144,bcontest, & rms0=0.0 endif + pxmax = 0; do iblk=1,nblks if(jh.lt.JZ-1) jh=jh+1 ja=ja+nstep jb=ja+nfft-1 x=id2(ja:jb) sq=dot_product(x,x) + xmax = maxval(x); + xmin = abs(minval(x)); + if (xmin > xmax) xmax = xmin; + if (xmax.gt.0.0) pxmax=20.0*log10(xmax); rms=sqrt(gain*sq/nfft) + rms2=sqrt(sq/nfft); green(jh)=0. - if(rms.gt.0.0) green(jh)=20.0*log10(rms) + if(rms.gt.0.0) then + green(jh)=20.0*log10(rms) + rmsNoGain=20.0*log10(rms2); + endif call four2a(x,nfft,1,-1,0) !Real-to-complex FFT df=12000.0/nfft fac=(1.0/nfft)**2 diff --git a/lib/symspec.f90 b/lib/symspec.f90 index ba5cc28af..d9df53a59 100644 --- a/lib/symspec.f90 +++ b/lib/symspec.f90 @@ -1,5 +1,5 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & - df3,ihsym,npts8) + df3,ihsym,npts8, rmsnogain, pxdbmax) ! Input: ! k pointer to the most recent new data @@ -27,6 +27,7 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & real*4 ssum(NSMAX) real*4 xc(0:MAXFFT3-1) real*4 tmp(NSMAX) + real*4 rmsnogain complex cx(0:MAXFFT3/2) integer nch(7) @@ -64,15 +65,20 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & endif gain=10.0**(0.1*ingain) sq=0. + pxmax=0.; do i=k0+1,k x1=shared_data%id2(i) + if (abs(x1).gt.pxmax) pxmax = abs(x1); sq=sq + x1*x1 enddo + rmsnogain = 0. + if (sq.gt.0.0) rmsnogain=20*log10(sqrt(sq/(k-k0))) sq=sq * gain rms=sqrt(sq/(k-k0)) pxdb=0. + pxdbmax = 20*log10(pxmax) if(rms.gt.0.0) pxdb=20.0*log10(rms) - if(pxdb.gt.60.0) pxdb=60.0 + if(pxdb.gt.90.0) pxdb=90.0 k0=k ja=ja+jstep !Index of first sample diff --git a/mainwindow.cpp b/mainwindow.cpp index 6a5590fa6..7b4e65d7b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -66,13 +66,14 @@ extern "C" { //----------------------------------------------------- C and Fortran routines void symspec_(struct dec_data *, int* k, int* ntrperiod, int* nsps, int* ingain, - int* minw, float* px, float s[], float* df3, int* nhsym, int* npts8); + int* minw, float* px, float s[], float* df3, int* nhsym, int* npts8, float *rmsnogain, float *m_pxmax); void hspec_(short int d2[], int* k, int* nutc0, int* ntrperiod, int* nrxfreq, int* ntol, bool* bmsk144, bool* bcontest, bool* btrain, double const pcoeffs[], int* ingain, char mycall[], char hiscall[], bool* bshmsg, bool* bswl, char ddir[], float green[], - float s[], int* jh, char line[], char mygrid[], + float s[], int* jh, float *pxmax, float *rmsNoGain, char line[], char mygrid[], int len1, int len2, int len3, int len4, int len5); +// float s[], int* jh, char line[], char mygrid[], void gen4_(char* msg, int* ichk, char* msgsent, int itone[], int* itext, int len1, int len2); @@ -139,6 +140,7 @@ float fast_green2[703]; float fast_s[44992]; //44992=64*703 float fast_s2[44992]; int fast_jh {0}; +int fast_jhpeak {0}; int fast_jh2 {0}; int narg[15]; QVector g_ColorTbl; @@ -264,6 +266,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_ihsym {0}, m_nzap {0}, m_px {0.0}, + m_rmsNoGain {0.0}, m_iptt0 {0}, m_btxok0 {false}, m_nsendingsh {0}, @@ -837,7 +840,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionEnable_AP_DXcall->setChecked(m_ndepth&64); m_UTCdisk=-1; - m_ntx = 1; m_fCPUmskrtd=0.0; m_bFastDone=false; m_bAltV=false; @@ -845,7 +847,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_bVHFwarned=false; m_bDoubleClicked=false; m_wait=0; - ui->txrb1->setChecked(true); if(m_mode.startsWith ("WSPR") and m_pctx>0) { QPalette palette {ui->sbTxPercent->palette ()}; @@ -1161,13 +1162,13 @@ void MainWindow::dataSink(qint64 frames) int nsps=m_nsps; if(m_bFastMode) nsps=6912; int nsmo=m_wideGraph->smoothYellow()-1; - symspec_(&dec_data,&k,&trmin,&nsps,&m_inGain,&nsmo,&m_px,s,&m_df3,&m_ihsym,&m_npts8); + symspec_(&dec_data,&k,&trmin,&nsps,&m_inGain,&nsmo,&m_px,s,&m_df3,&m_ihsym,&m_npts8,&m_rmsNoGain,&m_pxmax); if(m_mode=="WSPR") wspr_downsample_(dec_data.d2,&k); if(m_ihsym <=0) return; QString t; m_pctZap=m_nzap*100.0/m_nsps; // TODO: this is currently redundant t.sprintf(" Rx noise: %5.1f ",m_px); - if (ui) ui->signal_meter_widget->setValue(m_px); // Update thermometer + if (ui) ui->signal_meter_widget->setValue(m_rmsNoGain,m_pxmax); // Update thermometer if(m_monitoring || m_diskData) { m_wideGraph->dataSink2(s,m_df3,m_ihsym,m_diskData); } @@ -1383,15 +1384,17 @@ void MainWindow::fastSink(qint64 frames) dataDir = m_dataDir.absolutePath (); char ddir[512]; strncpy(ddir,dataDir.toLatin1(), sizeof (ddir) - 1); + float pxmax = 0; + float rmsNoGain = 0; hspec_(dec_data.d2,&k,&nutc0,&nTRpDepth,&RxFreq,&m_Ftol,&bmsk144,&bcontest, &m_bTrain,m_phaseEqCoefficients.constData(),&m_inGain,&dec_data.params.mycall[0], &dec_data.params.hiscall[0],&bshmsg,&bswl, - &ddir[0],fast_green,fast_s,&fast_jh,&line[0],&dec_data.params.mygrid[0], + &ddir[0],fast_green,fast_s,&fast_jh,&pxmax,&rmsNoGain,&line[0],&dec_data.params.mygrid[0], 12,12,512,80,6); float px = fast_green[fast_jh]; QString t; t.sprintf(" Rx noise: %5.1f ",px); - ui->signal_meter_widget->setValue(px); // Update thermometer + ui->signal_meter_widget->setValue(rmsNoGain,pxmax); // Update thermometer m_fastGraph->plotSpec(m_diskData,m_UTCdisk); if(bmsk144 and (line[0]!=0)) { @@ -3230,7 +3233,7 @@ void MainWindow::guiUpdate() t.time().toString() + " "; ui->labUTC->setText(utc); if(!m_monitoring and !m_diskData) { - ui->signal_meter_widget->setValue(0); + ui->signal_meter_widget->setValue(0,0); } m_sec0=nsec; displayDialFrequency (); @@ -3252,7 +3255,7 @@ void MainWindow::startTx2() if(t.mid(0,1)=="#") snr=t.mid(1,5).toDouble(); if(snr>0.0 or snr < -50.0) snr=99.0; transmit (snr); - ui->signal_meter_widget->setValue(0); + ui->signal_meter_widget->setValue(0,0); if(m_mode=="Echo" and !m_tune) m_bTransmittedEcho=true; if(m_mode.startsWith ("WSPR") and !m_tune) { @@ -5482,7 +5485,7 @@ void MainWindow::transmitDisplay (bool transmitting) { if (transmitting == m_transmitting) { if (transmitting) { - ui->signal_meter_widget->setValue(0); + ui->signal_meter_widget->setValue(0,0); if (m_monitoring) monitor (false); m_btxok=true; } diff --git a/mainwindow.h b/mainwindow.h index 7bbaad599..cc69f36da 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -444,6 +444,8 @@ private: int m_nzap; int m_npts8; float m_px; + float m_pxmax; + float m_rmsNoGain; float m_df3; int m_iptt0; bool m_btxok0; diff --git a/mainwindow.ui b/mainwindow.ui index 444ecda3d..0a63af286 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -2,6 +2,14 @@ MainWindow + + + 0 + 0 + 867 + 583 + + WSJT-X by K1JT @@ -1919,6 +1927,9 @@ list. The list can be maintained in Settings (F2). 0 + + <html><head/><body><p>Noise level of 30dB recommended<br/>dB annotations:<br/>* = clipping occured<br/>- = signal too low<br/>+ = signal too high</p></body></html> + QFrame::Panel @@ -1930,7 +1941,7 @@ list. The list can be maintained in Settings (F2). - Digital gain for audio input + Digital gain for graph windows -50 @@ -2355,6 +2366,14 @@ QPushButton[state="ok"] { + + + 0 + 0 + 867 + 21 + + File diff --git a/meterwidget.cpp b/meterwidget.cpp index 8d54f468e..ac0f66240 100644 --- a/meterwidget.cpp +++ b/meterwidget.cpp @@ -8,9 +8,12 @@ #include "moc_meterwidget.cpp" +#define MAXDB 90 + MeterWidget::MeterWidget(QWidget * parent) : QWidget {parent} , m_signal {0} + , m_noisePeak {0} , m_sigPeak {0} { for ( int i = 0; i < 10; i++ ) { @@ -30,7 +33,7 @@ void MeterWidget::setValue(int value) if (signalQueue.at(i) > tmp) tmp = signalQueue.at(i); } - m_sigPeak = tmp; + m_noisePeak = tmp; update(); } @@ -46,23 +49,35 @@ void MeterWidget::paintEvent (QPaintEvent * event) // Sanitize m_signal = m_signal < 0 ? 0 : m_signal; - m_signal = m_signal > 60 ? 60 : m_signal; + m_signal = m_signal > MAXDB ? MAXDB : m_signal; QPainter p {this}; p.setPen (Qt::NoPen); auto const& target = contentsRect (); - QRect r {QPoint {target.left (), static_cast (target.top () + target.height () - m_signal / 60. * target.height ())} + QRect r {QPoint {target.left (), static_cast (target.top () + target.height () - m_signal / (double)MAXDB * target.height ())} , QPoint {target.right (), target.bottom ()}}; - p.setBrush (QColor {255, 150, 0}); + p.setBrush (QColor {Qt::green}); + if (m_sigPeak > 85) { + p.setBrush(Qt::red); + } + else if (m_noisePeak < 15) { + p.setBrush(Qt::yellow); + } p.drawRect (r); - if (m_sigPeak) + if (m_noisePeak) { // Draw peak hold indicator - auto peak = static_cast (target.top () + target.height () - m_sigPeak / 60. * target.height ()); + auto peak = static_cast (target.top () + target.height () - m_noisePeak / (double)MAXDB * target.height ()); p.setBrush (Qt::black); p.translate (target.left (), peak); p.drawPolygon (QPolygon {{{0, -4}, {0, 4}, {target.width (), 0}}}); } } + +// +void MeterWidget::set_sigPeak(int value) +{ + m_sigPeak = value; +} diff --git a/meterwidget.h b/meterwidget.h index 8a263706a..08bda6d5a 100644 --- a/meterwidget.h +++ b/meterwidget.h @@ -19,13 +19,15 @@ public: // QWidget implementation QSize sizeHint () const override; + void set_sigPeak(int value); protected: void paintEvent( QPaintEvent * ) override; private: QQueue signalQueue; int m_signal; - int m_sigPeak; + int m_noisePeak; + int m_sigPeak; // peak value for color coding }; #endif // METERWIDGET_H diff --git a/signalmeter.cpp b/signalmeter.cpp index a24d6f605..5c81881a2 100644 --- a/signalmeter.cpp +++ b/signalmeter.cpp @@ -15,6 +15,8 @@ #include "moc_signalmeter.cpp" +#define MAXDB 90 + class Scale final : public QWidget { @@ -52,8 +54,10 @@ protected: p.translate (target.left () , target.top () + font_offset + i * (target.height () - font_metrics.ascent () - font_metrics.descent ()) / range); p.drawLine (0, 0, tick_length, 0); - auto text = i ? QString::number ((range - i) * scale) : QString {"%1%2"}.arg ((range - i) * scale).arg ('+'); - p.drawText (tick_length + text_indent, font_offset, text); + if((i%2==1)) { + auto text = QString::number ((range - i) * scale); + p.drawText (tick_length + text_indent, font_offset, text); + } p.restore (); } } @@ -62,7 +66,7 @@ private: static int constexpr tick_length {4}; static int constexpr text_indent {2}; static int constexpr line_spacing {0}; - static int constexpr range {6}; + static int constexpr range {MAXDB/10}; static int constexpr scale {10}; }; @@ -90,12 +94,13 @@ SignalMeter::SignalMeter (QWidget * parent) setLayout (outer_layout); } -void SignalMeter::setValue(float value) +void SignalMeter::setValue(float value, float valueMax) { if(value<0) value=0; QFontMetrics font_metrics {m_scale->font (), nullptr}; m_meter->setContentsMargins (0, font_metrics.ascent () / 2, 0, font_metrics.ascent () / 2 + font_metrics.descent ()); m_meter->setValue(int(value)); + m_meter->set_sigPeak(valueMax); QString t; t.sprintf("%4.1f dB",value); m_reading->setText(t); diff --git a/signalmeter.h b/signalmeter.h index 1a5061dbd..bf277ebde 100644 --- a/signalmeter.h +++ b/signalmeter.h @@ -16,7 +16,7 @@ public: explicit SignalMeter (QWidget * parent = nullptr); public slots: - void setValue (float value); + void setValue (float value, float valueMax); private: MeterWidget * m_meter;