From 52274048490998700bdf052a965592b6e843998e Mon Sep 17 00:00:00 2001 From: Naoki Pross Date: Sun, 24 Oct 2021 15:59:50 +0200 Subject: Create QPSK simulation without QT GUI --- simulation/QPSK/qpsk.grc | 20 +- simulation/QPSK/qpsk_nogui.grc | 479 +++++++++++++++++++++++++++++++++++++++++ simulation/QPSK/qpsk_nogui.py | 233 ++++++++++++++++++++ 3 files changed, 723 insertions(+), 9 deletions(-) create mode 100644 simulation/QPSK/qpsk_nogui.grc create mode 100755 simulation/QPSK/qpsk_nogui.py diff --git a/simulation/QPSK/qpsk.grc b/simulation/QPSK/qpsk.grc index ffc7103..11a2e6a 100644 --- a/simulation/QPSK/qpsk.grc +++ b/simulation/QPSK/qpsk.grc @@ -1,6 +1,7 @@ options: parameters: author: Pross Naoki, Halter Sara Cinzia + catch_exceptions: 'True' category: '[GRC Hier Blocks]' cmake_opt: '' comment: '' @@ -22,7 +23,6 @@ options: sizing_mode: fixed thread_safe_setters: '' title: QPSK - window_size: '' states: bus_sink: false bus_source: false @@ -51,7 +51,7 @@ blocks: gui_hint: 'params@1: 0,0,1,1' label: Equalizer Rate min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: '0' step: '.001' @@ -108,7 +108,7 @@ blocks: gui_hint: 'params@0: 1,0,1,1' label: Frequency Offset min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: -100e-3 step: 1e-3 @@ -141,7 +141,7 @@ blocks: gui_hint: 'params@0: 0,0,1,1' label: Noise Voltage min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: '0' step: '0.01' @@ -162,7 +162,7 @@ blocks: gui_hint: 'params@1: 1,0,1,1' label: Phase Bandwidth min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: '0' step: '.01' @@ -239,7 +239,7 @@ blocks: gui_hint: 'params@0: 0,1,1,1' label: Timing Offset min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: '0.999' step: '0.0001' @@ -260,7 +260,7 @@ blocks: gui_hint: 'params@0: 1,1,1,1' label: Time Bandwidth min_len: '200' - orient: Qt.Horizontal + orient: QtCore.Qt.Horizontal rangeType: float start: '0' step: 10e-3 @@ -271,7 +271,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [640, 604.0] + coordinate: [1008, 548.0] rotation: 0 state: true - name: analog_random_source_x_0 @@ -467,6 +467,7 @@ blocks: maxoutbuf: '0' minoutbuf: '0' samples_per_symbol: sps + truncate: 'False' verbose: 'False' states: bus_sink: false @@ -1036,6 +1037,7 @@ blocks: minoutbuf: '0' name: '"Channel"' nconnections: '1' + norm_window: 'False' showports: 'False' tr_chan: '0' tr_level: '0.0' @@ -1054,7 +1056,7 @@ blocks: width7: '1' width8: '1' width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS + wintype: window.WIN_BLACKMAN_hARRIS ymax: '10' ymin: '-140' states: diff --git a/simulation/QPSK/qpsk_nogui.grc b/simulation/QPSK/qpsk_nogui.grc new file mode 100644 index 0000000..e27ecc7 --- /dev/null +++ b/simulation/QPSK/qpsk_nogui.grc @@ -0,0 +1,479 @@ +options: + parameters: + author: Naoki Pross + catch_exceptions: 'True' + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: no_gui + hier_block_src_path: '.:' + id: qpsk_nogui + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '1' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: QPSK with IMGUI + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: chn_taps + id: variable + parameters: + comment: '' + value: '[1.0 + 0.0j, ]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 204.0] + rotation: 0 + state: true +- name: eq_gain + id: variable + parameters: + comment: '' + value: '.01' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1376, 420.0] + rotation: 0 + state: true +- name: eq_mod + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1376, 352.0] + rotation: 0 + state: true +- name: eq_ntaps + id: variable + parameters: + comment: '' + value: '15' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1456, 352.0] + rotation: 0 + state: true +- name: excess_bw + id: variable + parameters: + comment: '' + value: 350e-3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [352, 224.0] + rotation: 0 + state: true +- name: freq_offset + id: variable + parameters: + comment: '' + value: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [768, 204.0] + rotation: 0 + state: true +- name: nfilts + id: variable + parameters: + comment: '' + value: '32' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1040, 432.0] + rotation: 0 + state: true +- name: noise_volt + id: variable + parameters: + comment: '' + value: 100e-6 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 132.0] + rotation: 0 + state: true +- name: phase_bw + id: variable + parameters: + comment: '' + value: 2 * 3.141592653589793 / 100 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1680, 380.0] + rotation: 0 + state: true +- name: qpsk_const + id: variable_constellation_rect + parameters: + comment: '' + const_points: '[0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j]' + imag_sect: '2' + precision: '8' + real_sect: '2' + rot_sym: '4' + soft_dec_lut: None + sym_map: '[0, 1, 3, 2]' + w_imag_sect: '1' + w_real_sect: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [256, 396.0] + rotation: 0 + state: true +- name: rrc_taps + id: variable + parameters: + comment: '' + value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 45*nfilts) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1120, 432.0] + rotation: 0 + state: true +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [184, 12] + rotation: 0 + state: enabled +- name: sps + id: variable + parameters: + comment: '' + value: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [256, 224.0] + rotation: 0 + state: true +- name: time_offset + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [768, 132.0] + rotation: 0 + state: true +- name: timing_loop_bw + id: variable + parameters: + comment: '' + value: 2 * 3.141592653589793 / 100 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1040, 508.0] + rotation: 0 + state: true +- name: analog_random_source_x_0 + id: analog_random_source_x + parameters: + affinity: '' + alias: '' + comment: '' + max: '256' + maxoutbuf: '0' + min: '0' + minoutbuf: '0' + num_samps: '1000' + repeat: 'True' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [64, 288.0] + rotation: 0 + state: enabled +- name: blocks_char_to_float_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2304, 232.0] + rotation: 0 + state: true +- name: blocks_null_sink_0 + id: blocks_null_sink + parameters: + affinity: '' + alias: '' + bus_structure_sink: '[[0,],]' + comment: '' + num_inputs: '1' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2504, 240.0] + rotation: 0 + state: true +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [496, 312.0] + rotation: 0 + state: enabled +- name: blocks_unpack_k_bits_bb_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2224, 392.0] + rotation: 0 + state: true +- name: channels_channel_model_0 + id: channels_channel_model + parameters: + affinity: '' + alias: '' + block_tags: 'False' + comment: '' + epsilon: time_offset + freq_offset: freq_offset + maxoutbuf: '0' + minoutbuf: '0' + noise_voltage: noise_volt + seed: '0' + taps: chn_taps + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 272.0] + rotation: 0 + state: enabled +- name: digital_cma_equalizer_cc_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1376, 240.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: qpsk_const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2016, 232.0] + rotation: 0 + state: true +- name: digital_constellation_modulator_0 + id: digital_constellation_modulator + parameters: + affinity: '' + alias: '' + comment: '' + constellation: qpsk_const + differential: 'True' + excess_bw: excess_bw + log: 'False' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_symbol: sps + truncate: 'False' + verbose: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [256, 288.0] + rotation: 0 + state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1680, 240.0] + rotation: 0 + state: true +- name: digital_diff_decoder_bb_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2016, 312.0] + rotation: 180 + state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2016, 392.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '2' + sps: sps * 1.001 + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1040, 264.0] + rotation: 0 + state: true + +connections: +- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_char_to_float_0, '0', blocks_null_sink_0, '0'] +- [blocks_throttle_0, '0', channels_channel_model_0, '0'] +- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] +- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0, '0'] +- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] +- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] +- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] +- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] +- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] +- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] + +metadata: + file_format: 1 diff --git a/simulation/QPSK/qpsk_nogui.py b/simulation/QPSK/qpsk_nogui.py new file mode 100755 index 0000000..d37e636 --- /dev/null +++ b/simulation/QPSK/qpsk_nogui.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# SPDX-License-Identifier: GPL-3.0 +# +# GNU Radio Python Flow Graph +# Title: QPSK with IMGUI +# Author: Naoki Pross +# GNU Radio version: 3.9.2.0 + +from gnuradio import blocks +import numpy +from gnuradio import channels +from gnuradio.filter import firdes +from gnuradio import digital +from gnuradio import gr +from gnuradio.fft import window +import sys +import signal +from argparse import ArgumentParser +from gnuradio.eng_arg import eng_float, intx +from gnuradio import eng_notation + + + + +class qpsk_nogui(gr.top_block): + + def __init__(self): + gr.top_block.__init__(self, "QPSK with IMGUI", catch_exceptions=True) + + ################################################## + # Variables + ################################################## + self.sps = sps = 4 + self.nfilts = nfilts = 32 + self.timing_loop_bw = timing_loop_bw = 2 * 3.141592653589793 / 100 + self.time_offset = time_offset = 1 + self.samp_rate = samp_rate = 32000 + self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 45*nfilts) + self.qpsk_const = qpsk_const = digital.constellation_rect([0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j], [0, 1, 3, 2], + 4, 2, 2, 1, 1).base() + self.phase_bw = phase_bw = 2 * 3.141592653589793 / 100 + self.noise_volt = noise_volt = 100e-6 + self.freq_offset = freq_offset = 0 + self.excess_bw = excess_bw = 350e-3 + self.eq_ntaps = eq_ntaps = 15 + self.eq_mod = eq_mod = 1 + self.eq_gain = eq_gain = .01 + self.chn_taps = chn_taps = [1.0 + 0.0j, ] + + ################################################## + # Blocks + ################################################## + self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps * 1.001, timing_loop_bw, rrc_taps, nfilts, nfilts/2, 1.5, 2) + self.digital_map_bb_0 = digital.map_bb([0, 1, 3, 2]) + self.digital_diff_decoder_bb_0 = digital.diff_decoder_bb(4) + self.digital_costas_loop_cc_0 = digital.costas_loop_cc(phase_bw, 4, False) + self.digital_constellation_modulator_0 = digital.generic_mod( + constellation=qpsk_const, + differential=True, + samples_per_symbol=sps, + pre_diff_code=True, + excess_bw=excess_bw, + verbose=False, + log=False, + truncate=False) + self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(qpsk_const) + self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(eq_ntaps, eq_mod, eq_gain, 2) + self.channels_channel_model_0 = channels.channel_model( + noise_voltage=noise_volt, + frequency_offset=freq_offset, + epsilon=time_offset, + taps=chn_taps, + noise_seed=0, + block_tags=False) + self.blocks_unpack_k_bits_bb_0 = blocks.unpack_k_bits_bb(2) + self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True) + self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_float*1) + self.blocks_char_to_float_0 = blocks.char_to_float(1, 1) + self.analog_random_source_x_0 = blocks.vector_source_b(list(map(int, numpy.random.randint(0, 256, 1000))), True) + + + + ################################################## + # Connections + ################################################## + self.connect((self.analog_random_source_x_0, 0), (self.digital_constellation_modulator_0, 0)) + self.connect((self.blocks_char_to_float_0, 0), (self.blocks_null_sink_0, 0)) + self.connect((self.blocks_throttle_0, 0), (self.channels_channel_model_0, 0)) + self.connect((self.blocks_unpack_k_bits_bb_0, 0), (self.blocks_char_to_float_0, 0)) + self.connect((self.channels_channel_model_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0)) + self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_costas_loop_cc_0, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.digital_diff_decoder_bb_0, 0)) + self.connect((self.digital_constellation_modulator_0, 0), (self.blocks_throttle_0, 0)) + self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0)) + self.connect((self.digital_diff_decoder_bb_0, 0), (self.digital_map_bb_0, 0)) + self.connect((self.digital_map_bb_0, 0), (self.blocks_unpack_k_bits_bb_0, 0)) + self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) + + + def get_sps(self): + return self.sps + + def set_sps(self, sps): + self.sps = sps + self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 45*self.nfilts)) + + def get_nfilts(self): + return self.nfilts + + def set_nfilts(self, nfilts): + self.nfilts = nfilts + self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 45*self.nfilts)) + + def get_timing_loop_bw(self): + return self.timing_loop_bw + + def set_timing_loop_bw(self, timing_loop_bw): + self.timing_loop_bw = timing_loop_bw + self.digital_pfb_clock_sync_xxx_0.set_loop_bandwidth(self.timing_loop_bw) + + def get_time_offset(self): + return self.time_offset + + def set_time_offset(self, time_offset): + self.time_offset = time_offset + self.channels_channel_model_0.set_timing_offset(self.time_offset) + + def get_samp_rate(self): + return self.samp_rate + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + self.blocks_throttle_0.set_sample_rate(self.samp_rate) + + def get_rrc_taps(self): + return self.rrc_taps + + def set_rrc_taps(self, rrc_taps): + self.rrc_taps = rrc_taps + self.digital_pfb_clock_sync_xxx_0.update_taps(self.rrc_taps) + + def get_qpsk_const(self): + return self.qpsk_const + + def set_qpsk_const(self, qpsk_const): + self.qpsk_const = qpsk_const + + def get_phase_bw(self): + return self.phase_bw + + def set_phase_bw(self, phase_bw): + self.phase_bw = phase_bw + self.digital_costas_loop_cc_0.set_loop_bandwidth(self.phase_bw) + + def get_noise_volt(self): + return self.noise_volt + + def set_noise_volt(self, noise_volt): + self.noise_volt = noise_volt + self.channels_channel_model_0.set_noise_voltage(self.noise_volt) + + def get_freq_offset(self): + return self.freq_offset + + def set_freq_offset(self, freq_offset): + self.freq_offset = freq_offset + self.channels_channel_model_0.set_frequency_offset(self.freq_offset) + + def get_excess_bw(self): + return self.excess_bw + + def set_excess_bw(self, excess_bw): + self.excess_bw = excess_bw + + def get_eq_ntaps(self): + return self.eq_ntaps + + def set_eq_ntaps(self, eq_ntaps): + self.eq_ntaps = eq_ntaps + + def get_eq_mod(self): + return self.eq_mod + + def set_eq_mod(self, eq_mod): + self.eq_mod = eq_mod + self.digital_cma_equalizer_cc_0.set_modulus(self.eq_mod) + + def get_eq_gain(self): + return self.eq_gain + + def set_eq_gain(self, eq_gain): + self.eq_gain = eq_gain + self.digital_cma_equalizer_cc_0.set_gain(self.eq_gain) + + def get_chn_taps(self): + return self.chn_taps + + def set_chn_taps(self, chn_taps): + self.chn_taps = chn_taps + self.channels_channel_model_0.set_taps(self.chn_taps) + + + + +def main(top_block_cls=qpsk_nogui, options=None): + if gr.enable_realtime_scheduling() != gr.RT_OK: + print("Error: failed to enable real-time scheduling.") + tb = top_block_cls() + + def sig_handler(sig=None, frame=None): + tb.stop() + tb.wait() + + sys.exit(0) + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + + tb.start() + + try: + input('Press Enter to quit: ') + except EOFError: + pass + tb.stop() + tb.wait() + + +if __name__ == '__main__': + main() -- cgit v1.2.1