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(){
76 void SetUnitType(const std::string &type)
82 virtual QwtText trackerText( const QwtDoublePoint& p ) const
84 QwtText t(QString("%1 %2, %3 dB").arg(p.x(), 0, 'f',
85 GetFrequencyPrecision()).arg(_unitType.c_str()).arg(p.y(), 0, 'f', 2));
91 std::string _unitType;
94 FrequencyDisplayPlot::FrequencyDisplayPlot(QWidget* parent)
98 _stopFrequency = 4000;
100 timespec_reset(&_lastReplot);
102 resize(parent->width(), parent->height());
104 _displayIntervalTime = (1.0/10.0); // 1/10 of a second between updates
106 _useCenterFrequencyFlag = false;
109 _dataPoints = new double[_numPoints];
110 _minFFTPoints = new double[_numPoints];
111 _maxFFTPoints = new double[_numPoints];
112 _xAxisPoints = new double[_numPoints];
114 // Disable polygon clipping
115 QwtPainter::setDeviceClipping(false);
117 // We don't need the cache here
118 canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
119 canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
122 palette.setColor(canvas()->backgroundRole(), QColor("white"));
123 canvas()->setPalette(palette);
125 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0));
126 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
127 setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
131 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
132 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
133 setAxisTitle(QwtPlot::yLeft, "Power (dB)");
135 // Automatically deleted when parent is deleted
136 _fft_plot_curve = new QwtPlotCurve("Power Spectrum");
137 _fft_plot_curve->attach(this);
138 _fft_plot_curve->setPen(QPen(Qt::blue));
139 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
141 _min_fft_plot_curve = new QwtPlotCurve("Minimum Power");
142 _min_fft_plot_curve->attach(this);
143 _min_fft_plot_curve->setPen(QPen(Qt::magenta));
144 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
145 _min_fft_plot_curve->setVisible(false);
147 _max_fft_plot_curve = new QwtPlotCurve("Maximum Power");
148 _max_fft_plot_curve->attach(this);
149 _max_fft_plot_curve->setPen(QPen(Qt::darkYellow));
150 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
151 _max_fft_plot_curve->setVisible(false);
153 _lower_intensity_marker = new QwtPlotMarker();
154 _lower_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
155 _lower_intensity_marker->setLinePen(QPen(Qt::cyan));
156 _lower_intensity_marker->attach(this);
158 _upper_intensity_marker = new QwtPlotMarker();
159 _upper_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
160 _upper_intensity_marker->setLinePen(QPen(Qt::green));
161 _upper_intensity_marker->attach(this);
163 memset(_dataPoints, 0x0, _numPoints*sizeof(double));
164 memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
166 for(int64_t number = 0; number < _numPoints; number++){
167 _minFFTPoints[number] = 200.0;
168 _maxFFTPoints[number] = -280.0;
174 // set up peak marker
177 _markerPeakAmplitude = new QwtPlotMarker();
178 _markerPeakAmplitude->setLinePen(QPen(Qt::yellow));
179 symbol.setStyle(QwtSymbol::Diamond);
181 symbol.setPen(QPen(Qt::yellow));
182 symbol.setBrush(QBrush(Qt::yellow));
183 _markerPeakAmplitude->setSymbol(symbol);
184 _markerPeakAmplitude->attach(this);
186 _markerNoiseFloorAmplitude = new QwtPlotMarker();
187 _markerNoiseFloorAmplitude->setLineStyle(QwtPlotMarker::HLine);
188 _markerNoiseFloorAmplitude->setLinePen(QPen(Qt::darkRed, 0, Qt::DotLine));
189 _markerNoiseFloorAmplitude->attach(this);
192 _peakAmplitude = -HUGE_VAL;
194 _noiseFloorAmplitude = -HUGE_VAL;
198 _zoomer = new FreqDisplayZoomer(canvas(), 0);
199 #if QT_VERSION < 0x040000
200 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
201 Qt::RightButton, Qt::ControlModifier);
203 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
204 Qt::RightButton, Qt::ControlModifier);
206 _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
209 _panner = new QwtPlotPanner(canvas());
210 _panner->setAxisEnabled(QwtPlot::yRight, false);
211 _panner->setMouseButton(Qt::MidButton);
213 // Avoid jumping when labels with more/less digits
214 // appear/disappear when scrolling vertically
216 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
217 QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
218 sd->setMinimumExtent( fm.width("100.00") );
220 const QColor c(Qt::darkRed);
221 _zoomer->setRubberBandPen(c);
222 _zoomer->setTrackerPen(c);
225 FrequencyDisplayPlot::~FrequencyDisplayPlot()
227 delete[] _dataPoints;
228 delete[] _maxFFTPoints;
229 delete[] _minFFTPoints;
230 delete[] _xAxisPoints;
232 // _fft_plot_curves deleted when parent deleted
233 // _zoomer and _panner deleted when parent deleted
237 FrequencyDisplayPlot::set_yaxis(double min, double max)
239 // Get the new max/min values for the plot
243 // Set the axis max/min to the new values
244 setAxisScale(QwtPlot::yLeft, _minYAxis, _maxYAxis);
246 // Reset the base zoom level to the new axis scale set here
247 _zoomer->setZoomBase();
251 FrequencyDisplayPlot::SetFrequencyRange(const double constStartFreq,
252 const double constStopFreq,
253 const double constCenterFreq,
254 const bool useCenterFrequencyFlag,
255 const double units, const std::string &strunits)
257 double startFreq = constStartFreq / units;
258 double stopFreq = constStopFreq / units;
259 double centerFreq = constCenterFreq / units;
261 _useCenterFrequencyFlag = useCenterFrequencyFlag;
263 if(_useCenterFrequencyFlag){
264 startFreq = (startFreq + centerFreq);
265 stopFreq = (stopFreq + centerFreq);
268 _startFrequency = startFreq;
269 _stopFrequency = stopFreq;
272 double display_units = ceil(log10(units)/2.0);
273 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
274 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(display_units));
275 setAxisTitle(QwtPlot::xBottom, QString("Frequency (%1)").arg(strunits.c_str()));
276 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(display_units);
277 ((FreqDisplayZoomer*)_zoomer)->SetUnitType(strunits);
279 // Load up the new base zoom settings
280 _zoomer->setZoomBase();
282 // Zooms back to the base and clears any other zoom levels
288 FrequencyDisplayPlot::GetStartFrequency() const
290 return _startFrequency;
294 FrequencyDisplayPlot::GetStopFrequency() const
296 return _stopFrequency;
300 FrequencyDisplayPlot::replot()
302 const timespec startTime = get_highres_clock();
304 _markerNoiseFloorAmplitude->setYValue(_noiseFloorAmplitude);
306 // Make sure to take into account the start frequency
307 if(_useCenterFrequencyFlag){
308 _markerPeakAmplitude->setXValue((_peakFrequency/1000.0) + _startFrequency);
311 _markerPeakAmplitude->setXValue(_peakFrequency + _startFrequency);
313 _markerPeakAmplitude->setYValue(_peakAmplitude);
317 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
319 differenceTime *= 99.0;
320 // Require at least a 10% duty cycle
321 if(differenceTime > (1.0/10.0)){
322 _displayIntervalTime = differenceTime;
327 FrequencyDisplayPlot::resizeSlot( QSize *s )
329 resize(s->width(), s->height());
333 FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints,
334 const double noiseFloorAmplitude, const double peakFrequency,
335 const double peakAmplitude)
337 if(numDataPoints > 0){
339 if(numDataPoints != _numPoints){
340 _numPoints = numDataPoints;
342 delete[] _dataPoints;
343 delete[] _minFFTPoints;
344 delete[] _maxFFTPoints;
345 delete[] _xAxisPoints;
346 _dataPoints = new double[_numPoints];
347 _xAxisPoints = new double[_numPoints];
348 _minFFTPoints = new double[_numPoints];
349 _maxFFTPoints = new double[_numPoints];
351 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
352 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
353 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
360 memcpy(_dataPoints, dataPoints, numDataPoints*sizeof(double));
361 for(int64_t point = 0; point < numDataPoints; point++){
362 if(dataPoints[point] < _minFFTPoints[point]){
363 _minFFTPoints[point] = dataPoints[point];
365 if(dataPoints[point] > _maxFFTPoints[point]){
366 _maxFFTPoints[point] = dataPoints[point];
370 _noiseFloorAmplitude = noiseFloorAmplitude;
371 _peakFrequency = peakFrequency;
372 _peakAmplitude = peakAmplitude;
376 // Allow at least a 50% duty cycle
377 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
378 // Only replot the screen if it is visible
382 _lastReplot = get_highres_clock();
387 FrequencyDisplayPlot::ClearMaxData()
389 for(int64_t number = 0; number < _numPoints; number++){
390 _maxFFTPoints[number] = _minYAxis;
395 FrequencyDisplayPlot::ClearMinData()
397 for(int64_t number = 0; number < _numPoints; number++){
398 _minFFTPoints[number] = _maxYAxis;
403 FrequencyDisplayPlot::SetMaxFFTVisible(const bool visibleFlag)
405 _max_fft_plot_curve->setVisible(visibleFlag);
409 FrequencyDisplayPlot::SetMinFFTVisible(const bool visibleFlag)
411 _min_fft_plot_curve->setVisible(visibleFlag);
415 FrequencyDisplayPlot::_resetXAxisPoints()
417 double fft_bin_size = (_stopFrequency-_startFrequency) / static_cast<double>(_numPoints);
418 double freqValue = _startFrequency;
419 for(int64_t loc = 0; loc < _numPoints; loc++){
420 _xAxisPoints[loc] = freqValue;
421 freqValue += fft_bin_size;
426 FrequencyDisplayPlot::SetLowerIntensityLevel(const double lowerIntensityLevel)
428 _lower_intensity_marker->setYValue( lowerIntensityLevel );
432 FrequencyDisplayPlot::SetUpperIntensityLevel(const double upperIntensityLevel)
434 _upper_intensity_marker->setYValue( upperIntensityLevel );
438 #endif /* FREQUENCY_DISPLAY_PLOT_C */