1 /* -*- c++ -*- */ 2 #ifndef PLOTTER_H 3 #define PLOTTER_H 4 5 #include <QtGui> 6 #include <QFont> 7 #include <QFrame> 8 #include <QImage> 9 #include <vector> 10 #include <QMap> 11 12 #define HORZ_DIVS_MAX 12 //50 13 #define VERT_DIVS_MIN 5 14 #define MAX_SCREENSIZE 16384 15 16 #define PEAK_CLICK_MAX_H_DISTANCE 10 //Maximum horizontal distance of clicked point from peak 17 #define PEAK_CLICK_MAX_V_DISTANCE 20 //Maximum vertical distance of clicked point from peak 18 #define PEAK_H_TOLERANCE 2 19 20 21 class CPlotter : public QFrame 22 { 23 Q_OBJECT 24 25 public: 26 explicit CPlotter(QWidget *parent = nullptr); 27 ~CPlotter() override; 28 29 QSize minimumSizeHint() const override; 30 QSize sizeHint() const override; 31 32 //void SetSdrInterface(CSdrInterface* ptr){m_pSdrInterface = ptr;} 33 void draw(); //call to draw new fft data onto screen plot setRunningState(bool running)34 void setRunningState(bool running) { m_Running = running; } setClickResolution(int clickres)35 void setClickResolution(int clickres) { m_ClickResolution = clickres; } setFilterClickResolution(int clickres)36 void setFilterClickResolution(int clickres) { m_FilterClickResolution = clickres; } setFilterBoxEnabled(bool enabled)37 void setFilterBoxEnabled(bool enabled) { m_FilterBoxEnabled = enabled; } setCenterLineEnabled(bool enabled)38 void setCenterLineEnabled(bool enabled) { m_CenterLineEnabled = enabled; } setTooltipsEnabled(bool enabled)39 void setTooltipsEnabled(bool enabled) { m_TooltipsEnabled = enabled; } setBookmarksEnabled(bool enabled)40 void setBookmarksEnabled(bool enabled) { m_BookmarksEnabled = enabled; } setInvertScrolling(bool enabled)41 void setInvertScrolling(bool enabled) { m_InvertScrolling = enabled; } setBandPlanEnabled(bool enabled)42 void setBandPlanEnabled(bool enabled) { m_BandPlanEnabled = enabled; } setDXCSpotsEnabled(bool enabled)43 void setDXCSpotsEnabled(bool enabled) { m_DXCSpotsEnabled = enabled; } 44 45 void setNewFftData(float *fftData, int size); 46 void setNewFftData(float *fftData, float *wfData, int size); 47 48 void setCenterFreq(quint64 f); setFreqUnits(qint32 unit)49 void setFreqUnits(qint32 unit) { m_FreqUnits = unit; } 50 setDemodCenterFreq(quint64 f)51 void setDemodCenterFreq(quint64 f) { m_DemodCenterFreq = f; } 52 53 /*! \brief Move the filter to freq_hz from center. */ setFilterOffset(qint64 freq_hz)54 void setFilterOffset(qint64 freq_hz) 55 { 56 m_DemodCenterFreq = m_CenterFreq + freq_hz; 57 drawOverlay(); 58 } getFilterOffset()59 qint64 getFilterOffset() const 60 { 61 return m_DemodCenterFreq - m_CenterFreq; 62 } 63 getFilterBw()64 int getFilterBw() const 65 { 66 return m_DemodHiCutFreq - m_DemodLowCutFreq; 67 } 68 setHiLowCutFrequencies(int LowCut,int HiCut)69 void setHiLowCutFrequencies(int LowCut, int HiCut) 70 { 71 m_DemodLowCutFreq = LowCut; 72 m_DemodHiCutFreq = HiCut; 73 drawOverlay(); 74 } 75 getHiLowCutFrequencies(int * LowCut,int * HiCut)76 void getHiLowCutFrequencies(int *LowCut, int *HiCut) const 77 { 78 *LowCut = m_DemodLowCutFreq; 79 *HiCut = m_DemodHiCutFreq; 80 } 81 82 void setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCmax, bool symetric); 83 84 /* Shown bandwidth around SetCenterFreq() */ setSpanFreq(quint32 s)85 void setSpanFreq(quint32 s) 86 { 87 if (s > 0 && s < INT_MAX) { 88 m_Span = (qint32)s; 89 setFftCenterFreq(m_FftCenter); 90 } 91 drawOverlay(); 92 } 93 setHdivDelta(int delta)94 void setHdivDelta(int delta) { m_HdivDelta = delta; } setVdivDelta(int delta)95 void setVdivDelta(int delta) { m_VdivDelta = delta; } 96 setFreqDigits(int digits)97 void setFreqDigits(int digits) { m_FreqDigits = digits>=0 ? digits : 0; } 98 99 /* Determines full bandwidth. */ setSampleRate(float rate)100 void setSampleRate(float rate) 101 { 102 if (rate > 0.0) 103 { 104 m_SampleFreq = rate; 105 drawOverlay(); 106 } 107 } 108 getSampleRate()109 float getSampleRate() const 110 { 111 return m_SampleFreq; 112 } 113 setFftCenterFreq(qint64 f)114 void setFftCenterFreq(qint64 f) { 115 qint64 limit = ((qint64)m_SampleFreq + m_Span) / 2 - 1; 116 m_FftCenter = qBound(-limit, f, limit); 117 } 118 119 int getNearestPeak(QPoint pt); 120 void setWaterfallSpan(quint64 span_ms); 121 quint64 getWfTimeRes() const; 122 void setFftRate(int rate_hz); 123 void clearWaterfall(); 124 bool saveWaterfall(const QString & filename) const; 125 126 signals: 127 void newDemodFreq(qint64 freq, qint64 delta); /* delta is the offset from the center */ 128 void newLowCutFreq(int f); 129 void newHighCutFreq(int f); 130 void newFilterFreq(int low, int high); /* substitute for NewLow / NewHigh */ 131 void pandapterRangeChanged(float min, float max); 132 void newZoomLevel(float level); 133 void newSize(); 134 135 public slots: 136 // zoom functions 137 void resetHorizontalZoom(); 138 void moveToCenterFreq(); 139 void moveToDemodFreq(); 140 void zoomOnXAxis(float level); 141 142 // other FFT slots 143 void setFftPlotColor(const QColor& color); 144 void setFftFill(bool enabled); 145 void setPeakHold(bool enabled); 146 void setFftRange(float min, float max); 147 void setWfColormap(const QString &cmap); 148 void setPandapterRange(float min, float max); 149 void setWaterfallRange(float min, float max); 150 void setPeakDetection(bool enabled, float c); 151 void toggleBandPlan(bool state); 152 void updateOverlay(); 153 setPercent2DScreen(int percent)154 void setPercent2DScreen(int percent) 155 { 156 m_Percent2DScreen = percent; 157 m_Size = QSize(0,0); 158 resizeEvent(nullptr); 159 } 160 161 protected: 162 //re-implemented widget event handlers 163 void paintEvent(QPaintEvent *event) override; 164 void resizeEvent(QResizeEvent* event) override; 165 void mouseMoveEvent(QMouseEvent * event) override; 166 void mousePressEvent(QMouseEvent * event) override; 167 void mouseReleaseEvent(QMouseEvent * event) override; 168 void wheelEvent( QWheelEvent * event ) override; 169 170 private: 171 enum eCapturetype { 172 NOCAP, 173 LEFT, 174 CENTER, 175 RIGHT, 176 YAXIS, 177 XAXIS, 178 TAG 179 }; 180 181 void drawOverlay(); 182 void makeFrequencyStrs(); 183 int xFromFreq(qint64 freq); 184 qint64 freqFromX(int x); 185 void zoomStepX(float factor, int x); 186 static qint64 roundFreq(qint64 freq, int resolution); 187 quint64 msecFromY(int y); 188 void clampDemodParameters(); isPointCloseTo(int x,int xr,int delta)189 static bool isPointCloseTo(int x, int xr, int delta) 190 { 191 return ((x > (xr - delta)) && (x < (xr + delta))); 192 } 193 void getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth, 194 float maxdB, float mindB, 195 qint64 startFreq, qint64 stopFreq, 196 float *inBuf, qint32 *outBuf, 197 qint32 *maxbin, qint32 *minbin) const; 198 static void calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adjlow, qint64 &step, int& divs); 199 200 bool m_PeakHoldActive; 201 bool m_PeakHoldValid; 202 qint32 m_fftbuf[MAX_SCREENSIZE]{}; 203 quint8 m_wfbuf[MAX_SCREENSIZE]{}; // used for accumulating waterfall data at high time spans 204 qint32 m_fftPeakHoldBuf[MAX_SCREENSIZE]{}; 205 float *m_fftData{}; /*! pointer to incoming FFT data */ 206 float *m_wfData{}; 207 int m_fftDataSize{}; 208 209 int m_XAxisYCenter{}; 210 int m_YAxisWidth{}; 211 212 eCapturetype m_CursorCaptured; 213 QPixmap m_2DPixmap; 214 QPixmap m_OverlayPixmap; 215 QPixmap m_WaterfallPixmap; 216 QColor m_ColorTbl[256]; 217 QSize m_Size; 218 qreal m_DPR{}; 219 QString m_HDivText[HORZ_DIVS_MAX+1]; 220 bool m_Running; 221 bool m_DrawOverlay; 222 qint64 m_CenterFreq; // The HW frequency 223 qint64 m_FftCenter; // Center freq in the -span ... +span range 224 qint64 m_DemodCenterFreq; 225 qint64 m_StartFreqAdj{}; 226 qint64 m_FreqPerDiv{}; 227 bool m_CenterLineEnabled; /*!< Distinguish center line. */ 228 bool m_FilterBoxEnabled; /*!< Draw filter box. */ 229 bool m_TooltipsEnabled{}; /*!< Tooltips enabled */ 230 bool m_BandPlanEnabled; /*!< Show/hide band plan on spectrum */ 231 bool m_BookmarksEnabled; /*!< Show/hide bookmarks on spectrum */ 232 bool m_InvertScrolling; 233 bool m_DXCSpotsEnabled; /*!< Show/hide DXC Spots on spectrum */ 234 int m_DemodHiCutFreq; 235 int m_DemodLowCutFreq; 236 int m_DemodFreqX{}; //screen coordinate x position 237 int m_DemodHiCutFreqX{}; //screen coordinate x position 238 int m_DemodLowCutFreqX{}; //screen coordinate x position 239 int m_CursorCaptureDelta; 240 int m_GrabPosition; 241 int m_Percent2DScreen; 242 243 int m_FLowCmin; 244 int m_FLowCmax; 245 int m_FHiCmin; 246 int m_FHiCmax; 247 bool m_symetric; 248 249 int m_HorDivs; /*!< Current number of horizontal divisions. Calculated from width. */ 250 int m_VerDivs; /*!< Current number of vertical divisions. Calculated from height. */ 251 252 float m_PandMindB; 253 float m_PandMaxdB; 254 float m_WfMindB; 255 float m_WfMaxdB; 256 257 qint64 m_Span; 258 float m_SampleFreq; /*!< Sample rate. */ 259 qint32 m_FreqUnits; 260 int m_ClickResolution; 261 int m_FilterClickResolution; 262 263 int m_Xzero{}; 264 int m_Yzero{}; /*!< Used to measure mouse drag direction. */ 265 int m_FreqDigits; /*!< Number of decimal digits in frequency strings. */ 266 267 QFont m_Font; /*!< Font used for plotter (system font) */ 268 int m_HdivDelta; /*!< Minimum distance in pixels between two horizontal grid lines (vertical division). */ 269 int m_VdivDelta; /*!< Minimum distance in pixels between two vertical grid lines (horizontal division). */ 270 int m_BandPlanHeight; /*!< Height in pixels of band plan (if enabled) */ 271 272 quint32 m_LastSampleRate{}; 273 274 QColor m_FftColor, m_FftFillCol, m_PeakHoldColor; 275 bool m_FftFill{}; 276 277 float m_PeakDetection{}; 278 QMap<int,int> m_Peaks; 279 280 QList< QPair<QRect, qint64> > m_Taglist; 281 282 // Waterfall averaging 283 quint64 tlast_wf_ms; // last time waterfall has been updated 284 quint64 msec_per_wfline; // milliseconds between waterfall updates 285 quint64 wf_span; // waterfall span in milliseconds (0 = auto) 286 int fft_rate; // expected FFT rate (needed when WF span is auto) 287 }; 288 289 #endif // PLOTTER_H 290