Browse Source

refactor gnuradio source block to reduce cpu load (no significant change to measured sample rate)

Fabian Peter Hammerle 3 years ago
parent
commit
de39d347d0
2 changed files with 63 additions and 37 deletions
  1. 28 13
      epy_block_0.py
  2. 35 24
      scope.grc

+ 28 - 13
epy_block_0.py

@@ -1,4 +1,3 @@
-import struct
 import time
 
 import gnuradio
@@ -7,20 +6,36 @@ import serial
 
 
 class ArduinoAnalogReadings(gnuradio.gr.sync_block):
-    def __init__(self, port="/dev/ttyUSB0", baud_rate=115200, timeout=2):
+    def __init__(
+        self, port="/dev/ttyUSB0", baud_rate=115200, buffer_max_length=10, timeout=2
+    ):
         gnuradio.gr.sync_block.__init__(
-            self, name="Arduino Analog Readings", in_sig=[], out_sig=[numpy.int16]
+            self, name="Arduino Analog Readings", in_sig=None, out_sig=[numpy.int16]
         )
-        self._serial_port = serial.Serial(port, baud_rate, timeout=timeout)
-        self._readings_counter = 0
-        self._start_timestamp = None
+        self._serial_port = serial.Serial(
+            port=port, baudrate=baud_rate, bytesize=serial.EIGHTBITS, timeout=timeout
+        )
+        self._buffer_max_length = buffer_max_length
+        self._samples_counter = 0
+        self._sample_rate_report_timestamp = None
 
     def work(self, input_items, output_items):
         # pylint: disable=unused-argument
-        if not self._start_timestamp:
-            self._start_timestamp = time.time()
-        output_items[0][0] = struct.unpack(">H", self._serial_port.read(2))[0]
-        self._readings_counter += 1
-        if self._readings_counter % 4096 == 0:
-            print(self._readings_counter / (time.time() - self._start_timestamp), "Hz")
-        return 1
+        buffer = self._serial_port.read(
+            2 * min(len(output_items[0]), self._buffer_max_length)
+        )
+        assert len(buffer) % 2 == 0
+        buffer_samples_count = len(buffer) // 2
+        output_items[0][:buffer_samples_count] = numpy.frombuffer(buffer, dtype=">u2")
+        self._samples_counter += buffer_samples_count
+        current_timestamp = time.time()
+        if not self._sample_rate_report_timestamp:
+            self._sample_rate_report_timestamp = current_timestamp
+        elif (current_timestamp - self._sample_rate_report_timestamp) > 8:
+            sample_rate_hz = self._samples_counter / (
+                current_timestamp - self._sample_rate_report_timestamp
+            )
+            print(f"{sample_rate_hz:.01f} Hz")
+            self._samples_counter = 0
+            self._sample_rate_report_timestamp = current_timestamp
+        return buffer_samples_count

+ 35 - 24
scope.grc

@@ -41,7 +41,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [393, 199]
+    coordinate: [439, 210]
     rotation: 0
     state: true
 - name: resistor_1_ohm
@@ -53,7 +53,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [767, 18]
+    coordinate: [813, 29]
     rotation: 0
     state: true
 - name: resistor_2_ohm
@@ -65,7 +65,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [765, 117]
+    coordinate: [811, 128]
     rotation: 0
     state: true
 - name: sample_rate_hz
@@ -89,7 +89,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [770, 216]
+    coordinate: [816, 227]
     rotation: 0
     state: true
 - name: blocks_multiply_const_vxx_0
@@ -107,7 +107,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [765, 313]
+    coordinate: [811, 324]
     rotation: 0
     state: true
 - name: blocks_short_to_float_0
@@ -124,28 +124,38 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [426, 313]
+    coordinate: [472, 324]
     rotation: 0
     state: true
 - name: epy_block_0
   id: epy_block
   parameters:
