diff --git a/examples/dsa_statistics.grc b/examples/dsa_statistics.grc
new file mode 100644
index 0000000000000000000000000000000000000000..c4d1419cd5eb4ea47b9810780de3fb4d9a12f85f
--- /dev/null
+++ b/examples/dsa_statistics.grc
@@ -0,0 +1,366 @@
+options:
+  parameters:
+    author: ''
+    category: '[GRC Hier Blocks]'
+    cmake_opt: ''
+    comment: ''
+    copyright: University of Melbourne
+    description: ''
+    gen_cmake: 'On'
+    gen_linking: dynamic
+    generate_options: qt_gui
+    hier_block_src_path: '.:'
+    id: dsa_statistics
+    max_nouts: '0'
+    output_language: python
+    placement: (0,0)
+    qt_qss_theme: ''
+    realtime_scheduling: ''
+    run: 'True'
+    run_command: '{python} -u {filename}'
+    run_options: prompt
+    sizing_mode: fixed
+    thread_safe_setters: ''
+    title: DSA Statistics
+    window_size: ''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [8, 8]
+    rotation: 0
+    state: enabled
+
+blocks:
+- name: address0
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [11, 181]
+    rotation: 0
+    state: true
+- name: address1
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port + 1)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [10, 359]
+    rotation: 0
+    state: true
+- name: address2
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port + 2)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [11, 557]
+    rotation: 0
+    state: true
+- name: address3
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port + 3)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [10, 680]
+    rotation: 0
+    state: true
+- name: host
+  id: variable
+  parameters:
+    comment: ''
+    value: '''127.0.0.1'''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [181, 9]
+    rotation: 0
+    state: true
+- name: port
+  id: variable
+  parameters:
+    comment: ''
+    value: '50001'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [281, 9]
+    rotation: 0
+    state: true
+- name: reset_stats
+  id: variable_qtgui_entry
+  parameters:
+    comment: ''
+    gui_hint: 2,1,1,1
+    label: Reset Stats
+    type: bool
+    value: 'False'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [375, 9]
+    rotation: 0
+    state: true
+- name: cdc_dsa_stats_pu_mode_0
+  id: cdc_dsa_stats_pu_mode
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    period: '1'
+    reset: reset_stats
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [276, 507]
+    rotation: 0
+    state: true
+- name: cdc_dsa_stats_thruput_0
+  id: cdc_dsa_stats_thruput
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha: '0.0'
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    period: '1'
+    reset: reset_stats
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [280, 115]
+    rotation: 0
+    state: true
+- name: cdc_dsa_stats_thruput_0_0
+  id: cdc_dsa_stats_thruput
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha: '0.0'
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    period: '1'
+    reset: reset_stats
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [277, 294]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 0,0,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [551, 39]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 1,0,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: SU Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [551, 262]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0_0_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 1,1,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: SU Instant. Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [551, 374]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0_0_0_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 2,0,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: SU Scenario Detection (%)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [551, 487]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0_1
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 0,1,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Instant. Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [550, 151]
+    rotation: 0
+    state: true
+- name: zeromq_pull_msg_source_0
+  id: zeromq_pull_msg_source
+  parameters:
+    address: address0
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [12, 120]
+    rotation: 0
+    state: true
+- name: zeromq_pull_msg_source_0_0
+  id: zeromq_pull_msg_source
+  parameters:
+    address: address1
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [11, 298]
+    rotation: 0
+    state: true
+- name: zeromq_pull_msg_source_0_0_0
+  id: zeromq_pull_msg_source
+  parameters:
+    address: address2
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [11, 495]
+    rotation: 0
+    state: true
+- name: zeromq_pull_msg_source_0_0_0_0
+  id: zeromq_pull_msg_source
+  parameters:
+    address: address3
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [11, 619]
+    rotation: 0
+    state: true
+
+connections:
+- [cdc_dsa_stats_pu_mode_0, detect, qtgui_edit_box_msg_0_0_0_0, val]
+- [cdc_dsa_stats_thruput_0, tput, qtgui_edit_box_msg_0, val]
+- [cdc_dsa_stats_thruput_0, tput_new, qtgui_edit_box_msg_0_1, val]
+- [cdc_dsa_stats_thruput_0_0, tput, qtgui_edit_box_msg_0_0, val]
+- [cdc_dsa_stats_thruput_0_0, tput_new, qtgui_edit_box_msg_0_0_0, val]
+- [zeromq_pull_msg_source_0, out, cdc_dsa_stats_thruput_0, pdu]
+- [zeromq_pull_msg_source_0_0, out, cdc_dsa_stats_thruput_0_0, pdu]
+- [zeromq_pull_msg_source_0_0_0, out, cdc_dsa_stats_pu_mode_0, pu]
+- [zeromq_pull_msg_source_0_0_0_0, out, cdc_dsa_stats_pu_mode_0, su]
+
+metadata:
+  file_format: 1
diff --git a/examples/pu_rx_1_channel.grc b/examples/pu_rx_1_channel.grc
index 7581e88809aca8fa69dfd6c2b2fd4c2fdde5c1b6..ee6e224cc695bf60499b6e65bde2edba9dd4f162 100644
--- a/examples/pu_rx_1_channel.grc
+++ b/examples/pu_rx_1_channel.grc
@@ -32,16 +32,16 @@ options:
     state: enabled
 
 blocks:
-- name: decim_factor
+- name: address
   id: variable
   parameters:
     comment: ''
