Browse Source

piechart, max_freq, simple auto-tune

master
Clemens Richter 9 years ago
parent
commit
fd829f9b0f
  1. 3
      grc/CMakeLists.txt
  2. 1
      grc/crfa_max_freq.xml
  3. 7
      grc/crfa_rds_parser_table_qt.xml
  4. 52
      grc/crfa_smooth_vectors.xml
  5. 3
      python/CMakeLists.txt
  6. 1
      python/__init__.py
  7. 482
      python/chart.py
  8. BIN
      python/chart.pyc
  9. BIN
      python/core
  10. 71
      python/max_freq.py
  11. 16
      python/pylab_piechart
  12. 126
      python/rds_parser_table_qt.py
  13. 51
      python/smooth_vectors.py

3
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
)

1
grc/crfa_max_freq.xml

@ -10,6 +10,7 @@
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<callback>set_center_freq($center_freq);</callback>
<param>
<name>fft_len</name>
<key>fft_len</key>

7
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))</make>
<param>
<name>Label</name>
@ -42,5 +42,10 @@ $(gui_hint()($win))</make>
<nports>$nPorts</nports>
<!--<optional>1</optional>-->
</sink>
<sink>
<name>freq</name>
<type>message</type>
<optional>1</optional>
</sink>
</block>

52
grc/crfa_smooth_vectors.xml

@ -0,0 +1,52 @@
<?xml version="1.0"?>
<block>
<name>smooth_vectors</name>
<key>crfa_smooth_vectors</key>
<category>[crfa]</category>
<import>import crfa</import>
<make>crfa.smooth_vectors($vec_len, $decim, $moving_avg_len)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<param>
<name>vec_len</name>
<key>vec_len</key>
<value>1024</value>
<type>int</type>
</param>
<param>
<name>decim</name>
<key>decim</key>
<value>1</value>
<type>int</type>
</param>
<param>
<name>moving_avg_len</name>
<key>moving_avg_len</key>
<value>2</value>
<type>int</type>
</param>
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<sink>
<name>in</name>
<type>float</type>
<vlen>$vec_len</vlen>
</sink>
<!-- Make one 'source' node per output. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<source>
<name>out</name>
<type>float</type>
<vlen>$vec_len</vlen>
</source>
</block>

3
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
)
########################################################################

1
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
#

482
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()

BIN
python/chart.pyc

Binary file not shown.

BIN
python/core

Binary file not shown.

71
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])

16
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()

126
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="<font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font>"% (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())

51
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])
Loading…
Cancel
Save