summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau <tom@trondeau.com>2013-08-02 13:30:38 -0400
committerTom Rondeau <tom@trondeau.com>2013-08-02 13:30:38 -0400
commitf6a1e39fe3fca5b50ea664ad2055e37045ee6bef (patch)
treee4458278d89d7ba46204d870f18e0e943d0ef484
parent0a5c5d55040f6a6812db2f9c8d62b36838b70a91 (diff)
qtgui: Added histogram sink.
-rw-r--r--gr-qtgui/grc/qtgui_block_tree.xml3
-rw-r--r--gr-qtgui/grc/qtgui_histogram_sink_x.xml77
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h29
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h74
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/displayform.h2
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h104
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h79
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h28
-rw-r--r--gr-qtgui/lib/CMakeLists.txt5
-rw-r--r--gr-qtgui/lib/HistogramDisplayPlot.cc434
-rw-r--r--gr-qtgui/lib/displayform.cc5
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.cc381
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.h110
-rw-r--r--gr-qtgui/lib/histogramdisplayform.cc168
-rw-r--r--gr-qtgui/lib/spectrumUpdateEvents.cc43
-rwxr-xr-xgr-qtgui/python/qtgui/qa_qtgui.py3
-rw-r--r--gr-qtgui/swig/qtgui_swig.i3
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);