diff options
author | Tom Rondeau <tom@trondeau.com> | 2013-08-02 13:30:38 -0400 |
---|---|---|
committer | Tom Rondeau <tom@trondeau.com> | 2013-08-02 13:30:38 -0400 |
commit | f6a1e39fe3fca5b50ea664ad2055e37045ee6bef (patch) | |
tree | e4458278d89d7ba46204d870f18e0e943d0ef484 | |
parent | 0a5c5d55040f6a6812db2f9c8d62b36838b70a91 (diff) |
qtgui: Added histogram sink.
-rw-r--r-- | gr-qtgui/grc/qtgui_block_tree.xml | 3 | ||||
-rw-r--r-- | gr-qtgui/grc/qtgui_histogram_sink_x.xml | 77 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt | 3 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h | 29 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h | 74 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/displayform.h | 2 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h | 104 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h | 79 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h | 28 | ||||
-rw-r--r-- | gr-qtgui/lib/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gr-qtgui/lib/HistogramDisplayPlot.cc | 434 | ||||
-rw-r--r-- | gr-qtgui/lib/displayform.cc | 5 | ||||
-rw-r--r-- | gr-qtgui/lib/histogram_sink_f_impl.cc | 381 | ||||
-rw-r--r-- | gr-qtgui/lib/histogram_sink_f_impl.h | 110 | ||||
-rw-r--r-- | gr-qtgui/lib/histogramdisplayform.cc | 168 | ||||
-rw-r--r-- | gr-qtgui/lib/spectrumUpdateEvents.cc | 43 | ||||
-rwxr-xr-x | gr-qtgui/python/qtgui/qa_qtgui.py | 3 | ||||
-rw-r--r-- | gr-qtgui/swig/qtgui_swig.i | 3 |
18 files changed, 1535 insertions, 16 deletions
diff --git a/gr-qtgui/grc/qtgui_block_tree.xml b/gr-qtgui/grc/qtgui_block_tree.xml index e9d57a664c..14516df71e 100644 --- a/gr-qtgui/grc/qtgui_block_tree.xml +++ b/gr-qtgui/grc/qtgui_block_tree.xml @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright 2012 Free Software Foundation, Inc. + Copyright 2012-2013 Free Software Foundation, Inc. This file is part of GNU Radio @@ -37,6 +37,7 @@ <block>qtgui_const_sink_x</block> <block>qtgui_waterfall_sink_x</block> <block>qtgui_time_raster_sink_x</block> + <block>qtgui_histogram_sink_x</block> <block>qtgui_sink_x</block> </cat> </cat> diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml new file mode 100644 index 0000000000..f7405616d5 --- /dev/null +++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##QT GUI Histogram Sink +################################################### + --> +<block> + <name>QT GUI Histogram Sink</name> + <key>qtgui_histogram_sink_x</key> + <import>from PyQt4 import Qt</import> + <import>from gnuradio import qtgui</import> + <import>import sip</import> + <make>#set $win = 'self._%s_win'%$id +qtgui.histogram_sink_f( + $size, + $bins, + $name, + $nconnections +) +self.$(id).set_bins($bins) +self.$(id).set_update_time($update_time) +self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) +$(gui_hint()($win))</make> + <callback>set_update_time($update_time)</callback> + <callback>set_title($which, $title)</callback> + <callback>set_color($which, $color)</callback> + <callback>set_bins($bins)</callback> + <param> + <name>Name</name> + <key>name</key> + <value>QT GUI Plot</value> + <type>string</type> + </param> + <param> + <name>Number of Points</name> + <key>size</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Number of Bins</name> + <key>bins</key> + <value>100</value> + <type>int</type> + </param> + <param> + <name>Number of Inputs</name> + <key>nconnections</key> + <value>1</value> + <type>int</type> + <hide>part</hide> + </param> + <param> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> + <type>float</type> + <hide>part</hide> + </param> + <param> + <name>GUI Hint</name> + <key>gui_hint</key> + <value></value> + <type>gui_hint</type> + <hide>part</hide> + </param> + <sink> + <name>in</name> + <type>float</type> + <nports>$nconnections</nports> + </sink> + <doc> +The GUI hint can be used to position the widget within the application. \ +The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \ +Both the tab specification and the grid position are optional. + </doc> +</block> diff --git a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt index 8f95837fec..0d5cb58f5d 100644 --- a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt +++ b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt @@ -33,6 +33,9 @@ install(FILES freq_sink_c.h freq_sink_f.h FrequencyDisplayPlot.h + histogram_sink_f.h + histogramdisplayform.h + HistogramDisplayPlot.h plot_raster.h plot_waterfall.h qtgui_types.h diff --git a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h index bafc712aac..895328ad6e 100644 --- a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h +++ b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h @@ -180,20 +180,21 @@ public: // void PlotNewData(...); public slots: - void setYaxis(double min, double max); - void setXaxis(double min, double max); - void setLineLabel(int which, QString label); - QString getLineLabel(int which); - void setLineColor(int which, QColor color); - QColor getLineColor(int which) const; - void setLineWidth(int which, int width); - int getLineWidth(int which) const; - void setLineStyle(int which, Qt::PenStyle style); - const Qt::PenStyle getLineStyle(int which) const; - void setLineMarker(int which, QwtSymbol::Style marker); - const QwtSymbol::Style getLineMarker(int which) const; - void setMarkerAlpha(int which, int alpha); - int getMarkerAlpha(int which) const; + virtual void setYaxis(double min, double max); + virtual void setXaxis(double min, double max); + virtual void setLineLabel(int which, QString label); + virtual QString getLineLabel(int which); + virtual void setLineColor(int which, QColor color); + virtual QColor getLineColor(int which) const; + virtual void setLineWidth(int which, int width); + virtual int getLineWidth(int which) const; + virtual void setLineStyle(int which, Qt::PenStyle style); + virtual const Qt::PenStyle getLineStyle(int which) const; + virtual void setLineMarker(int which, QwtSymbol::Style marker); + virtual const QwtSymbol::Style getLineMarker(int which) const; + virtual void setMarkerAlpha(int which, int alpha); + virtual int getMarkerAlpha(int which) const; + // Need a function for each curve for setting via stylesheet. // Can't use preprocessor directives because we're inside a Q_OBJECT. void setLineColor1 (QColor); diff --git a/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h new file mode 100644 index 0000000000..bcf7272691 --- /dev/null +++ b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef HISTOGRAM_DISPLAY_PLOT_H +#define HISTOGRAM_DISPLAY_PLOT_H + +#include <stdint.h> +#include <cstdio> +#include <vector> +#include <gnuradio/qtgui/DisplayPlot.h> + +/*! + * \brief QWidget for displaying time domain plots. + * \ingroup qtgui_blk + */ +class HistogramDisplayPlot: public DisplayPlot +{ + Q_OBJECT + +public: + HistogramDisplayPlot(int nplots, QWidget*); + virtual ~HistogramDisplayPlot(); + + void plotNewData(const std::vector<double*> dataPoints, + const int64_t numDataPoints, const double timeInterval); + + void replot(); + +public slots: + void setAutoScale(bool state); + void setSemilogx(bool en); + void setSemilogy(bool en); + void setAccumulate(bool en); + + void setMarkerAlpha(int which, int alpha); + int getMarkerAlpha(int which) const; + void setLineColor(int which, QColor color); + + void setNumBins(int bins); + +private: + void _resetXAxisPoints(double bottom, double top); + void _autoScale(double bottom, double top); + + double* _xAxisPoints; + std::vector<double*> _yDataPoints; + + int _bins; + bool _accum; + + bool d_semilogx; + bool d_semilogy; +}; + +#endif /* HISTOGRAM_DISPLAY_PLOT_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/displayform.h b/gr-qtgui/include/gnuradio/qtgui/displayform.h index f94bb7fd04..54f878dc47 100644 --- a/gr-qtgui/include/gnuradio/qtgui/displayform.h +++ b/gr-qtgui/include/gnuradio/qtgui/displayform.h @@ -77,7 +77,7 @@ public slots: QwtSymbol::Style lineMarker(int which); int markerAlpha(int which); - virtual void setSampleRate(const QString &rate) = 0; + virtual void setSampleRate(const QString &rate); void setStop(bool on); void setStop(); diff --git a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h new file mode 100644 index 0000000000..8ec04d58b0 --- /dev/null +++ b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h @@ -0,0 +1,104 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QTGUI_HISTOGRAM_SINK_F_H +#define INCLUDED_QTGUI_HISTOGRAM_SINK_F_H + +#include <Python.h> +#include <gnuradio/qtgui/api.h> +#include <gnuradio/sync_block.h> +#include <qapplication.h> + +namespace gr { + namespace qtgui { + + /*! + * \brief A graphical sink to display a histogram. + * \ingroup instrumentation_blk + * \ingroup qtgui_blk + * + * \details + * This is a QT-based graphical sink the displays a histogram of + * the data. + */ + class QTGUI_API histogram_sink_f : virtual public sync_block + { + public: + // gr::qtgui::histogram_sink_f::sptr + typedef boost::shared_ptr<histogram_sink_f> sptr; + + /*! + * \brief Build floating point histogram sink + * + * \param size number of points to plot at once + * \param bins number of bins to sort the data into + * \param name title for the plot + * \param nconnections number of signals connected to sink + * \param parent a QWidget parent object, if any + */ + static sptr make(int size, int bins, + const std::string &name, + int nconnections=1, + QWidget *parent=NULL); + + virtual void exec_() = 0; + virtual PyObject* pyqwidget() = 0; + + virtual void set_y_axis(double min, double max) = 0; + virtual void set_update_time(double t) = 0; + virtual void set_title(const std::string &title) = 0; + virtual void set_line_label(int which, const std::string &line) = 0; + virtual void set_line_color(int which, const std::string &color) = 0; + virtual void set_line_width(int which, int width) = 0; + virtual void set_line_style(int which, int style) = 0; + virtual void set_line_marker(int which, int marker) = 0; + virtual void set_line_alpha(int which, double alpha) = 0; + virtual void set_nsamps(const int newsize) = 0; + virtual void set_bins(const int bins) = 0; + + virtual std::string title() = 0; + virtual std::string line_label(int which) = 0; + virtual std::string line_color(int which) = 0; + virtual int line_width(int which) = 0; + virtual int line_style(int which) = 0; + virtual int line_marker(int which) = 0; + virtual double line_alpha(int which) = 0; + + virtual void set_size(int width, int height) = 0; + + virtual void enable_menu(bool en=true) = 0; + virtual void enable_grid(bool en=true) = 0; + virtual void enable_autoscale(bool en=true) = 0; + virtual void enable_semilogx(bool en=true) = 0; + virtual void enable_semilogy(bool en=true) = 0; + virtual void enable_accumulate(bool en=true) = 0; + virtual int nsamps() const = 0; + virtual int bins() const = 0; + virtual void reset() = 0; + + QApplication *d_qApplication; + }; + + } /* namespace qtgui */ +} /* namespace gr */ + +#endif /* INCLUDED_QTGUI_HISTOGRAM_SINK_F_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h new file mode 100644 index 0000000000..39247b046e --- /dev/null +++ b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef HISTOGRAM_DISPLAY_FORM_H +#define HISTOGRAM_DISPLAY_FORM_H + +#include <gnuradio/qtgui/spectrumUpdateEvents.h> +#include <gnuradio/qtgui/HistogramDisplayPlot.h> +#include <QtGui/QtGui> +#include <vector> + +#include <gnuradio/qtgui/displayform.h> + +/*! + * \brief DisplayForm child for managing histogram domain plots. + * \ingroup qtgui_blk + */ +class HistogramDisplayForm : public DisplayForm +{ + Q_OBJECT + + public: + HistogramDisplayForm(int nplots=1, QWidget* parent = 0); + ~HistogramDisplayForm(); + + HistogramDisplayPlot* getPlot(); + + int getNPoints() const; + +public slots: + void customEvent(QEvent * e); + + void setYaxis(double min, double max); + void setNPoints(const int); + void autoScale(bool en); + void setSemilogx(bool en); + void setSemilogy(bool en); + + void setNumBins(const int); + void setAccumulate(bool en); + +private slots: + void newData(const QEvent*); + +private: + QIntValidator* _intValidator; + + double _startFrequency; + double _stopFrequency; + + int d_npoints; + + bool d_semilogx; + bool d_semilogy; + + QAction *d_semilogxmenu; + QAction *d_semilogymenu; +}; + +#endif /* HISTOGRAM_DISPLAY_FORM_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h b/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h index f3bb486d82..c1dbdafc26 100644 --- a/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h +++ b/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h @@ -262,4 +262,32 @@ private: }; +/********************************************************************/ + + +class HistogramUpdateEvent: public QEvent +{ +public: + HistogramUpdateEvent(const std::vector<double*> points, + const uint64_t npoints); + + ~HistogramUpdateEvent(); + + int which() const; + const std::vector<double*> getDataPoints() const; + uint64_t getNumDataPoints() const; + bool getRepeatDataFlag() const; + + static QEvent::Type Type() + { return QEvent::Type(SpectrumUpdateEventType); } + +protected: + +private: + size_t _nplots; + std::vector<double*> _points; + uint64_t _npoints; +}; + + #endif /* SPECTRUM_UPDATE_EVENTS_H */ diff --git a/gr-qtgui/lib/CMakeLists.txt b/gr-qtgui/lib/CMakeLists.txt index 2df8b31555..257f03a2a2 100644 --- a/gr-qtgui/lib/CMakeLists.txt +++ b/gr-qtgui/lib/CMakeLists.txt @@ -29,6 +29,7 @@ set(qtgui_moc_hdrs ${qtgui_mod_includedir}/freqdisplayform.h ${qtgui_mod_includedir}/constellationdisplayform.h ${qtgui_mod_includedir}/waterfalldisplayform.h + ${qtgui_mod_includedir}/histogramdisplayform.h ${qtgui_mod_includedir}/form_menus.h ${qtgui_mod_includedir}/DisplayPlot.h ${qtgui_mod_includedir}/FrequencyDisplayPlot.h @@ -36,6 +37,7 @@ set(qtgui_moc_hdrs ${qtgui_mod_includedir}/TimeRasterDisplayPlot.h ${qtgui_mod_includedir}/WaterfallDisplayPlot.h ${qtgui_mod_includedir}/ConstellationDisplayPlot.h + ${qtgui_mod_includedir}/HistogramDisplayPlot.h ) QT4_WRAP_CPP(qtgui_moc_srcs ${qtgui_moc_hdrs}) QT4_WRAP_UI(qtgui_ui_hdrs spectrumdisplayform.ui) @@ -58,12 +60,14 @@ set(qtgui_srcs WaterfallDisplayPlot.cc waterfallGlobalData.cc ConstellationDisplayPlot.cc + HistogramDisplayPlot.cc spectrumdisplayform.cc displayform.cc timedisplayform.cc timerasterdisplayform.cc freqdisplayform.cc constellationdisplayform.cc + histogramdisplayform.cc waterfalldisplayform.cc SpectrumGUIClass.cc spectrumUpdateEvents.cc @@ -80,6 +84,7 @@ set(qtgui_srcs const_sink_c_impl.cc waterfall_sink_c_impl.cc waterfall_sink_f_impl.cc + histogram_sink_f_impl.cc qtgui_util.cc ) diff --git a/gr-qtgui/lib/HistogramDisplayPlot.cc b/gr-qtgui/lib/HistogramDisplayPlot.cc new file mode 100644 index 0000000000..01b69d4a07 --- /dev/null +++ b/gr-qtgui/lib/HistogramDisplayPlot.cc @@ -0,0 +1,434 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef HISTOGRAM_DISPLAY_PLOT_C +#define HISTOGRAM_DISPLAY_PLOT_C + +#include <gnuradio/qtgui/HistogramDisplayPlot.h> + +#include <qwt_scale_draw.h> +#include <qwt_legend.h> +#include <QColor> +#include <cmath> +#include <iostream> +#include <volk/volk.h> +#include <gnuradio/math.h> +#include <boost/math/special_functions/round.hpp> + +class TimePrecisionClass +{ +public: + TimePrecisionClass(const int timePrecision) + { + _timePrecision = timePrecision; + } + + virtual ~TimePrecisionClass() + { + } + + virtual unsigned int getTimePrecision() const + { + return _timePrecision; + } + + virtual void setTimePrecision(const unsigned int newPrecision) + { + _timePrecision = newPrecision; + } +protected: + unsigned int _timePrecision; +}; + + +class HistogramDisplayZoomer: public QwtPlotZoomer, public TimePrecisionClass +{ +public: + HistogramDisplayZoomer(QwtPlotCanvas* canvas, const unsigned int timePrecision) + : QwtPlotZoomer(canvas),TimePrecisionClass(timePrecision) + { + setTrackerMode(QwtPicker::AlwaysOn); + } + + virtual ~HistogramDisplayZoomer() + { + } + + virtual void updateTrackerText() + { + updateDisplay(); + } + + void setUnitType(const std::string &type) + { + _unitType = type; + } + +protected: + using QwtPlotZoomer::trackerText; + virtual QwtText trackerText(const QPoint& p) const + { + QwtText t; + QwtDoublePoint dp = QwtPlotZoomer::invTransform(p); + if((dp.y() > 0.0001) && (dp.y() < 10000)) { + t.setText(QString("%1 %2, %3 V"). + arg(dp.x(), 0, 'f', getTimePrecision()). + arg(_unitType.c_str()). + arg(dp.y(), 0, 'f', 4)); + } + else { + t.setText(QString("%1 %2, %3 V"). + arg(dp.x(), 0, 'f', getTimePrecision()). + arg(_unitType.c_str()). + arg(dp.y(), 0, 'e', 4)); + } + + return t; + } + +private: + std::string _unitType; +}; + + +/*********************************************************************** + * Main Time domain plotter widget + **********************************************************************/ +HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) + : DisplayPlot(nplots, parent) +{ + _bins = 100; + _accum = false; + + // Initialize x-axis data array + _xAxisPoints = new double[_bins]; + memset(_xAxisPoints, 0x0, _bins*sizeof(double)); + + _zoomer = new HistogramDisplayZoomer(canvas(), 0); + +#if QWT_VERSION < 0x060000 + _zoomer->setSelectionFlags(QwtPicker::RectSelection | QwtPicker::DragSelection); +#endif + + _zoomer->setMousePattern(QwtEventPattern::MouseSelect2, + Qt::RightButton, Qt::ControlModifier); + _zoomer->setMousePattern(QwtEventPattern::MouseSelect3, + Qt::RightButton); + + const QColor c(Qt::darkRed); + _zoomer->setRubberBandPen(c); + _zoomer->setTrackerPen(c); + + d_semilogx = false; + d_semilogy = false; + + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setXaxis(-1, 1); + setAxisTitle(QwtPlot::xBottom, "Value"); + + setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setYaxis(-2.0, _bins); + setAxisTitle(QwtPlot::yLeft, "Count"); + + QList<QColor> colors; + colors << QColor(Qt::blue) << QColor(Qt::red) << QColor(Qt::green) + << QColor(Qt::black) << QColor(Qt::cyan) << QColor(Qt::magenta) + << QColor(Qt::yellow) << QColor(Qt::gray) << QColor(Qt::darkRed) + << QColor(Qt::darkGreen) << QColor(Qt::darkBlue) << QColor(Qt::darkGray); + + // Setup dataPoints and plot vectors + // Automatically deleted when parent is deleted + for(int i = 0; i < _nplots; i++) { + _yDataPoints.push_back(new double[_bins]); + memset(_yDataPoints[i], 0, _bins*sizeof(double)); + + _plot_curve.push_back(new QwtPlotCurve(QString("Data %1").arg(i))); + _plot_curve[i]->attach(this); + _plot_curve[i]->setPen(QPen(colors[i])); + _plot_curve[i]->setRenderHint(QwtPlotItem::RenderAntialiased); + + // Adjust color's transparency for the brush + colors[i].setAlpha(127 / _nplots); + _plot_curve[i]->setBrush(QBrush(colors[i])); + + colors[i].setAlpha(255 / _nplots); + QwtSymbol *symbol = new QwtSymbol(QwtSymbol::NoSymbol, QBrush(colors[i]), + QPen(colors[i]), QSize(7,7)); + +#if QWT_VERSION < 0x060000 + _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins); + _plot_curve[i]->setSymbol(*symbol); +#else + _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins); + _plot_curve[i]->setSymbol(symbol); +#endif + } + + _resetXAxisPoints(-1, 1); +} + +HistogramDisplayPlot::~HistogramDisplayPlot() +{ + for(int i = 0; i < _nplots; i++) + delete[] _yDataPoints[i]; + delete[] _xAxisPoints; + + // _zoomer and _panner deleted when parent deleted +} + +void +HistogramDisplayPlot::replot() +{ + QwtPlot::replot(); +} + +void +HistogramDisplayPlot::plotNewData(const std::vector<double*> dataPoints, + const int64_t numDataPoints, + const double timeInterval) +{ + if(!_stop) { + if((numDataPoints > 0)) { + + double bottom = *std::min_element(dataPoints[0], dataPoints[0]+numDataPoints); + double top = *std::max_element(dataPoints[0], dataPoints[0]+numDataPoints); + for(int n = 1; n < _nplots; n++) { + bottom = std::min(bottom, *std::min_element(dataPoints[n], dataPoints[n]+numDataPoints)); + top = std::max(top, *std::max_element(dataPoints[n], dataPoints[n]+numDataPoints)); + } + + _resetXAxisPoints(bottom, top); + + int index; + double width = (top - bottom)/(_bins-1); + + // Something's wrong with the data (NaN, Inf, or something else) + if((bottom == top) || (bottom > top)) + return; + + for(int n = 0; n < _nplots; n++) { + if(!_accum) + memset(_yDataPoints[n], 0, _bins*sizeof(double)); + for(int64_t point = 0; point < numDataPoints; point++) { + index = boost::math::iround(1e-20 + (dataPoints[n][point] - bottom)/width); + index = std::max(std::min(index, _bins), 0); + _yDataPoints[n][static_cast<int>(index)] += 1; + } + } + + double height = *std::max_element(_yDataPoints[0], _yDataPoints[0]+_bins); + for(int n = 1; n < _nplots; n++) { + height = std::max(height, *std::max_element(_yDataPoints[n], _yDataPoints[n]+_bins)); + } + _autoScale(0, height); + + replot(); + } + } +} + +void +HistogramDisplayPlot::_resetXAxisPoints(double bottom, double top) +{ + double width = (top - bottom)/(_bins-1); + for(long loc = 0; loc < _bins; loc++){ + _xAxisPoints[loc] = bottom + loc*width; + } + + // Set up zoomer base for maximum unzoom x-axis + // and reset to maximum unzoom level + QwtDoubleRect zbase = _zoomer->zoomBase(); + + if(d_semilogx) { + setAxisScale(QwtPlot::xBottom, 1e-1, _xAxisPoints[_bins-1]); + zbase.setLeft(1e-1); + } + else { + setAxisScale(QwtPlot::xBottom, _xAxisPoints[0], _xAxisPoints[_bins-1]); + zbase.setLeft(_xAxisPoints[0]); + } + + zbase.setRight(_xAxisPoints[_bins-1]); + _zoomer->zoom(zbase); + _zoomer->setZoomBase(zbase); + _zoomer->zoom(0); +} + +void +HistogramDisplayPlot::_autoScale(double bottom, double top) +{ + // Auto scale the y-axis with a margin of 20% (10 dB for log scale) + double _bot = bottom - fabs(bottom)*0.20; + double _top = top + fabs(top)*0.20; + if(d_semilogy) { + if(bottom > 0) { + setYaxis(_bot-10, _top+10); + } + else { + setYaxis(1e-3, _top+10); + } + } + else { + setYaxis(_bot, _top); + } +} + +void +HistogramDisplayPlot::setAutoScale(bool state) +{ + _autoscale_state = state; +} + +void +HistogramDisplayPlot::setSemilogx(bool en) +{ + d_semilogx = en; + if(!d_semilogx) { + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + } + else { + setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine); + } +} + +void +HistogramDisplayPlot::setSemilogy(bool en) +{ + if(d_semilogy != en) { + d_semilogy = en; + double max = axisScaleDiv(QwtPlot::yLeft)->upperBound(); + if(!d_semilogy) { + setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setYaxis(-pow(10.0, max/10.0), pow(10.0, max/10.0)); + } + else { + setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine); + setYaxis(1e-10, 10.0*log10(100*max)); + } + } +} + +void +HistogramDisplayPlot::setAccumulate(bool state) +{ + _accum = state; +} + +void +HistogramDisplayPlot::setMarkerAlpha(int which, int alpha) +{ + if(which < _nplots) { + // Get the pen color + QPen pen(_plot_curve[which]->pen()); + QBrush brush(_plot_curve[which]->brush()); + QColor color = brush.color(); + + // Set new alpha and update pen + color.setAlpha(alpha); + brush.setColor(color); + color.setAlpha(std::min(255, static_cast<int>(alpha*1.5))); + pen.setColor(color); + _plot_curve[which]->setBrush(brush); + _plot_curve[which]->setPen(pen); + + // And set the new color for the markers +#if QWT_VERSION < 0x060000 + QwtSymbol sym = (QwtSymbol)_plot_curve[which]->symbol(); + setLineMarker(which, sym.style()); +#else + QwtSymbol *sym = (QwtSymbol*)_plot_curve[which]->symbol(); + if(sym) { + sym->setColor(color); + sym->setPen(pen); + _plot_curve[which]->setSymbol(sym); + } +#endif + } +} + +int +HistogramDisplayPlot::getMarkerAlpha(int which) const +{ + if(which < _nplots) { + return _plot_curve[which]->brush().color().alpha(); + } + else { + return 0; + } +} + +void +HistogramDisplayPlot::setLineColor(int which, QColor color) +{ + if(which < _nplots) { + // Adjust color's transparency for the brush + color.setAlpha(127 / _nplots); + + QBrush brush(_plot_curve[which]->brush()); + brush.setColor(color); + _plot_curve[which]->setBrush(brush); + + // Adjust color's transparency darker for the pen and markers + color.setAlpha(255 / _nplots); + + QPen pen(_plot_curve[which]->pen()); + pen.setColor(color); + _plot_curve[which]->setPen(pen); + +#if QWT_VERSION < 0x060000 + _plot_curve[which]->setPen(pen); + QwtSymbol sym = (QwtSymbol)_plot_curve[which]->symbol(); + setLineMarker(which, sym.style()); +#else + QwtSymbol *sym = (QwtSymbol*)_plot_curve[which]->symbol(); + if(sym) { + sym->setColor(color); + sym->setPen(pen); + _plot_curve[which]->setSymbol(sym); + } +#endif + } +} + +void +HistogramDisplayPlot::setNumBins(int bins) +{ + _bins = bins; + + delete [] _xAxisPoints; + _xAxisPoints = new double[_bins]; + memset(_xAxisPoints, 0x0, _bins*sizeof(double)); + + for(int i = 0; i < _nplots; i++) { + delete [] _yDataPoints[i]; + _yDataPoints[i] = new double[_bins]; + memset(_yDataPoints[i], 0, _bins*sizeof(double)); + +#if QWT_VERSION < 0x060000 + _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins); +#else + _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins); +#endif + } +} + +#endif /* HISTOGRAM_DISPLAY_PLOT_C */ diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc index ecc878b0a8..ce83c96389 100644 --- a/gr-qtgui/lib/displayform.cc +++ b/gr-qtgui/lib/displayform.cc @@ -300,6 +300,11 @@ DisplayForm::markerAlpha(int which) } void +DisplayForm::setSampleRate(const QString &rate) +{ +} + +void DisplayForm::setStop(bool on) { if(!on) { diff --git a/gr-qtgui/lib/histogram_sink_f_impl.cc b/gr-qtgui/lib/histogram_sink_f_impl.cc new file mode 100644 index 0000000000..293fb2c0ec --- /dev/null +++ b/gr-qtgui/lib/histogram_sink_f_impl.cc @@ -0,0 +1,381 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "histogram_sink_f_impl.h" +#include <gnuradio/io_signature.h> +#include <string.h> +#include <volk/volk.h> +#include <gnuradio/fft/fft.h> +#include <qwt_symbol.h> + +namespace gr { + namespace qtgui { + + histogram_sink_f::sptr + histogram_sink_f::make(int size, int bins, + const std::string &name, + int nconnections, + QWidget *parent) + { + return gnuradio::get_initial_sptr + (new histogram_sink_f_impl(size, bins, name, + nconnections, parent)); + } + + histogram_sink_f_impl::histogram_sink_f_impl(int size, int bins, + const std::string &name, + int nconnections, + QWidget *parent) + : sync_block("histogram_sink_f", + io_signature::make(nconnections, nconnections, sizeof(float)), + io_signature::make(0, 0, 0)), + d_size(size), d_bins(bins), d_name(name), + d_nconnections(nconnections), d_parent(parent) + { + d_main_gui = NULL; + + d_index = 0; + + for(int i = 0; i < d_nconnections; i++) { + d_residbufs.push_back(fft::malloc_double(d_size)); + memset(d_residbufs[i], 0, d_size*sizeof(double)); + } + + // Set alignment properties for VOLK + const int alignment_multiple = + volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1,alignment_multiple)); + + initialize(); + } + + histogram_sink_f_impl::~histogram_sink_f_impl() + { + if(!d_main_gui->isClosed()) + d_main_gui->close(); + + // d_main_gui is a qwidget destroyed with its parent + for(int i = 0; i < d_nconnections; i++) { + fft::free(d_residbufs[i]); + } + } + + bool + histogram_sink_f_impl::check_topology(int ninputs, int noutputs) + { + return ninputs == d_nconnections; + } + + void + histogram_sink_f_impl::initialize() + { + if(qApp != NULL) { + d_qApplication = qApp; + } + else { + int argc=0; + char **argv = NULL; + d_qApplication = new QApplication(argc, argv); + } + + d_main_gui = new HistogramDisplayForm(d_nconnections, d_parent); + d_main_gui->setNPoints(d_size); + + // initialize update time to 10 times a second + set_update_time(0.1); + } + + void + histogram_sink_f_impl::exec_() + { + d_qApplication->exec(); + } + + QWidget* + histogram_sink_f_impl::qwidget() + { + return d_main_gui; + } + + PyObject* + histogram_sink_f_impl::pyqwidget() + { + PyObject *w = PyLong_FromVoidPtr((void*)d_main_gui); + PyObject *retarg = Py_BuildValue("N", w); + return retarg; + } + + void + histogram_sink_f_impl::set_y_axis(double min, double max) + { + d_main_gui->setYaxis(min, max); + } + + void + histogram_sink_f_impl::set_update_time(double t) + { + //convert update time to ticks + gr::high_res_timer_type tps = gr::high_res_timer_tps(); + d_update_time = t * tps; + d_main_gui->setUpdateTime(t); + d_last_time = 0; + } + + void + histogram_sink_f_impl::set_title(const std::string &title) + { + d_main_gui->setTitle(title.c_str()); + } + + void + histogram_sink_f_impl::set_line_label(int which, const std::string &label) + { + d_main_gui->setLineLabel(which, label.c_str()); + } + + void + histogram_sink_f_impl::set_line_color(int which, const std::string &color) + { + d_main_gui->setLineColor(which, color.c_str()); + } + + void + histogram_sink_f_impl::set_line_width(int which, int width) + { + d_main_gui->setLineWidth(which, width); + } + + void + histogram_sink_f_impl::set_line_style(int which, int style) + { + d_main_gui->setLineStyle(which, (Qt::PenStyle)style); + } + + void + histogram_sink_f_impl::set_line_marker(int which, int marker) + { + d_main_gui->setLineMarker(which, (QwtSymbol::Style)marker); + } + + void + histogram_sink_f_impl::set_line_alpha(int which, double alpha) + { + d_main_gui->setMarkerAlpha(which, (int)(255.0*alpha)); + } + + void + histogram_sink_f_impl::set_size(int width, int height) + { + d_main_gui->resize(QSize(width, height)); + } + + std::string + histogram_sink_f_impl::title() + { + return d_main_gui->title().toStdString(); + } + + std::string + histogram_sink_f_impl::line_label(int which) + { + return d_main_gui->lineLabel(which).toStdString(); + } + + std::string + histogram_sink_f_impl::line_color(int which) + { + return d_main_gui->lineColor(which).toStdString(); + } + + int + histogram_sink_f_impl::line_width(int which) + { + return d_main_gui->lineWidth(which); + } + + int + histogram_sink_f_impl::line_style(int which) + { + return d_main_gui->lineStyle(which); + } + + int + histogram_sink_f_impl::line_marker(int which) + { + return d_main_gui->lineMarker(which); + } + + double + histogram_sink_f_impl::line_alpha(int which) + { + return (double)(d_main_gui->markerAlpha(which))/255.0; + } + + void + histogram_sink_f_impl::set_nsamps(const int newsize) + { + gr::thread::scoped_lock lock(d_mutex); + + if(newsize != d_size) { + // Resize residbuf and replace data + for(int i = 0; i < d_nconnections; i++) { + fft::free(d_residbufs[i]); + d_residbufs[i] = fft::malloc_double(newsize); + + memset(d_residbufs[i], 0, newsize*sizeof(double)); + } + + // Set new size and reset buffer index + // (throws away any currently held data, but who cares?) + d_size = newsize; + d_index = 0; + + d_main_gui->setNPoints(d_size); + } + } + + void + histogram_sink_f_impl::set_bins(const int bins) + { + gr::thread::scoped_lock lock(d_mutex); + d_bins = bins; + d_main_gui->setNumBins(d_bins); + } + + int + histogram_sink_f_impl::nsamps() const + { + return d_size; + } + + int + histogram_sink_f_impl::bins() const + { + return d_bins; + } + + void + histogram_sink_f_impl::npoints_resize() + { + int newsize = d_main_gui->getNPoints(); + set_nsamps(newsize); + } + + void + histogram_sink_f_impl::enable_menu(bool en) + { + d_main_gui->enableMenu(en); + } + + void + histogram_sink_f_impl::enable_grid(bool en) + { + d_main_gui->setGrid(en); + } + + void + histogram_sink_f_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void + histogram_sink_f_impl::enable_semilogx(bool en) + { + d_main_gui->setSemilogx(en); + } + + void + histogram_sink_f_impl::enable_semilogy(bool en) + { + d_main_gui->setSemilogy(en); + } + + void + histogram_sink_f_impl::enable_accumulate(bool en) + { + d_main_gui->setAccumulate(en); + } + + void + histogram_sink_f_impl::reset() + { + d_index = 0; + } + + int + histogram_sink_f_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + int n=0, j=0, idx=0; + const float *in = (const float*)input_items[idx]; + + npoints_resize(); + + for(int i=0; i < noutput_items; i+=d_size) { + unsigned int datasize = noutput_items - i; + unsigned int resid = d_size-d_index; + idx = 0; + + // If we have enough input for one full plot, do it + if(datasize >= resid) { + + // Fill up residbufs with d_size number of items + for(n = 0; n < d_nconnections; n++) { + in = (const float*)input_items[idx++]; + volk_32f_convert_64f_u(&d_residbufs[n][d_index], + &in[j], resid); + } + + // Update the plot if its time + if(gr::high_res_timer_now() - d_last_time > d_update_time) { + d_last_time = gr::high_res_timer_now(); + d_qApplication->postEvent(d_main_gui, + new HistogramUpdateEvent(d_residbufs, d_size)); + } + + d_index = 0; + j += resid; + } + // Otherwise, copy what we received into the residbufs for next time + // because we set the output_multiple, this should never need to be called + else { + for(n = 0; n < d_nconnections; n++) { + in = (const float*)input_items[idx++]; + volk_32f_convert_64f_u(&d_residbufs[n][d_index], + &in[j], datasize); + } + d_index += datasize; + j += datasize; + } + } + + return j; + } + + } /* namespace qtgui */ +} /* namespace gr */ diff --git a/gr-qtgui/lib/histogram_sink_f_impl.h b/gr-qtgui/lib/histogram_sink_f_impl.h new file mode 100644 index 0000000000..962d6e43a4 --- /dev/null +++ b/gr-qtgui/lib/histogram_sink_f_impl.h @@ -0,0 +1,110 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H +#define INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H + +#include <gnuradio/qtgui/histogram_sink_f.h> +#include <gnuradio/qtgui/histogramdisplayform.h> +#include <gnuradio/thread/thread.h> +#include <gnuradio/high_res_timer.h> + +namespace gr { + namespace qtgui { + + class QTGUI_API histogram_sink_f_impl : public histogram_sink_f + { + private: + void initialize(); + + gr::thread::mutex d_mutex; + + int d_size; + int d_bins; + std::string d_name; + int d_nconnections; + + int d_index; + std::vector<double*> d_residbufs; + + QWidget *d_parent; + HistogramDisplayForm *d_main_gui; + + gr::high_res_timer_type d_update_time; + gr::high_res_timer_type d_last_time; + + void npoints_resize(); + + public: + histogram_sink_f_impl(int size, int bins, + const std::string &name, + int nconnections, + QWidget *parent=NULL); + ~histogram_sink_f_impl(); + + bool check_topology(int ninputs, int noutputs); + + void exec_(); + QWidget* qwidget(); + PyObject* pyqwidget(); + + void set_y_axis(double min, double max); + void set_update_time(double t); + void set_title(const std::string &title); + void set_line_label(int which, const std::string &label); + void set_line_color(int which, const std::string &color); + void set_line_width(int which, int width); + void set_line_style(int which, int style); + void set_line_marker(int which, int marker); + void set_line_alpha(int which, double alpha); + void set_nsamps(const int newsize); + void set_bins(const int bins); + + std::string title(); + std::string line_label(int which); + std::string line_color(int which); + int line_width(int which); + int line_style(int which); + int line_marker(int which); + double line_alpha(int which); + + void set_size(int width, int height); + + void enable_menu(bool en); + void enable_grid(bool en); + void enable_autoscale(bool en); + void enable_semilogx(bool en); + void enable_semilogy(bool en); + void enable_accumulate(bool en); + int nsamps() const; + int bins() const; + void reset(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace qtgui */ +} /* namespace gr */ + +#endif /* INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H */ diff --git a/gr-qtgui/lib/histogramdisplayform.cc b/gr-qtgui/lib/histogramdisplayform.cc new file mode 100644 index 0000000000..2542d24a23 --- /dev/null +++ b/gr-qtgui/lib/histogramdisplayform.cc @@ -0,0 +1,168 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <cmath> +#include <QMessageBox> +#include <gnuradio/qtgui/histogramdisplayform.h> +#include <iostream> + +HistogramDisplayForm::HistogramDisplayForm(int nplots, QWidget* parent) + : DisplayForm(nplots, parent) +{ + d_semilogx = false; + d_semilogy = false; + + _intValidator = new QIntValidator(this); + _intValidator->setBottom(0); + + _layout = new QGridLayout(this); + _displayPlot = new HistogramDisplayPlot(nplots, this); + _layout->addWidget(_displayPlot, 0, 0); + setLayout(_layout); + + NPointsMenu *nptsmenu = new NPointsMenu(this); + _menu->addAction(nptsmenu); + connect(nptsmenu, SIGNAL(whichTrigger(int)), + this, SLOT(setNPoints(const int))); + + NPointsMenu *nbinsmenu = new NPointsMenu(this); + nbinsmenu->setText("Number of Bins"); + _menu->addAction(nbinsmenu); + connect(nbinsmenu, SIGNAL(whichTrigger(int)), + this, SLOT(setNumBins(const int))); + + QAction *accummenu = new QAction("Accumulate", this); + accummenu->setCheckable(true); + _menu->addAction(accummenu); + connect(accummenu, SIGNAL(triggered(bool)), + this, SLOT(setAccumulate(bool))); + +// d_semilogxmenu = new QAction("Semilog X", this); +// d_semilogxmenu->setCheckable(true); +// _menu->addAction(d_semilogxmenu); +// connect(d_semilogxmenu, SIGNAL(triggered(bool)), +// this, SLOT(setSemilogx(bool))); +// +// d_semilogymenu = new QAction("Semilog Y", this); +// d_semilogymenu->setCheckable(true); +// _menu->addAction(d_semilogymenu); +// connect(d_semilogymenu, SIGNAL(triggered(bool)), +// this, SLOT(setSemilogy(bool))); + + Reset(); + + connect(_displayPlot, SIGNAL(plotPointSelected(const QPointF)), + this, SLOT(onPlotPointSelected(const QPointF))); +} + +HistogramDisplayForm::~HistogramDisplayForm() +{ + // Qt deletes children when parent is deleted + + // Don't worry about deleting Display Plots - they are deleted when parents are deleted + delete _intValidator; +} + +HistogramDisplayPlot* +HistogramDisplayForm::getPlot() +{ + return ((HistogramDisplayPlot*)_displayPlot); +} + +void +HistogramDisplayForm::newData(const QEvent* updateEvent) +{ + HistogramUpdateEvent *hevent = (HistogramUpdateEvent*)updateEvent; + const std::vector<double*> dataPoints = hevent->getDataPoints(); + const uint64_t numDataPoints = hevent->getNumDataPoints(); + + getPlot()->plotNewData(dataPoints, + numDataPoints, + d_update_time); +} + +void +HistogramDisplayForm::customEvent(QEvent * e) +{ + if(e->type() == HistogramUpdateEvent::Type()) { + newData(e); + } +} + +void +HistogramDisplayForm::setYaxis(double min, double max) +{ + getPlot()->setYaxis(min, max); +} + +int +HistogramDisplayForm::getNPoints() const +{ + return d_npoints; +} + +void +HistogramDisplayForm::setNPoints(const int npoints) +{ + d_npoints = npoints; +} + +void +HistogramDisplayForm::autoScale(bool en) +{ + _autoscale_state = en; + _autoscale_act->setChecked(en); + getPlot()->setAutoScale(_autoscale_state); + getPlot()->replot(); +} + +void +HistogramDisplayForm::setSemilogx(bool en) +{ + d_semilogx = en; + d_semilogxmenu->setChecked(en); + getPlot()->setSemilogx(d_semilogx); + getPlot()->replot(); +} + +void +HistogramDisplayForm::setSemilogy(bool en) +{ + d_semilogy = en; + d_semilogymenu->setChecked(en); + getPlot()->setSemilogy(d_semilogy); + getPlot()->replot(); +} + +void +HistogramDisplayForm::setNumBins(const int bins) +{ + getPlot()->setNumBins(bins); + getPlot()->replot(); +} + +void +HistogramDisplayForm::setAccumulate(bool en) +{ + getPlot()->setAccumulate(en); + getPlot()->replot(); +} diff --git a/gr-qtgui/lib/spectrumUpdateEvents.cc b/gr-qtgui/lib/spectrumUpdateEvents.cc index 7d7f689f25..393cd3edec 100644 --- a/gr-qtgui/lib/spectrumUpdateEvents.cc +++ b/gr-qtgui/lib/spectrumUpdateEvents.cc @@ -439,4 +439,47 @@ TimeRasterUpdateEvent::getNumDataPoints() const return _numDataPoints; } +/***************************************************************************/ + + +HistogramUpdateEvent::HistogramUpdateEvent(const std::vector<double*> points, + const uint64_t npoints) + : QEvent(QEvent::Type(SpectrumUpdateEventType)) +{ + if(npoints < 1) { + _npoints = 1; + } + else { + _npoints = npoints; + } + + _nplots = points.size(); + for(size_t i = 0; i < _nplots; i++) { + _points.push_back(new double[_npoints]); + if(npoints > 0) { + memcpy(_points[i], points[i], _npoints*sizeof(double)); + } + } +} + +HistogramUpdateEvent::~HistogramUpdateEvent() +{ + for(size_t i = 0; i < _nplots; i++) { + delete[] _points[i]; + } +} + +const std::vector<double*> +HistogramUpdateEvent::getDataPoints() const +{ + return _points; +} + +uint64_t +HistogramUpdateEvent::getNumDataPoints() const +{ + return _npoints; +} + + #endif /* SPECTRUM_UPDATE_EVENTS_C */ diff --git a/gr-qtgui/python/qtgui/qa_qtgui.py b/gr-qtgui/python/qtgui/qa_qtgui.py index 51c0727de4..580ca51f22 100755 --- a/gr-qtgui/python/qtgui/qa_qtgui.py +++ b/gr-qtgui/python/qtgui/qa_qtgui.py @@ -77,5 +77,8 @@ class test_qtgui(gr_unittest.TestCase): self.qtsnk = qtgui.time_raster_sink_f(1024, 100, 100.5, [], [], "Test", 1) + def test12(self): + self.qtsnk = qtgui.histogram_sink_f(1024, 100, "Test", 1) + if __name__ == '__main__': gr_unittest.run(test_qtgui, "test_qtgui.xml") diff --git a/gr-qtgui/swig/qtgui_swig.i b/gr-qtgui/swig/qtgui_swig.i index f974fa2e86..124c5ee7fc 100644 --- a/gr-qtgui/swig/qtgui_swig.i +++ b/gr-qtgui/swig/qtgui_swig.i @@ -46,6 +46,7 @@ #include "gnuradio/qtgui/const_sink_c.h" #include "gnuradio/qtgui/waterfall_sink_c.h" #include "gnuradio/qtgui/waterfall_sink_f.h" +#include "gnuradio/qtgui/histogram_sink_f.h" %} %include "gnuradio/qtgui/sink_c.h" @@ -59,6 +60,7 @@ %include "gnuradio/qtgui/const_sink_c.h" %include "gnuradio/qtgui/waterfall_sink_c.h" %include "gnuradio/qtgui/waterfall_sink_f.h" +%include "gnuradio/qtgui/histogram_sink_f.h" GR_SWIG_BLOCK_MAGIC2(qtgui, sink_c); GR_SWIG_BLOCK_MAGIC2(qtgui, sink_f); @@ -71,3 +73,4 @@ GR_SWIG_BLOCK_MAGIC2(qtgui, freq_sink_f); GR_SWIG_BLOCK_MAGIC2(qtgui, const_sink_c); GR_SWIG_BLOCK_MAGIC2(qtgui, waterfall_sink_c); GR_SWIG_BLOCK_MAGIC2(qtgui, waterfall_sink_f); +GR_SWIG_BLOCK_MAGIC2(qtgui, histogram_sink_f); |