-    value: '5'
+    value: '''tcp://{}:{}''.format(host, port)'
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [608, 12]
+    coordinate: [864, 15]
     rotation: 0
     state: enabled
 - name: fft_len
@@ -53,7 +53,19 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [710, 12]
+    coordinate: [522, 13]
+    rotation: 0
+    state: enabled
+- name: host
+  id: variable
+  parameters:
+    comment: ''
+    value: '''127.0.0.1'''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [669, 14]
     rotation: 0
     state: enabled
 - name: pdu_size
@@ -65,14 +77,41 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [781, 11]
+    coordinate: [592, 13]
+    rotation: 0
+    state: enabled
+- name: port
+  id: variable
+  parameters:
+    comment: ''
+    value: '50001'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [770, 15]
     rotation: 0
     state: enabled
+- name: reset_stats
+  id: variable_qtgui_entry
+  parameters:
+    comment: ''
+    gui_hint: 3,2,1,1
+    label: Reset Stats
+    type: bool
+    value: 'False'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1021, 15]
+    rotation: 0
+    state: true
 - name: rf_freq
   id: variable_qtgui_range
   parameters:
     comment: ''
-    gui_hint: ''
+    gui_hint: 2,0,1,1
     label: RF Frequency
     min_len: '200'
     orient: Qt.Horizontal
@@ -93,7 +132,7 @@ blocks:
   id: variable_qtgui_range
   parameters:
     comment: ''
-    gui_hint: ''
+    gui_hint: 2,1,1,1
     label: Rx Gain
     min_len: '200'
     orient: Qt.Horizontal
@@ -136,28 +175,27 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [583, 307]
+    coordinate: [561, 223]
     rotation: 0
     state: true
-- name: cdc_dsa_db_connect_0
-  id: cdc_dsa_db_connect
+- name: cdc_dsa_stats_thruput_0
+  id: cdc_dsa_stats_thruput
   parameters:
     affinity: ''
     alias: ''
+    alpha: '0.0'
     comment: ''
-    host: 127.0.0.1
     maxoutbuf: '0'
     minoutbuf: '0'
-    pktsize: pdu_size
-    port: '9000'
-    radiotype: dsa.RADIO_PU_RX
+    period: '1'
+    reset: reset_stats
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [855, 283]
+    coordinate: [844, 211]
     rotation: 0
-    state: disabled
+    state: true
 - name: digital_ofdm_rx_0
   id: digital_ofdm_rx
   parameters:
@@ -190,22 +228,53 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [329, 227]
+    coordinate: [318, 143]
     rotation: 0
     state: true
-- name: import_0_1
-  id: import
+- name: qtgui_edit_box_msg_0
+  id: qtgui_edit_box_msg
   parameters:
+    affinity: ''
     alias: ''
     comment: ''
-    imports: from gnuradio import filter
+    gui_hint: 2,2,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [523, 12]
+    coordinate: [1089, 122]
     rotation: 0
-    state: enabled
+    state: true
+- name: qtgui_edit_box_msg_0_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 2,3,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Instant. Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1089, 234]
+    rotation: 0
+    state: true
 - name: qtgui_freq_sink_x_0
   id: qtgui_freq_sink_x
   parameters:
@@ -222,7 +291,7 @@ blocks:
     alpha8: '1.0'
     alpha9: '1.0'
     autoscale: 'False'
-    average: '1.0'
+    average: '0.05'
     axislabels: 'True'
     bw: samp_rate
     color1: '"blue"'
@@ -241,7 +310,7 @@ blocks:
     fftsize: '1024'
     freqhalf: 'True'
     grid: 'False'
-    gui_hint: ''
+    gui_hint: 0,0,2,4
     label: Relative Gain
     label1: ''
     label10: ''''''
@@ -283,9 +352,9 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [328, 435]
+    coordinate: [317, 351]
     rotation: 0
-    state: true
+    state: enabled
 - name: uhd_usrp_source_0
   id: uhd_usrp_source
   parameters:
@@ -654,12 +723,30 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [80, 259]
+    coordinate: [69, 175]
     rotation: 0
-    state: true
+    state: enabled
+- name: zeromq_push_msg_sink_0
+  id: zeromq_push_msg_sink
+  parameters:
+    address: address
+    affinity: ''
+    alias: ''
+    comment: ''
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [827, 287]
+    rotation: 0
+    state: disabled
 
 connections:
-- [blocks_tagged_stream_to_pdu_0, pdus, cdc_dsa_db_connect_0, cmd]
+- [blocks_tagged_stream_to_pdu_0, pdus, cdc_dsa_stats_thruput_0, pdu]
+- [blocks_tagged_stream_to_pdu_0, pdus, zeromq_push_msg_sink_0, in]
+- [cdc_dsa_stats_thruput_0, tput, qtgui_edit_box_msg_0, val]
+- [cdc_dsa_stats_thruput_0, tput_new, qtgui_edit_box_msg_0_0, val]
 - [digital_ofdm_rx_0, '0', blocks_tagged_stream_to_pdu_0, '0']
 - [uhd_usrp_source_0, '0', digital_ofdm_rx_0, '0']
 - [uhd_usrp_source_0, '0', qtgui_freq_sink_x_0, '0']
diff --git a/examples/pu_rx_4_channel.grc b/examples/pu_rx_4_channel.grc
index ad4f52407914d61c1f9bb73247e36da16e4b9bad..63484eedd570cd0354685ddb4f31a045855cb83a 100644
--- a/examples/pu_rx_4_channel.grc
+++ b/examples/pu_rx_4_channel.grc
@@ -32,6 +32,18 @@ options:
     state: enabled
 
 blocks:
+- name: address
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1121, 11]
+    rotation: 0
+    state: enabled
 - name: decim_factor
   id: variable
   parameters:
@@ -56,6 +68,18 @@ blocks:
     coordinate: [656, 10]
     rotation: 0
     state: enabled
+- name: host
+  id: variable
+  parameters:
+    comment: ''
+    value: '''127.0.0.1'''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [927, 11]
+    rotation: 0
+    state: enabled
 - name: pdu_size
   id: variable
   parameters:
@@ -68,11 +92,38 @@ blocks:
     coordinate: [725, 10]
     rotation: 0
     state: enabled
+- name: port
+  id: variable
+  parameters:
+    comment: ''
+    value: '50001'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1028, 11]
+    rotation: 0
+    state: enabled
+- name: reset_stats
+  id: variable_qtgui_entry
+  parameters:
+    comment: ''
+    gui_hint: 3,2,1,1
+    label: Reset Stats
+    type: bool
+    value: 'False'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [802, 10]
+    rotation: 0
+    state: true
 - name: rf_freq
   id: variable_qtgui_range
   parameters:
     comment: ''
-    gui_hint: ''
+    gui_hint: 2,0,1,1
     label: RF Frequency
     min_len: '200'
     orient: Qt.Horizontal
@@ -93,7 +144,7 @@ blocks:
   id: variable_qtgui_range
   parameters:
     comment: ''
-    gui_hint: ''
+    gui_hint: 2,1,1,1
     label: Rx Gain
     min_len: '200'
     orient: Qt.Horizontal
@@ -202,25 +253,24 @@ blocks:
     coordinate: [867, 841]
     rotation: 0
     state: true
-- name: cdc_dsa_db_connect_0
-  id: cdc_dsa_db_connect
+- name: cdc_dsa_stats_thruput_0
+  id: cdc_dsa_stats_thruput
   parameters:
     affinity: ''
     alias: ''
+    alpha: '0.0'
     comment: ''
-    host: 127.0.0.1
     maxoutbuf: '0'
     minoutbuf: '0'
-    pktsize: pdu_size
-    port: '9000'
-    radiotype: dsa.RADIO_PU_RX
+    period: '1'
+    reset: reset_stats
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1194, 197]
+    coordinate: [1169, 205]
     rotation: 0
-    state: disabled
+    state: true
 - name: digital_ofdm_rx_0
   id: digital_ofdm_rx
   parameters:
@@ -458,6 +508,50 @@ blocks:
     coordinate: [555, 72]
     rotation: 0
     state: enabled
+- name: qtgui_edit_box_msg_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 2,2,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1420, 173]
+    rotation: 0
+    state: true
+- name: qtgui_edit_box_msg_0_0
+  id: qtgui_edit_box_msg
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    gui_hint: 2,3,1,1
+    is_pair: 'False'
+    is_static: 'True'
+    key: ''
+    label: PU Instant. Thruput (kbps)
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    type: double
+    value: '0.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1420, 283]
+    rotation: 0
+    state: true
 - name: qtgui_freq_sink_x_0
   id: qtgui_freq_sink_x
   parameters:
@@ -493,7 +587,7 @@ blocks:
     fftsize: '1024'
     freqhalf: 'True'
     grid: 'False'
-    gui_hint: ''
+    gui_hint: 0,0,2,4
     label: Relative Gain
     label1: ''
     label10: ''''''
@@ -908,13 +1002,34 @@ blocks:
     bus_structure: null
     coordinate: [64, 172]
     rotation: 0
-    state: true
+    state: enabled
+- name: zeromq_push_msg_sink_0
+  id: zeromq_push_msg_sink
+  parameters:
+    address: address
+    affinity: ''
+    alias: ''
+    comment: ''
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1168, 292]
+    rotation: 0
+    state: disabled
 
 connections:
-- [blocks_tagged_stream_to_pdu_0, pdus, cdc_dsa_db_connect_0, cmd]
-- [blocks_tagged_stream_to_pdu_0_0, pdus, cdc_dsa_db_connect_0, cmd]
-- [blocks_tagged_stream_to_pdu_0_0_0, pdus, cdc_dsa_db_connect_0, cmd]
-- [blocks_tagged_stream_to_pdu_0_0_0_0, pdus, cdc_dsa_db_connect_0, cmd]
+- [blocks_tagged_stream_to_pdu_0, pdus, cdc_dsa_stats_thruput_0, pdu]
+- [blocks_tagged_stream_to_pdu_0, pdus, zeromq_push_msg_sink_0, in]
+- [blocks_tagged_stream_to_pdu_0_0, pdus, cdc_dsa_stats_thruput_0, pdu]
+- [blocks_tagged_stream_to_pdu_0_0, pdus, zeromq_push_msg_sink_0, in]
+- [blocks_tagged_stream_to_pdu_0_0_0, pdus, cdc_dsa_stats_thruput_0, pdu]
+- [blocks_tagged_stream_to_pdu_0_0_0, pdus, zeromq_push_msg_sink_0, in]
+- [blocks_tagged_stream_to_pdu_0_0_0_0, pdus, cdc_dsa_stats_thruput_0, pdu]
+- [blocks_tagged_stream_to_pdu_0_0_0_0, pdus, zeromq_push_msg_sink_0, in]
+- [cdc_dsa_stats_thruput_0, tput, qtgui_edit_box_msg_0, val]
+- [cdc_dsa_stats_thruput_0, tput_new, qtgui_edit_box_msg_0_0, val]
 - [digital_ofdm_rx_0, '0', blocks_tagged_stream_to_pdu_0, '0']
 - [digital_ofdm_rx_0_0, '0', blocks_tagged_stream_to_pdu_0_0, '0']
 - [digital_ofdm_rx_0_0_0, '0', blocks_tagged_stream_to_pdu_0_0_0, '0']
diff --git a/examples/pu_tx_1_channel_mod.grc b/examples/pu_tx_1_channel_mod.grc
index 17939d330e70832844080cfe3e08de8690e5a3c6..60a32e89ec31293c82a0008832c4ab96f768d134 100644
--- a/examples/pu_tx_1_channel_mod.grc
+++ b/examples/pu_tx_1_channel_mod.grc
@@ -32,6 +32,18 @@ options:
     state: enabled
 
 blocks:
+- name: address
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1226, 10]
+    rotation: 0
+    state: enabled
 - name: fft_len
   id: variable
   parameters:
@@ -44,6 +56,18 @@ blocks:
     coordinate: [267, 8]
     rotation: 0
     state: enabled
+- name: host
+  id: variable
+  parameters:
+    comment: ''
+    value: '''127.0.0.1'''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1031, 9]
+    rotation: 0
+    state: enabled
 - name: pdu_size
   id: variable
   parameters:
@@ -53,7 +77,19 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [259, 71]
+    coordinate: [182, 69]
+    rotation: 0
+    state: enabled
+- name: port
+  id: variable
+  parameters:
+    comment: ''
+    value: '50003'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1132, 10]
     rotation: 0
     state: enabled
 - name: random_scenario
@@ -82,7 +118,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [808, 8]
+    coordinate: [704, 8]
     rotation: 0
     state: true
 - name: rf_freq
@@ -136,7 +172,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [695, 9]
+    coordinate: [591, 9]
     rotation: 0
     state: true
 - name: scenario_duration
@@ -151,7 +187,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [960, 9]
+    coordinate: [856, 9]
     rotation: 0
     state: true
 - name: tx_gain
@@ -166,7 +202,7 @@ blocks:
     start: '0'
     step: '1'
     stop: '92'
-    value: '40'
+    value: '90'
     widget: counter
   states:
     bus_sink: false
@@ -210,7 +246,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [247, 517]
+    coordinate: [243, 463]
     rotation: 0
     state: true
 - name: blocks_stream_to_tagged_stream_0
@@ -248,7 +284,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [477, 540]
+    coordinate: [445, 549]
     rotation: 0
     state: enabled
 - name: cdc_dsa_pu_scenario_2_0
@@ -340,7 +376,7 @@ blocks:
     comment: ''
     ctrlpanel: 'False'
     fc: '0'
-    fftsize: '720'
+    fftsize: '1024'
     freqhalf: 'True'
     grid: 'False'
     gui_hint: ''
@@ -385,7 +421,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [674, 613]
+    coordinate: [646, 624]
     rotation: 0
     state: true
 - name: qtgui_time_sink_x_0
@@ -443,7 +479,7 @@ blocks:
     marker9: '-1'
     name: '""'
     nconnections: '1'
-    size: '720'
+    size: '1024'
     srate: samp_rate
     stemplot: 'False'
     style1: '1'
@@ -482,7 +518,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [694, 524]
+    coordinate: [644, 533]
     rotation: 0
     state: true
 - name: uhd_usrp_sink_0
@@ -758,7 +794,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [491, 407]
+    coordinate: [486, 407]
     rotation: 0
     state: disabled
 - name: virtual_sink_1
@@ -771,7 +807,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [933, 258]
+    coordinate: [952, 242]
     rotation: 0
     state: true
 - name: virtual_source_1
@@ -784,9 +820,24 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [26, 517]
+    coordinate: [22, 463]
     rotation: 0
     state: true
+- name: zeromq_push_msg_sink_0
+  id: zeromq_push_msg_sink
+  parameters:
+    address: address
+    affinity: ''
+    alias: ''
+    comment: ''
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [951, 290]
+    rotation: 0
+    state: disabled
 
 connections:
 - [analog_random_source_x_0, '0', blocks_stream_to_tagged_stream_0, '0']
@@ -796,6 +847,7 @@ connections:
 - [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
 - [blocks_throttle_0, '0', qtgui_time_sink_x_0, '0']
 - [cdc_dsa_pu_scenario_2_0, '0', virtual_sink_1, '0']
+- [cdc_dsa_pu_scenario_2_0, mode, zeromq_push_msg_sink_0, in]
 - [digital_ofdm_tx_0, '0', cdc_dsa_pu_scenario_2_0, '0']
 - [virtual_source_1, '0', blocks_multiply_const_vxx_0, '0']
 
diff --git a/examples/pu_tx_4_channel_mod.grc b/examples/pu_tx_4_channel_mod.grc
index e55df26aded12d5b0ccf015bb12f1fed1c7703d1..1377bce3500b612882a9bdfcf402ba7c98feb49a 100644
--- a/examples/pu_tx_4_channel_mod.grc
+++ b/examples/pu_tx_4_channel_mod.grc
@@ -32,6 +32,18 @@ options:
     state: enabled
 
 blocks:
+- name: address
+  id: variable
+  parameters:
+    comment: ''
+    value: '''tcp://{}:{}''.format(host, port)'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1344, 10]
+    rotation: 0
+    state: enabled
 - name: decim_factor
   id: variable
   parameters:
