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){
12 _frequencyPrecision = freqPrecision;
15 virtual ~FreqPrecisionClass(){
18 virtual unsigned int GetFrequencyPrecision()const{
19 return _frequencyPrecision;
22 virtual void SetFrequencyPrecision(const unsigned int newPrecision){
23 _frequencyPrecision = newPrecision;
26 unsigned int _frequencyPrecision;
32 class FreqDisplayScaleDraw: public QwtScaleDraw, public FreqPrecisionClass{
34 FreqDisplayScaleDraw(const unsigned int precision):QwtScaleDraw(), FreqPrecisionClass(precision){
38 virtual ~FreqDisplayScaleDraw(){
42 virtual QwtText label(double value)const{
43 return QString("%1").arg(value, 0, 'f', GetFrequencyPrecision());
52 class FreqDisplayZoomer: public QwtPlotZoomer, public FreqPrecisionClass
55 FreqDisplayZoomer(QwtPlotCanvas* canvas, const unsigned int freqPrecision):QwtPlotZoomer(canvas),FreqPrecisionClass(freqPrecision)
57 setTrackerMode(QwtPicker::AlwaysOn);
60 virtual ~FreqDisplayZoomer(){
64 virtual void updateTrackerText(){
69 virtual QwtText trackerText( const QwtDoublePoint& p ) const
71 QwtText t(QString("%1 %2, %3 dB").arg(p.x(), 0, 'f', GetFrequencyPrecision()).arg( (GetFrequencyPrecision() == 0) ? "Hz" : "kHz").arg(p.y(), 0, 'f', 2));
77 FrequencyDisplayPlot::FrequencyDisplayPlot(QWidget* parent):QwtPlot(parent){
79 _stopFrequency = 4000;
81 timespec_reset(&_lastReplot);
83 resize(parent->width(), parent->height());
85 _displayIntervalTime = (1.0/10.0); // 1/10 of a second between updates
87 _useCenterFrequencyFlag = false;
90 _dataPoints = new double[_numPoints];
91 _minFFTPoints = new double[_numPoints];
92 _maxFFTPoints = new double[_numPoints];
93 _xAxisPoints = new double[_numPoints];
95 // Disable polygon clipping
96 QwtPainter::setDeviceClipping(false);
98 // We don't need the cache here
99 canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
100 canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
103 palette.setColor(canvas()->backgroundRole(), QColor("white"));
104 canvas()->setPalette(palette);
106 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0));
107 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
108 setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
110 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
111 setAxisScale(QwtPlot::yLeft, -210, 5);
112 setAxisTitle(QwtPlot::yLeft, "Power (dB)");
114 // Automatically deleted when parent is deleted
115 _fft_plot_curve = new QwtPlotCurve("Power Spectrum");
116 _fft_plot_curve->attach(this);
117 _fft_plot_curve->setPen(QPen(Qt::blue));
118 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
120 _min_fft_plot_curve = new QwtPlotCurve("Minimum Power");
121 _min_fft_plot_curve->attach(this);
122 _min_fft_plot_curve->setPen(QPen(Qt::magenta));
123 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
124 _min_fft_plot_curve->setVisible(false);
126 _max_fft_plot_curve = new QwtPlotCurve("Maximum Power");
127 _max_fft_plot_curve->attach(this);
128 _max_fft_plot_curve->setPen(QPen(Qt::darkYellow));
129 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
130 _max_fft_plot_curve->setVisible(false);
132 _lower_intensity_marker = new QwtPlotMarker();
133 _lower_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
134 _lower_intensity_marker->setLinePen(QPen(Qt::cyan));
135 _lower_intensity_marker->attach(this);
137 _upper_intensity_marker = new QwtPlotMarker();
138 _upper_intensity_marker->setLineStyle(QwtPlotMarker::HLine);
139 _upper_intensity_marker->setLinePen(QPen(Qt::green));
140 _upper_intensity_marker->attach(this);
142 memset(_dataPoints, 0x0, _numPoints*sizeof(double));
143 memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
145 for(int64_t number = 0; number < _numPoints; number++){
146 _minFFTPoints[number] = 200.0;
147 _maxFFTPoints[number] = -280.0;
153 // set up peak marker
156 _markerPeakAmplitude = new QwtPlotMarker();
157 _markerPeakAmplitude->setLinePen(QPen(Qt::yellow));
158 symbol.setStyle(QwtSymbol::Diamond);
160 symbol.setPen(QPen(Qt::yellow));
161 symbol.setBrush(QBrush(Qt::yellow));
162 _markerPeakAmplitude->setSymbol(symbol);
163 _markerPeakAmplitude->attach(this);
165 _markerNoiseFloorAmplitude = new QwtPlotMarker();
166 _markerNoiseFloorAmplitude->setLineStyle(QwtPlotMarker::HLine);
167 _markerNoiseFloorAmplitude->setLinePen(QPen(Qt::darkRed, 0, Qt::DotLine));
168 _markerNoiseFloorAmplitude->attach(this);
171 _peakAmplitude = -HUGE_VAL;
173 _noiseFloorAmplitude = -HUGE_VAL;
177 _zoomer = new FreqDisplayZoomer(canvas(), 0);
178 #if QT_VERSION < 0x040000
179 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
180 Qt::RightButton, Qt::ControlModifier);
182 _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
183 Qt::RightButton, Qt::ControlModifier);
185 _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
188 _panner = new QwtPlotPanner(canvas());
189 _panner->setAxisEnabled(QwtPlot::yRight, false);
190 _panner->setMouseButton(Qt::MidButton);
192 // Avoid jumping when labels with more/less digits
193 // appear/disappear when scrolling vertically
195 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
196 QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
197 sd->setMinimumExtent( fm.width("100.00") );
199 const QColor c(Qt::darkRed);
200 _zoomer->setRubberBandPen(c);
201 _zoomer->setTrackerPen(c);
205 FrequencyDisplayPlot::~FrequencyDisplayPlot(){
206 delete[] _dataPoints;
207 delete[] _maxFFTPoints;
208 delete[] _minFFTPoints;
209 delete[] _xAxisPoints;
211 // _fft_plot_curves deleted when parent deleted
212 // _zoomer and _panner deleted when parent deleted
215 void FrequencyDisplayPlot::SetFrequencyRange(const double constStartFreq, const double constStopFreq, const double centerFrequency, const bool useCenterFrequencyFlag){
216 double startFreq = constStartFreq;
217 double stopFreq = constStopFreq;
219 _useCenterFrequencyFlag = useCenterFrequencyFlag;
221 if(_useCenterFrequencyFlag){
222 startFreq = (startFreq + centerFrequency) / 1000.0;
223 stopFreq = (stopFreq + centerFrequency) / 1000.0;
226 if((stopFreq > 0) && (stopFreq > startFreq)){
227 _startFrequency = startFreq;
228 _stopFrequency = stopFreq;
231 // Load up the new base zoom settings
232 QwtDoubleRect newSize = _zoomer->zoomBase();
233 newSize.setLeft(_startFrequency);
234 newSize.setWidth(_stopFrequency-_startFrequency);
235 _zoomer->setZoomBase(newSize);
237 // Zooms back to the base and clears any other zoom levels
240 setAxisScale(QwtPlot::xBottom, _startFrequency, _stopFrequency);
243 if(useCenterFrequencyFlag){
244 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(3));
245 setAxisTitle(QwtPlot::xBottom, "RF Frequency (kHz)");
246 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(3);
249 setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0));
250 setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
251 ((FreqDisplayZoomer*)_zoomer)->SetFrequencyPrecision(0);
254 // Load up the new base zoom settings
255 QwtDoubleRect newSize = _zoomer->zoomBase();
256 newSize.setLeft(_startFrequency);
257 newSize.setWidth(_stopFrequency-_startFrequency);
258 _zoomer->setZoomBase(newSize);
260 // Zooms back to the base and clears any other zoom levels
265 double FrequencyDisplayPlot::GetStartFrequency()const{
266 return _startFrequency;
269 double FrequencyDisplayPlot::GetStopFrequency()const{
270 return _stopFrequency;
273 void FrequencyDisplayPlot::replot(){
275 const timespec startTime = get_highres_clock();
277 _markerNoiseFloorAmplitude->setYValue(_noiseFloorAmplitude);
279 // Make sure to take into account the start frequency
280 if(_useCenterFrequencyFlag){
281 _markerPeakAmplitude->setXValue((_peakFrequency/1000.0) + _startFrequency);
284 _markerPeakAmplitude->setXValue(_peakFrequency + _startFrequency);
286 _markerPeakAmplitude->setYValue(_peakAmplitude);
290 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
292 differenceTime *= 99.0;
293 // Require at least a 10% duty cycle
294 if(differenceTime > (1.0/10.0)){
295 _displayIntervalTime = differenceTime;
299 void FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints, const double noiseFloorAmplitude, const double peakFrequency, const double peakAmplitude){
300 if(numDataPoints > 0){
302 if(numDataPoints != _numPoints){
303 _numPoints = numDataPoints;
305 delete[] _dataPoints;
306 delete[] _minFFTPoints;
307 delete[] _maxFFTPoints;
308 delete[] _xAxisPoints;
309 _dataPoints = new double[_numPoints];
310 _xAxisPoints = new double[_numPoints];
311 _minFFTPoints = new double[_numPoints];
312 _maxFFTPoints = new double[_numPoints];
314 _fft_plot_curve->setRawData(_xAxisPoints, _dataPoints, _numPoints);
315 _min_fft_plot_curve->setRawData(_xAxisPoints, _minFFTPoints, _numPoints);
316 _max_fft_plot_curve->setRawData(_xAxisPoints, _maxFFTPoints, _numPoints);
322 memcpy(_dataPoints, dataPoints, numDataPoints*sizeof(double));
323 for(int64_t point = 0; point < numDataPoints; point++){
324 if(dataPoints[point] < _minFFTPoints[point]){
325 _minFFTPoints[point] = dataPoints[point];
327 if(dataPoints[point] > _maxFFTPoints[point]){
328 _maxFFTPoints[point] = dataPoints[point];
332 _noiseFloorAmplitude = noiseFloorAmplitude;
333 _peakFrequency = peakFrequency;
334 _peakAmplitude = peakAmplitude;
338 // Allow at least a 50% duty cycle
339 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
340 // Only replot the screen if it is visible
344 _lastReplot = get_highres_clock();
348 void FrequencyDisplayPlot::ClearMaxData(){
349 for(int64_t number = 0; number < _numPoints; number++){
350 _maxFFTPoints[number] = -280.0;
354 void FrequencyDisplayPlot::ClearMinData(){
355 for(int64_t number = 0; number < _numPoints; number++){
356 _minFFTPoints[number] = 200.0;
360 void FrequencyDisplayPlot::SetMaxFFTVisible(const bool visibleFlag){
361 _max_fft_plot_curve->setVisible(visibleFlag);
364 void FrequencyDisplayPlot::SetMinFFTVisible(const bool visibleFlag){
365 _min_fft_plot_curve->setVisible(visibleFlag);
368 void FrequencyDisplayPlot::_resetXAxisPoints(){
369 double fft_bin_size = (_stopFrequency-_startFrequency) / static_cast<double>(_numPoints);
370 double freqValue = _startFrequency;
371 for(int64_t loc = 0; loc < _numPoints; loc++){
372 _xAxisPoints[loc] = freqValue;
373 freqValue += fft_bin_size;
377 void FrequencyDisplayPlot::SetLowerIntensityLevel(const double lowerIntensityLevel){
378 _lower_intensity_marker->setYValue( lowerIntensityLevel );
381 void FrequencyDisplayPlot::SetUpperIntensityLevel(const double upperIntensityLevel){
382 _upper_intensity_marker->setYValue( upperIntensityLevel );
386 #endif /* FREQUENCY_DISPLAY_PLOT_C */