diff options
author | trondeau | 2009-02-28 04:15:05 +0000 |
---|---|---|
committer | trondeau | 2009-02-28 04:15:05 +0000 |
commit | c57b705cf907ad3329da629f9d4dbbd82dc53c08 (patch) | |
tree | 6efa03e5c510a723832ada88caf6f5467321c70e /gr-qtgui | |
parent | 916a20271b7d81edc40dfc18468634311172c952 (diff) | |
download | gnuradio-c57b705cf907ad3329da629f9d4dbbd82dc53c08.tar.gz gnuradio-c57b705cf907ad3329da629f9d4dbbd82dc53c08.tar.bz2 gnuradio-c57b705cf907ad3329da629f9d4dbbd82dc53c08.zip |
Adding a constellation plot and an example for viewing constellations of digital modulations.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10537 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-qtgui')
-rw-r--r-- | gr-qtgui/src/lib/ConstellationDisplayPlot.cc | 167 | ||||
-rw-r--r-- | gr-qtgui/src/lib/ConstellationDisplayPlot.h | 49 | ||||
-rw-r--r-- | gr-qtgui/src/lib/Makefile.am | 3 | ||||
-rw-r--r-- | gr-qtgui/src/lib/spectrumdisplayform.cc | 34 | ||||
-rw-r--r-- | gr-qtgui/src/lib/spectrumdisplayform.h | 2 | ||||
-rw-r--r-- | gr-qtgui/src/lib/spectrumdisplayform.ui | 61 | ||||
-rwxr-xr-x | gr-qtgui/src/python/qt_digital.py | 40 |
7 files changed, 324 insertions, 32 deletions
diff --git a/gr-qtgui/src/lib/ConstellationDisplayPlot.cc b/gr-qtgui/src/lib/ConstellationDisplayPlot.cc new file mode 100644 index 000000000..c422c8f52 --- /dev/null +++ b/gr-qtgui/src/lib/ConstellationDisplayPlot.cc @@ -0,0 +1,167 @@ +#ifndef CONSTELLATION_DISPLAY_PLOT_C +#define CONSTELLATION_DISPLAY_PLOT_C + +#include <ConstellationDisplayPlot.h> + +#include <qwt_scale_draw.h> +#include <qwt_legend.h> + + +class ConstellationDisplayZoomer: public QwtPlotZoomer +{ +public: + ConstellationDisplayZoomer(QwtPlotCanvas* canvas):QwtPlotZoomer(canvas) + { + setTrackerMode(QwtPicker::AlwaysOn); + } + + virtual ~ConstellationDisplayZoomer(){ + + } + + virtual void updateTrackerText(){ + updateDisplay(); + } + +protected: + virtual QwtText trackerText( const QwtDoublePoint& p ) const + { + QwtText t(QString("Sample %1, %2 V").arg(p.x(), 0, 'f', 0).arg(p.y(), 0, 'f', 4)); + + return t; + } +}; + +ConstellationDisplayPlot::ConstellationDisplayPlot(QWidget* parent):QwtPlot(parent){ + timespec_reset(&_lastReplot); + + resize(parent->width(), parent->height()); + + _displayIntervalTime = (1.0/10.0); // 1/10 of a second between updates + + _numPoints = 1024; + _realDataPoints = new double[_numPoints]; + _imagDataPoints = new double[_numPoints]; + + // Disable polygon clipping + QwtPainter::setDeviceClipping(false); + + // We don't need the cache here + canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false); + canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false); + + QPalette palette; + palette.setColor(canvas()->backgroundRole(), QColor("white")); + canvas()->setPalette(palette); + + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setAxisScale(QwtPlot::xBottom, -1.0, 1.0); + setAxisTitle(QwtPlot::xBottom, "In-phase"); + + setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setAxisScale(QwtPlot::yLeft, -1.0, 1.0); + setAxisTitle(QwtPlot::yLeft, "Quadrature"); + + // Automatically deleted when parent is deleted + _plot_curve = new QwtPlotCurve("Constellation Points"); + _plot_curve->attach(this); + _plot_curve->setPen(QPen(Qt::blue, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + _plot_curve->setStyle(QwtPlotCurve::Dots); + _plot_curve->setRawData(_realDataPoints, _imagDataPoints, _numPoints); + + memset(_realDataPoints, 0x0, _numPoints*sizeof(double)); + memset(_imagDataPoints, 0x0, _numPoints*sizeof(double)); + + replot(); + + _zoomer = new ConstellationDisplayZoomer(canvas()); +#if QT_VERSION < 0x040000 + _zoomer->setMousePattern(QwtEventPattern::MouseSelect2, + Qt::RightButton, Qt::ControlModifier); +#else + _zoomer->setMousePattern(QwtEventPattern::MouseSelect2, + Qt::RightButton, Qt::ControlModifier); +#endif + _zoomer->setMousePattern(QwtEventPattern::MouseSelect3, + Qt::RightButton); + + _panner = new QwtPlotPanner(canvas()); + _panner->setAxisEnabled(QwtPlot::yRight, false); + _panner->setMouseButton(Qt::MidButton); + + // Avoid jumping when labels with more/less digits + // appear/disappear when scrolling vertically + + const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font()); + QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft); + sd->setMinimumExtent( fm.width("100.00") ); + + const QColor c(Qt::darkRed); + _zoomer->setRubberBandPen(c); + _zoomer->setTrackerPen(c); + + QwtLegend* legendDisplay = new QwtLegend(this); + legendDisplay->setItemMode(QwtLegend::CheckableItem); + insertLegend(legendDisplay); + + connect(this, SIGNAL( legendChecked(QwtPlotItem *, bool ) ), this, SLOT( LegendEntryChecked(QwtPlotItem *, bool ) )); +} + +ConstellationDisplayPlot::~ConstellationDisplayPlot(){ + delete[] _realDataPoints; + delete[] _imagDataPoints; + + // _fft_plot_curves deleted when parent deleted + // _zoomer and _panner deleted when parent deleted +} + + + +void ConstellationDisplayPlot::replot(){ + + const timespec startTime = get_highres_clock(); + + QwtPlot::replot(); + + double differenceTime = (diff_timespec(get_highres_clock(), startTime)); + + differenceTime *= 99.0; + // Require at least a 10% duty cycle + if(differenceTime > (1.0/10.0)){ + _displayIntervalTime = differenceTime; + } +} + +void ConstellationDisplayPlot::PlotNewData(const double* realDataPoints, const double* imagDataPoints, const int64_t numDataPoints){ + if(numDataPoints > 0){ + + if(numDataPoints != _numPoints){ + _numPoints = numDataPoints; + + delete[] _realDataPoints; + delete[] _imagDataPoints; + _realDataPoints = new double[_numPoints]; + _imagDataPoints = new double[_numPoints]; + + _plot_curve->setRawData(_realDataPoints, _imagDataPoints, _numPoints); + } + memcpy(_realDataPoints, realDataPoints, numDataPoints*sizeof(double)); + memcpy(_imagDataPoints, imagDataPoints, numDataPoints*sizeof(double)); + + } + + // Allow at least a 50% duty cycle + if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){ + // Only replot the screen if it is visible + if(isVisible()){ + replot(); + } + _lastReplot = get_highres_clock(); + } +} + +void ConstellationDisplayPlot::LegendEntryChecked(QwtPlotItem* plotItem, bool on){ + plotItem->setVisible(!on); +} + +#endif /* CONSTELLATION_DISPLAY_PLOT_C */ diff --git a/gr-qtgui/src/lib/ConstellationDisplayPlot.h b/gr-qtgui/src/lib/ConstellationDisplayPlot.h new file mode 100644 index 000000000..d7604ea84 --- /dev/null +++ b/gr-qtgui/src/lib/ConstellationDisplayPlot.h @@ -0,0 +1,49 @@ +#ifndef CONSTELLATION_DISPLAY_PLOT_HPP +#define CONSTELLATION_DISPLAY_PLOT_HPP + +#include <qwt_plot.h> +#include <qwt_painter.h> +#include <qwt_plot_canvas.h> +#include <qwt_plot_curve.h> +#include <qwt_scale_engine.h> +#include <qwt_scale_widget.h> +#include <qwt_plot_zoomer.h> +#include <qwt_plot_panner.h> +#include <qwt_plot_marker.h> +#include <highResTimeFunctions.h> +#include <qwt_symbol.h> + +class ConstellationDisplayPlot:public QwtPlot{ + Q_OBJECT + +public: + ConstellationDisplayPlot(QWidget*); + virtual ~ConstellationDisplayPlot(); + + void PlotNewData(const double* realDataPoints, const double* imagDataPoints, + const int64_t numDataPoints); + + virtual void replot(); + +protected slots: + void LegendEntryChecked(QwtPlotItem *plotItem, bool on); + +protected: + +private: + QwtPlotCurve* _plot_curve; + + QwtPlotPanner* _panner; + QwtPlotZoomer* _zoomer; + + double* _realDataPoints; + double* _imagDataPoints; + + timespec _lastReplot; + + int64_t _numPoints; + + double _displayIntervalTime; +}; + +#endif /* CONSTELLATION_DISPLAY_PLOT_HPP */ diff --git a/gr-qtgui/src/lib/Makefile.am b/gr-qtgui/src/lib/Makefile.am index 41281e687..034eff053 100644 --- a/gr-qtgui/src/lib/Makefile.am +++ b/gr-qtgui/src/lib/Makefile.am @@ -54,6 +54,7 @@ QMAKE_SOURCES = \ TimeDomainDisplayPlot_moc.cc \ WaterfallDisplayPlot_moc.cc \ Waterfall3DDisplayPlot_moc.cc \ + ConstellationDisplayPlot_moc.cc \ spectrumdisplayform_ui.h endif @@ -81,6 +82,7 @@ libqtgui_la_SOURCES = \ WaterfallDisplayPlot.cc \ Waterfall3DDisplayPlot.cc \ waterfallGlobalData.cc \ + ConstellationDisplayPlot.cc \ spectrumdisplayform.cc \ SpectrumGUIClass.cc \ spectrumUpdateEvents.cc \ @@ -100,6 +102,7 @@ grinclude_HEADERS = \ WaterfallDisplayPlot.h \ Waterfall3DDisplayPlot.h \ waterfallGlobalData.h \ + ConstellationDisplayPlot.h \ highResTimeFunctions.h \ plot_waterfall.h \ spectrumdisplayform.h \ diff --git a/gr-qtgui/src/lib/spectrumdisplayform.cc b/gr-qtgui/src/lib/spectrumdisplayform.cc index e0b43ae30..a898015be 100644 --- a/gr-qtgui/src/lib/spectrumdisplayform.cc +++ b/gr-qtgui/src/lib/spectrumdisplayform.cc @@ -15,6 +15,7 @@ SpectrumDisplayForm::SpectrumDisplayForm(QWidget* parent) : QDialog(parent){ _waterfallDisplayPlot = new WaterfallDisplayPlot(Tab2PlotDisplayFrame); _waterfall3DDisplayPlot = new Waterfall3DDisplayPlot(Waterfall3DPlotDisplayFrame); _timeDomainDisplayPlot = new TimeDomainDisplayPlot(TimeDomainDisplayFrame); + _constellationDisplayPlot = new ConstellationDisplayPlot(ConstellationDisplayFrame); _numRealDataPoints = 1024; _realFFTDataPoints = new double[_numRealDataPoints]; _averagedValues = new double[_numRealDataPoints]; @@ -42,8 +43,10 @@ SpectrumDisplayForm::SpectrumDisplayForm(QWidget* parent) : QDialog(parent){ _noiseFloorAmplitude = -HUGE_VAL; - connect(_waterfallDisplayPlot, SIGNAL(UpdatedLowerIntensityLevel(const double)), _frequencyDisplayPlot, SLOT(SetLowerIntensityLevel(const double))); - connect(_waterfallDisplayPlot, SIGNAL(UpdatedUpperIntensityLevel(const double)), _frequencyDisplayPlot, SLOT(SetUpperIntensityLevel(const double))); + connect(_waterfallDisplayPlot, SIGNAL(UpdatedLowerIntensityLevel(const double)), + _frequencyDisplayPlot, SLOT(SetLowerIntensityLevel(const double))); + connect(_waterfallDisplayPlot, SIGNAL(UpdatedUpperIntensityLevel(const double)), + _frequencyDisplayPlot, SLOT(SetUpperIntensityLevel(const double))); _frequencyDisplayPlot->SetLowerIntensityLevel(-200); _frequencyDisplayPlot->SetUpperIntensityLevel(-200); @@ -72,7 +75,9 @@ SpectrumDisplayForm::~SpectrumDisplayForm(){ delete _historyVector; } -void SpectrumDisplayForm::setSystem( SpectrumGUIClass * newSystem, const uint64_t numFFTDataPoints, const uint64_t numTimeDomainDataPoints ) +void SpectrumDisplayForm::setSystem( SpectrumGUIClass * newSystem, + const uint64_t numFFTDataPoints, + const uint64_t numTimeDomainDataPoints ) { ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints); @@ -168,6 +173,9 @@ void SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumU _timeDomainDisplayPlot->PlotNewData(realTimeDomainDataPoints, imagTimeDomainDataPoints, numTimeDomainDataPoints); + _constellationDisplayPlot->PlotNewData(realTimeDomainDataPoints, + imagTimeDomainDataPoints, + numTimeDomainDataPoints); } // Don't update the repeated data for the waterfall if(!repeatDataFlag){ @@ -199,27 +207,29 @@ void SpectrumDisplayForm::resizeEvent( QResizeEvent *e ) SpectrumTypeTab->resize( e->size().width(), SpectrumTypeTab->height()); // Tell the TabXFreqDisplay to resize - Tab1PlotDisplayFrame->resize(e->size().width()-4, + Tab1PlotDisplayFrame->resize(e->size().width()-4, Tab1PlotDisplayFrame->height()); Tab2PlotDisplayFrame->resize(e->size().width()-4, Tab2PlotDisplayFrame->height()); - Waterfall3DPlotDisplayFrame->resize(e->size().width()-4, + Waterfall3DPlotDisplayFrame->resize(e->size().width()-4, Waterfall3DPlotDisplayFrame->height()); - TimeDomainDisplayFrame->resize(e->size().width()-4, + TimeDomainDisplayFrame->resize(e->size().width()-4, TimeDomainDisplayFrame->height()); - _frequencyDisplayPlot->resize( Tab1PlotDisplayFrame->width()-4, + _frequencyDisplayPlot->resize( Tab1PlotDisplayFrame->width()-4, Tab1PlotDisplayFrame->height()); - _waterfallDisplayPlot->resize( Tab2PlotDisplayFrame->width()-4, + _waterfallDisplayPlot->resize( Tab2PlotDisplayFrame->width()-4, Tab2PlotDisplayFrame->height()); - _waterfall3DDisplayPlot->resize( Waterfall3DPlotDisplayFrame->width()-4, + _waterfall3DDisplayPlot->resize( Waterfall3DPlotDisplayFrame->width()-4, Waterfall3DPlotDisplayFrame->height()); - _timeDomainDisplayPlot->resize( TimeDomainDisplayFrame->width()-4, + _timeDomainDisplayPlot->resize( TimeDomainDisplayFrame->width()-4, TimeDomainDisplayFrame->height()); // Move the IntensityWheels and Labels - WaterfallMaximumIntensityLabel->move(width() - 5 - WaterfallMaximumIntensityLabel->width(), + WaterfallMaximumIntensityLabel->move(width() - 5 - + WaterfallMaximumIntensityLabel->width(), WaterfallMaximumIntensityLabel->y()); - WaterfallMinimumIntensityLabel->move(width() - 5 - WaterfallMinimumIntensityLabel->width(), + WaterfallMinimumIntensityLabel->move(width() - 5 - + WaterfallMinimumIntensityLabel->width(), WaterfallMinimumIntensityLabel->y()); WaterfallMaximumIntensityWheel->resize(WaterfallMaximumIntensityLabel->x() - 5 - WaterfallMaximumIntensityWheel->x(), diff --git a/gr-qtgui/src/lib/spectrumdisplayform.h b/gr-qtgui/src/lib/spectrumdisplayform.h index 97b14a6c9..6e57e2cec 100644 --- a/gr-qtgui/src/lib/spectrumdisplayform.h +++ b/gr-qtgui/src/lib/spectrumdisplayform.h @@ -11,6 +11,7 @@ class SpectrumGUIClass; #include <WaterfallDisplayPlot.h> #include <Waterfall3DDisplayPlot.h> #include <TimeDomainDisplayPlot.h> +#include <ConstellationDisplayPlot.h> #include <QValidator> #include <vector> @@ -73,6 +74,7 @@ private: WaterfallDisplayPlot* _waterfallDisplayPlot; Waterfall3DDisplayPlot* _waterfall3DDisplayPlot; TimeDomainDisplayPlot* _timeDomainDisplayPlot; + ConstellationDisplayPlot* _constellationDisplayPlot; SpectrumGUIClass* _system; bool _systemSpecifiedFlag; double _centerFrequency; diff --git a/gr-qtgui/src/lib/spectrumdisplayform.ui b/gr-qtgui/src/lib/spectrumdisplayform.ui index aac323dac..561be64cb 100644 --- a/gr-qtgui/src/lib/spectrumdisplayform.ui +++ b/gr-qtgui/src/lib/spectrumdisplayform.ui @@ -358,7 +358,7 @@ </property> </item> </widget> - <widget class="QwtWheel" native="1" name="WaterfallMaximumIntensityWheel" > + <widget class="QwtWheel" name="WaterfallMaximumIntensityWheel" > <property name="geometry" > <rect> <x>215</x> @@ -373,16 +373,16 @@ <property name="focusPolicy" > <enum>Qt::WheelFocus</enum> </property> - <property name="valid" stdset="0" > + <property name="valid" > <bool>true</bool> </property> - <property name="totalAngle" stdset="0" > + <property name="totalAngle" > <double>200.000000000000000</double> </property> - <property name="viewAngle" stdset="0" > + <property name="viewAngle" > <double>20.000000000000000</double> </property> - <property name="mass" stdset="0" > + <property name="mass" > <double>0.000000000000000</double> </property> </widget> @@ -418,7 +418,7 @@ <enum>QFrame::Plain</enum> </property> </widget> - <widget class="QwtWheel" native="1" name="WaterfallMinimumIntensityWheel" > + <widget class="QwtWheel" name="WaterfallMinimumIntensityWheel" > <property name="geometry" > <rect> <x>215</x> @@ -427,16 +427,16 @@ <height>24</height> </rect> </property> - <property name="valid" stdset="0" > + <property name="valid" > <bool>true</bool> </property> - <property name="totalAngle" stdset="0" > + <property name="totalAngle" > <double>200.000000000000000</double> </property> - <property name="viewAngle" stdset="0" > + <property name="viewAngle" > <double>20.000000000000000</double> </property> - <property name="mass" stdset="0" > + <property name="mass" > <double>0.000000000000000</double> </property> </widget> @@ -525,7 +525,7 @@ <string>Auto Scale</string> </property> </widget> - <widget class="QwtWheel" native="1" name="Waterfall3DMinimumIntensityWheel" > + <widget class="QwtWheel" name="Waterfall3DMinimumIntensityWheel" > <property name="geometry" > <rect> <x>215</x> @@ -534,16 +534,16 @@ <height>24</height> </rect> </property> - <property name="valid" stdset="0" > + <property name="valid" > <bool>true</bool> </property> - <property name="totalAngle" stdset="0" > + <property name="totalAngle" > <double>200.000000000000000</double> </property> - <property name="viewAngle" stdset="0" > + <property name="viewAngle" > <double>20.000000000000000</double> </property> - <property name="mass" stdset="0" > + <property name="mass" > <double>0.000000000000000</double> </property> </widget> @@ -614,7 +614,7 @@ </property> </item> </widget> - <widget class="QwtWheel" native="1" name="Waterfall3DMaximumIntensityWheel" > + <widget class="QwtWheel" name="Waterfall3DMaximumIntensityWheel" > <property name="geometry" > <rect> <x>215</x> @@ -629,16 +629,16 @@ <property name="focusPolicy" > <enum>Qt::WheelFocus</enum> </property> - <property name="valid" stdset="0" > + <property name="valid" > <bool>true</bool> </property> - <property name="totalAngle" stdset="0" > + <property name="totalAngle" > <double>200.000000000000000</double> </property> - <property name="viewAngle" stdset="0" > + <property name="viewAngle" > <double>20.000000000000000</double> </property> - <property name="mass" stdset="0" > + <property name="mass" > <double>0.000000000000000</double> </property> </widget> @@ -664,6 +664,27 @@ </property> </widget> </widget> + <widget class="QWidget" name="ConstellationPage" > + <attribute name="title" > + <string>Constellation Display</string> + </attribute> + <widget class="QFrame" name="ConstellationDisplayFrame" > + <property name="geometry" > + <rect> + <x>5</x> + <y>5</y> + <width>620</width> + <height>340</height> + </rect> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + </widget> + </widget> </widget> </widget> <layoutdefault spacing="6" margin="11" /> diff --git a/gr-qtgui/src/python/qt_digital.py b/gr-qtgui/src/python/qt_digital.py new file mode 100755 index 000000000..f7635b4a5 --- /dev/null +++ b/gr-qtgui/src/python/qt_digital.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +from gnuradio import gr, blks2 +from gnuradio.qtgui import qtgui +import scipy + +class my_top_block(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + sps = 2 + excess_bw = 0.35 + gray_code = True + + fftsize = 2048 + + data = scipy.random.randint(0, 255, 1000) + src = gr.vector_source_b(data, True) + mod = blks2.dqpsk_mod(sps, excess_bw, gray_code, False, False) + + rrctaps = gr.firdes.root_raised_cosine(1, sps, 1, excess_bw, 21) + rx_rrc = gr.fir_filter_ccf(sps, rrctaps) + + thr = gr.throttle(gr.sizeof_gr_complex, 10*fftsize) + self.snk_tx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS, -1/2, 1/2) + self.snk_rx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS, -1/2, 1/2) + + self.connect(src, mod, self.snk_tx) + self.connect(mod, rx_rrc, thr, self.snk_rx) + + self.snk_tx.initialize() + qapp = self.snk_tx.get_qapplication() + self.snk_rx.initialize(qapp) + +if __name__ == "__main__": + tb = my_top_block(); + tb.start() + tb.snk_tx.start_app(); + #tb.wait(); + |