@@ -71,6 +83,18 @@ blocks:
     coordinate: [261, 8]
     rotation: 0
     state: enabled
+- name: host
+  id: variable
+  parameters:
+    comment: ''
+    value: '''127.0.0.1'''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1149, 9]
+    rotation: 0
+    state: enabled
 - name: interp_factor
   id: variable
   parameters:
@@ -95,6 +119,18 @@ blocks:
     coordinate: [255, 69]
     rotation: 0
     state: enabled
+- name: port
+  id: variable
+  parameters:
+    comment: ''
+    value: '50003'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1250, 10]
+    rotation: 0
+    state: enabled
 - name: random_scenario
   id: variable_qtgui_chooser
   parameters:
@@ -579,7 +615,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1819, 385]
+    coordinate: [1824, 385]
     rotation: 0
     state: enabled
 - name: cdc_dsa_pu_scenario_2_0
@@ -1226,9 +1262,24 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1870, 231]
+    coordinate: [1871, 231]
     rotation: 0
     state: disabled
+- name: zeromq_push_msg_sink_0
+  id: zeromq_push_msg_sink
+  parameters:
+    address: address
+    affinity: ''
+    alias: ''
+    comment: ''
+    timeout: '100'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [747, 678]
+    rotation: 180
+    state: disabled
 
 connections:
 - [analog_random_source_x_0, '0', blocks_stream_to_tagged_stream_0, '0']
