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