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 QString strunits = (GetFrequencyPrecision() == 0) ? "Hz" : "kHz";
80 QwtText t(QString("%1 %2, %3 dB").arg(p.x(), 0, 'f',
81 GetFrequencyPrecision()).arg(strunits).arg(p.y(), 0, 'f', 2));
87 FrequencyDisplayPlot::FrequencyDisplayPlot(QWidget* parent)
91 _stopFrequency = 4000;
93 timespec_reset(&_lastReplot);
95 resize(parent->width(), parent->height());
97 _displayIntervalTime = (1.0/10.0); // 1/10 of a second between updates
99 _useCenterFrequencyFlag = false;
102 _dataPoints = new double[_numPoints];
103 _minFFTPoints = new double[_numPoints];
104 _maxFFTPoints = new double[_numPoints];
105 _xAxisPoints = new double[_numPoints];
107 // Disable polygon clipping
108 QwtPainter::setDeviceClipping(false);
110 // We don't need the cache here
111 canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
112 canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
115 palette.setColor(canvas()->backgroundRole(), QColor("white"));
116 canvas()->setPalette(palette);
118 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0));
119 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
120 setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
124 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
125 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
126 setAxisTitle(QwtPlot::yLeft, "Power (dB)");
128 // Automatically deleted when parent is deleted
129 _fft_plot_curve = new QwtPlotCurve("Power Spectrum");
130 _fft_plot_curve->attach(this);
131 _fft_plot_curve->setPen(QPen(Qt::blue));
132 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
134 _min_fft_plot_curve = new QwtPlotCurve("Minimum Power");
135 _min_fft_plot_curve->attach(this);
136 _min_fft_plot_curve->setPen(QPen(Qt::magenta));
137 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
138 _min_fft_plot_curve->setVisible(false);
140 _max_fft_plot_curve = new QwtPlotCurve("Maximum Power");
141 _max_fft_plot_curve->attach(this);
142 _max_fft_plot_curve->setPen(QPen(Qt::darkYellow));
143 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
144 _max_fft_plot_curve->setVisible(false);
146 _lower_intensity_marker = new QwtPlotMarker();
147 _lower_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
148 _lower_intensity_marker->setLinePen(QPen(Qt::cyan));
149 _lower_intensity_marker->attach(this);
151 _upper_intensity_marker = new QwtPlotMarker();
152 _upper_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
153 _upper_intensity_marker->setLinePen(QPen(Qt::green));
154 _upper_intensity_marker->attach(this);
156 memset(_dataPoints, 0x0, _numPoints*sizeof(double));
157 memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
159 for(int64_t number = 0; number < _numPoints; number++){
160 _minFFTPoints[number] = 200.0;
161 _maxFFTPoints[number] = -280.0;
167 // set up peak marker
170 _markerPeakAmplitude = new QwtPlotMarker();
171 _markerPeakAmplitude->setLinePen(QPen(Qt::yellow));
172 symbol.setStyle(QwtSymbol::Diamond);
174 symbol.setPen(QPen(Qt::yellow));
175 symbol.setBrush(QBrush(Qt::yellow));
176 _markerPeakAmplitude->setSymbol(symbol);
177 _markerPeakAmplitude->attach(this);
179 _markerNoiseFloorAmplitude = new QwtPlotMarker();
180 _markerNoiseFloorAmplitude->setLineStyle(QwtPlotMarker::HLine);
181 _markerNoiseFloorAmplitude->setLinePen(QPen(Qt::darkRed, 0, Qt::DotLine));
182 _markerNoiseFloorAmplitude->attach(this);
185 _peakAmplitude = -HUGE_VAL;
187 _noiseFloorAmplitude = -HUGE_VAL;
191 _zoomer = new FreqDisplayZoomer(canvas(), 0);
192 #if QT_VERSION < 0x040000
193 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
194 Qt::RightButton, Qt::ControlModifier);
196 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
197 Qt::RightButton, Qt::ControlModifier);
199 _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
202 _panner = new QwtPlotPanner(canvas());
203 _panner->setAxisEnabled(QwtPlot::yRight, false);
204 _panner->setMouseButton(Qt::MidButton);
206 // Avoid jumping when labels with more/less digits
207 // appear/disappear when scrolling vertically
209 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
210 QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
211 sd->setMinimumExtent( fm.width("100.00") );
213 const QColor c(Qt::darkRed);
214 _zoomer->setRubberBandPen(c);
215 _zoomer->setTrackerPen(c);
218 FrequencyDisplayPlot::~FrequencyDisplayPlot()
220 delete[] _dataPoints;
221 delete[] _maxFFTPoints;
222 delete[] _minFFTPoints;
223 delete[] _xAxisPoints;
225 // _fft_plot_curves deleted when parent deleted
226 // _zoomer and _panner deleted when parent deleted
230 FrequencyDisplayPlot::set_yaxis(double min, double max)
232 // Get the new max/min values for the plot
236 // Set the axis max/min to the new values
237 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
239 // Reset the base zoom level to the new axis scale set here
240 _zoomer->setZoomBase();
244 FrequencyDisplayPlot::SetFrequencyRange(const double constStartFreq,
245 const double constStopFreq,
246 const double constCenterFreq,
247 const bool useCenterFrequencyFlag,
248 const double units, const std::string &strunits)
250 double startFreq = constStartFreq / units;
251 double stopFreq = constStopFreq / units;
252 double centerFreq = constCenterFreq / units;
254 _useCenterFrequencyFlag = useCenterFrequencyFlag;
256 if(_useCenterFrequencyFlag){
257 startFreq = (startFreq + centerFreq);
258 stopFreq = (stopFreq + centerFreq);
261 _startFrequency = startFreq;
262 _stopFrequency = stopFreq;
265 double display_units = ceil(log10(units)/2.0);
266 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
267 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(display_units));
268 setAxisTitle(QwtPlot::xBottom, QString("Frequency (%1)").arg(strunits.c_str()));
269 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(display_units);
271 // Load up the new base zoom settings
272 _zoomer->setZoomBase();
274 // Zooms back to the base and clears any other zoom levels
280 FrequencyDisplayPlot::GetStartFrequency() const
282 return _startFrequency;
286 FrequencyDisplayPlot::GetStopFrequency() const
288 return _stopFrequency;
292 FrequencyDisplayPlot::replot()
294 const timespec startTime = get_highres_clock();
296 _markerNoiseFloorAmplitude->setYValue(_noiseFloorAmplitude);
298 // Make sure to take into account the start frequency
299 if(_useCenterFrequencyFlag){
300 _markerPeakAmplitude->setXValue((_peakFrequency/1000.0) + _startFrequency);
303 _markerPeakAmplitude->setXValue(_peakFrequency + _startFrequency);
305 _markerPeakAmplitude->setYValue(_peakAmplitude);
309 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
311 differenceTime *= 99.0;
312 // Require at least a 10% duty cycle
313 if(differenceTime > (1.0/10.0)){
314 _displayIntervalTime = differenceTime;
319 FrequencyDisplayPlot::resizeSlot( QSize *s )
321 resize(s->width(), s->height());
325 FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints,
326 const double noiseFloorAmplitude, const double peakFrequency,
327 const double peakAmplitude)
329 if(numDataPoints > 0){
331 if(numDataPoints != _numPoints){
332 _numPoints = numDataPoints;
334 delete[] _dataPoints;
335 delete[] _minFFTPoints;
336 delete[] _maxFFTPoints;
337 delete[] _xAxisPoints;
338 _dataPoints = new double[_numPoints];
339 _xAxisPoints = new double[_numPoints];
340 _minFFTPoints = new double[_numPoints];
341 _maxFFTPoints = new double[_numPoints];
343 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
344 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
345 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
352 memcpy(_dataPoints, dataPoints, numDataPoints*sizeof(double));
353 for(int64_t point = 0; point < numDataPoints; point++){
354 if(dataPoints[point] < _minFFTPoints[point]){
355 _minFFTPoints[point] = dataPoints[point];
357 if(dataPoints[point] > _maxFFTPoints[point]){
358 _maxFFTPoints[point] = dataPoints[point];
362 _noiseFloorAmplitude = noiseFloorAmplitude;
363 _peakFrequency = peakFrequency;
364 _peakAmplitude = peakAmplitude;
368 // Allow at least a 50% duty cycle
369 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
370 // Only replot the screen if it is visible
374 _lastReplot = get_highres_clock();
379 FrequencyDisplayPlot::ClearMaxData()
381 for(int64_t number = 0; number < _numPoints; number++){
382 _maxFFTPoints[number] = _minYAxis;
387 FrequencyDisplayPlot::ClearMinData()
389 for(int64_t number = 0; number < _numPoints; number++){
390 _minFFTPoints[number] = _maxYAxis;
395 FrequencyDisplayPlot::SetMaxFFTVisible(const bool visibleFlag)
397 _max_fft_plot_curve->setVisible(visibleFlag);
401 FrequencyDisplayPlot::SetMinFFTVisible(const bool visibleFlag)
403 _min_fft_plot_curve->setVisible(visibleFlag);
407 FrequencyDisplayPlot::_resetXAxisPoints()
409 double fft_bin_size = (_stopFrequency-_startFrequency) / static_cast<double>(_numPoints);
410 double freqValue = _startFrequency;
411 for(int64_t loc = 0; loc < _numPoints; loc++){
412 _xAxisPoints[loc] = freqValue;
413 freqValue += fft_bin_size;
418 FrequencyDisplayPlot::SetLowerIntensityLevel(const double lowerIntensityLevel)
420 _lower_intensity_marker->setYValue( lowerIntensityLevel );
424 FrequencyDisplayPlot::SetUpperIntensityLevel(const double upperIntensityLevel)
426 _upper_intensity_marker->setYValue( upperIntensityLevel );
430 #endif /* FREQUENCY_DISPLAY_PLOT_C */