@@ -1256,6 +1307,7 @@ connections:
 - [cdc_dsa_pu_scenario_2_0, '1', rational_resampler_xxx_0_0_0, '0']
 - [cdc_dsa_pu_scenario_2_0, '2', rational_resampler_xxx_0_0_0_0, '0']
 - [cdc_dsa_pu_scenario_2_0, '3', rational_resampler_xxx_0_0_0_0_0, '0']
+- [cdc_dsa_pu_scenario_2_0, mode, zeromq_push_msg_sink_0, in]
 - [digital_ofdm_tx_0, '0', cdc_dsa_pu_scenario_2_0, '0']
 - [digital_ofdm_tx_0_0, '0', cdc_dsa_pu_scenario_2_0, '1']
 - [digital_ofdm_tx_0_0_0, '0', cdc_dsa_pu_scenario_2_0, '2']
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 84e2ad5da77f69f2d0580ce583b8fc2368cde50b..b5450ec2781970fdcaf67840b72cbbc95be139ce 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -24,5 +24,6 @@ install(FILES
     cdc_dsa_database.block.yml
     cdc_dsa_db_interface.block.yml
     cdc_fixed_pdu_generator.block.yml
-    DESTINATION share/gnuradio/grc/blocks
+    cdc_dsa_stats_thruput.block.yml
+    cdc_dsa_stats_pu_mode.block.yml DESTINATION share/gnuradio/grc/blocks
 )
