Remove one of the loop when posting new data; calculations are done the same time...
[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   displayTimer->stop();
97   delete displayTimer;
98 }
99
100 void
101 SpectrumDisplayForm::setSystem( SpectrumGUIClass * newSystem, 
102                                 const uint64_t numFFTDataPoints, 
103                                 const uint64_t numTimeDomainDataPoints )
104 {
105   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
106   
107   if(newSystem != NULL){
108     _system = newSystem;
109     _systemSpecifiedFlag = true;
110   }
111   else{
112     _systemSpecifiedFlag = false;
113   }
114 }
115
116 void
117 SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumUpdateEvent)
118 {
119   //_lastSpectrumEvent = (SpectrumUpdateEvent)(*spectrumUpdateEvent);
120   const std::complex<float>* complexDataPoints = spectrumUpdateEvent->getFFTPoints();
121   const uint64_t numFFTDataPoints = spectrumUpdateEvent->getNumFFTDataPoints();
122   const double* realTimeDomainDataPoints = spectrumUpdateEvent->getRealTimeDomainPoints();
123   const double* imagTimeDomainDataPoints = spectrumUpdateEvent->getImagTimeDomainPoints();
124   const uint64_t numTimeDomainDataPoints = spectrumUpdateEvent->getNumTimeDomainDataPoints();
125   const timespec dataTimestamp = spectrumUpdateEvent->getDataTimestamp();
126   const bool repeatDataFlag = spectrumUpdateEvent->getRepeatDataFlag();
127   const bool lastOfMultipleUpdatesFlag = spectrumUpdateEvent->getLastOfMultipleUpdateFlag();
128   const timespec generatedTimestamp = spectrumUpdateEvent->getEventGeneratedTimestamp();
129
130   // REMEMBER: The dataTimestamp is NOT valid when the repeat data flag is true...
131   ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints);
132
133   // Calculate the Magnitude of the complex point
134   const std::complex<float>* complexDataPointsPtr = complexDataPoints+numFFTDataPoints/2;
135   double* realFFTDataPointsPtr = _realFFTDataPoints;
136
137   double sumMean, localPeakAmplitude, localPeakFrequency;
138   const double fftBinSize = (_stopFrequency-_startFrequency) /
139     static_cast<double>(numFFTDataPoints);
140   localPeakAmplitude = -HUGE_VAL;
141   sumMean = 0.0;
142
143   // Run this twice to perform the fftshift operation on the data here as well
144   std::complex<float> scaleFactor = std::complex<float>((float)numFFTDataPoints);
145   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
146     std::complex<float> pt = (*complexDataPointsPtr) / scaleFactor;
147     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
148
149     if(*realFFTDataPointsPtr > localPeakAmplitude) {
150       localPeakFrequency = static_cast<float>(point) * fftBinSize;
151       localPeakAmplitude = *realFFTDataPointsPtr;
152     }
153     sumMean += *realFFTDataPointsPtr;
154     
155     complexDataPointsPtr++;
156     realFFTDataPointsPtr++;
157   }
158   
159   // This loop takes the first half of the input data and puts it in the 
160   // second half of the plotted data
161   complexDataPointsPtr = complexDataPoints;
162   for(uint64_t point = 0; point < numFFTDataPoints/2; point++){
163     std::complex<float> pt = (*complexDataPointsPtr) / scaleFactor;
164     *realFFTDataPointsPtr = 10.0*log10((pt.real() * pt.real() + pt.imag()*pt.imag()) + 1e-20);
165
166     if(*realFFTDataPointsPtr > localPeakAmplitude) {
167       localPeakFrequency = static_cast<float>(point) * fftBinSize;
168       localPeakAmplitude = *realFFTDataPointsPtr;
169     }
170     sumMean += *realFFTDataPointsPtr;
171
172     complexDataPointsPtr++;
173     realFFTDataPointsPtr++;
174   }
175
176   // Don't update the averaging history if this is repeated data
177   if(!repeatDataFlag){
178     _AverageHistory(_realFFTDataPoints);
179
180     // Only use the local info if we are not repeating data
181     _peakAmplitude = localPeakAmplitude;
182     _peakFrequency = localPeakFrequency;
183
184     // calculate the spectral mean
185     // +20 because for the comparison below we only want to throw out bins
186     // that are significantly higher (and would, thus, affect the mean more)
187     const double meanAmplitude = (sumMean / numFFTDataPoints) + 20.0;
188
189     // now throw out any bins higher than the mean
190     sumMean = 0.0;
191     uint64_t newNumDataPoints = numFFTDataPoints;
192     for(uint64_t number = 0; number < numFFTDataPoints; number++){
193       if (_realFFTDataPoints[number] <= meanAmplitude)
194         sumMean += _realFFTDataPoints[number];
195       else
196         newNumDataPoints--;
197     }
198
199     if (newNumDataPoints == 0)             // in the odd case that all
200       _noiseFloorAmplitude = meanAmplitude; // amplitudes are equal!
201     else
202       _noiseFloorAmplitude = sumMean / newNumDataPoints;
203   }
204
205   if(lastOfMultipleUpdatesFlag){
206     int tabindex = SpectrumTypeTab->currentIndex();
207     if(tabindex == d_plot_fft) {
208       _frequencyDisplayPlot->PlotNewData(_averagedValues, numFFTDataPoints, 
209                                          _noiseFloorAmplitude, _peakFrequency, 
210                                          _peakAmplitude, d_update_time);
211     }
212     if(tabindex == d_plot_time) {
213       _timeDomainDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
214                                           imagTimeDomainDataPoints, 
215                                           numTimeDomainDataPoints,
216                                           d_update_time);
217     }
218     if(tabindex == d_plot_constellation) {
219       _constellationDisplayPlot->PlotNewData(realTimeDomainDataPoints, 
220                                              imagTimeDomainDataPoints, 
221                                              numTimeDomainDataPoints,
222                                              d_update_time);
223     }
224
225     // Don't update the repeated data for the waterfall
226     if(!repeatDataFlag){
227       if(tabindex == d_plot_waterfall) {
228         _waterfallDisplayPlot->PlotNewData(_realFFTDataPoints, numFFTDataPoints, 
229                                            d_update_time, dataTimestamp, 
230                                            spectrumUpdateEvent->getDroppedFFTFrames());
231       }
232       /*
233       if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
234         if( _openGLWaterfall3DFlag == 1 && (tabindex == d_plot_waterfall3d)) {
235           _waterfall3DDisplayPlot->PlotNewData(_realFFTDataPoints, numFFTDataPoints, 
236                                                d_update_time, dataTimestamp, 
237                                                spectrumUpdateEvent->getDroppedFFTFrames());
238         }
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       /*
299       if(!_waterfall3DDisplayPlot->format().directRendering()){
300         // Only ask this once while the program is running...
301         if(_openGLWaterfall3DFlag == -1){
302           _openGLWaterfall3DFlag = 0;
303           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){
304             _openGLWaterfall3DFlag = 1;
305           }
306         }
307       }
308       else{
309         _openGLWaterfall3DFlag = 1;
310       }
311       */
312     }
313     
314     if(_openGLWaterfall3DFlag != 1){
315       ToggleTabWaterfall3D(false);
316     }
317
318     // Clear any previous display
319     Reset();
320   }
321   else if(e->type() == 10005){
322     SpectrumUpdateEvent* spectrumUpdateEvent = (SpectrumUpdateEvent*)e;
323     newFrequencyData(spectrumUpdateEvent);
324   }
325   else if(e->type() == 10008){
326     setWindowTitle(((SpectrumWindowCaptionEvent*)e)->getLabel());
327   }
328   else if(e->type() == 10009){
329     Reset();
330     if(_systemSpecifiedFlag){
331       _system->ResetPendingGUIUpdateEvents();
332     }
333   }
334   else if(e->type() == 10010){
335     _startFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStartFrequency();
336     _stopFrequency = ((SpectrumFrequencyRangeEvent*)e)->GetStopFrequency();
337     _centerFrequency  = ((SpectrumFrequencyRangeEvent*)e)->GetCenterFrequency();
338
339     UseRFFrequenciesCB(UseRFFrequenciesCheckBox->isChecked());
340   }
341 }
342
343 void
344 SpectrumDisplayForm::UpdateGuiTimer()
345 {
346   // This is called by the displayTimer and redraws the canvases of
347   // all of the plots.
348   _frequencyDisplayPlot->canvas()->update();
349   _waterfallDisplayPlot->canvas()->update();
350   //if((QGLFormat::hasOpenGL()) && (_useOpenGL))
351   //_waterfall3DDisplayPlot->canvas()->update();
352   _timeDomainDisplayPlot->canvas()->update();
353   _constellationDisplayPlot->canvas()->update();
354 }
355
356
357 void
358 SpectrumDisplayForm::AvgLineEdit_valueChanged( int value )
359 {
360   SetAverageCount(value);
361 }
362
363
364 void
365 SpectrumDisplayForm::MaxHoldCheckBox_toggled( bool newState )
366 {
367   MaxHoldResetBtn->setEnabled(newState);
368   _frequencyDisplayPlot->SetMaxFFTVisible(newState);
369   MaxHoldResetBtn_clicked();
370 }
371
372
373 void
374 SpectrumDisplayForm::MinHoldCheckBox_toggled( bool newState )
375 {
376   MinHoldResetBtn->setEnabled(newState);
377   _frequencyDisplayPlot->SetMinFFTVisible(newState);
378   MinHoldResetBtn_clicked();
379 }
380
381
382 void
383 SpectrumDisplayForm::MinHoldResetBtn_clicked()
384 {
385   _frequencyDisplayPlot->ClearMinData();
386   _frequencyDisplayPlot->replot();
387 }
388
389
390 void
391 SpectrumDisplayForm::MaxHoldResetBtn_clicked()
392 {
393   _frequencyDisplayPlot->ClearMaxData();
394   _frequencyDisplayPlot->replot();
395 }
396
397
398 void
399 SpectrumDisplayForm::TabChanged(int index)
400 {
401   // This might be dangerous to call this with NULL
402   resizeEvent(NULL);  
403 }
404
405 void
406 SpectrumDisplayForm::SetFrequencyRange(const double newCenterFrequency,
407                                        const double newStartFrequency, 
408                                        const double newStopFrequency)
409 {
410   double fdiff;
411   if(UseRFFrequenciesCheckBox->isChecked()) {
412     fdiff = newCenterFrequency;
413   }
414   else {
415     fdiff = std::max(fabs(newStartFrequency), fabs(newStopFrequency));
416   }
417
418   if(fdiff > 0) {
419     std::string strunits[4] = {"Hz", "kHz", "MHz", "GHz"};
420     std::string strtime[4] = {"sec", "ms", "us", "ns"};
421     double units10 = floor(log10(fdiff));
422     double units3  = std::max(floor(units10 / 3.0), 0.0);
423     double units = pow(10, (units10-fmod(units10, 3.0)));
424     int iunit = static_cast<int>(units3);
425     
426     _startFrequency = newStartFrequency;
427     _stopFrequency = newStopFrequency;
428     _centerFrequency = newCenterFrequency;
429
430     _frequencyDisplayPlot->SetFrequencyRange(_startFrequency,
431                                              _stopFrequency,
432                                              _centerFrequency,
433                                              UseRFFrequenciesCheckBox->isChecked(),
434                                              units, strunits[iunit]);
435     _waterfallDisplayPlot->SetFrequencyRange(_startFrequency,
436                                              _stopFrequency,
437                                              _centerFrequency,
438                                              UseRFFrequenciesCheckBox->isChecked(),
439                                              units, strunits[iunit]);
440     if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
441       /*
442       _waterfall3DDisplayPlot->SetFrequencyRange(_startFrequency,
443                                                  _stopFrequency,
444                                                  _centerFrequency,
445                                                  UseRFFrequenciesCheckBox->isChecked(),
446                                                  units, strunits[iunit]);
447       */
448     }
449     _timeDomainDisplayPlot->SetSampleRate(_stopFrequency - _startFrequency,
450                                           units, strtime[iunit]);
451   }
452 }
453
454 int
455 SpectrumDisplayForm::GetAverageCount()
456 {
457   return _historyVector->size();
458 }
459
460 void
461 SpectrumDisplayForm::SetAverageCount(const int newCount)
462 {
463   if(newCount > -1){
464     if(newCount != static_cast<int>(_historyVector->size())){
465       std::vector<double*>::iterator pos;
466       while(newCount < static_cast<int>(_historyVector->size())){
467         pos = _historyVector->begin();
468         delete[] (*pos);
469         _historyVector->erase(pos);
470       }
471
472       while(newCount > static_cast<int>(_historyVector->size())){
473         _historyVector->push_back(new double[_numRealDataPoints]);
474       }
475       AverageDataReset();
476     }
477   }
478 }
479
480 void
481 SpectrumDisplayForm::_AverageHistory(const double* newBuffer)
482 {
483   if(_numRealDataPoints > 0){
484     if(_historyVector->size() > 0){
485       memcpy(_historyVector->operator[](_historyEntry), newBuffer,
486              _numRealDataPoints*sizeof(double));
487
488       // Increment the next location to store data
489       _historyEntryCount++;
490       if(_historyEntryCount > static_cast<int>(_historyVector->size())){
491         _historyEntryCount = _historyVector->size();
492       }
493       _historyEntry = (++_historyEntry)%_historyVector->size();
494
495       // Total up and then average the values
496       double sum;
497       for(uint64_t location = 0; location < _numRealDataPoints; location++){
498         sum = 0;
499         for(int number = 0; number < _historyEntryCount; number++){
500           sum += _historyVector->operator[](number)[location];
501         }
502         _averagedValues[location] = sum/static_cast<double>(_historyEntryCount);
503       }
504     }
505     else{
506       memcpy(_averagedValues, newBuffer, _numRealDataPoints*sizeof(double));
507     }
508   }
509 }
510
511 void
512 SpectrumDisplayForm::ResizeBuffers( const uint64_t numFFTDataPoints,
513                                     const uint64_t /*numTimeDomainDataPoints*/ )
514 {
515   // Convert from Complex to Real for certain Displays
516   if(_numRealDataPoints != numFFTDataPoints){
517     _numRealDataPoints = numFFTDataPoints;
518     delete[] _realFFTDataPoints;
519     delete[] _averagedValues;
520     
521     _realFFTDataPoints = new double[_numRealDataPoints];
522     _averagedValues = new double[_numRealDataPoints];
523     memset(_realFFTDataPoints, 0x0, _numRealDataPoints*sizeof(double));
524     
525     const int historySize = _historyVector->size();
526     SetAverageCount(0); // Clear the existing history
527     SetAverageCount(historySize);
528     
529     Reset();
530   }
531 }
532
533 void
534 SpectrumDisplayForm::Reset()
535 {
536   AverageDataReset();
537
538   _waterfallDisplayPlot->Reset();
539   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
540     //_waterfall3DDisplayPlot->Reset();
541   }
542 }
543
544
545 void
546 SpectrumDisplayForm::AverageDataReset()
547 {
548   _historyEntry = 0;
549   _historyEntryCount = 0;
550
551   memset(_averagedValues, 0x0, _numRealDataPoints*sizeof(double));
552
553   MaxHoldResetBtn_clicked();
554   MinHoldResetBtn_clicked();
555 }
556
557
558 void
559 SpectrumDisplayForm::closeEvent( QCloseEvent *e )
560 {
561   if(_systemSpecifiedFlag){
562     _system->SetWindowOpenFlag(false);
563   }
564
565   qApp->processEvents();
566
567   QWidget::closeEvent(e);
568 }
569
570
571 void
572 SpectrumDisplayForm::WindowTypeChanged( int newItem )
573 {
574   if(_systemSpecifiedFlag){
575    _system->SetWindowType(newItem);
576   }
577 }
578
579
580 void
581 SpectrumDisplayForm::UseRFFrequenciesCB( bool useRFFlag )
582 {
583   SetFrequencyRange(_centerFrequency, _startFrequency, _stopFrequency);
584 }
585
586
587 void
588 SpectrumDisplayForm::waterfallMaximumIntensityChangedCB( double newValue )
589 {
590   if(newValue > WaterfallMinimumIntensityWheel->value()){
591     WaterfallMaximumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
592   }
593   else{
594     WaterfallMaximumIntensityWheel->setValue(WaterfallMinimumIntensityWheel->value());
595   }
596
597   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
598                                            WaterfallMaximumIntensityWheel->value());
599 }
600
601
602 void
603 SpectrumDisplayForm::waterfallMinimumIntensityChangedCB( double newValue )
604 {
605   if(newValue < WaterfallMaximumIntensityWheel->value()){
606     WaterfallMinimumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
607   }
608   else{
609     WaterfallMinimumIntensityWheel->setValue(WaterfallMaximumIntensityWheel->value());
610   }
611
612   _waterfallDisplayPlot->SetIntensityRange(WaterfallMinimumIntensityWheel->value(),
613                                            WaterfallMaximumIntensityWheel->value());
614 }
615
616 void
617 SpectrumDisplayForm::waterfall3DMaximumIntensityChangedCB( double newValue )
618 {
619   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
620     if(newValue > Waterfall3DMinimumIntensityWheel->value()){
621       Waterfall3DMaximumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
622     }
623     else{
624       Waterfall3DMaximumIntensityWheel->setValue(Waterfall3DMinimumIntensityWheel->value());
625     }
626
627     /*
628     _waterfall3DDisplayPlot->SetIntensityRange(Waterfall3DMinimumIntensityWheel->value(),
629                                                Waterfall3DMaximumIntensityWheel->value());
630     */
631   }
632 }
633
634
635 void
636 SpectrumDisplayForm::waterfall3DMinimumIntensityChangedCB( double newValue )
637 {
638   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
639     if(newValue < Waterfall3DMaximumIntensityWheel->value()){
640       Waterfall3DMinimumIntensityLabel->setText(QString("%1 dB").arg(newValue, 0, 'f', 0));
641     }
642     else{
643       Waterfall3DMinimumIntensityWheel->setValue(Waterfall3DMaximumIntensityWheel->value());
644     }
645
646     /*
647     _waterfall3DDisplayPlot->SetIntensityRange(Waterfall3DMinimumIntensityWheel->value(),
648                                                Waterfall3DMaximumIntensityWheel->value());
649     */
650   }
651 }
652
653
654 void
655 SpectrumDisplayForm::FFTComboBoxSelectedCB( const QString &fftSizeString )
656 {
657   if(_systemSpecifiedFlag){
658     _system->SetFFTSize(fftSizeString.toLong());
659   }
660 }
661
662
663 void
664 SpectrumDisplayForm::WaterfallAutoScaleBtnCB()
665 {
666   double minimumIntensity = _noiseFloorAmplitude - 5;
667   if(minimumIntensity < WaterfallMinimumIntensityWheel->minValue()){
668     minimumIntensity = WaterfallMinimumIntensityWheel->minValue();
669   }
670   WaterfallMinimumIntensityWheel->setValue(minimumIntensity);
671   double maximumIntensity = _peakAmplitude + 10;
672   if(maximumIntensity > WaterfallMaximumIntensityWheel->maxValue()){
673     maximumIntensity = WaterfallMaximumIntensityWheel->maxValue();
674   }
675   WaterfallMaximumIntensityWheel->setValue(maximumIntensity);
676   waterfallMaximumIntensityChangedCB(maximumIntensity);
677 }
678
679 void
680 SpectrumDisplayForm::Waterfall3DAutoScaleBtnCB()
681 {
682   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
683     double minimumIntensity = _noiseFloorAmplitude - 5;
684     if(minimumIntensity < Waterfall3DMinimumIntensityWheel->minValue()){
685       minimumIntensity = Waterfall3DMinimumIntensityWheel->minValue();
686     }
687     Waterfall3DMinimumIntensityWheel->setValue(minimumIntensity);
688     double maximumIntensity = _peakAmplitude + 10;
689     if(maximumIntensity > Waterfall3DMaximumIntensityWheel->maxValue()){
690       maximumIntensity = Waterfall3DMaximumIntensityWheel->maxValue();
691     }
692     Waterfall3DMaximumIntensityWheel->setValue(maximumIntensity);
693     waterfallMaximumIntensityChangedCB(maximumIntensity);
694   }
695 }
696
697 void
698 SpectrumDisplayForm::WaterfallIntensityColorTypeChanged( int newType )
699 {
700   QColor lowIntensityColor;
701   QColor highIntensityColor;
702   if(newType == WaterfallDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED){
703     // Select the Low Intensity Color
704     lowIntensityColor = _waterfallDisplayPlot->GetUserDefinedLowIntensityColor();
705     if(!lowIntensityColor.isValid()){
706       lowIntensityColor = Qt::black;
707     }
708     QMessageBox::information(this, "Low Intensity Color Selection", "In the next window, select the low intensity color for the waterfall display",  QMessageBox::Ok);
709     lowIntensityColor = QColorDialog::getColor(lowIntensityColor, this);
710     
711     // Select the High Intensity Color
712     highIntensityColor = _waterfallDisplayPlot->GetUserDefinedHighIntensityColor();
713     if(!highIntensityColor.isValid()){
714       highIntensityColor = Qt::white;
715     }
716     QMessageBox::information(this, "High Intensity Color Selection", "In the next window, select the high intensity color for the waterfall display",  QMessageBox::Ok);
717     highIntensityColor = QColorDialog::getColor(highIntensityColor, this);
718   }
719   
720   _waterfallDisplayPlot->SetIntensityColorMapType(newType, lowIntensityColor, highIntensityColor);
721 }
722
723 void
724 SpectrumDisplayForm::Waterfall3DIntensityColorTypeChanged( int newType )
725 {
726   if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
727     QColor lowIntensityColor;
728     QColor highIntensityColor;
729     if(newType == Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED){
730       // Select the Low Intensity Color
731       lowIntensityColor = _waterfallDisplayPlot->GetUserDefinedLowIntensityColor();
732       if(!lowIntensityColor.isValid()){
733         lowIntensityColor = Qt::black;
734       }
735       QMessageBox::information(this, "Low Intensity Color Selection", "In the next window, select the low intensity color for the waterfall display",  QMessageBox::Ok);
736       lowIntensityColor = QColorDialog::getColor(lowIntensityColor, this);
737       
738       // Select the High Intensity Color
739       highIntensityColor = _waterfallDisplayPlot->GetUserDefinedHighIntensityColor();
740       if(!highIntensityColor.isValid()){
741         highIntensityColor = Qt::white;
742       }
743       QMessageBox::information(this, "High Intensity Color Selection", "In the next window, select the high intensity color for the waterfall display",  QMessageBox::Ok);
744       highIntensityColor = QColorDialog::getColor(highIntensityColor, this);
745     }
746     /*
747     _waterfall3DDisplayPlot->SetIntensityColorMapType(newType, lowIntensityColor,
748                                                       highIntensityColor);
749     */
750   }
751 }
752
753
754 void
755 SpectrumDisplayForm::ToggleTabFrequency(const bool state)
756 {
757   if(state == true) {
758     if(d_plot_fft == -1) {
759       SpectrumTypeTab->addTab(FrequencyPage, "Frequency Display");
760       d_plot_fft = SpectrumTypeTab->count()-1;
761     }
762   }
763   else {
764     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(FrequencyPage));
765     d_plot_fft = -1;
766   }
767 }
768
769 void
770 SpectrumDisplayForm::ToggleTabWaterfall(const bool state)
771 {
772   if(state == true) {
773     if(d_plot_waterfall == -1) {
774       SpectrumTypeTab->addTab(WaterfallPage, "Waterfall Display");
775       d_plot_waterfall = SpectrumTypeTab->count()-1;
776     }
777   }
778   else {
779     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(WaterfallPage));
780     d_plot_waterfall = -1;
781   }
782 }
783
784 void
785 SpectrumDisplayForm::ToggleTabWaterfall3D(const bool state)
786 {
787   if(state == true) {
788     /*
789     if((QGLFormat::hasOpenGL()) && (_useOpenGL)) {
790       if(d_plot_waterfall3d == -1) {
791         SpectrumTypeTab->addTab(Waterfall3DPage, "3D Waterfall Display");
792         d_plot_waterfall3d = SpectrumTypeTab->count()-1;
793       }
794     }
795     */
796     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(Waterfall3DPage));
797     d_plot_waterfall3d = -1;
798     fprintf(stderr, "\nWARNING: The Waterfall3D plot has been disabled until we get it working.\n\n");
799   }
800   else {
801     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(Waterfall3DPage));
802     d_plot_waterfall3d = -1;
803   }
804 }
805
806 void
807 SpectrumDisplayForm::ToggleTabTime(const bool state)
808 {
809   if(state == true) {
810     if(d_plot_time == -1) {
811       SpectrumTypeTab->addTab(TimeDomainPage, "Time Domain Display");
812       d_plot_time = SpectrumTypeTab->count()-1;
813     }
814   }
815   else {
816     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(TimeDomainPage));
817     d_plot_time = -1;
818   }
819 }
820
821 void
822 SpectrumDisplayForm::ToggleTabConstellation(const bool state)
823 {
824   if(state == true) {
825     if(d_plot_constellation == -1) {
826       SpectrumTypeTab->addTab(ConstellationPage, "Constellation Display");
827       d_plot_constellation = SpectrumTypeTab->count()-1;
828     }
829   }
830   else {
831     SpectrumTypeTab->removeTab(SpectrumTypeTab->indexOf(ConstellationPage));
832     d_plot_constellation = -1;
833   }
834 }
835
836
837 void
838 SpectrumDisplayForm::SetTimeDomainAxis(double min, double max)
839 {
840   _timeDomainDisplayPlot->set_yaxis(min, max);
841 }
842
843 void
844 SpectrumDisplayForm::SetConstellationAxis(double xmin, double xmax,
845                                                 double ymin, double ymax)
846 {
847   _constellationDisplayPlot->set_axis(xmin, xmax, ymin, ymax);
848 }
849
850 void
851 SpectrumDisplayForm::SetConstellationPenSize(int size)
852 {
853   _constellationDisplayPlot->set_pen_size( size );
854 }
855
856 void
857 SpectrumDisplayForm::SetFrequencyAxis(double min, double max)
858 {
859   _frequencyDisplayPlot->set_yaxis(min, max);
860 }
861
862 void
863 SpectrumDisplayForm::SetUpdateTime(double t)
864 {
865   d_update_time = t;
866   // QTimer class takes millisecond input
867   displayTimer->start(d_update_time*1000);
868 }