0170f78623afa3d05ed9758ffdddef051a007bbe
[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   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
21     _waterfall3DDisplayPlot = new Waterfall3DDisplayPlot(Waterfall3DPlotDisplayFrame);
22   }
23
24   _timeDomainDisplayPlot = new TimeDomainDisplayPlot(TimeDomainDisplayFrame);
25   _constellationDisplayPlot = new ConstellationDisplayPlot(ConstellationDisplayFrame);
26   _numRealDataPoints = 1024;
27   _realFFTDataPoints = new double[_numRealDataPoints];
28   _averagedValues = new double[_numRealDataPoints];
29   _historyVector = new std::vector<double*>;
30   
31   AvgLineEdit->setRange(0, 500);                 // Set range of Average box value from 0 to 500
32   MinHoldCheckBox_toggled( false );
33   MaxHoldCheckBox_toggled( false );
34   
35   WaterfallMaximumIntensityWheel->setRange(-200, 0);
36   WaterfallMaximumIntensityWheel->setTickCnt(50);
37   WaterfallMinimumIntensityWheel->setRange(-200, 0);
38   WaterfallMinimumIntensityWheel->setTickCnt(50);
39   WaterfallMinimumIntensityWheel->setValue(-200);
40   
41   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
42     Waterfall3DMaximumIntensityWheel->setRange(-200, 0);
43     Waterfall3DMaximumIntensityWheel->setTickCnt(50);
44     Waterfall3DMinimumIntensityWheel->setRange(-200, 0);
45     Waterfall3DMinimumIntensityWheel->setTickCnt(50);
46     Waterfall3DMinimumIntensityWheel->setValue(-200);
47   }
48
49   _peakFrequency = 0;
50   _peakAmplitude = -HUGE_VAL;
51   
52   _noiseFloorAmplitude = -HUGE_VAL;
53
54   connect(_waterfallDisplayPlot, SIGNAL(UpdatedLowerIntensityLevel(const double)), 
55           _frequencyDisplayPlot, SLOT(SetLowerIntensityLevel(const double)));
56   connect(_waterfallDisplayPlot, SIGNAL(UpdatedUpperIntensityLevel(const double)), 
57           _frequencyDisplayPlot, SLOT(SetUpperIntensityLevel(const double)));
58   
59   _frequencyDisplayPlot->SetLowerIntensityLevel(-200);
60   _frequencyDisplayPlot->SetUpperIntensityLevel(-200);
61
62   // Load up the acceptable FFT sizes...
63   FFTSizeComboBox->clear();
64   for(long fftSize = SpectrumGUIClass::MIN_FFT_SIZE; fftSize <= SpectrumGUIClass::MAX_FFT_SIZE; fftSize *= 2){
65     FFTSizeComboBox->insertItem(FFTSizeComboBox->count(), QString("%1").arg(fftSize));
66   }
67   Reset();
68
69   ToggleTabFrequency(false);
70   ToggleTabWaterfall(false);
71   ToggleTabWaterfall3D(false);
72   ToggleTabTime(false);
73   ToggleTabConstellation(false);
74
75   // Create a timer to update plots at the specified rate
76   displayTimer = new QTimer(this);
77   connect(displayTimer, SIGNAL(timeout()), this, SLOT(UpdateGuiTimer()));
78 }
79
80 SpectrumDisplayForm::~SpectrumDisplayForm()
81 {
82   // Qt deletes children when parent is deleted
83
84   // Don't worry about deleting Display Plots - they are deleted when parents are deleted
85   /*   delete _intValidator; */
86
87   delete[] _realFFTDataPoints;
88   delete[] _averagedValues;
89
90   for(unsigned int count = 0; count < _historyVector->size(); count++){
91     delete[] _historyVector->operator[](count);
92   }
93
94   delete _historyVector;
95
96   delete displayTimer;
97 }
98
99 void
100 SpectrumDisplayForm::setSystem( SpectrumGUIClass * newSystem, 
101                                 const uint64_t numFFTDataPoints, 
102                                 const uint64_t numTimeDomainDataPoints )
103 {
104   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
105   
106   if(newSystem != NULL){
107     _system = newSystem;
108     _systemSpecifiedFlag = true;
109   }
110   else{
111     _systemSpecifiedFlag = false;
112   }
113 }
114
115 void
116 SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumUpdateEvent)
117 {
118   //_lastSpectrumEvent = (SpectrumUpdateEvent)(*spectrumUpdateEvent);
119   const std::complex<float>* complexDataPoints = spectrumUpdateEvent->getFFTPoints();
120   const uint64_t numFFTDataPoints = spectrumUpdateEvent->getNumFFTDataPoints();
121   const double* realTimeDomainDataPoints = spectrumUpdateEvent->getRealTimeDomainPoints();
122   const double* imagTimeDomainDataPoints = spectrumUpdateEvent->getImagTimeDomainPoints();
123   const uint64_t numTimeDomainDataPoints = spectrumUpdateEvent->getNumTimeDomainDataPoints();
124   const timespec dataTimestamp = spectrumUpdateEvent->getDataTimestamp();;
125   const bool repeatDataFlag = spectrumUpdateEvent->getRepeatDataFlag();
126   const bool lastOfMultipleUpdatesFlag = spectrumUpdateEvent->getLastOfMultipleUpdateFlag();
127   const timespec generatedTimestamp = spectrumUpdateEvent->getEventGeneratedTimestamp();
128
129   // REMEMBER: The dataTimestamp is NOT valid when the repeat data flag is true...
130   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
131
132   // Calculate the Magnitude of the complex point
133   const std::complex<float>* complexDataPointsPtr = complexDataPoints+numFFTDataPoints/2;
134   double* realFFTDataPointsPtr = _realFFTDataPoints;
135
136   // Run this twice to perform the fftshift operation on the data here as well
137   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
138     // Calculate dBm
139     // 50 ohm load assumption
140     // 10 * log10 (v^2 / (2 * 50.0 * .001)) = 10 * log10( v^2 * 10)
141     // 75 ohm load assumption
142     // 10 * log10 (v^2 / (2 * 75.0 * .001)) = 10 * log10( v^2 * 15)
143
144     // perform scaling here
145     std::complex<float> pt = (*complexDataPointsPtr) / std::complex<float>((float)numFFTDataPoints);
146     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
147
148     complexDataPointsPtr++;
149     realFFTDataPointsPtr++;
150   }
151   
152   // This loop takes the first half of the input data and puts it in the 
153   // second half of the plotted data
154   complexDataPointsPtr = complexDataPoints;
155   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
156     std::complex<float> pt = (*complexDataPointsPtr) / std::complex<float>((float)numFFTDataPoints);
157     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
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     double sumMean;
168     const double fft_bin_size = (_stopFrequency-_startFrequency) /
169       static_cast<double>(numFFTDataPoints);
170
171     // find the peak, sum (for mean), etc
172     _peakAmplitude = -HUGE_VAL;
173     sumMean = 0.0;
174     for(uint64_t number = 0; number < numFFTDataPoints; number++){
175       // find peak
176       if(_realFFTDataPoints[number] > _peakAmplitude){
177         // Calculate the frequency relative to the local bw, adjust for _startFrequency later
178         _peakFrequency = (static_cast<float>(number) * fft_bin_size);
179         _peakAmplitude = _realFFTDataPoints[number];
180         // _peakBin = number;
181       }
182       // sum (for mean)
183       sumMean += _realFFTDataPoints[number];
184     }
185
186     // calculate the spectral mean
187     // +20 because for the comparison below we only want to throw out bins
188     // that are significantly higher (and would, thus, affect the mean more)
189     const double meanAmplitude = (sumMean / numFFTDataPoints) + 20.0;
190
191     // now throw out any bins higher than the mean
192     sumMean = 0.0;
193     uint64_t newNumDataPoints = numFFTDataPoints;
194     for(uint64_t number = 0; number < numFFTDataPoints; number++){
195       if (_realFFTDataPoints[number] <= meanAmplitude)
196         sumMean += _realFFTDataPoints[number];
197       else
198         newNumDataPoints--;
199     }
200
201     if (newNumDataPoints == 0)             // in the odd case that all
202       _noiseFloorAmplitude = meanAmplitude; // amplitudes are equal!
203     else
204       _noiseFloorAmplitude = sumMean / newNumDataPoints;
205   }
206
207   if(lastOfMultipleUpdatesFlag){
208     int tabindex = SpectrumTypeTab->currentIndex();
209     if(tabindex == d_plot_fft) {
210       _frequencyDisplayPlot->PlotNewData(_averagedValues, numFFTDataPoints, 
211                                          _noiseFloorAmplitude, _peakFrequency, 
212                                          _peakAmplitude, d_update_time);
213     }
214     if(tabindex == d_plot_time) {
215       _timeDomainDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
216                                           imagTimeDomainDataPoints, 
217                                           numTimeDomainDataPoints,
218                                           d_update_time);
219     }
220     if(tabindex == d_plot_constellation) {
221       _constellationDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
222                                              imagTimeDomainDataPoints, 
223                                              numTimeDomainDataPoints,
224                                              d_update_time);
225     }
226
227     // Don't update the repeated data for the waterfall
228     if(!repeatDataFlag){
229       if(tabindex == d_plot_waterfall) {
230         _waterfallDisplayPlot->PlotNewData(_realFFTDataPoints, numFFTDataPoints, 
231                                            d_update_time, dataTimestamp, 
232                                            spectrumUpdateEvent->getDroppedFFTFrames());
233       }
234       if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
235         if( _openGLWaterfall3DFlag == 1 && (tabindex == d_plot_waterfall3d)) {
236           _waterfall3DDisplayPlot->PlotNewData(_realFFTDataPoints, numFFTDataPoints, 
237                                                d_update_time, dataTimestamp, 
238                                                spectrumUpdateEvent->getDroppedFFTFrames());
239         }
240       }
241     }
242
243     
244     // Tell the system the GUI has been updated
245     if(_systemSpecifiedFlag){
246       _system->SetLastGUIUpdateTime(generatedTimestamp);
247       _system->DecrementPendingGUIUpdateEvents();
248     }
249   }
250 }
251
252 void
253 SpectrumDisplayForm::resizeEvent( QResizeEvent *e )
254 {
255   QSize s;
256   s.setWidth(FrequencyPlotDisplayFrame->width());
257   s.setHeight(FrequencyPlotDisplayFrame->height());
258   emit _frequencyDisplayPlot->resizeSlot(&s);
259
260   s.setWidth(TimeDomainDisplayFrame->width());
261   s.setHeight(TimeDomainDisplayFrame->height());
262   emit _timeDomainDisplayPlot->resizeSlot(&s);
263
264   s.setWidth(WaterfallPlotDisplayFrame->width());
265   s.setHeight(WaterfallPlotDisplayFrame->height());
266   emit _waterfallDisplayPlot->resizeSlot(&s);
267
268   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
269     s.setWidth(Waterfall3DPlotDisplayFrame->width());
270     s.setHeight(Waterfall3DPlotDisplayFrame->height());
271     emit _waterfall3DDisplayPlot->resizeSlot(&s);
272   }
273
274   s.setWidth(ConstellationDisplayFrame->width());
275   s.setHeight(ConstellationDisplayFrame->height());
276   emit _constellationDisplayPlot->resizeSlot(&s);
277 }
278
279 void
280 SpectrumDisplayForm::customEvent( QEvent * e)
281 {
282   if(e->type() == QEvent::User+3){
283     if(_systemSpecifiedFlag){
284       WindowComboBox->setCurrentIndex(_system->GetWindowType());
285       FFTSizeComboBox->setCurrentIndex(_system->GetFFTSizeIndex());
286       //FFTSizeComboBox->setCurrentIndex(1);
287     }
288
289     waterfallMinimumIntensityChangedCB(WaterfallMinimumIntensityWheel->value());
290     waterfallMaximumIntensityChangedCB(WaterfallMaximumIntensityWheel->value());
291
292     // If the video card doesn't support OpenGL then don't display the 3D Waterfall
293     if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
294       waterfall3DMinimumIntensityChangedCB(Waterfall3DMinimumIntensityWheel->value());
295       waterfall3DMaximumIntensityChangedCB(Waterfall3DMaximumIntensityWheel->value());
296       
297       // Check for Hardware Acceleration of the OpenGL
298       if(!_waterfall3DDisplayPlot->format().directRendering()){
299         // Only ask this once while the program is running...
300         if(_openGLWaterfall3DFlag == -1){
301           _openGLWaterfall3DFlag = 0;
302           if(QMessageBox::warning(this, "OpenGL Direct Rendering NOT Supported", "<center>The system's video card hardware or current drivers do not support direct hardware rendering of the OpenGL modules.</center><br><center>Software rendering is VERY processor intensive.</center><br><center>Do you want to use software rendering?</center>", QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Yes){
303             _openGLWaterfall3DFlag = 1;
304           }
305         }
306       }
307       else{
308         _openGLWaterfall3DFlag = 1;
309       }
310     }
311     
312     if(_openGLWaterfall3DFlag != 1){
313       ToggleTabWaterfall3D(false);
314     }
315
316     // Clear any previous display
317     Reset();
318   }
319   else if(e->type() == 10005){
320     SpectrumUpdateEvent* spectrumUpdateEvent = (SpectrumUpdateEvent*)e;
321     newFrequencyData(spectrumUpdateEvent);
322   }
323   else if(e->type() == 10008){
324     setWindowTitle(((SpectrumWindowCaptionEvent*)e)->getLabel());
325   }
326   else if(e->type() == 10009){
327     Reset();
328     if(_systemSpecifiedFlag){
329       _system->ResetPendingGUIUpdateEvents();
330     }
331   }
332   else if(e->type() == 10010){
333     _startFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStartFrequency();
334     _stopFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStopFrequency();
335     _centerFrequency  = ((SpectrumFrequencyRangeEvent*)e)->GetCenterFrequency();
336
337     UseRFFrequenciesCB(UseRFFrequenciesCheckBox->isChecked());
338   }
339 }
340
341 void
342 SpectrumDisplayForm::UpdateGuiTimer()
343 {
344   // This is called by the displayTimer and redraws the canvases of
345   // all of the plots.
346   _frequencyDisplayPlot->canvas()->update();
347   _waterfallDisplayPlot->canvas()->update();
348   //if((QGLFormat::hasOpenGL()) && (_useOpenGL))
349   //_waterfall3DDisplayPlot->canvas()->update();
350   _timeDomainDisplayPlot->canvas()->update();
351   _constellationDisplayPlot->canvas()->update();
352 }
353
354
355 void
356 SpectrumDisplayForm::AvgLineEdit_valueChanged( int value )
357 {
358   SetAverageCount(value);
359 }
360
361
362 void
363 SpectrumDisplayForm::MaxHoldCheckBox_toggled( bool newState )
364 {
365   MaxHoldResetBtn->setEnabled(newState);
366   _frequencyDisplayPlot->SetMaxFFTVisible(newState);
367   MaxHoldResetBtn_clicked();
368 }
369
370
371 void
372 SpectrumDisplayForm::MinHoldCheckBox_toggled( bool newState )
373 {
374   MinHoldResetBtn->setEnabled(newState);
375   _frequencyDisplayPlot->SetMinFFTVisible(newState);
376   MinHoldResetBtn_clicked();
377 }
378
379
380 void
381 SpectrumDisplayForm::MinHoldResetBtn_clicked()
382 {
383   _frequencyDisplayPlot->ClearMinData();
384   _frequencyDisplayPlot->replot();
385 }
386
387
388 void
389 SpectrumDisplayForm::MaxHoldResetBtn_clicked()
390 {
391   _frequencyDisplayPlot->ClearMaxData();
392   _frequencyDisplayPlot->replot();
393 }
394
395
396 void
397 SpectrumDisplayForm::TabChanged(int index)
398 {
399   // This might be dangerous to call this with NULL
400   resizeEvent(NULL);  
401 }
402
403 void
404 SpectrumDisplayForm::SetFrequencyRange(const double newCenterFrequency,
405                                        const double newStartFrequency, 
406                                        const double newStopFrequency)
407 {
408   double fdiff;
409   if(UseRFFrequenciesCheckBox->isChecked()) {
410     fdiff = newCenterFrequency;
411   }
412   else {
413     fdiff = std::max(fabs(newStartFrequency), fabs(newStopFrequency));
414   }
415
416   if(fdiff > 0) {
417     std::string strunits[4] = {"Hz", "kHz", "MHz", "GHz"};
418     double units10 = floor(log10(fdiff));
419     double units3  = std::max(floor(units10 / 3.0), 0.0);
420     double units = pow(10, (units10-fmod(units10, 3.0)));
421     int iunit = static_cast<int>(units3);
422     
423     _startFrequency = newStartFrequency;
424     _stopFrequency = newStopFrequency;
425     _centerFrequency = newCenterFrequency;
426
427     _frequencyDisplayPlot->SetFrequencyRange(newStartFrequency,
428                                              newStopFrequency,
429                                              newCenterFrequency,
430                                              UseRFFrequenciesCheckBox->isChecked(),
431                                              units, strunits[iunit]);
432     _waterfallDisplayPlot->SetFrequencyRange(newStartFrequency,
433                                              newStopFrequency,
434                                              newCenterFrequency,
435                                              UseRFFrequenciesCheckBox->isChecked(),
436                                              units, strunits[iunit]);
437     if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
438       _waterfall3DDisplayPlot->SetFrequencyRange(newStartFrequency,
439                                                  newStopFrequency,
440                                                  newCenterFrequency,
441                                                  UseRFFrequenciesCheckBox->isChecked(),
442                                                  units, strunits[iunit]);
443     }
444   }
445 }
446
447 int
448 SpectrumDisplayForm::GetAverageCount()
449 {
450   return _historyVector->size();
451 }
452
453 void
454 SpectrumDisplayForm::SetAverageCount(const int newCount)
455 {
456   if(newCount > -1){
457     if(newCount != static_cast<int>(_historyVector->size())){
458       std::vector<double*>::iterator pos;
459       while(newCount < static_cast<int>(_historyVector->size())){
460         pos = _historyVector->begin();
461         delete[] (*pos);
462         _historyVector->erase(pos);
463       }
464
465       while(newCount > static_cast<int>(_historyVector->size())){
466         _historyVector->push_back(new double[_numRealDataPoints]);
467       }
468       AverageDataReset();
469     }
470   }
471 }
472
473 void
474 SpectrumDisplayForm::_AverageHistory(const double* newBuffer)
475 {
476   if(_numRealDataPoints > 0){
477     if(_historyVector->size() > 0){
478       memcpy(_historyVector->operator[](_historyEntry), newBuffer,
479              _numRealDataPoints*sizeof(double));
480
481       // Increment the next location to store data
482       _historyEntryCount++;
483       if(_historyEntryCount > static_cast<int>(_historyVector->size())){
484         _historyEntryCount = _historyVector->size();
485       }
486       _historyEntry = (++_historyEntry)%_historyVector->size();
487
488       // Total up and then average the values
489       double sum;
490       for(uint64_t location = 0; location < _numRealDataPoints; location++){
491         sum = 0;
492         for(int number = 0; number < _historyEntryCount; number++){
493           sum += _historyVector->operator[](number)[location];
494         }
495         _averagedValues[location] = sum/static_cast<double>(_historyEntryCount);
496       }
497     }
498     else{
499       memcpy(_averagedValues, newBuffer, _numRealDataPoints*sizeof(double));
500     }
501   }
502 }
503
504 void
505 SpectrumDisplayForm::ResizeBuffers( const uint64_t numFFTDataPoints,
506                                     const uint64_t /*numTimeDomainDataPoints*/ )
507 {
508   // Convert from Complex to Real for certain Displays
509   if(_numRealDataPoints != numFFTDataPoints){
510     _numRealDataPoints = numFFTDataPoints;
511     delete[] _realFFTDataPoints;
512     delete[] _averagedValues;
513     
514     _realFFTDataPoints = new double[_numRealDataPoints];
515     _averagedValues = new double[_numRealDataPoints];
516     memset(_realFFTDataPoints, 0x0, _numRealDataPoints*sizeof(double));
517     
518     const int historySize = _historyVector->size();
519     SetAverageCount(0); // Clear the existing history
520     SetAverageCount(historySize);
521     
522     Reset();
523   }
524 }
525
526 void
527 SpectrumDisplayForm::Reset()
528 {
529   AverageDataReset();
530
531   _waterfallDisplayPlot->Reset();
532   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
533     _waterfall3DDisplayPlot->Reset();
534   }
535 }
536
537
538 void
539 SpectrumDisplayForm::AverageDataReset()
540 {
541   _historyEntry = 0;
542   _historyEntryCount = 0;
543
544   memset(_averagedValues, 0x0, _numRealDataPoints*sizeof(double));
545
546   MaxHoldResetBtn_clicked();
547   MinHoldResetBtn_clicked();
548 }
549
550
551 void
552 SpectrumDisplayForm::closeEvent( QCloseEvent *e )
553 {
554   if(_systemSpecifiedFlag){
555     _system->SetWindowOpenFlag(false);
556   }
557
558   qApp->processEvents();
559
560   QWidget::closeEvent(e);
561 }
562
563
564 void
565 SpectrumDisplayForm::WindowTypeChanged( int newItem )
566 {
567   if(_systemSpecifiedFlag){
568    _system->SetWindowType(newItem);
569   }
570 }
571
572
573 void
574 SpectrumDisplayForm::UseRFFrequenciesCB( bool useRFFlag )
575 {
576   SetFrequencyRange(_centerFrequency, _startFrequency, _stopFrequency);
577 }
578
579
580 void
581 SpectrumDisplayForm::waterfallMaximumIntensityChangedCB( double newValue )
582 {
583   if(newValue > WaterfallMinimumIntensityWheel->value()){
584     WaterfallMaximumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
585   }
586   else{
587     WaterfallMaximumIntensityWheel->setValue(WaterfallMinimumIntensityWheel->value());
588   }
589
590   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
591                                            WaterfallMaximumIntensityWheel->value());
592 }
593
594
595 void
596 SpectrumDisplayForm::waterfallMinimumIntensityChangedCB( double newValue )
597 {
598   if(newValue < WaterfallMaximumIntensityWheel->value()){
599     WaterfallMinimumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
600   }
601   else{
602     WaterfallMinimumIntensityWheel->setValue(WaterfallMaximumIntensityWheel->value());
603   }
604
605   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
606                                            WaterfallMaximumIntensityWheel->value());
607 }
608
609 void
610 SpectrumDisplayForm::waterfall3DMaximumIntensityChangedCB( double newValue )
611 {
612   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
613     if(newValue > Waterfall3DMinimumIntensityWheel->value()){
614       Waterfall3DMaximumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
615     }
616     else{
617       Waterfall3DMaximumIntensityWheel->setValue(Waterfall3DMinimumIntensityWheel->value());
618     }
619     
620     _waterfall3DDisplayPlot->SetIntensityRange(Waterfall3DMinimumIntensityWheel->value(),
621                                                Waterfall3DMaximumIntensityWheel->value());
622   }
623 }
624
625
626 void
627 SpectrumDisplayForm::waterfall3DMinimumIntensityChangedCB( double newValue )
628 {
629   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
630     if(newValue < Waterfall3DMaximumIntensityWheel->value()){
631       Waterfall3DMinimumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
632     }
633     else{
634       Waterfall3DMinimumIntensityWheel->setValue(Waterfall3DMaximumIntensityWheel->value());
635     }
636     
637     _waterfall3DDisplayPlot->SetIntensityRange(Waterfall3DMinimumIntensityWheel->value(),
638                                                Waterfall3DMaximumIntensityWheel->value());
639   }
640 }
641
642
643 void
644 SpectrumDisplayForm::FFTComboBoxSelectedCB( const QString &fftSizeString )
645 {
646   if(_systemSpecifiedFlag){
647     _system->SetFFTSize(fftSizeString.toLong());
648   }
649 }
650
651
652 void
653 SpectrumDisplayForm::WaterfallAutoScaleBtnCB()
654 {
655   double minimumIntensity = _noiseFloorAmplitude - 5;
656   if(minimumIntensity < WaterfallMinimumIntensityWheel->minValue()){
657     minimumIntensity = WaterfallMinimumIntensityWheel->minValue();
658   }
659   WaterfallMinimumIntensityWheel->setValue(minimumIntensity);
660   double maximumIntensity = _peakAmplitude + 10;
661   if(maximumIntensity > WaterfallMaximumIntensityWheel->maxValue()){
662     maximumIntensity = WaterfallMaximumIntensityWheel->maxValue();
663   }
664   WaterfallMaximumIntensityWheel->setValue(maximumIntensity);
665   waterfallMaximumIntensityChangedCB(maximumIntensity);
666 }
667
668 void
669 SpectrumDisplayForm::Waterfall3DAutoScaleBtnCB()
670 {
671   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
672     double minimumIntensity = _noiseFloorAmplitude - 5;
673     if(minimumIntensity < Waterfall3DMinimumIntensityWheel->minValue()){
674       minimumIntensity = Waterfall3DMinimumIntensityWheel->minValue();
675     }
676     Waterfall3DMinimumIntensityWheel->setValue(minimumIntensity);
677     double maximumIntensity = _peakAmplitude + 10;
678     if(maximumIntensity > Waterfall3DMaximumIntensityWheel->maxValue()){
679       maximumIntensity = Waterfall3DMaximumIntensityWheel->maxValue();
680     }
681     Waterfall3DMaximumIntensityWheel->setValue(maximumIntensity);
682     waterfallMaximumIntensityChangedCB(maximumIntensity);
683   }
684 }
685
686 void
687 SpectrumDisplayForm::WaterfallIntensityColorTypeChanged( int newType )
688 {
689   QColor lowIntensityColor;
690   QColor highIntensityColor;
691   if(newType == WaterfallDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED){
692     // Select the Low Intensity Color
693     lowIntensityColor = _waterfallDisplayPlot->GetUserDefinedLowIntensityColor();
694     if(!lowIntensityColor.isValid()){
695       lowIntensityColor = Qt::black;
696     }
697     QMessageBox::information(this, "Low Intensity Color Selection", "In the next window, select the low intensity color for the waterfall display",  QMessageBox::Ok);
698     lowIntensityColor = QColorDialog::getColor(lowIntensityColor, this);
699     
700     // Select the High Intensity Color
701     highIntensityColor = _waterfallDisplayPlot->GetUserDefinedHighIntensityColor();
702     if(!highIntensityColor.isValid()){
703       highIntensityColor = Qt::white;
704     }
705     QMessageBox::information(this, "High Intensity Color Selection", "In the next window, select the high intensity color for the waterfall display",  QMessageBox::Ok);
706     highIntensityColor = QColorDialog::getColor(highIntensityColor, this);
707   }
708   
709   _waterfallDisplayPlot->SetIntensityColorMapType(newType, lowIntensityColor, highIntensityColor);
710 }
711
712 void
713 SpectrumDisplayForm::Waterfall3DIntensityColorTypeChanged( int newType )
714 {
715   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
716     QColor lowIntensityColor;
717     QColor highIntensityColor;
718     if(newType == Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED){
719       // Select the Low Intensity Color
720       lowIntensityColor = _waterfallDisplayPlot->GetUserDefinedLowIntensityColor();
721       if(!lowIntensityColor.isValid()){
722         lowIntensityColor = Qt::black;
723       }
724       QMessageBox::information(this, "Low Intensity Color Selection", "In the next window, select the low intensity color for the waterfall display",  QMessageBox::Ok);
725       lowIntensityColor = QColorDialog::getColor(lowIntensityColor, this);
726       
727       // Select the High Intensity Color
728       highIntensityColor = _waterfallDisplayPlot->GetUserDefinedHighIntensityColor();
729       if(!highIntensityColor.isValid()){
730         highIntensityColor = Qt::white;
731       }
732       QMessageBox::information(this, "High Intensity Color Selection", "In the next window, select the high intensity color for the waterfall display",  QMessageBox::Ok);
733       highIntensityColor = QColorDialog::getColor(highIntensityColor, this);
734     }
735     _waterfall3DDisplayPlot->SetIntensityColorMapType(newType, lowIntensityColor,
736                                                       highIntensityColor);
737   }
738 }
739
740
741 void
742 SpectrumDisplayForm::ToggleTabFrequency(const bool state)
743 {
744   if(state == true) {
745     if(d_plot_fft == -1) {
746       SpectrumTypeTab->addTab(FrequencyPage, "Frequency Display");
747       d_plot_fft = SpectrumTypeTab->count()-1;
748     }
749   }
750   else {
751     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(FrequencyPage));
752     d_plot_fft = -1;
753   }
754 }
755
756 void
757 SpectrumDisplayForm::ToggleTabWaterfall(const bool state)
758 {
759   if(state == true) {
760     if(d_plot_waterfall == -1) {
761       SpectrumTypeTab->addTab(WaterfallPage, "Waterfall Display");
762       d_plot_waterfall = SpectrumTypeTab->count()-1;
763     }
764   }
765   else {
766     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(WaterfallPage));
767     d_plot_waterfall = -1;
768   }
769 }
770
771 void
772 SpectrumDisplayForm::ToggleTabWaterfall3D(const bool state)
773 {
774   if(state == true) {
775     if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
776       if(d_plot_waterfall3d == -1) {
777         SpectrumTypeTab->addTab(Waterfall3DPage, "3D Waterfall Display");
778         d_plot_waterfall3d = SpectrumTypeTab->count()-1;
779       }
780     }
781   }
782   else {
783     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(Waterfall3DPage));
784     d_plot_waterfall3d = -1;
785   }
786 }
787
788 void
789 SpectrumDisplayForm::ToggleTabTime(const bool state)
790 {
791   if(state == true) {
792     if(d_plot_time == -1) {
793       SpectrumTypeTab->addTab(TimeDomainPage, "Time Domain Display");
794       d_plot_time = SpectrumTypeTab->count()-1;
795     }
796   }
797   else {
798     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(TimeDomainPage));
799     d_plot_time = -1;
800   }
801 }
802
803 void
804 SpectrumDisplayForm::ToggleTabConstellation(const bool state)
805 {
806   if(state == true) {
807     if(d_plot_constellation == -1) {
808       SpectrumTypeTab->addTab(ConstellationPage, "Constellation Display");
809       d_plot_constellation = SpectrumTypeTab->count()-1;
810     }
811   }
812   else {
813     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(ConstellationPage));
814     d_plot_constellation = -1;
815   }
816 }
817
818
819 void
820 SpectrumDisplayForm::SetTimeDomainAxis(double min, double max)
821 {
822   _timeDomainDisplayPlot->set_yaxis(min, max);
823 }
824
825 void
826 SpectrumDisplayForm::SetConstellationAxis(double xmin, double xmax,
827                                                 double ymin, double ymax)
828 {
829   _constellationDisplayPlot->set_axis(xmin, xmax, ymin, ymax);
830 }
831
832 void
833 SpectrumDisplayForm::SetConstellationPenSize(int size)
834 {
835   _constellationDisplayPlot->set_pen_size( size );
836 }
837
838 void
839 SpectrumDisplayForm::SetFrequencyAxis(double min, double max)
840 {
841   _frequencyDisplayPlot->set_yaxis(min, max);
842 }
843
844 void
845 SpectrumDisplayForm::SetUpdateTime(double t)
846 {
847   d_update_time = t;
848   // QTimer class takes millisecond input
849   displayTimer->start(d_update_time*1000);
850 }