diff --git a/grc/cdc_dsa_pu_scenario_2.block.yml b/grc/cdc_dsa_pu_scenario_2.block.yml
index 6d8722f9f59625f294b59430281ede95027fe781..d0e5fa4632eec08b69add7c76fc646b77a660451 100644
--- a/grc/cdc_dsa_pu_scenario_2.block.yml
+++ b/grc/cdc_dsa_pu_scenario_2.block.yml
@@ -46,5 +46,8 @@ outputs:
   domain: stream
   dtype: complex
   multiplicity: ${num_channels}
+- label: mode
+  domain: message
+  optional: True
 
 file_format: 1
diff --git a/grc/cdc_dsa_stats_pu_mode.block.yml b/grc/cdc_dsa_stats_pu_mode.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..28c4560d380e654b9cb61cfa9b51fc621c0cb2d8
--- /dev/null
+++ b/grc/cdc_dsa_stats_pu_mode.block.yml
@@ -0,0 +1,33 @@
+id: cdc_dsa_stats_pu_mode
+label: DSA Stats PU Mode
+category: '[cdc]'
+
+templates:
+  imports: import cdc
+  make: cdc.dsa_stats_pu_mode(${period})
+  callbacks:
+  - reset_stats(${reset})
+
+parameters:
+- id: period
+  label: Period (sec)
+  dtype: int
+  default: 1
+- id: reset
+  label: Reset
+  dytpe: raw
+  default: False
+
+inputs:
+- label: pu
+  domain: message
+  optional: False
+- label: su
+  domain: message
+  optional: False
+
+outputs:
+- label: detect
+  domain: message
+
+file_format: 1
diff --git a/grc/cdc_dsa_stats_thruput.block.yml b/grc/cdc_dsa_stats_thruput.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..221ccaeff9dcc99971022ee39cdd3e96161afaf3
--- /dev/null
+++ b/grc/cdc_dsa_stats_thruput.block.yml
@@ -0,0 +1,38 @@
+id: cdc_dsa_stats_thruput
+label: DSA Stats Thruput
+category: '[cdc]'
+
+templates:
+  imports: import cdc
+  make: cdc.dsa_stats_thruput(${period}, ${alpha})
+  callbacks:
+  - reset_stats(${reset})
+
+parameters:
+- id: period
+  label: Period (sec)
+  dtype: int
+  default: 1
+- id: alpha
+  label: Alpha
+  dtype: float
+  default: 0.0
+- id: reset
+  label: Reset
+  dtype: raw
+  default: False
+
+inputs:
+- label: pdu
+  domain: message
+  optional: True
+
+outputs:
+- label: tput
+  domain: message
+  optional: True
+- label: tput_new
+  domain: message
+  optional: True
+
+file_format: 1
diff --git a/include/cdc/CMakeLists.txt b/include/cdc/CMakeLists.txt
index 060300f67a4c26412941659df3ca9d6b4e63b390..8984e0251bed1e3d43ddd56c3ec169df9348aff9 100644
--- a/include/cdc/CMakeLists.txt
+++ b/include/cdc/CMakeLists.txt
@@ -28,5 +28,7 @@ install(FILES
     dsa_pu_scenario_2.h
     dsa_db_connect.h
     dsa_database.h
-    dsa_db_interface.h DESTINATION include/cdc
+    dsa_db_interface.h
+    dsa_stats_thruput.h
+    dsa_stats_pu_mode.h DESTINATION include/cdc
 )
