1 #ifndef FREQUENCY_DISPLAY_PLOT_C
2 #define FREQUENCY_DISPLAY_PLOT_C
4 #include <FrequencyDisplayPlot.h>
6 #include <qwt_scale_draw.h>
8 class FreqPrecisionClass
11 FreqPrecisionClass(const int freqPrecision)
13 _frequencyPrecision = freqPrecision;
16 virtual ~FreqPrecisionClass()
20 virtual unsigned int GetFrequencyPrecision() const
22 return _frequencyPrecision;
25 virtual void SetFrequencyPrecision(const unsigned int newPrecision)
27 _frequencyPrecision = newPrecision;
30 unsigned int _frequencyPrecision;
36 class FreqDisplayScaleDraw: public QwtScaleDraw, public FreqPrecisionClass
39 FreqDisplayScaleDraw(const unsigned int precision)
40 : QwtScaleDraw(), FreqPrecisionClass(precision)
44 virtual ~FreqDisplayScaleDraw()
48 virtual QwtText label(double value) const
50 return QString("%1").arg(value, 0, 'f', GetFrequencyPrecision());
59 class FreqDisplayZoomer: public QwtPlotZoomer, public FreqPrecisionClass
62 FreqDisplayZoomer(QwtPlotCanvas* canvas, const unsigned int freqPrecision)
63 : QwtPlotZoomer(canvas),FreqPrecisionClass(freqPrecision)
65 setTrackerMode(QwtPicker::AlwaysOn);
68 virtual ~FreqDisplayZoomer(){
72 virtual void updateTrackerText(){
77 virtual QwtText trackerText( const QwtDoublePoint& p ) const
79 QwtText t(QString("%1 %2, %3 dB").arg(p.x(), 0, 'f', GetFrequencyPrecision()).arg( (GetFrequencyPrecision() == 0) ? "Hz" : "kHz").arg(p.y(), 0, 'f', 2));
85 FrequencyDisplayPlot::FrequencyDisplayPlot(QWidget* parent)
89 _stopFrequency = 4000;
91 timespec_reset(&_lastReplot);
93 resize(parent->width(), parent->height());
95 _displayIntervalTime = (1.0/10.0); // 1/10 of a second between updates
97 _useCenterFrequencyFlag = false;
100 _dataPoints = new double[_numPoints];
101 _minFFTPoints = new double[_numPoints];
102 _maxFFTPoints = new double[_numPoints];
103 _xAxisPoints = new double[_numPoints];
105 // Disable polygon clipping
106 QwtPainter::setDeviceClipping(false);
108 // We don't need the cache here
109 canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
110 canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
113 palette.setColor(canvas()->backgroundRole(), QColor("white"));
114 canvas()->setPalette(palette);
116 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0));
117 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
118 setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
122 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
123 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
124 setAxisTitle(QwtPlot::yLeft, "Power (dB)");
126 // Automatically deleted when parent is deleted
127 _fft_plot_curve = new QwtPlotCurve("Power Spectrum");
128 _fft_plot_curve->attach(this);
129 _fft_plot_curve->setPen(QPen(Qt::blue));
130 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
132 _min_fft_plot_curve = new QwtPlotCurve("Minimum Power");
133 _min_fft_plot_curve->attach(this);
134 _min_fft_plot_curve->setPen(QPen(Qt::magenta));
135 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
136 _min_fft_plot_curve->setVisible(false);
138 _max_fft_plot_curve = new QwtPlotCurve("Maximum Power");
139 _max_fft_plot_curve->attach(this);
140 _max_fft_plot_curve->setPen(QPen(Qt::darkYellow));
141 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
142 _max_fft_plot_curve->setVisible(false);
144 _lower_intensity_marker = new QwtPlotMarker();
145 _lower_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
146 _lower_intensity_marker->setLinePen(QPen(Qt::cyan));
147 _lower_intensity_marker->attach(this);
149 _upper_intensity_marker = new QwtPlotMarker();
150 _upper_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
151 _upper_intensity_marker->setLinePen(QPen(Qt::green));
152 _upper_intensity_marker->attach(this);
154 memset(_dataPoints, 0x0, _numPoints*sizeof(double));
155 memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
157 for(int64_t number = 0; number < _numPoints; number++){
158 _minFFTPoints[number] = 200.0;
159 _maxFFTPoints[number] = -280.0;
165 // set up peak marker
168 _markerPeakAmplitude = new QwtPlotMarker();
169 _markerPeakAmplitude->setLinePen(QPen(Qt::yellow));
170 symbol.setStyle(QwtSymbol::Diamond);
172 symbol.setPen(QPen(Qt::yellow));
173 symbol.setBrush(QBrush(Qt::yellow));
174 _markerPeakAmplitude->setSymbol(symbol);
175 _markerPeakAmplitude->attach(this);
177 _markerNoiseFloorAmplitude = new QwtPlotMarker();
178 _markerNoiseFloorAmplitude->setLineStyle(QwtPlotMarker::HLine);
179 _markerNoiseFloorAmplitude->setLinePen(QPen(Qt::darkRed, 0, Qt::DotLine));
180 _markerNoiseFloorAmplitude->attach(this);
183 _peakAmplitude = -HUGE_VAL;
185 _noiseFloorAmplitude = -HUGE_VAL;
189 _zoomer = new FreqDisplayZoomer(canvas(), 0);
190 #if QT_VERSION < 0x040000
191 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
192 Qt::RightButton, Qt::ControlModifier);
194 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
195 Qt::RightButton, Qt::ControlModifier);
197 _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
200 _panner = new QwtPlotPanner(canvas());
201 _panner->setAxisEnabled(QwtPlot::yRight, false);
202 _panner->setMouseButton(Qt::MidButton);
204 // Avoid jumping when labels with more/less digits
205 // appear/disappear when scrolling vertically
207 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
208 QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
209 sd->setMinimumExtent( fm.width("100.00") );
211 const QColor c(Qt::darkRed);
212 _zoomer->setRubberBandPen(c);
213 _zoomer->setTrackerPen(c);
216 FrequencyDisplayPlot::~FrequencyDisplayPlot()
218 delete[] _dataPoints;
219 delete[] _maxFFTPoints;
220 delete[] _minFFTPoints;
221 delete[] _xAxisPoints;
223 // _fft_plot_curves deleted when parent deleted
224 // _zoomer and _panner deleted when parent deleted
228 FrequencyDisplayPlot::set_yaxis(double min, double max)
230 // Get the new max/min values for the plot
234 // Set the axis max/min to the new values
235 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
237 // Reset the base zoom level to the new axis scale set here
238 _zoomer->setZoomBase();
242 FrequencyDisplayPlot::SetFrequencyRange(const double constStartFreq,
243 const double constStopFreq,
244 const double constCenterFreq,
245 const bool useCenterFrequencyFlag,
246 const double units, const std::string &strunits)
248 double startFreq = constStartFreq / units;
249 double stopFreq = constStopFreq / units;
250 double centerFreq = constCenterFreq / units;
252 _useCenterFrequencyFlag = useCenterFrequencyFlag;
254 if(_useCenterFrequencyFlag){
255 startFreq = (startFreq + centerFreq);
256 stopFreq = (stopFreq + centerFreq);
259 _startFrequency = startFreq;
260 _stopFrequency = stopFreq;
263 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
264 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(2));
265 setAxisTitle(QwtPlot::xBottom, QString("Frequency (%1)").arg(strunits.c_str()));
266 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(2);
268 // Load up the new base zoom settings
269 _zoomer->setZoomBase();
271 // Zooms back to the base and clears any other zoom levels
277 FrequencyDisplayPlot::GetStartFrequency() const
279 return _startFrequency;
283 FrequencyDisplayPlot::GetStopFrequency() const
285 return _stopFrequency;
289 FrequencyDisplayPlot::replot()
291 const timespec startTime = get_highres_clock();
293 _markerNoiseFloorAmplitude->setYValue(_noiseFloorAmplitude);
295 // Make sure to take into account the start frequency
296 if(_useCenterFrequencyFlag){
297 _markerPeakAmplitude->setXValue((_peakFrequency/1000.0) + _startFrequency);
300 _markerPeakAmplitude->setXValue(_peakFrequency + _startFrequency);
302 _markerPeakAmplitude->setYValue(_peakAmplitude);
306 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
308 differenceTime *= 99.0;
309 // Require at least a 10% duty cycle
310 if(differenceTime > (1.0/10.0)){
311 _displayIntervalTime = differenceTime;
316 FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints,
317 const double noiseFloorAmplitude, const double peakFrequency,
318 const double peakAmplitude)
320 if(numDataPoints > 0){
322 if(numDataPoints != _numPoints){
323 _numPoints = numDataPoints;
325 delete[] _dataPoints;
326 delete[] _minFFTPoints;
327 delete[] _maxFFTPoints;
328 delete[] _xAxisPoints;
329 _dataPoints = new double[_numPoints];
330 _xAxisPoints = new double[_numPoints];
331 _minFFTPoints = new double[_numPoints];
332 _maxFFTPoints = new double[_numPoints];
334 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
335 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
336 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
342 memcpy(_dataPoints, dataPoints, numDataPoints*sizeof(double));
343 for(int64_t point = 0; point < numDataPoints; point++){
344 if(dataPoints[point] < _minFFTPoints[point]){
345 _minFFTPoints[point] = dataPoints[point];
347 if(dataPoints[point] > _maxFFTPoints[point]){
348 _maxFFTPoints[point] = dataPoints[point];
352 _noiseFloorAmplitude = noiseFloorAmplitude;
353 _peakFrequency = peakFrequency;
354 _peakAmplitude = peakAmplitude;
358 // Allow at least a 50% duty cycle
359 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
360 // Only replot the screen if it is visible
364 _lastReplot = get_highres_clock();
369 FrequencyDisplayPlot::ClearMaxData()
371 for(int64_t number = 0; number < _numPoints; number++){
372 _maxFFTPoints[number] = _maxYAxis;
377 FrequencyDisplayPlot::ClearMinData()
379 for(int64_t number = 0; number < _numPoints; number++){
380 _minFFTPoints[number] = _minYAxis;
385 FrequencyDisplayPlot::SetMaxFFTVisible(const bool visibleFlag)
387 _max_fft_plot_curve->setVisible(visibleFlag);
391 FrequencyDisplayPlot::SetMinFFTVisible(const bool visibleFlag)
393 _min_fft_plot_curve->setVisible(visibleFlag);
397 FrequencyDisplayPlot::_resetXAxisPoints()
399 double fft_bin_size = (_stopFrequency-_startFrequency) / static_cast<double>(_numPoints);
400 double freqValue = _startFrequency;
401 for(int64_t loc = 0; loc < _numPoints; loc++){
402 _xAxisPoints[loc] = freqValue;
403 freqValue += fft_bin_size;
408 FrequencyDisplayPlot::SetLowerIntensityLevel(const double lowerIntensityLevel)
410 _lower_intensity_marker->setYValue( lowerIntensityLevel );
414 FrequencyDisplayPlot::SetUpperIntensityLevel(const double upperIntensityLevel)
416 _upper_intensity_marker->setYValue( upperIntensityLevel );
420 #endif /* FREQUENCY_DISPLAY_PLOT_C */