diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 4221eea..e298d86 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -22,5 +22,6 @@ install(FILES
crfa_rds_table_qt.xml
crfa_rds_parser_table_qt.xml
crfa_rds_decoder.xml
- crfa_max_freq.xml DESTINATION share/gnuradio/grc/blocks
+ crfa_max_freq.xml
+ crfa_smooth_vectors.xml DESTINATION share/gnuradio/grc/blocks
)
diff --git a/grc/crfa_max_freq.xml b/grc/crfa_max_freq.xml
index ccdc004..0d012a7 100644
--- a/grc/crfa_max_freq.xml
+++ b/grc/crfa_max_freq.xml
@@ -10,6 +10,7 @@
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
+ set_center_freq($center_freq);
fft_len
fft_len
diff --git a/grc/crfa_rds_parser_table_qt.xml b/grc/crfa_rds_parser_table_qt.xml
index df29063..4422c6d 100644
--- a/grc/crfa_rds_parser_table_qt.xml
+++ b/grc/crfa_rds_parser_table_qt.xml
@@ -13,7 +13,7 @@
#end if
$(signals) = rds_parser_table_qt_Signals()
self.$(id) = crfa.rds_parser_table_qt($(signals),$nPorts)
-$(win) = rds_parser_table_qt_Widget($signals, $label)
+$(win) = rds_parser_table_qt_Widget($signals, $label,self.$(id))
$(gui_hint()($win))
Label
@@ -42,5 +42,10 @@ $(gui_hint()($win))
$nPorts
+
+ freq
+ message
+ 1
+
diff --git a/grc/crfa_smooth_vectors.xml b/grc/crfa_smooth_vectors.xml
new file mode 100644
index 0000000..2250d34
--- /dev/null
+++ b/grc/crfa_smooth_vectors.xml
@@ -0,0 +1,52 @@
+
+
+ smooth_vectors
+ crfa_smooth_vectors
+ [crfa]
+ import crfa
+ crfa.smooth_vectors($vec_len, $decim, $moving_avg_len)
+
+
+ vec_len
+ vec_len
+ 1024
+ int
+
+
+ decim
+ decim
+ 1
+ int
+
+
+ moving_avg_len
+ moving_avg_len
+ 2
+ int
+
+
+
+
+ in
+ float
+ $vec_len
+
+
+
+ out
+ float
+ $vec_len
+
+
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 9bcc146..a9cb4a4 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -35,7 +35,8 @@ GR_PYTHON_INSTALL(
qtguitest.py
rds_table_qt.py
rds_parser_table_qt.py
- max_freq.py DESTINATION ${GR_PYTHON_DIR}/crfa
+ max_freq.py
+ smooth_vectors.py DESTINATION ${GR_PYTHON_DIR}/crfa
)
########################################################################
diff --git a/python/__init__.py b/python/__init__.py
index 9af8807..520d1fd 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -36,4 +36,5 @@ from qtguitest import qtguitest
from rds_table_qt import rds_table_qt
from rds_parser_table_qt import rds_parser_table_qt
from max_freq import max_freq
+from smooth_vectors import smooth_vectors
#
diff --git a/python/chart.py b/python/chart.py
new file mode 100644
index 0000000..ce2132a
--- /dev/null
+++ b/python/chart.py
@@ -0,0 +1,482 @@
+from itertools import cycle
+from PyQt4.Qt import *
+
+DEFAULT_COLORS = [0x3366cc, 0xdc3912, 0xff9900, 0x109618, 0x990099,
+ 0x0099c6, 0xdd4477, 0x66aa00, 0xb82e2e, 0x316395,
+ 0x994499, 0x22aa99, 0xaaaa11, 0x6633cc, 0x16d620]
+
+class Chart(object):
+ def __init__(self, data, colors=None):
+ self.data = data
+ self.colors = colors
+
+ self._ref_col = 0
+ self._ref_isv = True
+
+ def setVerticalAxisColumn(self, column):
+ self._ref_col = column
+ self._ref_isv = True
+
+ def setHorizontalAxisColumn(self, column):
+ self._ref_col = column
+ self._ref_isv = False
+
+ def save(self, filename, chart_size, legend_width=None):
+ image_size = chart_size
+ if legend_width is not None:
+ image_size = image_size + QSize(legend_width, 0)
+
+ image = QImage(image_size, QImage.Format_ARGB32_Premultiplied)
+ painter = QPainter(image)
+ painter.setRenderHint(QPainter.Antialiasing)
+ painter.fillRect(image.rect(), Qt.white)
+ self.draw(painter, QRect(QPoint(0, 0), chart_size))
+ if legend_width is not None:
+ self.drawLegend(painter, QRect(QPoint(chart_size.width(), 10), QSize(legend_width, chart_size.height())))
+ painter.end()
+ return image.save(filename)
+
+ def draw(self, painter, rectangle):
+ raise NotImplementedError
+
+ def drawLegend(self, painter, rectangle):
+ SPACE = 2
+
+ font_metrics = painter.fontMetrics()
+ size = font_metrics.xHeight() * 2
+
+ y = SPACE
+ x0 = SPACE
+ x1 = x0 + size + SPACE * 3
+
+ w = rectangle.width() - size - SPACE
+ tw = w - x1
+
+ painter.save()
+ painter.translate(rectangle.x(), rectangle.y())
+
+ color = self._icolors()
+ for i, column in enumerate(self._fetchLegendData()):
+ if (y + size + SPACE * 2) >= (rectangle.y() + rectangle.height()) and i < (len(self.data.columns) - 1):
+ painter.drawText(x1, y, tw, size, Qt.AlignLeft | Qt.AlignVCenter, "...")
+ y += size + SPACE
+ break
+
+ text = font_metrics.elidedText(column, Qt.ElideRight, tw)
+ painter.fillRect(x0, y, size, size, QColor(next(color)))
+ painter.drawText(x1, y, tw, size, Qt.AlignLeft | Qt.AlignVCenter, text)
+ y += size + SPACE
+
+ painter.setPen(Qt.lightGray)
+ painter.drawRect(0, 0, w, y)
+ painter.restore()
+
+ def _fetchLegendData(self):
+ for i, column in enumerate(self.data.columns):
+ if i != self._ref_col:
+ yield column
+
+ def _icolors(self):
+ if self.colors is None:
+ return cycle(DEFAULT_COLORS)
+ return cycle(self.colors)
+
+class PieChart(Chart):
+ def draw(self, painter, rectangle):
+ painter.save()
+ painter.translate(rectangle.x(), rectangle.y())
+
+ # Calculate Values
+ vtotal = float(sum(row[not self._ref_col] for row in self.data.rows))
+ values = [row[not self._ref_col] / vtotal for row in self.data.rows]
+
+ # Draw Char
+ start_angle = 90 * 16
+ for color, v in zip(self._icolors(), values):
+ span_angle = v * -360.0 * 16
+ painter.setPen(Qt.white)
+ painter.setBrush(QColor(color))
+ painter.drawPie(rectangle, start_angle, span_angle)
+ start_angle += span_angle
+
+ painter.restore()
+
+ def _fetchLegendData(self):
+ for row in self.data.rows:
+ yield row[self._ref_col]
+
+class ScatterChart(Chart):
+ SPAN = 10
+
+ def __init__(self, data, **kwargs):
+ super(ScatterChart, self).__init__(data, **kwargs)
+
+ self.haxis_title = None
+ self.haxis_vmin = None
+ self.haxis_vmax = None
+ self.haxis_step = None
+ self.haxis_grid = True
+
+ self.vaxis_title = None
+ self.vaxis_vmin = None
+ self.vaxis_vmax = None
+ self.vaxis_step = None
+ self.vaxis_grid = True
+
+ def draw(self, painter, rectangle):
+ self._setupDefaultValues()
+
+ font_metrics = painter.fontMetrics()
+ h = font_metrics.xHeight() * 2
+ x = font_metrics.width(self._vToString(self.vaxis_vmax))
+
+ # Calculate X steps
+ nxstep = int(round((self.haxis_vmax - self.haxis_vmin) / self.haxis_step))
+ nystep = int(round((self.vaxis_vmax - self.vaxis_vmin) / self.vaxis_step))
+
+ # Calculate chart space
+ xmin = h + self.SPAN + x
+ xstep = (rectangle.width() - xmin - (h + self.SPAN)) / nxstep
+ xmax = xmin + xstep * nxstep
+
+ # Calculate Y steps
+ ymin = h + self.SPAN
+ ystep = (rectangle.height() - ymin - (h * 2 + self.SPAN)) / nystep
+ ymax = ymin + ystep * nystep
+
+ painter.save()
+ painter.translate(rectangle.x(), rectangle.y())
+
+ # Draw Axis Titles
+ painter.save()
+ self._drawAxisTitles(painter, xmin, xmax, ymin, ymax)
+ painter.restore()
+
+ # Draw Axis Labels
+ painter.save()
+ self._drawAxisLabels(painter, xmin, xmax, ymin, ymax, xstep, nxstep, ystep, nystep)
+ painter.restore()
+
+ # Draw Data
+ painter.save()
+ painter.setClipRect(xmin + 1, ymin, xmax - xmin - 2, ymax - ymin - 1)
+ self._drawData(painter, xmin, xmax, ymin, ymax)
+ painter.restore()
+
+ # Draw Border
+ painter.setPen(Qt.black)
+ painter.drawLine(xmin, ymin, xmin, ymax)
+ painter.drawLine(xmin, ymax, xmax, ymax)
+
+ painter.restore()
+
+ def _drawAxisTitles(self, painter, xmin, xmax, ymin, ymax):
+ font_metrics = painter.fontMetrics()
+ h = font_metrics.xHeight() * 2
+ hspan = self.SPAN / 2
+
+ font = painter.font()
+ font.setItalic(True)
+ painter.setFont(font)
+
+ if self.haxis_title is not None:
+ painter.drawText(xmin + ((xmax - xmin) / 2 - font_metrics.width(self.haxis_title) / 2), ymax + h * 2 + hspan, self.haxis_title)
+
+ if self.vaxis_title is not None:
+ painter.rotate(90)
+ painter.drawText(ymin + (ymax - ymin) / 2 - font_metrics.width(self.vaxis_title) / 2, -hspan, self.vaxis_title)
+
+ def _drawAxisLabels(self, painter, xmin, xmax, ymin, ymax, xstep, nxstep, ystep, nystep):
+ font_metrics = painter.fontMetrics()
+ h = font_metrics.xHeight() * 2
+
+ # Draw Internal Grid
+ painter.setPen(Qt.lightGray)
+ x = xmin + xstep
+ ys = ymin if self.haxis_grid else ymax - 4
+ for _ in xrange(nxstep):
+ painter.drawLine(x, ys, x, ymax)
+ x += xstep
+
+ y = ymin
+ xe = xmax if self.vaxis_grid else xmin + 4
+ for _ in xrange(nystep):
+ painter.drawLine(xmin, y, xe, y)
+ y += ystep
+
+ # Draw Axis Labels
+ painter.setPen(Qt.black)
+ for i in xrange(1 + nxstep):
+ x = xmin + (i * xstep)
+ v = self._hToString(self.haxis_vmin + i * self.haxis_step)
+ painter.drawText(x - font_metrics.width(v) / 2, 2 + ymax + h, v)
+
+ for i in xrange(1 + nystep):
+ y = ymin + (i * ystep)
+ v = self._vToString(self.vaxis_vmin + (nystep - i) * self.vaxis_step)
+ painter.drawText(xmin - font_metrics.width(v) - 2, y, v)
+
+ def _drawData(self, painter, xmin, xmax, ymin, ymax):
+ c = 0
+ color = self._icolors()
+ while c < len(self.data.columns):
+ if c != self._ref_col:
+ if self._ref_isv:
+ a, b = c, self._ref_col
+ else:
+ a, b = self._ref_col, c
+ self._drawColumnData(painter, next(color), a, b, xmin, xmax, ymin, ymax)
+ c += 1
+
+ def _drawColumnData(self, painter, color, xcol, ycol, xmin, xmax, ymin, ymax):
+ painter.setPen(QPen(QColor(color), 7, Qt.SolidLine, Qt.RoundCap))
+ for row in self.data.rows:
+ x, y = self._xyFromData(row[xcol], row[ycol], xmin, xmax, ymin, ymax)
+ painter.drawPoint(x, y)
+
+ def _xyFromData(self, xdata, ydata, xmin, xmax, ymin, ymax):
+ x = xmin + (float(xdata - self.haxis_vmin) / (self.haxis_vmax - self.haxis_vmin)) * (xmax - xmin)
+ y = ymin + (1.0 - (float(ydata - self.vaxis_vmin) / (self.vaxis_vmax - self.vaxis_vmin))) * (ymax - ymin)
+ return x, y
+
+ def _vToString(self, value):
+ if isinstance(self.vaxis_step, float):
+ return '%.2f' % value
+ if isinstance(self.vaxis_step, int):
+ return '%d' % value
+ return '%s' % value
+
+ def _hToString(self, value):
+ if isinstance(self.haxis_step, float):
+ return '%.2f' % value
+ if isinstance(self.haxis_step, int):
+ return '%d' % value
+ return '%s' % value
+
+ def _setupDefaultValues(self):
+ def _minMaxDelta(col):
+ vmin = None
+ vmax = None
+ vdelta = 0
+ ndelta = 1
+
+ last_value = self.data.rows[0][col]
+ vmin = vmax = last_value
+ for row in self.data.rows[1:]:
+ vdelta += abs(row[col] - last_value)
+ ndelta += 1
+ if row[col] > vmax:
+ vmax = row[col]
+ elif row[col] < vmin:
+ vmin = row[col]
+
+ return vmin, vmax, vdelta / ndelta
+
+ ref_min, ref_max, ref_step = _minMaxDelta(self._ref_col)
+ oth_min = oth_max = oth_step = None
+ for col in xrange(len(self.data.columns)):
+ if col == self._ref_col:
+ continue
+
+ cmin, cmax, cstep = _minMaxDelta(col)
+ oth_min = cmin if oth_min is None else min(cmin, oth_min)
+ oth_max = cmax if oth_max is None else max(cmax, oth_max)
+ oth_step = cstep if oth_step is None else (oth_step + cstep) / 2
+
+ if self._ref_isv:
+ if self.vaxis_vmin is None: self.vaxis_vmin = ref_min
+ if self.vaxis_vmax is None: self.vaxis_vmax = ref_max
+ if self.vaxis_step is None: self.vaxis_step = ref_step
+ if self.haxis_vmin is None: self.haxis_vmin = oth_min
+ if self.haxis_vmax is None: self.haxis_vmax = oth_max
+ if self.haxis_step is None: self.haxis_step = oth_step
+ else:
+ if self.haxis_vmin is None: self.haxis_vmin = ref_min
+ if self.haxis_vmax is None: self.haxis_vmax = ref_max
+ if self.haxis_step is None: self.haxis_step = ref_step
+ if self.vaxis_vmin is None: self.vaxis_vmin = oth_min
+ if self.vaxis_vmax is None: self.vaxis_vmax = oth_max
+ if self.vaxis_step is None: self.vaxis_step = oth_step
+
+class LineChart(ScatterChart):
+ def _drawColumnData(self, painter, color, xcol, ycol, xmin, xmax, ymin, ymax):
+ painter.setPen(QPen(QColor(color), 2, Qt.SolidLine, Qt.RoundCap))
+
+ path = QPainterPath()
+
+ row = self.data.rows[0]
+ x, y = self._xyFromData(row[xcol], row[ycol], xmin, xmax, ymin, ymax)
+ path.moveTo(x, y)
+
+ for row in self.data.rows[1:]:
+ x, y = self._xyFromData(row[xcol], row[ycol], xmin, xmax, ymin, ymax)
+ path.lineTo(x, y)
+ painter.drawPath(path)
+
+class AreaChart(ScatterChart):
+ def _drawColumnData(self, painter, color, xcol, ycol, xmin, xmax, ymin, ymax):
+ painter.setPen(QPen(QColor(color), 2, Qt.SolidLine, Qt.RoundCap))
+
+ color = QColor(color)
+ color.setAlpha(40)
+ painter.setBrush(color)
+
+ path = QPainterPath()
+ path.moveTo(xmin, ymax)
+ for row in self.data.rows:
+ x, y = self._xyFromData(row[xcol], row[ycol], xmin, xmax, ymin, ymax)
+ path.lineTo(x, y)
+ path.lineTo(xmax, ymax)
+ path.moveTo(xmin, ymax)
+ painter.drawPath(path)
+
+class Viewer(QWidget):
+ def __init__(self):
+ QWidget.__init__(self)
+ self.graph = None
+
+ def setGraph(self, func):
+ self.graph = func
+ self.update()
+
+ def paintEvent(self, event):
+ painter = QPainter(self)
+ painter.setRenderHint(QPainter.Antialiasing)
+
+ if self.graph is not None:
+ self.graph.draw(painter, QRect(0, 0, event.rect().width() - 120, event.rect().height()))
+ self.graph.drawLegend(painter, QRect(event.rect().width() - 120, 20, 120, event.rect().height() - 20))
+
+ painter.end()
+
+class DialogViewer(QDialog):
+ def __init__(self):
+ QDialog.__init__(self)
+ self.viewer = Viewer()
+ self.setLayout(QVBoxLayout())
+ self.layout().setContentsMargins(0, 0, 0, 0)
+ self.layout().addWidget(self.viewer)
+
+ def setGraph(self, func):
+ self.viewer.setGraph(func)
+
+class DataTable(object):
+ def __init__(self):
+ self.columns = []
+ self.rows = []
+
+ def addColumn(self, label):
+ self.columns.append(label)
+
+ def addRow(self, row):
+ assert len(row) == len(self.columns)
+ self.rows.append(row)
+
+def _pieChartDemo():
+ table = DataTable()
+ table.addColumn('Lang')
+ table.addColumn('Rating')
+ table.addRow(['Java', 17.874])
+ table.addRow(['C', 17.322])
+ table.addRow(['C++', 8.084])
+ table.addRow(['C#', 7.319])
+ table.addRow(['PHP', 6.096])
+
+ chart = PieChart(table)
+ #chart.save('pie.png', QSize(240, 240), 100)
+
+ view = DialogViewer()
+ view.setGraph(chart)
+ view.resize(360, 240)
+ view.exec_()
+
+def _scatterChartDemo():
+ table = DataTable()
+ table.addColumn('Quality')
+ table.addColumn('Test 1')
+ table.addColumn('Test 2')
+ table.addRow([ 92, 4.9, 8.0])
+ table.addRow([ 94, 2.0, 2.5])
+ table.addRow([ 96, 7.2, 6.9])
+ table.addRow([ 98, 3.5, 1.2])
+ table.addRow([100, 8.0, 5.3])
+ table.addRow([102, 15.0, 14.2])
+
+ chart = ScatterChart(table)
+ chart.haxis_title = 'Process input'
+ chart.haxis_vmin = 0
+ chart.haxis_vmax = 16
+ chart.haxis_step = 2
+ chart.vaxis_title = 'Quality'
+ chart.vaxis_vmin = 90
+ chart.vaxis_vmax = 104
+ chart.vaxis_step = 1
+
+ #chart.save('scatter.png', QSize(400, 240), 100)
+
+ view = DialogViewer()
+ view.setGraph(chart)
+ view.resize(400, 240)
+ view.exec_()
+
+def _lineChartDemo():
+ table = DataTable()
+ table.addColumn('Time')
+ table.addColumn('Site 1')
+ table.addColumn('Site 2')
+ table.addColumn('Site 3')
+ table.addRow([ 4.00, 120, 80, 400])
+ table.addRow([ 6.00, 270, 850, 320])
+ table.addRow([ 8.30, 50, 1200, 280])
+ table.addRow([10.15, 320, 1520, 510])
+ table.addRow([12.00, 150, 930, 1100])
+ table.addRow([18.20, 62, 1100, 240])
+
+ chart = LineChart(table)
+ chart.setHorizontalAxisColumn(0)
+ chart.haxis_title = 'Time'
+ chart.haxis_vmin = 0.0
+ chart.haxis_vmax = 20.0
+ chart.haxis_step = 2
+
+ #chart.save('line.png', QSize(400, 240), 100)
+
+ view = DialogViewer()
+ view.setGraph(chart)
+ view.resize(400, 240)
+ view.exec_()
+
+def _areaChartDemo():
+ table = DataTable()
+ table.addColumn('Time')
+ table.addColumn('Site 1')
+ table.addColumn('Site 2')
+ table.addRow([ 4.00, 120, 500])
+ table.addRow([ 6.00, 270, 460])
+ table.addRow([ 8.30, 1260, 1120])
+ table.addRow([10.15, 2030, 540])
+ table.addRow([12.00, 520, 890])
+ table.addRow([18.20, 1862, 1500])
+
+ chart = AreaChart(table)
+ chart.setHorizontalAxisColumn(0)
+ chart.haxis_title = 'Time'
+ chart.haxis_vmin = 0.0
+ chart.haxis_vmax = 20.0
+ chart.haxis_step = 5
+
+ #chart.save('area.png', QSize(400, 240), 100)
+
+ view = DialogViewer()
+ view.setGraph(chart)
+ view.resize(400, 240)
+ view.exec_()
+
+if __name__ == '__main__':
+ import sys
+ app = QApplication(sys.argv)
+
+ _pieChartDemo()
+ _scatterChartDemo()
+ _lineChartDemo()
+ _areaChartDemo()
diff --git a/python/chart.pyc b/python/chart.pyc
new file mode 100644
index 0000000..6759715
Binary files /dev/null and b/python/chart.pyc differ
diff --git a/python/core b/python/core
new file mode 100644
index 0000000..ca453ea
Binary files /dev/null and b/python/core differ
diff --git a/python/max_freq.py b/python/max_freq.py
index be79306..7538161 100644
--- a/python/max_freq.py
+++ b/python/max_freq.py
@@ -21,7 +21,7 @@
import numpy as np
from gnuradio import gr
-import code
+import code,math,pmt
class max_freq(gr.sync_block):
"""
@@ -36,27 +36,22 @@ class max_freq(gr.sync_block):
self.num_decoders=num_decoders
self.center_freq=center_freq
self.samp_rate=samp_rate
- self.num_averages=5
- self.avg_counter=-1
- self.numbers_avg=[]
-
-
+ self.snapto=1e5 #100k
+ self.message_port_register_out(pmt.intern('out'))
+ def set_center_freq(self, freq=None):
+ if freq is not None:
+ if isinstance(freq, float) or isinstance(freq, int):
+ self.center_freq=freq
+ else:
+ self.center_freq = int(freq)
def work(self, input_items, output_items):
#in0 = input_items[0]
#ii=input_items
- numbers=abs(input_items[0][0])
- threshold=6
- if self.avg_counter == -1: #init
- self.numbers_avg=numbers
- self.avg_counter=0
- elif self.avg_counter <= self.num_averages:
- #np.mean( np.array([ old_set, new_set ]), axis=0 )
- self.numbers_avg=np.mean( np.array([ self.numbers_avg, numbers ]), axis=0 )
- self.avg_counter+=1
- elif len(np.where(self.numbers_avg>threshold)[0]) >0:
- self.avg_counter=0
- numbers=self.numbers_avg
- min_consec_max_threshold=4#minimum number of consecutive maximums (in fft domain) to consider signal as station
+ carrier_width=2
+ carrier=self.fft_len/2
+ numbers=np.delete(input_items[0][0],range(carrier-carrier_width,carrier+carrier_width+1))#reads input and disregards center
+ threshold=100
+ min_consec_max_threshold=1#minimum number of consecutive maximums (in fft domain) to consider signal as station
#TODO: what if no numbers over threshold?
#TODO auto threshold
#max_indices=[[421, 428, 429, 430, 431, 432, 433, 434, 436, 437, 438, 831, 832, 837, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851,852, 853, 854, 855, 856, 857]]
@@ -67,9 +62,14 @@ class max_freq(gr.sync_block):
#last_index=0
count=1#counts number of consecutive maximums
threshold_reached=False
- fuzzyness=10
+ fuzzyness=2
# max_indices[0].append(0)#to detect last station
max_indices=np.append(max_indices,0)#to detect last station
+ #try:
+
+ #max_indices.remove(self.fft_len/2)#suppress local oscillator of hackrf
+ #except ValueError:
+ #pass
for i in max_indices:
if abs(i-last_index) <= fuzzyness:
count+=i-last_index
@@ -89,31 +89,14 @@ class max_freq(gr.sync_block):
for index in station_indices:
startfreq=self.center_freq-self.samp_rate/2
freq=self.samp_rate*index/self.fft_len+startfreq
- station_freqs.append(freq)
-
- """
-[422 423 426 427 428 430 431 432 433 434 435 436 437 836 837 838 842 843
- 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 861 862
- 0]
-[]
-[]
-[423 424 425 426 427 428 429 430 431 432 433 434 842 843 844 845 848 849
- 850 851 852 853 854 855 858 859 860 0]
-[428, 851]
-[101303125.0, 102294531.0]
-[415 416 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
- 844 845 846 847 848 849 850 851 852 853 854 855 856 861 862 863 0]
-[853]
-[102299218.0]
-"""
- #f=open("/tmp/obj","r")
- #import pickle
- #pickle.load(ii,f)
- #(array([431, 433, 437, 439, 849, 854, 856, 858, 861, 862]),)
- #code.interact(local=locals())
- # <+signal processing here+>
+ num_decimals=int(round(math.log(self.snapto,10)))
+ station_freqs.append(round(freq,-num_decimals))
+ for i in range(0,min(self.num_decoders,len(station_freqs))):
+ msg_string=str(i+1)+" "+str(station_freqs[i])
+ send_pmt = pmt.string_to_symbol(msg_string)
+ self.message_port_pub(pmt.intern('out'), send_pmt)
print(max_indices)
print(station_indices)
print(station_freqs)
- return len(input_items[0])
+ return len(input_items[0])
diff --git a/python/pylab_piechart b/python/pylab_piechart
new file mode 100644
index 0000000..ac94618
--- /dev/null
+++ b/python/pylab_piechart
@@ -0,0 +1,16 @@
+#from pylab import *
+import pylab
+
+# make a square figure and axes
+pylab.figure(1, figsize=(10, 3))
+ax = axes([0.1, 0.1, 0.8, 0.8])
+
+labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
+fracs = [15,30,45, 10]
+
+explode=(0, 0.05, 0, 0)
+pylab.pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
+pylab.title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5})
+
+pylab.gca().set_aspect('1')
+pylab.show()
\ No newline at end of file
diff --git a/python/rds_parser_table_qt.py b/python/rds_parser_table_qt.py
index 4addc70..282e403 100644
--- a/python/rds_parser_table_qt.py
+++ b/python/rds_parser_table_qt.py
@@ -21,7 +21,8 @@
from __future__ import print_function#print without newline print('.', end="")
import numpy
from gnuradio import gr
-import pmt,functools,csv,md5
+import pmt,functools,csv,md5,collections
+import chart#local file
from PyQt4 import Qt, QtCore, QtGui
import pprint,code#for easier testing
pp = pprint.PrettyPrinter()
@@ -46,15 +47,16 @@ class rds_parser_table_qt(gr.sync_block):
for i in range(0,nPorts):
self.message_port_register_in(pmt.intern('in%d'%i))
self.set_msg_handler(pmt.intern('in%d'%i), functools.partial(self.handle_msg, port=i))
-
+ self.message_port_register_in(pmt.intern('freq'))
+ self.set_msg_handler(pmt.intern('freq'), self.set_freq)
self.signals=signals
self.RDS_data={}
self.printcounter=0
self.ODA_application_names={}
self.TMC_data={}
self.colorder=['ID','freq','name','PTY','AF','time','text','quality','buttons']
- #workdir="/user/wire2/richter/hackrf_prototypes/"
- workdir="/media/clemens/intdaten/uni_bulk/forschungsarbeit/hackrf_prototypes/"
+ workdir="/user/wire2/richter/hackrf_prototypes/"
+ #workdir="/media/clemens/intdaten/uni_bulk/forschungsarbeit/hackrf_prototypes/"
reader = csv.reader(open(workdir+'RDS_ODA AIDs_names_only.csv'), delimiter=',', quotechar='"')
reader.next()#skip header
for row in reader:
@@ -77,6 +79,18 @@ class rds_parser_table_qt(gr.sync_block):
reader.next()#skip header
self.pty_dict=dict((int(rows[0]),rows[1]) for rows in reader)
f.close()
+ def set_freq(self,msg):
+ m = pmt.symbol_to_string(msg)
+ tgtnum=int(m.split()[0])-1#msgs are 1-indexed
+ freq_str=m.split()[1]
+ try:
+ freq=float(freq_str)
+ freq_str="%0.1fM"% (freq/1e6)
+ except ValueError:
+ pass#leave string as is
+ self.signals.DataUpdateEvent.emit({'row':tgtnum,'freq':freq_str})
+ #print("nr:%i freq:%s"%(tgtnum,freq_str))
+
def handle_msg(self, msg, port):
#code.interact(local=locals())
array=pmt.to_python(msg)[1]
@@ -103,6 +117,7 @@ class rds_parser_table_qt(gr.sync_block):
self.RDS_data[PI]["AF"]={}
self.RDS_data[PI]["DI"]=[2,2,2,2]
self.RDS_data[PI]["last_item_toggle_bit"]=2
+ self.RDS_data[PI]["internals"]={"last_rt_tooltip":""}
print("found station %s"%PI)
self.RDS_data[PI]["blockcounts"]["any"]+=1
if self.RDS_data[PI]["blockcounts"]["any"]==5:
@@ -321,30 +336,44 @@ class rds_parser_table_qt(gr.sync_block):
tag2_len=int(tag2&(2**5-1))
if not self.RDS_data[PI].has_key("RT+"):
self.RDS_data[PI]["RT+"]={}
- if(self.RDS_data[PI].has_key("RT") and self.RDS_data[PI]["RT_all_valid"]):#TODO better (more fine grained) detection of valid RT+ info
+ if self.RDS_data[PI].has_key("RT"):
rt=self.RDS_data[PI]["RT"]
- if not tag1_type=="DUMMY_CLASS":
+ rt_valid=self.RDS_data[PI]["RT_valid"]
+ if not tag1_type=="DUMMY_CLASS" and all(rt_valid[tag1_start:tag1_start+tag1_len+1]):
self.RDS_data[PI]["RT+"][tag1_type]=rt[tag1_start:tag1_start+tag1_len+1]
- if not tag2_type=="DUMMY_CLASS":
+ if not tag2_type=="DUMMY_CLASS" and all(rt_valid[tag2_start:tag2_start+tag2_len+1]):
self.RDS_data[PI]["RT+"][tag2_type]=rt[tag2_start:tag2_start+tag2_len+1]
-
- if(tag1_type=="ITEM.ARTIST"and tag2_type=="ITEM.TITLE" and self.RDS_data[PI].has_key("RT") and self.RDS_data[PI]["RT_all_valid"]):
+ tags="ir:%i,it:%i"%(item_running_bit,item_toggle_bit)
+ afcol=self.colorder.index('AF')
+ self.signals.DataUpdateEvent.emit({'col':afcol,'row':port,'PI':PI,'string':tags})
+ #if(tag1_type=="ITEM.ARTIST"and tag2_type=="ITEM.TITLE" and self.RDS_data[PI].has_key("RT") and self.RDS_data[PI]["RT_all_valid"]):
+ if(tag2_type=="ITEM.TITLE" and self.RDS_data[PI].has_key("RT")):#TODO remove duplicate code
rt=self.RDS_data[PI]["RT"]
- artist=rt[tag1_start:tag1_start+tag1_len+1]
- song=rt[tag2_start:tag2_start+tag2_len+1]
- formatted_text="%s by %s %i"%(song,artist,item_running_bit)
+ rt_valid=self.RDS_data[PI]["RT_valid"]
+ artist="?"
+ song="?"
+ if all(rt_valid[tag1_start:tag1_start+tag1_len+1]):
+ artist=rt[tag1_start:tag1_start+tag1_len+1]
+ if all(rt_valid[tag2_start:tag2_start+tag2_len+1]):
+ song=rt[tag2_start:tag2_start+tag2_len+1]
+ formatted_text="%s by %s"%(song,artist)
rtcol=self.colorder.index('text')
- self.signals.DataUpdateEvent.emit({'col':rtcol,'row':port,'PI':PI,'tooltip':formatted_text})
- #self.signals.DataUpdateEvent.emit({'col':8,'row':port,'PI':PI,'string':formatted_text})
- elif(not tag1_type=="ITEM.ARTIST" and not tag1_type=="DUMMY_CLASS"):
- print("%s:RT+: tag1_type:%s, tag2_type:%s"%(PI,tag1_type,tag2_type))
+ #only update tooltip if text changed -> remove flicker, still flickers :(
+ if not formatted_text == self.RDS_data[PI]["internals"]["last_rt_tooltip"]:
+ self.signals.DataUpdateEvent.emit({'col':rtcol,'row':port,'PI':PI,'tooltip':formatted_text})
+ self.RDS_data[PI]["internals"]["last_rt_tooltip"] = formatted_text
+ #elif(not tag1_type=="ITEM.ARTIST" and not tag1_type=="DUMMY_CLASS"):
+ # print("%s:RT+: tag1_type:%s, tag2_type:%s"%(PI,tag1_type,tag2_type))
if not self.RDS_data[PI]["last_item_toggle_bit"] == item_toggle_bit: #new item
self.RDS_data[PI]["last_item_toggle_bit"] = item_toggle_bit
rtcol=self.colorder.index('text')
+ print("toggle bit changed on PI:%s, cleared RT-tt"%PI)
self.signals.DataUpdateEvent.emit({'col':rtcol,'row':port,'PI':PI,'tooltip':""})
- else:#other group
- printdelay=50
- self.printcounter+=1
+ #else:#other group
+ if 1==1:
+ #printdelay=50
+ printdelay=500
+ self.printcounter+=0#printing disabled
if self.RDS_data[PI]["blockcounts"].has_key(groupType):
self.RDS_data[PI]["blockcounts"][groupType] +=1 #increment
else:
@@ -403,9 +432,10 @@ class rds_parser_table_qt(gr.sync_block):
formatted_text="%s%s%s"% (textcolor,text[:start],segmentcolor,text[start:end],textcolor,text[end:])
return formatted_text
class rds_parser_table_qt_Widget(QtGui.QWidget):
- def __init__(self, signals,label):
- print("gui initializing")
+ def __init__(self, signals,label,tableobj):
+ #print("gui initializing")self.tableobj.RDS_data["D3A2"]
self.signals = signals
+ self.tableobj=tableobj
self.signals.DataUpdateEvent.connect(self.display_data)
""" Creates the QT Range widget """
QtGui.QWidget.__init__(self)
@@ -422,14 +452,12 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
empty_text64='________________________________________________________________'
#empty_text64='\xe4'*64
self.data = {'ID':range(1,6),
- 'freq':['','','',''],
+ 'freq':[ QtGui.QLabel() for i in range(4)],
'name':[ QtGui.QLabel() for i in range(4)],
'PTY':[ QtGui.QLabel() for i in range(4)],
- #'flags':[ QtGui.QLabel() for i in range(4)],
- 'AF':['','','',''],
+ 'AF':[ QtGui.QLabel() for i in range(4)],
'time':[ QtGui.QLabel() for i in range(4)],
'text':[ QtGui.QLabel("_"*64) for i in range(4)],
- #'RT+':[ QtGui.QLabel() for i in range(4)],
'quality':[ QtGui.QLabel() for i in range(4)],
'buttons':[]}
#Enter data onto Table
@@ -448,9 +476,10 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
newitem = QtGui.QTableWidgetItem(item)
self.table.setItem(m, n, newitem)
for i in range(0,4):#create buttons
- button=QtGui.QPushButton("play")
+ button=QtGui.QPushButton("getDetails")
self.table.setCellWidget(i,self.table.columnCount()-1,button)
- button.clicked.connect(self.onCLick)
+ button.clicked.connect(functools.partial(self.getDetails, row=i))
+ #button.clicked.connect(self.getDetails)
#Add Header
layout.addWidget(self.label)
layout.addWidget(self.table)
@@ -464,8 +493,9 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
self.event_filter=QtGui.QLineEdit()#QPlainTextEdit ?
self.location_filter=QtGui.QLineEdit()
- self.button = QtGui.QPushButton("i am a button")
- layout.addWidget(self.button)
+ button = QtGui.QPushButton("code.interact")
+ button.clicked.connect(self.onCLick)
+ layout.addWidget(button)
filter_layout = Qt.QHBoxLayout()
filter_layout.addWidget(QtGui.QLabel("event filter:"))
@@ -487,9 +517,14 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
def display_data(self, event):
#pp.pprint(event)
+
if type(event)==dict and event.has_key('TMC_log'):
self.logOutput.append(Qt.QString.fromUtf8(event['TMC_log']))
if type(event)==dict and event.has_key('row'):
+ if event.has_key('freq'):
+ freqcol=self.colorder.index('freq')
+ item=self.table.cellWidget(event['row'],freqcol)
+ item.setText(event['freq'])
if event.has_key('wrong_blocks'):
item=self.table.cellWidget(event['row'],self.colorder.index('quality'))
quality_string="%i%% %s"% (100-2*event['wrong_blocks'],event['dots'])
@@ -511,8 +546,9 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
PIcol=self.colorder.index('ID')
#rtpcol=self.colorder.index('RT+')
rtcol=self.colorder.index('text')
- if not self.table.item(event['row'],PIcol).text() == event['PI']:
+ if not str(self.table.item(event['row'],PIcol).text()) == event['PI']:
#self.table.cellWidget(event['row'],rtpcol).setText("")#clear RT+ on changed PI
+ print("PI changed on row %i, cleared RT-tt"%event['row'])
self.table.cellWidget(event['row'],rtcol).setToolTip(Qt.QString(""))
self.table.item(event['row'],PIcol).setText(event['PI'])
if event.has_key('AF'):
@@ -525,6 +561,36 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
item=self.table.cellWidget(event['row'],PSNcol)
item.setText(event['PSN'])
self.table.resizeColumnsToContents()
+ def getDetails(self,row):
+ PIcol=self.colorder.index('ID')
+ PI=str(self.table.item(row,PIcol).text())
+ #PI=
+ #print("row:%i,PI:%s"%(row,PI))
+ #print(self.tableobj.RDS_data[PI])
+ table=chart.DataTable()
+ table.addColumn('groupType')
+ table.addColumn('numPackets')
+ #ordered_blockcounts=self.tableobj.RDS_data["D00F"]['blockcounts']
+ blockcounts=self.tableobj.RDS_data[PI]['blockcounts'].copy()
+ del blockcounts['any']
+ #lambda function removes last character of PI string (A or B) and sorts based on integer valure of number in front
+ for key in sorted(blockcounts,key=lambda elem: int(elem[0:-1])):
+ count=blockcounts[key]
+ table.addRow([key+": "+str(count),count])
+ mychart=chart.PieChart(table)
+ view = chart.DialogViewer()
+ view.setGraph(mychart)
+ #view.resize(360, 240)
+ view.resize(330, 420)
+ rds_data=self.tableobj.RDS_data[PI].copy()
+ del rds_data['blockcounts']
+ del rds_data['PSN_valid']
+ del rds_data['RT_valid']
+ l=QtGui.QLabel("Data:%s"%str(rds_data))
+ l.setWordWrap(True)
+ #l=QtGui.QLabel("Data:")
+ view.layout().addWidget(l)
+ view.exec_()
def onCLick(self):
print("button clicked")
code.interact(local=locals())
diff --git a/python/smooth_vectors.py b/python/smooth_vectors.py
new file mode 100644
index 0000000..753d1d6
--- /dev/null
+++ b/python/smooth_vectors.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2016 <+YOU OR YOUR COMPANY+>.
+#
+# This 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.
+#
+# This software 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 this software; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import numpy as np
+from gnuradio import gr
+
+class smooth_vectors(gr.decim_block):
+ """
+ docstring for block smooth_vectors
+ """
+ def __init__(self, vec_len,decim,moving_avg_len):
+ gr.decim_block.__init__(self,
+ name="smooth_vectors",
+ in_sig=[(np.float32,vec_len)],
+ out_sig=[(np.float32,vec_len)], decim=decim)
+ self.vec_len=vec_len
+ self.decim=decim
+ self.moving_avg_len=moving_avg_len
+ self.last_inputs=[]
+ self.count=0
+
+
+ def work(self, input_items, output_items):
+ in0 = input_items[0]
+ out = output_items[0]
+ self.last_inputs.insert(0,in0)
+ out[:] =np.mean( np.array(self.last_inputs), axis=0 )
+ # <+signal processing here+>
+ if len(self.last_inputs)>self.moving_avg_len:
+ self.last_inputs.pop(len(self.last_inputs)-1)#remove last
+ #out[:] = in0
+ return len(output_items[0])
+