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)");
120 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
122 setAxisTitle(QwtPlot::yLeft, "Power (dB)");
124 // Automatically deleted when parent is deleted
125 _fft_plot_curve = new QwtPlotCurve("Power Spectrum");
126 _fft_plot_curve->attach(this);
127 _fft_plot_curve->setPen(QPen(Qt::blue));
128 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
130 _min_fft_plot_curve = new QwtPlotCurve("Minimum Power");
131 _min_fft_plot_curve->attach(this);
132 _min_fft_plot_curve->setPen(QPen(Qt::magenta));
133 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
134 _min_fft_plot_curve->setVisible(false);
136 _max_fft_plot_curve = new QwtPlotCurve("Maximum Power");
137 _max_fft_plot_curve->attach(this);
138 _max_fft_plot_curve->setPen(QPen(Qt::darkYellow));
139 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
140 _max_fft_plot_curve->setVisible(false);
142 _lower_intensity_marker = new QwtPlotMarker();
143 _lower_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
144 _lower_intensity_marker->setLinePen(QPen(Qt::cyan));
145 _lower_intensity_marker->attach(this);
147 _upper_intensity_marker = new QwtPlotMarker();
148 _upper_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
149 _upper_intensity_marker->setLinePen(QPen(Qt::green));
150 _upper_intensity_marker->attach(this);
152 memset(_dataPoints, 0x0, _numPoints*sizeof(double));
153 memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
155 for(int64_t number = 0; number < _numPoints; number++){
156 _minFFTPoints[number] = 200.0;
157 _maxFFTPoints[number] = -280.0;
163 // set up peak marker
166 _markerPeakAmplitude = new QwtPlotMarker();
167 _markerPeakAmplitude->setLinePen(QPen(Qt::yellow));
168 symbol.setStyle(QwtSymbol::Diamond);
170 symbol.setPen(QPen(Qt::yellow));
171 symbol.setBrush(QBrush(Qt::yellow));
172 _markerPeakAmplitude->setSymbol(symbol);
173 _markerPeakAmplitude->attach(this);
175 _markerNoiseFloorAmplitude = new QwtPlotMarker();
176 _markerNoiseFloorAmplitude->setLineStyle(QwtPlotMarker::HLine);
177 _markerNoiseFloorAmplitude->setLinePen(QPen(Qt::darkRed, 0, Qt::DotLine));
178 _markerNoiseFloorAmplitude->attach(this);
181 _peakAmplitude = -HUGE_VAL;
183 _noiseFloorAmplitude = -HUGE_VAL;
187 _zoomer = new FreqDisplayZoomer(canvas(), 0);
188 #if QT_VERSION < 0x040000
189 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
190 Qt::RightButton, Qt::ControlModifier);
192 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
193 Qt::RightButton, Qt::ControlModifier);
195 _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
198 _panner = new QwtPlotPanner(canvas());
199 _panner->setAxisEnabled(QwtPlot::yRight, false);
200 _panner->setMouseButton(Qt::MidButton);
202 // Avoid jumping when labels with more/less digits
203 // appear/disappear when scrolling vertically
205 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
206 QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
207 sd->setMinimumExtent( fm.width("100.00") );
209 const QColor c(Qt::darkRed);
210 _zoomer->setRubberBandPen(c);
211 _zoomer->setTrackerPen(c);
214 FrequencyDisplayPlot::~FrequencyDisplayPlot()
216 delete[] _dataPoints;
217 delete[] _maxFFTPoints;
218 delete[] _minFFTPoints;
219 delete[] _xAxisPoints;
221 // _fft_plot_curves deleted when parent deleted
222 // _zoomer and _panner deleted when parent deleted
226 FrequencyDisplayPlot::set_yaxis(double min, double max)
228 setAxisScale(QwtPlot::yLeft, min, max);
232 FrequencyDisplayPlot::SetFrequencyRange(const double constStartFreq,
233 const double constStopFreq,
234 const double constCenterFreq,
235 const bool useCenterFrequencyFlag,
236 const double units, const std::string &strunits)
238 double startFreq = constStartFreq / units;
239 double stopFreq = constStopFreq / units;
240 double centerFreq = constCenterFreq / units;
242 _useCenterFrequencyFlag = useCenterFrequencyFlag;
244 if(_useCenterFrequencyFlag){
245 startFreq = (startFreq + centerFreq);
246 stopFreq = (stopFreq + centerFreq);
249 _startFrequency = startFreq;
250 _stopFrequency = stopFreq;
253 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
254 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(2));
255 setAxisTitle(QwtPlot::xBottom, QString("Frequency (%1)").arg(strunits.c_str()));
256 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(2);
258 // Load up the new base zoom settings
259 QwtDoubleRect newSize = _zoomer->zoomBase();
260 newSize.setLeft(_startFrequency);
261 newSize.setWidth(_stopFrequency-_startFrequency);
262 _zoomer->setZoomBase(newSize);
264 // Zooms back to the base and clears any other zoom levels
270 FrequencyDisplayPlot::GetStartFrequency() const
272 return _startFrequency;
276 FrequencyDisplayPlot::GetStopFrequency() const
278 return _stopFrequency;
282 FrequencyDisplayPlot::replot()
284 const timespec startTime = get_highres_clock();
286 _markerNoiseFloorAmplitude->setYValue(_noiseFloorAmplitude);
288 // Make sure to take into account the start frequency
289 if(_useCenterFrequencyFlag){
290 _markerPeakAmplitude->setXValue((_peakFrequency/1000.0) + _startFrequency);
293 _markerPeakAmplitude->setXValue(_peakFrequency + _startFrequency);
295 _markerPeakAmplitude->setYValue(_peakAmplitude);
299 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
301 differenceTime *= 99.0;
302 // Require at least a 10% duty cycle
303 if(differenceTime > (1.0/10.0)){
304 _displayIntervalTime = differenceTime;
309 FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints,
310 const double noiseFloorAmplitude, const double peakFrequency,
311 const double peakAmplitude)
313 if(numDataPoints > 0){
315 if(numDataPoints != _numPoints){
316 _numPoints = numDataPoints;
318 delete[] _dataPoints;
319 delete[] _minFFTPoints;
320 delete[] _maxFFTPoints;
321 delete[] _xAxisPoints;
322 _dataPoints = new double[_numPoints];
323 _xAxisPoints = new double[_numPoints];
324 _minFFTPoints = new double[_numPoints];
325 _maxFFTPoints = new double[_numPoints];
327 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
328 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
329 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
335 memcpy(_dataPoints, dataPoints, numDataPoints*sizeof(double));
336 for(int64_t point = 0; point < numDataPoints; point++){
337 if(dataPoints[point] < _minFFTPoints[point]){
338 _minFFTPoints[point] = dataPoints[point];
340 if(dataPoints[point] > _maxFFTPoints[point]){
341 _maxFFTPoints[point] = dataPoints[point];
345 _noiseFloorAmplitude = noiseFloorAmplitude;
346 _peakFrequency = peakFrequency;
347 _peakAmplitude = peakAmplitude;
351 // Allow at least a 50% duty cycle
352 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
353 // Only replot the screen if it is visible
357 _lastReplot = get_highres_clock();
362 FrequencyDisplayPlot::ClearMaxData()
364 for(int64_t number = 0; number < _numPoints; number++){
365 _maxFFTPoints[number] = -280.0;
370 FrequencyDisplayPlot::ClearMinData()
372 for(int64_t number = 0; number < _numPoints; number++){
373 _minFFTPoints[number] = 200.0;
378 FrequencyDisplayPlot::SetMaxFFTVisible(const bool visibleFlag)
380 _max_fft_plot_curve->setVisible(visibleFlag);
384 FrequencyDisplayPlot::SetMinFFTVisible(const bool visibleFlag)
386 _min_fft_plot_curve->setVisible(visibleFlag);
390 FrequencyDisplayPlot::_resetXAxisPoints()
392 double fft_bin_size = (_stopFrequency-_startFrequency) / static_cast<double>(_numPoints);
393 double freqValue = _startFrequency;
394 for(int64_t loc = 0; loc < _numPoints; loc++){
395 _xAxisPoints[loc] = freqValue;
396 freqValue += fft_bin_size;
401 FrequencyDisplayPlot::SetLowerIntensityLevel(const double lowerIntensityLevel)
403 _lower_intensity_marker->setYValue( lowerIntensityLevel );
407 FrequencyDisplayPlot::SetUpperIntensityLevel(const double upperIntensityLevel)
409 _upper_intensity_marker->setYValue( upperIntensityLevel );
413 #endif /* FREQUENCY_DISPLAY_PLOT_C */