Removing Waterfall3DPlot. The qwt_plot3d is too much of a hassle to deal with and...
[debian/gnuradio] / gr-qtgui / src / lib / spectrumdisplayform.cc
1 #include <cmath>
2 #include <QColorDialog>
3 #include <QMessageBox>
4 #include <spectrumdisplayform.h>
5
6 int SpectrumDisplayForm::_openGLWaterfall3DFlag = -1;
7
8 SpectrumDisplayForm::SpectrumDisplayForm(bool useOpenGL, QWidget* parent)
9   : QWidget(parent)
10 {
11   setupUi(this);
12
13   _useOpenGL = useOpenGL;
14   _systemSpecifiedFlag = false;
15   _intValidator = new QIntValidator(this);
16   _intValidator->setBottom(0);
17   _frequencyDisplayPlot = new FrequencyDisplayPlot(FrequencyPlotDisplayFrame);
18   _waterfallDisplayPlot = new WaterfallDisplayPlot(WaterfallPlotDisplayFrame);
19
20   _timeDomainDisplayPlot = new TimeDomainDisplayPlot(TimeDomainDisplayFrame);
21   _constellationDisplayPlot = new ConstellationDisplayPlot(ConstellationDisplayFrame);
22   _numRealDataPoints = 1024;
23   _realFFTDataPoints = new double[_numRealDataPoints];
24   _averagedValues = new double[_numRealDataPoints];
25   _historyVector = new std::vector<double*>;
26   
27   AvgLineEdit->setRange(0, 500);                 // Set range of Average box value from 0 to 500
28   MinHoldCheckBox_toggled( false );
29   MaxHoldCheckBox_toggled( false );
30   
31   WaterfallMaximumIntensityWheel->setRange(-200, 0);
32   WaterfallMaximumIntensityWheel->setTickCnt(50);
33   WaterfallMinimumIntensityWheel->setRange(-200, 0);
34   WaterfallMinimumIntensityWheel->setTickCnt(50);
35   WaterfallMinimumIntensityWheel->setValue(-200);
36   
37   _peakFrequency = 0;
38   _peakAmplitude = -HUGE_VAL;
39   
40   _noiseFloorAmplitude = -HUGE_VAL;
41
42   connect(_waterfallDisplayPlot, SIGNAL(UpdatedLowerIntensityLevel(const double)), 
43           _frequencyDisplayPlot, SLOT(SetLowerIntensityLevel(const double)));
44   connect(_waterfallDisplayPlot, SIGNAL(UpdatedUpperIntensityLevel(const double)), 
45           _frequencyDisplayPlot, SLOT(SetUpperIntensityLevel(const double)));
46   
47   _frequencyDisplayPlot->SetLowerIntensityLevel(-200);
48   _frequencyDisplayPlot->SetUpperIntensityLevel(-200);
49
50   // Load up the acceptable FFT sizes...
51   FFTSizeComboBox->clear();
52   for(long fftSize = SpectrumGUIClass::MIN_FFT_SIZE; fftSize <= SpectrumGUIClass::MAX_FFT_SIZE; fftSize *= 2){
53     FFTSizeComboBox->insertItem(FFTSizeComboBox->count(), QString("%1").arg(fftSize));
54   }
55   Reset();
56
57   ToggleTabFrequency(false);
58   ToggleTabWaterfall(false);
59   ToggleTabTime(false);
60   ToggleTabConstellation(false);
61
62   // Create a timer to update plots at the specified rate
63   displayTimer = new QTimer(this);
64   connect(displayTimer, SIGNAL(timeout()), this, SLOT(UpdateGuiTimer()));
65 }
66
67 SpectrumDisplayForm::~SpectrumDisplayForm()
68 {
69   // Qt deletes children when parent is deleted
70
71   // Don't worry about deleting Display Plots - they are deleted when parents are deleted
72   delete _intValidator;
73
74   delete[] _realFFTDataPoints;
75   delete[] _averagedValues;
76
77   for(unsigned int count = 0; count < _historyVector->size(); count++){
78     delete[] _historyVector->operator[](count);
79   }
80
81   delete _historyVector;
82
83   displayTimer->stop();
84   delete displayTimer;
85 }
86
87 void
88 SpectrumDisplayForm::setSystem( SpectrumGUIClass * newSystem, 
89                                 const uint64_t numFFTDataPoints, 
90                                 const uint64_t numTimeDomainDataPoints )
91 {
92   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
93   
94   if(newSystem != NULL){
95     _system = newSystem;
96     _systemSpecifiedFlag = true;
97   }
98   else{
99     _systemSpecifiedFlag = false;
100   }
101 }
102
103 void
104 SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumUpdateEvent)
105 {
106   //_lastSpectrumEvent = (SpectrumUpdateEvent)(*spectrumUpdateEvent);
107   const std::complex<float>* complexDataPoints = spectrumUpdateEvent->getFFTPoints();
108   const uint64_t numFFTDataPoints = spectrumUpdateEvent->getNumFFTDataPoints();
109   const double* realTimeDomainDataPoints = spectrumUpdateEvent->getRealTimeDomainPoints();
110   const double* imagTimeDomainDataPoints = spectrumUpdateEvent->getImagTimeDomainPoints();
111   const uint64_t numTimeDomainDataPoints = spectrumUpdateEvent->getNumTimeDomainDataPoints();
112   const timespec dataTimestamp = spectrumUpdateEvent->getDataTimestamp();
113   const bool repeatDataFlag = spectrumUpdateEvent->getRepeatDataFlag();
114   const bool lastOfMultipleUpdatesFlag = spectrumUpdateEvent->getLastOfMultipleUpdateFlag();
115   const timespec generatedTimestamp = spectrumUpdateEvent->getEventGeneratedTimestamp();
116
117   // REMEMBER: The dataTimestamp is NOT valid when the repeat data flag is true...
118   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
119
120   // Calculate the Magnitude of the complex point
121   const std::complex<float>* complexDataPointsPtr = complexDataPoints+numFFTDataPoints/2;
122   double* realFFTDataPointsPtr = _realFFTDataPoints;
123
124   double sumMean = 0.0;
125   double localPeakAmplitude = -HUGE_VAL;
126   double localPeakFrequency = 0.0;
127   const double fftBinSize = (_stopFrequency-_startFrequency) /
128     static_cast<double>(numFFTDataPoints);
129
130   // Run this twice to perform the fftshift operation on the data here as well
131   std::complex<float> scaleFactor = std::complex<float>((float)numFFTDataPoints);
132   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
133     std::complex<float> pt = (*complexDataPointsPtr) / scaleFactor;
134     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
135
136     if(*realFFTDataPointsPtr > localPeakAmplitude) {
137       localPeakFrequency = static_cast<float>(point) * fftBinSize;
138       localPeakAmplitude = *realFFTDataPointsPtr;
139     }
140     sumMean += *realFFTDataPointsPtr;
141     
142     complexDataPointsPtr++;
143     realFFTDataPointsPtr++;
144   }
145   
146   // This loop takes the first half of the input data and puts it in the 
147   // second half of the plotted data
148   complexDataPointsPtr = complexDataPoints;
149   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
150     std::complex<float> pt = (*complexDataPointsPtr) / scaleFactor;
151     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
152
153     if(*realFFTDataPointsPtr > localPeakAmplitude) {
154       localPeakFrequency = static_cast<float>(point) * fftBinSize;
155       localPeakAmplitude = *realFFTDataPointsPtr;
156     }
157     sumMean += *realFFTDataPointsPtr;
158
159     complexDataPointsPtr++;
160     realFFTDataPointsPtr++;
161   }
162
163   // Don't update the averaging history if this is repeated data
164   if(!repeatDataFlag){
165     _AverageHistory(_realFFTDataPoints);
166
167     // Only use the local info if we are not repeating data
168     _peakAmplitude = localPeakAmplitude;
169     _peakFrequency = localPeakFrequency;
170
171     // calculate the spectral mean
172     // +20 because for the comparison below we only want to throw out bins
173     // that are significantly higher (and would, thus, affect the mean more)
174     const double meanAmplitude = (sumMean / numFFTDataPoints) + 20.0;
175
176     // now throw out any bins higher than the mean
177     sumMean = 0.0;
178     uint64_t newNumDataPoints = numFFTDataPoints;
179     for(uint64_t number = 0; number < numFFTDataPoints; number++){
180       if (_realFFTDataPoints[number] <= meanAmplitude)
181         sumMean += _realFFTDataPoints[number];
182       else
183         newNumDataPoints--;
184     }
185
186     if (newNumDataPoints == 0)             // in the odd case that all
187       _noiseFloorAmplitude = meanAmplitude; // amplitudes are equal!
188     else
189       _noiseFloorAmplitude = sumMean / newNumDataPoints;
190   }
191
192   if(lastOfMultipleUpdatesFlag){
193     int tabindex = SpectrumTypeTab->currentIndex();
194     if(tabindex == d_plot_fft) {
195       _frequencyDisplayPlot->PlotNewData(_averagedValues, numFFTDataPoints, 
196                                          _noiseFloorAmplitude, _peakFrequency, 
197                                          _peakAmplitude, d_update_time);
198     }
199     if(tabindex == d_plot_time) {
200       _timeDomainDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
201                                           imagTimeDomainDataPoints, 
202                                           numTimeDomainDataPoints,
203                                           d_update_time);
204     }
205     if(tabindex == d_plot_constellation) {
206       _constellationDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
207                                              imagTimeDomainDataPoints, 
208                                              numTimeDomainDataPoints,
209                                              d_update_time);
210     }
211
212     // Don't update the repeated data for the waterfall
213     if(!repeatDataFlag){
214       if(tabindex == d_plot_waterfall) {
215         _waterfallDisplayPlot->PlotNewData(_realFFTDataPoints, numFFTDataPoints, 
216                                            d_update_time, dataTimestamp, 
217                                            spectrumUpdateEvent->getDroppedFFTFrames());
218       }
219     }
220
221     
222     // Tell the system the GUI has been updated
223     if(_systemSpecifiedFlag){
224       _system->SetLastGUIUpdateTime(generatedTimestamp);
225       _system->DecrementPendingGUIUpdateEvents();
226     }
227   }
228 }
229
230 void
231 SpectrumDisplayForm::resizeEvent( QResizeEvent *e )
232 {
233   QSize s;
234   s.setWidth(FrequencyPlotDisplayFrame->width());
235   s.setHeight(FrequencyPlotDisplayFrame->height());
236   emit _frequencyDisplayPlot->resizeSlot(&s);
237
238   s.setWidth(TimeDomainDisplayFrame->width());
239   s.setHeight(TimeDomainDisplayFrame->height());
240   emit _timeDomainDisplayPlot->resizeSlot(&s);
241
242   s.setWidth(WaterfallPlotDisplayFrame->width());
243   s.setHeight(WaterfallPlotDisplayFrame->height());
244   emit _waterfallDisplayPlot->resizeSlot(&s);
245
246   s.setWidth(ConstellationDisplayFrame->width());
247   s.setHeight(ConstellationDisplayFrame->height());
248   emit _constellationDisplayPlot->resizeSlot(&s);
249 }
250
251 void
252 SpectrumDisplayForm::customEvent( QEvent * e)
253 {
254   if(e->type() == QEvent::User+3){
255     if(_systemSpecifiedFlag){
256       WindowComboBox->setCurrentIndex(_system->GetWindowType());
257       FFTSizeComboBox->setCurrentIndex(_system->GetFFTSizeIndex());
258       //FFTSizeComboBox->setCurrentIndex(1);
259     }
260
261     waterfallMinimumIntensityChangedCB(WaterfallMinimumIntensityWheel->value());
262     waterfallMaximumIntensityChangedCB(WaterfallMaximumIntensityWheel->value());
263
264     // Clear any previous display
265     Reset();
266   }
267   else if(e->type() == 10005){
268     SpectrumUpdateEvent* spectrumUpdateEvent = (SpectrumUpdateEvent*)e;
269     newFrequencyData(spectrumUpdateEvent);
270   }
271   else if(e->type() == 10008){
272     setWindowTitle(((SpectrumWindowCaptionEvent*)e)->getLabel());
273   }
274   else if(e->type() == 10009){
275     Reset();
276     if(_systemSpecifiedFlag){
277       _system->ResetPendingGUIUpdateEvents();
278     }
279   }
280   else if(e->type() == 10010){
281     _startFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStartFrequency();
282     _stopFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStopFrequency();
283     _centerFrequency  = ((SpectrumFrequencyRangeEvent*)e)->GetCenterFrequency();
284
285     UseRFFrequenciesCB(UseRFFrequenciesCheckBox->isChecked());
286   }
287 }
288
289 void
290 SpectrumDisplayForm::UpdateGuiTimer()
291 {
292   // This is called by the displayTimer and redraws the canvases of
293   // all of the plots.
294   _frequencyDisplayPlot->canvas()->update();
295   _waterfallDisplayPlot->canvas()->update();
296   _timeDomainDisplayPlot->canvas()->update();
297   _constellationDisplayPlot->canvas()->update();
298 }
299
300
301 void
302 SpectrumDisplayForm::AvgLineEdit_valueChanged( int value )
303 {
304   SetAverageCount(value);
305 }
306
307
308 void
309 SpectrumDisplayForm::MaxHoldCheckBox_toggled( bool newState )
310 {
311   MaxHoldResetBtn->setEnabled(newState);
312   _frequencyDisplayPlot->SetMaxFFTVisible(newState);
313   MaxHoldResetBtn_clicked();
314 }
315
316
317 void
318 SpectrumDisplayForm::MinHoldCheckBox_toggled( bool newState )
319 {
320   MinHoldResetBtn->setEnabled(newState);
321   _frequencyDisplayPlot->SetMinFFTVisible(newState);
322   MinHoldResetBtn_clicked();
323 }
324
325
326 void
327 SpectrumDisplayForm::MinHoldResetBtn_clicked()
328 {
329   _frequencyDisplayPlot->ClearMinData();
330   _frequencyDisplayPlot->replot();
331 }
332
333
334 void
335 SpectrumDisplayForm::MaxHoldResetBtn_clicked()
336 {
337   _frequencyDisplayPlot->ClearMaxData();
338   _frequencyDisplayPlot->replot();
339 }
340
341
342 void
343 SpectrumDisplayForm::TabChanged(int index)
344 {
345   // This might be dangerous to call this with NULL
346   resizeEvent(NULL);  
347 }
348
349 void
350 SpectrumDisplayForm::SetFrequencyRange(const double newCenterFrequency,
351                                        const double newStartFrequency, 
352                                        const double newStopFrequency)
353 {
354   double fdiff;
355   if(UseRFFrequenciesCheckBox->isChecked()) {
356     fdiff = newCenterFrequency;
357   }
358   else {
359     fdiff = std::max(fabs(newStartFrequency), fabs(newStopFrequency));
360   }
361
362   if(fdiff > 0) {
363     std::string strunits[4] = {"Hz", "kHz", "MHz", "GHz"};
364     std::string strtime[4] = {"sec", "ms", "us", "ns"};
365     double units10 = floor(log10(fdiff));
366     double units3  = std::max(floor(units10 / 3.0), 0.0);
367     double units = pow(10, (units10-fmod(units10, 3.0)));
368     int iunit = static_cast<int>(units3);
369     
370     _startFrequency = newStartFrequency;
371     _stopFrequency = newStopFrequency;
372     _centerFrequency = newCenterFrequency;
373
374     _frequencyDisplayPlot->SetFrequencyRange(_startFrequency,
375                                              _stopFrequency,
376                                              _centerFrequency,
377                                              UseRFFrequenciesCheckBox->isChecked(),
378                                              units, strunits[iunit]);
379     _waterfallDisplayPlot->SetFrequencyRange(_startFrequency,
380                                              _stopFrequency,
381                                              _centerFrequency,
382                                              UseRFFrequenciesCheckBox->isChecked(),
383                                              units, strunits[iunit]);
384     _timeDomainDisplayPlot->SetSampleRate(_stopFrequency - _startFrequency,
385                                           units, strtime[iunit]);
386   }
387 }
388
389 int
390 SpectrumDisplayForm::GetAverageCount()
391 {
392   return _historyVector->size();
393 }
394
395 void
396 SpectrumDisplayForm::SetAverageCount(const int newCount)
397 {
398   if(newCount > -1){
399     if(newCount != static_cast<int>(_historyVector->size())){
400       std::vector<double*>::iterator pos;
401       while(newCount < static_cast<int>(_historyVector->size())){
402         pos = _historyVector->begin();
403         delete[] (*pos);
404         _historyVector->erase(pos);
405       }
406
407       while(newCount > static_cast<int>(_historyVector->size())){
408         _historyVector->push_back(new double[_numRealDataPoints]);
409       }
410       AverageDataReset();
411     }
412   }
413 }
414
415 void
416 SpectrumDisplayForm::_AverageHistory(const double* newBuffer)
417 {
418   if(_numRealDataPoints > 0){
419     if(_historyVector->size() > 0){
420       memcpy(_historyVector->operator[](_historyEntry), newBuffer,
421              _numRealDataPoints*sizeof(double));
422
423       // Increment the next location to store data
424       _historyEntryCount++;
425       if(_historyEntryCount > static_cast<int>(_historyVector->size())){
426         _historyEntryCount = _historyVector->size();
427       }
428       _historyEntry = (++_historyEntry)%_historyVector->size();
429
430       // Total up and then average the values
431       double sum;
432       for(uint64_t location = 0; location < _numRealDataPoints; location++){
433         sum = 0;
434         for(int number = 0; number < _historyEntryCount; number++){
435           sum += _historyVector->operator[](number)[location];
436         }
437         _averagedValues[location] = sum/static_cast<double>(_historyEntryCount);
438       }
439     }
440     else{
441       memcpy(_averagedValues, newBuffer, _numRealDataPoints*sizeof(double));
442     }
443   }
444 }
445
446 void
447 SpectrumDisplayForm::ResizeBuffers( const uint64_t numFFTDataPoints,
448                                     const uint64_t /*numTimeDomainDataPoints*/ )
449 {
450   // Convert from Complex to Real for certain Displays
451   if(_numRealDataPoints != numFFTDataPoints){
452     _numRealDataPoints = numFFTDataPoints;
453     delete[] _realFFTDataPoints;
454     delete[] _averagedValues;
455     
456     _realFFTDataPoints = new double[_numRealDataPoints];
457     _averagedValues = new double[_numRealDataPoints];
458     memset(_realFFTDataPoints, 0x0, _numRealDataPoints*sizeof(double));
459     
460     const int historySize = _historyVector->size();
461     SetAverageCount(0); // Clear the existing history
462     SetAverageCount(historySize);
463     
464     Reset();
465   }
466 }
467
468 void
469 SpectrumDisplayForm::Reset()
470 {
471   AverageDataReset();
472
473   _waterfallDisplayPlot->Reset();
474 }
475
476
477 void
478 SpectrumDisplayForm::AverageDataReset()
479 {
480   _historyEntry = 0;
481   _historyEntryCount = 0;
482
483   memset(_averagedValues, 0x0, _numRealDataPoints*sizeof(double));
484
485   MaxHoldResetBtn_clicked();
486   MinHoldResetBtn_clicked();
487 }
488
489
490 void
491 SpectrumDisplayForm::closeEvent( QCloseEvent *e )
492 {
493   if(_systemSpecifiedFlag){
494     _system->SetWindowOpenFlag(false);
495   }
496
497   qApp->processEvents();
498
499   QWidget::closeEvent(e);
500 }
501
502
503 void
504 SpectrumDisplayForm::WindowTypeChanged( int newItem )
505 {
506   if(_systemSpecifiedFlag){
507    _system->SetWindowType(newItem);
508   }
509 }
510
511
512 void
513 SpectrumDisplayForm::UseRFFrequenciesCB( bool useRFFlag )
514 {
515   SetFrequencyRange(_centerFrequency, _startFrequency, _stopFrequency);
516 }
517
518
519 void
520 SpectrumDisplayForm::waterfallMaximumIntensityChangedCB( double newValue )
521 {
522   if(newValue > WaterfallMinimumIntensityWheel->value()){
523     WaterfallMaximumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
524   }
525   else{
526     WaterfallMaximumIntensityWheel->setValue(WaterfallMinimumIntensityWheel->value());
527   }
528
529   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
530                                            WaterfallMaximumIntensityWheel->value());
531 }
532
533
534 void
535 SpectrumDisplayForm::waterfallMinimumIntensityChangedCB( double newValue )
536 {
537   if(newValue < WaterfallMaximumIntensityWheel->value()){
538     WaterfallMinimumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
539   }
540   else{
541     WaterfallMinimumIntensityWheel->setValue(WaterfallMaximumIntensityWheel->value());
542   }
543
544   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
545                                            WaterfallMaximumIntensityWheel->value());
546 }
547
548 void
549 SpectrumDisplayForm::FFTComboBoxSelectedCB( const QString &fftSizeString )
550 {
551   if(_systemSpecifiedFlag){
552     _system->SetFFTSize(fftSizeString.toLong());
553   }
554 }
555
556
557 void
558 SpectrumDisplayForm::WaterfallAutoScaleBtnCB()
559 {
560   double minimumIntensity = _noiseFloorAmplitude - 5;
561   if(minimumIntensity < WaterfallMinimumIntensityWheel->minValue()){
562     minimumIntensity = WaterfallMinimumIntensityWheel->minValue();
563   }
564   WaterfallMinimumIntensityWheel->setValue(minimumIntensity);
565   double maximumIntensity = _peakAmplitude + 10;
566   if(maximumIntensity > WaterfallMaximumIntensityWheel->maxValue()){
567     maximumIntensity = WaterfallMaximumIntensityWheel->maxValue();
568   }
569   WaterfallMaximumIntensityWheel->setValue(maximumIntensity);
570   waterfallMaximumIntensityChangedCB(maximumIntensity);
571 }
572
573 void
574 SpectrumDisplayForm::WaterfallIntensityColorTypeChanged( int newType )
575 {
576   QColor lowIntensityColor;
577   QColor highIntensityColor;
578   if(newType == WaterfallDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED){
579     // Select the Low Intensity Color
580     lowIntensityColor = _waterfallDisplayPlot->GetUserDefinedLowIntensityColor();
581     if(!lowIntensityColor.isValid()){
582       lowIntensityColor = Qt::black;
583     }
584     QMessageBox::information(this, "Low Intensity Color Selection", "In the next window, select the low intensity color for the waterfall display",  QMessageBox::Ok);
585     lowIntensityColor = QColorDialog::getColor(lowIntensityColor, this);
586     
587     // Select the High Intensity Color
588     highIntensityColor = _waterfallDisplayPlot->GetUserDefinedHighIntensityColor();
589     if(!highIntensityColor.isValid()){
590       highIntensityColor = Qt::white;
591     }
592     QMessageBox::information(this, "High Intensity Color Selection", "In the next window, select the high intensity color for the waterfall display",  QMessageBox::Ok);
593     highIntensityColor = QColorDialog::getColor(highIntensityColor, this);
594   }
595   
596   _waterfallDisplayPlot->SetIntensityColorMapType(newType, lowIntensityColor, highIntensityColor);
597 }
598
599 void
600 SpectrumDisplayForm::ToggleTabFrequency(const bool state)
601 {
602   if(state == true) {
603     if(d_plot_fft == -1) {
604       SpectrumTypeTab->addTab(FrequencyPage, "Frequency Display");
605       d_plot_fft = SpectrumTypeTab->count()-1;
606     }
607   }
608   else {
609     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(FrequencyPage));
610     d_plot_fft = -1;
611   }
612 }
613
614 void
615 SpectrumDisplayForm::ToggleTabWaterfall(const bool state)
616 {
617   if(state == true) {
618     if(d_plot_waterfall == -1) {
619       SpectrumTypeTab->addTab(WaterfallPage, "Waterfall Display");
620       d_plot_waterfall = SpectrumTypeTab->count()-1;
621     }
622   }
623   else {
624     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(WaterfallPage));
625     d_plot_waterfall = -1;
626   }
627 }
628
629 void
630 SpectrumDisplayForm::ToggleTabTime(const bool state)
631 {
632   if(state == true) {
633     if(d_plot_time == -1) {
634       SpectrumTypeTab->addTab(TimeDomainPage, "Time Domain Display");
635       d_plot_time = SpectrumTypeTab->count()-1;
636     }
637   }
638   else {
639     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(TimeDomainPage));
640     d_plot_time = -1;
641   }
642 }
643
644 void
645 SpectrumDisplayForm::ToggleTabConstellation(const bool state)
646 {
647   if(state == true) {
648     if(d_plot_constellation == -1) {
649       SpectrumTypeTab->addTab(ConstellationPage, "Constellation Display");
650       d_plot_constellation = SpectrumTypeTab->count()-1;
651     }
652   }
653   else {
654     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(ConstellationPage));
655     d_plot_constellation = -1;
656   }
657 }
658
659
660 void
661 SpectrumDisplayForm::SetTimeDomainAxis(double min, double max)
662 {
663   _timeDomainDisplayPlot->set_yaxis(min, max);
664 }
665
666 void
667 SpectrumDisplayForm::SetConstellationAxis(double xmin, double xmax,
668                                                 double ymin, double ymax)
669 {
670   _constellationDisplayPlot->set_axis(xmin, xmax, ymin, ymax);
671 }
672
673 void
674 SpectrumDisplayForm::SetConstellationPenSize(int size)
675 {
676   _constellationDisplayPlot->set_pen_size( size );
677 }
678
679 void
680 SpectrumDisplayForm::SetFrequencyAxis(double min, double max)
681 {
682   _frequencyDisplayPlot->set_yaxis(min, max);
683 }
684
685 void
686 SpectrumDisplayForm::SetUpdateTime(double t)
687 {
688   d_update_time = t;
689   // QTimer class takes millisecond input
690   displayTimer->start(d_update_time*1000);
691 }