SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
chanalyzergui.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include <QDockWidget>
19 #include <QMainWindow>
20 
21 #include "device/deviceuiset.h"
22 #include "dsp/downchannelizer.h"
25 #include "dsp/spectrumvis.h"
26 #include "dsp/dspengine.h"
27 #include "gui/glspectrum.h"
28 #include "gui/glscope.h"
30 #include "plugin/pluginapi.h"
31 #include "util/simpleserializer.h"
32 #include "util/db.h"
33 #include "mainwindow.h"
34 
35 #include "ui_chanalyzergui.h"
36 #include "chanalyzer.h"
37 #include "chanalyzergui.h"
38 
40 {
41  ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceUISet, rxChannel);
42  return gui;
43 }
44 
46 {
47  delete this;
48 }
49 
50 void ChannelAnalyzerGUI::setName(const QString& name)
51 {
52  setObjectName(name);
53 }
54 
56 {
57  return objectName();
58 }
59 
61 {
63 }
64 
65 void ChannelAnalyzerGUI::setCenterFrequency(qint64 centerFrequency)
66 {
67  m_channelMarker.setCenterFrequency(centerFrequency);
69  applySettings();
70 }
71 
73 {
75 }
76 
78 {
79  m_channelMarker.blockSignals(true);
84 
85  if (m_settings.m_ssb)
86  {
87  if (m_settings.m_bandwidth < 0) {
89  } else {
91  }
92  }
93  else
94  {
96  }
97 
98  m_channelMarker.blockSignals(false);
99  m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
100 
102  setWindowTitle(m_channelMarker.getTitle());
103 
104  ui->channelSampleRate->setValueRange(7, 0.501*m_channelAnalyzer->getInputSampleRate(), m_channelAnalyzer->getInputSampleRate());
105  ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
106 
107  blockApplySettings(true);
108 
109  ui->useRationalDownsampler->setChecked(m_settings.m_downSample);
110  setNewFinalRate();
111  if (m_settings.m_ssb) {
112  ui->BWLabel->setText("LP");
113  } else {
114  ui->BWLabel->setText("BP");
115  }
116  ui->ssb->setChecked(m_settings.m_ssb);
117  ui->BW->setValue(m_settings.m_bandwidth/100);
118  ui->lowCut->setValue(m_settings.m_lowCutoff/100);
119  ui->deltaFrequency->setValue(m_settings.m_frequency);
120  ui->spanLog2->setCurrentIndex(m_settings.m_spanLog2);
122  ui->signalSelect->setCurrentIndex((int) m_settings.m_inputType);
123  ui->rrcFilter->setChecked(m_settings.m_rrc);
124  QString rolloffStr = QString::number(m_settings.m_rrcRolloff/100.0, 'f', 2);
125  ui->rrcRolloffText->setText(rolloffStr);
126 
127  blockApplySettings(false);
128 }
129 
131 {
132  if (m_settings.m_fll)
133  {
134  ui->pllPskOrder->setCurrentIndex(5);
135  }
136  else
137  {
138  int i = 0;
139  for(; ((m_settings.m_pllPskOrder>>i) & 1) == 0; i++);
140  ui->pllPskOrder->setCurrentIndex(i);
141  }
142 
143  ui->pll->setChecked(m_settings.m_pll);
144 }
145 
147 {
148  qDebug("ChannelAnalyzerGUI::setSpectrumDisplay: m_rate: %d", m_rate);
149  if (m_settings.m_ssb)
150  {
151  ui->glSpectrum->setCenterFrequency(m_rate/4);
152  ui->glSpectrum->setSampleRate(m_rate/2);
153  ui->glSpectrum->setSsbSpectrum(true);
154  ui->glSpectrum->setLsbDisplay(ui->BW->value() < 0);
155  }
156  else
157  {
158  ui->glSpectrum->setCenterFrequency(0);
159  ui->glSpectrum->setSampleRate(m_rate);
160  ui->glSpectrum->setSsbSpectrum(false);
161  ui->glSpectrum->setLsbDisplay(false);
162  }
163 }
164 
166 {
167  return m_settings.serialize();
168 }
169 
170 bool ChannelAnalyzerGUI::deserialize(const QByteArray& data)
171 {
172  if(m_settings.deserialize(data))
173  {
174  displaySettings();
175  applySettings(true); // will have true
176  return true;
177  }
178  else
179  {
181  displaySettings();
182  applySettings(true); // will have true
183  return false;
184  }
185 }
186 
188 {
190  {
191  qDebug() << "ChannelAnalyzerGUI::handleMessage: MsgReportChannelSampleRateChanged:" << m_channelAnalyzer->getInputSampleRate();
192  ui->channelSampleRate->setValueRange(7, 0.501*m_channelAnalyzer->getInputSampleRate(), m_channelAnalyzer->getInputSampleRate());
193  ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
194  m_settings.m_downSampleRate = ui->channelSampleRate->getValueNew();
195  setNewFinalRate();
196 
197  return true;
198  }
199 
200  return false;
201 }
202 
204 {
205  Message* message;
206 
207  while ((message = getInputMessageQueue()->pop()) != 0)
208  {
209  qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier());
210 
211  if (handleMessage(*message))
212  {
213  delete message;
214  }
215  }
216 }
217 
219 {
220  ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
221  applySettings();
222 }
223 
225 {
227 }
228 
230 {
232  double powDb = CalcDb::dbPower((double) m_channelPowerAvg);
233  ui->channelPower->setText(tr("%1 dB").arg(powDb, 0, 'f', 1));
234 
236  ui->pll->setStyleSheet("QToolButton { background-color : green; }");
237  } else {
238  ui->pll->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
239  }
240 
241  if (ui->pll->isChecked())
242  {
243  double sampleRate = ((double) m_channelAnalyzer->getChannelSampleRate()) / m_channelAnalyzer->getDecimation();
244  int freq = (m_channelAnalyzer->getPllFrequency() * sampleRate) / (2.0*M_PI);
245  ui->pll->setToolTip(tr("PLL lock. Freq = %1 Hz").arg(freq));
246  }
247 }
248 
250 {
252  setNewFinalRate();
253  applySettings();
254 }
255 
257 {
258  if (!checked) {
259  ui->pll->setToolTip(tr("PLL lock"));
260  }
261 
262  m_settings.m_pll = checked;
263  applySettings();
264 }
265 
267 {
268  if (index < 5) {
269  m_settings.m_pllPskOrder = (1<<index);
270  }
271 
272  m_settings.m_fll = (index == 5);
273  applySettings();
274 }
275 
277 {
278  m_settings.m_downSample = checked;
279  setNewFinalRate();
280  applySettings();
281 }
282 
284 {
285  if (ui->useRationalDownsampler->isChecked()) {
286  return ui->channelSampleRate->getValueNew();
287  } else {
289  }
290 }
291 
293 {
295  applySettings();
296 }
297 
299 {
302  applySettings();
303 }
304 
306 {
307  m_settings.m_rrc = checked;
308  applySettings();
309 }
310 
312 {
313  m_settings.m_rrcRolloff = value;
314  QString rolloffStr = QString::number(value/100.0, 'f', 2);
315  ui->rrcRolloffText->setText(rolloffStr);
316  applySettings();
317 }
318 
320 {
321  (void) value;
323  m_settings.m_bandwidth = ui->BW->value() * 100;
324  m_settings.m_lowCutoff = ui->lowCut->value() * 100;
325  applySettings();
326 }
327 
329 {
330  (void) value;
332  m_settings.m_bandwidth = ui->BW->value() * 100;
333  m_settings.m_lowCutoff = ui->lowCut->value() * 100;
334  applySettings();
335 }
336 
338 {
339  if ((index < 0) || (index > 6)) {
340  return;
341  }
342 
343  m_settings.m_spanLog2 = index;
344  setNewFinalRate();
345  applySettings();
346 }
347 
349 {
350  m_settings.m_ssb = checked;
351  if (checked) {
352  ui->BWLabel->setText("LP");
353  } else {
354  ui->BWLabel->setText("BP");
355  }
357  applySettings();
358 }
359 
360 void ChannelAnalyzerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
361 {
362  (void) widget;
363  (void) rollDown;
364 }
365 
367 {
369  {
371  dialog.move(p);
372  dialog.exec();
373 
377 
378  setWindowTitle(m_settings.m_title);
380 
381  applySettings();
382  }
383 
385 }
386 
387 ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) :
388  RollupWidget(parent),
389  ui(new Ui::ChannelAnalyzerGUI),
390  m_pluginAPI(pluginAPI),
391  m_deviceUISet(deviceUISet),
392  m_channelMarker(this),
393  m_doApplySettings(true),
394  m_rate(48000)
395 {
396  ui->setupUi(this);
397  setAttribute(Qt::WA_DeleteOnClose, true);
398  connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
399  connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
400 
401  m_spectrumVis = new SpectrumVis(SDR_RX_SCALEF, ui->glSpectrum);
402  m_scopeVis = new ScopeVis(ui->glScope);
404  m_channelAnalyzer = (ChannelAnalyzer*) rxChannel; //new ChannelAnalyzer(m_deviceUISet->m_deviceSourceAPI);
407 
408  ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
409  ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
410  ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
411 
412  ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
413  ui->channelSampleRate->setValueRange(7, 0.501*m_rate, m_rate);
414 
415  ui->glSpectrum->setCenterFrequency(m_rate/2);
416  ui->glSpectrum->setSampleRate(m_rate);
417  ui->glSpectrum->setDisplayWaterfall(true);
418  ui->glSpectrum->setDisplayMaxHold(true);
419  ui->glSpectrum->setSsbSpectrum(false);
420  ui->glSpectrum->setLsbDisplay(false);
421 
422  ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer());
423  ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer());
424  connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
425 
426  m_channelMarker.blockSignals(true);
427  m_channelMarker.setColor(Qt::gray);
431  m_channelMarker.setTitle("Channel Analyzer");
432  m_channelMarker.blockSignals(false);
433  m_channelMarker.setVisible(true); // activate signal on the last setting only
435 
439 
440  ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
441  ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
442 
444  m_settings.setSpectrumGUI(ui->spectrumGUI);
445  m_settings.setScopeGUI(ui->scopeGUI);
446 
447  connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
448  connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
449  connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
450 
451  displaySettings();
452  applySettings(true);
453 }
454 
456 {
458  delete m_channelAnalyzer; // TODO: check this: when the GUI closes it has to delete the demodulator
459  delete m_spectrumVis;
460  delete m_scopeVis;
462  delete ui;
463 }
464 
466 {
468  if (m_rate == 0) {
469  m_rate = 48000;
470  }
471  qDebug("ChannelAnalyzerGUI::setNewFinalRate: %d m_spanLog2: %d", m_rate, m_settings.m_spanLog2);
472 
474 
475  QString s = QString::number(m_rate/1000.0, 'f', 1);
476  ui->spanText->setText(tr("%1 kS/s").arg(s));
477 
479 }
480 
482 {
483  bool dsb = !ui->ssb->isChecked();
484  int bw = ui->BW->value();
485  int lw = ui->lowCut->value();
486  int bwMax = m_rate / 200;
487 
488  bw = bw < -bwMax ? -bwMax : bw > bwMax ? bwMax : bw;
489 
490  if (bw < 0) {
491  lw = lw < bw+1 ? bw+1 : lw < 0 ? lw : 0;
492  } else if (bw > 0) {
493  lw = lw > bw-1 ? bw-1 : lw < 0 ? 0 : lw;
494  } else {
495  lw = 0;
496  }
497 
498  if (dsb)
499  {
500  bw = bw < 0 ? -bw : bw;
501  lw = 0;
502  }
503 
504  QString bwStr = QString::number(bw/10.0, 'f', 1);
505  QString lwStr = QString::number(lw/10.0, 'f', 1);
506 
507  if (dsb) {
508  ui->BWText->setText(tr("%1%2k").arg(QChar(0xB1, 0x00)).arg(bwStr));
509  } else {
510  ui->BWText->setText(tr("%1k").arg(bwStr));
511  }
512 
513  ui->lowCutText->setText(tr("%1k").arg(lwStr));
514 
515  ui->BW->blockSignals(true);
516  ui->lowCut->blockSignals(true);
517 
518  ui->BW->setMaximum(bwMax);
519  ui->BW->setMinimum(dsb ? 0 : -bwMax);
520  ui->BW->setValue(bw);
521 
522  ui->lowCut->setMaximum(dsb ? 0 : bw);
523  ui->lowCut->setMinimum(dsb ? 0 : -bw);
524  ui->lowCut->setValue(lw);
525 
526  ui->lowCut->blockSignals(false);
527  ui->BW->blockSignals(false);
528 
530 
531  m_channelMarker.setBandwidth(bw * 200);
533 
534  if (!dsb) {
535  m_channelMarker.setLowCutoff(lw * 100);
536  }
537 }
538 
540 {
541  ui->glScope->blockSignals(block);
542  ui->glSpectrum->blockSignals(block);
543  m_doApplySettings = !block;
544 }
545 
547 {
548  if (m_doApplySettings)
549  {
550  int sampleRate = getRequestedChannelSampleRate();
551 
554  m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer);
555 
559 
561  }
562 }
563 
565 {
567 }
568 
570 {
572 }
573 
static MainWindow * getInstance()
Definition: mainwindow.h:73
virtual void setCenterFrequency(qint64 centerFrequency)
double getMagSqAvg() const
Definition: chanalyzer.h:129
SpectrumScopeComboVis * m_spectrumScopeComboVis
Definition: chanalyzergui.h:75
int getCenterFrequency() const
Definition: channelmarker.h:42
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: chanalyzer.h:76
void setLowCutoff(int lowCutoff)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void on_rrcRolloff_valueChanged(int value)
DeviceUISet * m_deviceUISet
Definition: chanalyzergui.h:67
void on_rrcFilter_toggled(bool checked)
int m_rate
sample rate after final in-channel decimation (spanlog2)
Definition: chanalyzergui.h:71
void applySettings(bool force=false)
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
void setChannelMarker(Serializable *channelMarker)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setName(const QString &name)
void on_deltaFrequency_changed(qint64 value)
void onMenuDialogCalled(const QPoint &p)
void on_pll_toggled(bool checked)
void on_lowCut_valueChanged(int value)
void resetContextMenuType()
Definition: rollupwidget.h:50
int getRequestedChannelSampleRate()
void addChannelMarker(ChannelMarker *channelMarker)
Add channel marker to spectrum.
Definition: deviceuiset.cpp:72
bool deserialize(const QByteArray &data)
void leaveEvent(QEvent *)
QByteArray serialize() const
#define M_PI
Definition: rdsdemod.cpp:27
void setLiveRate(int sampleRate)
Definition: scopevis.cpp:83
void on_spanLog2_currentIndexChanged(int index)
virtual bool handleMessage(const Message &message)
ContextMenuType m_contextMenuType
Definition: rollupwidget.h:33
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
SpectrumVis * m_spectrumVis
Definition: chanalyzergui.h:76
#define SDR_RX_SCALEF
Definition: dsptypes.h:33
MovingAverageUtil< double, double, 40 > m_channelPowerAvg
Definition: chanalyzergui.h:72
void onWidgetRolled(QWidget *widget, bool rollDown)
PluginAPI * m_pluginAPI
Definition: chanalyzergui.h:66
Real getPllFrequency() const
Definition: chanalyzer.cpp:383
void setScopeGUI(Serializable *scopeGUI)
void blockApplySettings(bool block)
void channelMarkerChangedByCursor()
void setSpectrumGUI(Serializable *spectrumGUI)
void on_useRationalDownsampler_toggled(bool checked)
virtual void setMessageQueueToGUI(MessageQueue *queue)
virtual void destroy()
ChannelAnalyzerGUI(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget *parent=0)
void on_pllPskOrder_currentIndexChanged(int index)
void setTitleColor(const QColor &c)
void setSampleSink(BasebandSampleSink *sampleSink)
Definition: chanalyzer.h:112
void on_signalSelect_currentIndexChanged(int index)
quint32 m_rrcRolloff
in 100ths
QByteArray serialize() const
void setHighlighted(bool highlighted)
void on_BW_valueChanged(int value)
DownChannelizer * getChannelizer()
Definition: chanalyzer.h:124
void registerRxChannelInstance(const QString &channelName, PluginInstanceGUI *pluginGUI)
Definition: deviceuiset.cpp:82
int32_t i
Definition: decimators.h:244
void addRollupWidget(QWidget *widget)
Add rollup widget to channel window.
Definition: deviceuiset.cpp:77
void removeRxChannelInstance(PluginInstanceGUI *pluginGUI)
Definition: deviceuiset.cpp:94
const QString & getTitle() const
Definition: channelmarker.h:38
static bool match(const Message *message)
Definition: message.cpp:45
virtual ~ChannelAnalyzerGUI()
ScopeVis * m_scopeVis
Definition: chanalyzergui.h:77
bool getHighlighted() const
Definition: channelmarker.h:61
int getInputSampleRate() const
virtual qint64 getCenterFrequency() const
ChannelMarker m_channelMarker
Definition: chanalyzergui.h:68
static ChannelAnalyzerGUI * create(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
bool isPllLocked() const
Definition: chanalyzer.h:130
int getInputSampleRate() const
Definition: chanalyzer.h:125
void setHighlighted(bool highlighted)
void setColor(const QColor &color)
static MsgConfigureChannelAnalyzer * create(const ChannelAnalyzerSettings &settings, bool force)
Definition: chanalyzer.h:53
void setNewFinalRate()
set sample rate after final in-channel decimation
void setVisible(bool visible)
bool deserialize(const QByteArray &data)
virtual const char * getIdentifier() const
Definition: message.cpp:35
void setBandwidth(int bandwidth)
const QColor & getColor() const
Definition: channelmarker.h:64
void setTitle(const QString &title)
void setCenterFrequency(int centerFrequency)
void setSidebands(sidebands_t sidebands)
void setLiveRateLog2Decim(int log2Decim)
Definition: scopevis.cpp:92
Ui::ChannelAnalyzerGUI * ui
Definition: chanalyzergui.h:65
ChannelAnalyzerSettings m_settings
Definition: chanalyzergui.h:69
int getChannelSampleRate() const
Definition: chanalyzer.h:126
static const QString m_channelIdURI
Definition: chanalyzer.h:157
void on_channelSampleRate_changed(quint64 value)
void widgetRolled(QWidget *widget, bool rollDown)
void on_ssb_toggled(bool checked)
void enterEvent(QEvent *)
virtual MessageQueue * getInputMessageQueue()
Definition: chanalyzergui.h:57
ChannelAnalyzer * m_channelAnalyzer
Definition: chanalyzergui.h:74
QString getName() const
int getDecimation() const
Definition: chanalyzer.h:127
void channelMarkerHighlightedByCursor()