diff --git a/include/cdc/dsa_stats_pu_mode.h b/include/cdc/dsa_stats_pu_mode.h
new file mode 100644
index 0000000000000000000000000000000000000000..4afe0f427467a9fb548f921d2edc0cc27e66a4bc
--- /dev/null
+++ b/include/cdc/dsa_stats_pu_mode.h
@@ -0,0 +1,57 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifndef INCLUDED_CDC_DSA_STATS_PU_MODE_H
+#define INCLUDED_CDC_DSA_STATS_PU_MODE_H
+
+#include <cdc/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+namespace cdc {
+
+/*!
+ * \brief <+description of block+>
+ * \ingroup cdc
+ *
+ */
+class CDC_API dsa_stats_pu_mode : virtual public gr::block
+{
+public:
+    typedef boost::shared_ptr<dsa_stats_pu_mode> sptr;
+
+    virtual void reset_stats(bool reset) = 0;
+
+    /*!
+     * \brief Return a shared_ptr to a new instance of cdc::dsa_stats_pu_mode.
+     *
+     * To avoid accidental use of raw pointers, cdc::dsa_stats_pu_mode's
+     * constructor is in a private implementation
+     * class. cdc::dsa_stats_pu_mode::make is the public interface for
+     * creating new instances.
+     */
+    static sptr make(long period);
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_DSA_STATS_PU_MODE_H */
+
diff --git a/include/cdc/dsa_stats_thruput.h b/include/cdc/dsa_stats_thruput.h
new file mode 100644
index 0000000000000000000000000000000000000000..b5c8f407c435ab1ce986edc1a1bd0d8f2fb1e838
--- /dev/null
+++ b/include/cdc/dsa_stats_thruput.h
@@ -0,0 +1,58 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifndef INCLUDED_CDC_DSA_THRUPUT_STATS_H
+#define INCLUDED_CDC_DSA_THRUPUT_STATS_H
+
+#include <cdc/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+namespace cdc {
+
+/*!
+ * \brief <+description of block+>
+ * \ingroup cdc
+ *
+ */
+class CDC_API dsa_stats_thruput : virtual public gr::block
+{
+public:
+    typedef boost::shared_ptr<dsa_stats_thruput> sptr;
+
+    virtual void reset_stats(bool reset) = 0;
+
+    /*!
+     * \brief Return a shared_ptr to a new instance of cdc::dsa_stats_thruput.
+     *
+     * To avoid accidental use of raw pointers, cdc::dsa_stats_thrupu's
+     * constructor is in a private implementation
+     * class. cdc::dsa_stats_thruput::make is the public interface for
+     * creating new instances.
+     */
+    static sptr make(long period,
+                     float alpha);
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_DSA_RX_STATS_H */
+
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2830891cd53d2895669511305856d26758d8677e..ba1e31a141bd455b204818c9f3b29a15ddba3090 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -27,7 +27,9 @@ list(APPEND cdc_sources
     dsa_pu_scenario_2_impl.cc
     dsa_db_connect_impl.cc
     dsa_database.cc
-    dsa_db_interface.cc )
+    dsa_db_interface.cc
+    dsa_stats_thruput_impl.cc
+    dsa_stats_pu_mode_impl.cc )
 
 set(cdc_sources "${cdc_sources}" PARENT_SCOPE)
 if(NOT cdc_sources)
diff --git a/lib/dsa_pu_scenario_2_impl.cc b/lib/dsa_pu_scenario_2_impl.cc
index 7913e86833a07f02604b31f21010126ee0cd6231..f39e98943f87bfef69bc52f773153e2fd59c7770 100644
--- a/lib/dsa_pu_scenario_2_impl.cc
+++ b/lib/dsa_pu_scenario_2_impl.cc
@@ -56,6 +56,7 @@ dsa_pu_scenario_2_impl::dsa_pu_scenario_2_impl(int scenario,
       d_samp_rate(samp_rate),
       d_duration_ms(duration_ms)
 {
+    message_port_register_out(pmt::mp("mode"));
 }
 
 /*
@@ -82,6 +83,7 @@ dsa_pu_scenario_2_impl::update_scenario(int n_chan)
         d_samp_cnt = int(d_duration_ms * d_samp_rate / 1000.0);
         if (d_random)
             d_scenario = (*d_uniform)(d_engine);
+        message_port_pub(pmt::mp("mode"), pmt::mp(d_scenario));
     }
 
     for (int i_chan=0; i_chan < n_chan; i_chan++)
diff --git a/lib/dsa_stats_pu_mode_impl.cc b/lib/dsa_stats_pu_mode_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..307a04a32fd0d23f0f030ce7d2550895ac933e36
--- /dev/null
+++ b/lib/dsa_stats_pu_mode_impl.cc
@@ -0,0 +1,157 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include "dsa_stats_pu_mode_impl.h"
+
+namespace gr {
+namespace cdc {
+
+dsa_stats_pu_mode::sptr
+dsa_stats_pu_mode::make(long period)
+{
+    return gnuradio::get_initial_sptr
+        (new dsa_stats_pu_mode_impl(period));
+}
+
+
+/*
+ * The private constructor
+ */
+dsa_stats_pu_mode_impl::dsa_stats_pu_mode_impl(long period)
+    : gr::block("dsa_stats_pu_mode",
+          gr::io_signature::make(0, 0, 0),
+          gr::io_signature::make(0, 0, 0)),
+      d_period(period)
+{
+    message_port_register_in(pmt::mp("pu"));
+    message_port_register_in(pmt::mp("su"));
+    message_port_register_out(pmt::mp("detect"));
+
+    set_msg_handler(pmt::mp("pu"),
+                    boost::bind(&dsa_stats_pu_mode_impl::handle_pu, this, _1));
+    set_msg_handler(pmt::mp("su"),
+                    boost::bind(&dsa_stats_pu_mode_impl::handle_su, this, _1));
+
+    reset_stats();
+}
+
+/*
+ * Our virtual destructor.
+ */
+dsa_stats_pu_mode_impl::~dsa_stats_pu_mode_impl()
+{ }
+
+bool
+dsa_stats_pu_mode_impl::start()
+{
+    d_finished = false;
+
+    d_thread = boost::shared_ptr<gr::thread::thread>(
+        new gr::thread::thread(boost::bind(&dsa_stats_pu_mode_impl::run, this)));
+
+    return block::start();
+}
+
+bool
+dsa_stats_pu_mode_impl::stop()
+{
+    // Shut down the thread
+    d_finished = true;
+    d_thread->interrupt();
+    d_thread->join();
+
+    return block::stop();
+}
+
+void
+dsa_stats_pu_mode_impl::run()
+{
+    while (!d_finished) {
+        boost::this_thread::sleep(
+            boost::posix_time::seconds(static_cast<long>(d_period)));
+        
+        if (d_finished)
+            return;
+
+        int num_mode;
+        int num_detect;
+        {
+            gr::thread::scoped_lock(d_mtx);
+            
+            num_mode = d_num_mode;
+            num_detect = d_num_detect;
+        }
+
+        double detect = 0.0;
+        if (num_mode > 0)
+            detect = (100.0 * num_detect) / num_mode;
+        message_port_pub(pmt::mp("detect"), pmt::mp(detect));
+   }
+}
+
+void
+dsa_stats_pu_mode_impl::handle_pu(pmt::pmt_t msg)
+{
+    gr::thread::scoped_lock(d_mtx);
+
+    if (d_num_correct > d_num_wrong)
+        d_num_detect += 1;
+    d_num_mode += 1;
+    d_num_correct = 0;
+    d_num_wrong = 0;
+
+    d_mode = pmt::to_long(msg);
+}
+
+void
+dsa_stats_pu_mode_impl::handle_su(pmt::pmt_t msg)
+{
+    gr::thread::scoped_lock(d_mtx);
+
+    long mode = pmt::to_long(msg);
+    if (mode == d_mode)
+        d_num_correct += 1;
+    else
+        d_num_wrong += 1;
+}
+
+void
+dsa_stats_pu_mode_impl::reset_stats(bool reset)
+{
+    if (reset)
+    {
+        gr::thread::scoped_lock(d_mtx);
+
+        d_mode = -1;
+        d_num_mode = -1;
+        d_num_detect = 0;
+        d_num_correct = 0;
+        d_num_wrong = 0;
+    }
+}
+
+} /* namespace cdc */
+} /* namespace gr */
+
diff --git a/lib/dsa_stats_pu_mode_impl.h b/lib/dsa_stats_pu_mode_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..1176b729a17f5768dd91f03233584885a9737bd2
--- /dev/null
+++ b/lib/dsa_stats_pu_mode_impl.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifndef INCLUDED_CDC_DSA_STATS_PU_MODE_IMPL_H
+#define INCLUDED_CDC_DSA_STATS_PU_MODE_IMPL_H
+
+#include <cdc/dsa_stats_pu_mode.h>
+
+namespace gr {
+namespace cdc {
+
+class dsa_stats_pu_mode_impl : public dsa_stats_pu_mode
+{
+private:
+    boost::shared_ptr<gr::thread::thread> d_thread;
+    bool d_finished;
+    long d_period;
+
+    // track stats
+    long d_mode;
+    int d_num_mode;
+    int d_num_detect;
+    int d_num_correct;
+    int d_num_wrong;
+
+    void run();
+
+    void handle_pu(pmt::pmt_t msg);
+
+    void handle_su(pmt::pmt_t msg);
+
+public:
+    dsa_stats_pu_mode_impl(long period);
+
+    ~dsa_stats_pu_mode_impl();
+
+    void reset_stats(bool reset=true);
+
+    // Overload gr::block start/stop to start internal thread
+    bool start();
+    bool stop();
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_DSA_STATS_PU_MODE_IMPL_H */
+
diff --git a/lib/dsa_stats_thruput_impl.cc b/lib/dsa_stats_thruput_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5ad2628f6855b58b07b08e304978665679eaf92b
--- /dev/null
+++ b/lib/dsa_stats_thruput_impl.cc
@@ -0,0 +1,149 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include "dsa_stats_thruput_impl.h"
+
+using std::chrono::steady_clock;
+
+namespace gr {
+namespace cdc {
+
+dsa_stats_thruput::sptr
+dsa_stats_thruput::make(long period,
+                        float alpha)
+{
+    return gnuradio::get_initial_sptr
+        (new dsa_stats_thruput_impl(period, alpha));
+}
+
+
+/*
+ * The private constructor
+ */
+dsa_stats_thruput_impl::dsa_stats_thruput_impl(long period,
+                                               float alpha)
+  : gr::block("dsa_stats_thruput",
+          gr::io_signature::make(0, 0, 0),
+          gr::io_signature::make(0, 0, 0)),
+    d_period(period),
+    d_alpha(alpha)
+{
+    message_port_register_in(pmt::mp("pdu"));
+    message_port_register_out(pmt::mp("tput"));
+    message_port_register_out(pmt::mp("tput_new"));
+
+    set_msg_handler(pmt::mp("pdu"),
+                    boost::bind(&dsa_stats_thruput_impl::handle_pdu, this, _1));
+
+    reset_stats();
+}
+
+/*
+ * Our virtual destructor.
+ */
+dsa_stats_thruput_impl::~dsa_stats_thruput_impl()
+{
+}
+
+bool
+dsa_stats_thruput_impl::start()
+{
+    d_finished = false;
+
+    d_thread = boost::shared_ptr<gr::thread::thread>(
+        new gr::thread::thread(boost::bind(&dsa_stats_thruput_impl::run, this)));
+
+    return block::start();
+}
+
+bool
+dsa_stats_thruput_impl::stop()
+{
+    // Shut down the thread
+    d_finished = true;
+    d_thread->interrupt();
+    d_thread->join();
+
+    return block::stop();
+}
+
+void
+dsa_stats_thruput_impl::run()
+{
+    while (!d_finished) {
+        boost::this_thread::sleep(
+            boost::posix_time::seconds(static_cast<long>(d_period)));
+        
+        if (d_finished)
+            return;
+
+        // elapsed time
+        auto now = steady_clock::now();
+        std::chrono::duration<double> dur0 = (now - d_start_tp);
+        std::chrono::duration<double> dur1 = (now - d_last_tp);
+        d_last_tp = now;
+
+        // get latest stats
+        double bytes_new = 0;
+        {
+            gr::thread::scoped_lock(d_mtx);
+
+            bytes_new = d_bytes_new;
+            d_bytes_new = 0;
+        }
+        d_bytes += bytes_new;
+        double tput = 8.0*d_bytes / (1000.0*dur0.count());
+        d_tput_new *= d_alpha;
+        d_tput_new += (1 - d_alpha)*8.0*bytes_new / (1000.0*dur1.count());
+
+        message_port_pub(pmt::mp("tput"), pmt::mp(tput));
+        message_port_pub(pmt::mp("tput_new"), pmt::mp(d_tput_new));
+    }
+}
+
+void
+dsa_stats_thruput_impl::handle_pdu(pmt::pmt_t msg)
+{
+    d_bytes_new += pmt::blob_length(pmt::cdr(msg));
+}
+
+void
+dsa_stats_thruput_impl::reset_stats(bool reset)
+{
+    if (reset)
+    {
+        gr::thread::scoped_lock(d_mtx);
+
+        d_bytes = 0.0;
+        d_bytes_new = 0.0;
+        d_tput_new = 0.0;
+        d_start_tp = steady_clock::now();
+        d_last_tp = d_start_tp;
+    }
+}
+
+} /* namespace cdc */
+} /* namespace gr */
+
diff --git a/lib/dsa_stats_thruput_impl.h b/lib/dsa_stats_thruput_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..0fc4f6958b0c47e7adf8cee1b50b5049d26691c7
--- /dev/null
+++ b/lib/dsa_stats_thruput_impl.h
@@ -0,0 +1,68 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2021 University of Melbourne.
+ *
+ * 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.
+ */
+
+#ifndef INCLUDED_CDC_DSA_STATS_THRUPUT_IMPL_H
+#define INCLUDED_CDC_DSA_STATS_THRUPUT_IMPL_H
+
+#include <cdc/dsa_stats_thruput.h>
+#include <chrono>
+
+namespace gr {
+namespace cdc {
+
+class dsa_stats_thruput_impl : public dsa_stats_thruput
+{
+private:
+    boost::shared_ptr<gr::thread::thread> d_thread;
+    bool d_finished;
+    long d_period;
+    float d_alpha;
+
+    // stat variables
+    gr::thread::mutex d_mtx;
+    std::chrono::time_point<std::chrono::steady_clock> d_start_tp;
+    std::chrono::time_point<std::chrono::steady_clock> d_last_tp;
+    double d_bytes = 0.0;
+    double d_bytes_new = 0.0;
+    double d_tput_new = 0.0;
+
+    void run();
+
+    void handle_pdu(pmt::pmt_t pdu);
+
+public:
+    dsa_stats_thruput_impl(long period,
+                           float alpha);
+
+    ~dsa_stats_thruput_impl();
+
+    void reset_stats(bool reset=true);
+
+    // Overload gr::block start/stop to start internal thread
+    bool start();
+    bool stop();
+
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_DSA_STATS_THRUPUT_IMPL_H */
+
diff --git a/swig/cdc_swig.i b/swig/cdc_swig.i
index 5702e9df95294491ac7089ed4170067920eaadf1..55a4c34ee2ddd4af76c4290d7e7e59348e331bbd 100644
--- a/swig/cdc_swig.i
+++ b/swig/cdc_swig.i
@@ -14,6 +14,8 @@
 #include "cdc/dsa_db_connect.h"
 #include "cdc/dsa_database.h"
 #include "cdc/dsa_db_interface.h"
+#include "cdc/dsa_stats_thruput.h"
+#include "cdc/dsa_stats_pu_mode.h"
 %}
 
 %include "cdc/dsa.h"
@@ -25,6 +27,11 @@ GR_SWIG_BLOCK_MAGIC2(cdc, dsa_pu_scenario_2);
 GR_SWIG_BLOCK_MAGIC2(cdc, dsa_db_connect);
 %include "cdc/dsa_database.h"
 %include "cdc/dsa_db_interface.h"
+%include "cdc/dsa_stats_thruput.h"
+GR_SWIG_BLOCK_MAGIC2(cdc, dsa_stats_thruput);
+%include "cdc/dsa_stats_pu_mode.h"
+GR_SWIG_BLOCK_MAGIC2(cdc, dsa_stats_pu_mode);
+
 
 // properly package up non-block objects
 %include "dsa.i"