-    _source_code: "import struct\nimport time\n\nimport gnuradio\nimport numpy\nimport\
-      \ serial\n\n\nclass ArduinoAnalogReadings(gnuradio.gr.sync_block):\n    def\
-      \ __init__(self, port=\"/dev/ttyUSB0\", baud_rate=115200, timeout=2):\n    \
-      \    gnuradio.gr.sync_block.__init__(\n            self, name=\"Arduino Analog\
-      \ Readings\", in_sig=[], out_sig=[numpy.int16]\n        )\n        self._serial_port\
-      \ = serial.Serial(port, baud_rate, timeout=timeout)\n        self._readings_counter\
-      \ = 0\n        self._start_timestamp = None\n\n    def work(self, input_items,\
-      \ output_items):\n        # pylint: disable=unused-argument\n        if not\
-      \ self._start_timestamp:\n            self._start_timestamp = time.time()\n\
-      \        output_items[0][0] = struct.unpack(\">H\", self._serial_port.read(2))[0]\n\
-      \        self._readings_counter += 1\n        if self._readings_counter % 4096\
-      \ == 0:\n            print(self._readings_counter / (time.time() - self._start_timestamp),\
-      \ \"Hz\")\n        return 1\n"
+    _source_code: "import time\n\nimport gnuradio\nimport numpy\nimport serial\n\n\
+      \nclass ArduinoAnalogReadings(gnuradio.gr.sync_block):\n    def __init__(\n\
+      \        self, port=\"/dev/ttyUSB0\", baud_rate=115200, buffer_max_length=10,\
+      \ timeout=2\n    ):\n        gnuradio.gr.sync_block.__init__(\n            self,\
+      \ name=\"Arduino Analog Readings\", in_sig=None, out_sig=[numpy.int16]\n   \
+      \     )\n        self._serial_port = serial.Serial(\n            port=port,\
+      \ baudrate=baud_rate, bytesize=serial.EIGHTBITS, timeout=timeout\n        )\n\
+      \        self._buffer_max_length = buffer_max_length\n        self._samples_counter\
+      \ = 0\n        self._sample_rate_report_timestamp = None\n\n    def work(self,\
+      \ input_items, output_items):\n        # pylint: disable=unused-argument\n \
+      \       buffer = self._serial_port.read(\n            2 * min(len(output_items[0]),\
+      \ self._buffer_max_length)\n        )\n        assert len(buffer) % 2 == 0\n\
+      \        buffer_samples_count = len(buffer) // 2\n        output_items[0][:buffer_samples_count]\
+      \ = numpy.frombuffer(buffer, dtype=\">u2\")\n        self._samples_counter +=\
+      \ buffer_samples_count\n        current_timestamp = time.time()\n        if\
+      \ not self._sample_rate_report_timestamp:\n            self._sample_rate_report_timestamp\
+      \ = current_timestamp\n        elif (current_timestamp - self._sample_rate_report_timestamp)\
+      \ > 8:\n            sample_rate_hz = self._samples_counter / (\n           \
+      \     current_timestamp - self._sample_rate_report_timestamp\n            )\n\
+      \            print(f\"{sample_rate_hz:.01f} Hz\")\n            self._samples_counter\
+      \ = 0\n            self._sample_rate_report_timestamp = current_timestamp\n\
+      \        return buffer_samples_count\n"
     affinity: ''
     alias: ''
     baud_rate: '115200'
+    buffer_max_length: int(sample_rate_hz)
     comment: ''
     maxoutbuf: '0'
     minoutbuf: '0'
@@ -153,11 +163,12 @@ blocks:
     timeout: '2'
   states:
     _io_cache: ('Arduino Analog Readings', 'ArduinoAnalogReadings', [('port', "'/dev/ttyUSB0'"),
-      ('baud_rate', '115200'), ('timeout', '2')], [], [('0', 'short', 1)], '', [])
+      ('baud_rate', '115200'), ('buffer_max_length', '10'), ('timeout', '2')], [],
+      [('0', 'short', 1)], '', [])
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [58, 281]
+    coordinate: [32, 276]
     rotation: 0
     state: true
 - name: qtgui_freq_sink_x_0
@@ -237,7 +248,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [776, 431]
+    coordinate: [822, 442]
     rotation: 0
     state: true
 - name: qtgui_number_sink_0
@@ -300,7 +311,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1109, 280]
+    coordinate: [1155, 291]
     rotation: 0
     state: true
 - name: qtgui_time_sink_x_0
@@ -397,7 +408,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1113, 127]
+    coordinate: [1159, 138]
     rotation: 0
     state: true