GNU Radio World

PySDR: BPSK Timing and Frequency Synchronization

Companion to the Synchronization chapter of PySDR

Press Load to open this flowgraph in an editor embedded above, then ▶ to run it. Nothing is downloaded until you do.

Open in the full editor ▶ Download the .grc

Blocks used

BlockModuleUsed
VariableGNU Radio4
QT GUI Constellation SinkGNU Radio3
QT GUI RangeGNU Radio3
AGC2GNU Radio1
Channel ModelGNU Radio1
Constellation ModulatorGNU Radio1
Constellation ObjectGNU Radio1
Costas LoopGNU Radio1
GUI LayoutGNU Radio1
NoteGNU Radio1
Polyphase Clock SyncGNU Radio1
QT GUI Time SinkGNU Radio1
Random Uniform SourceGNU Radio1
ThrottleGNU Radio1

Notes in this flowgraph

Flowgraph source

digital/synchronization_bpsk_recovery.grc
options:
    parameters:
        author: Marc
        comment: ''
        copyright: ''
        description: Companion to the Synchronization chapter of PySDR
        generate_options: qt_gui
        id: PySDR__BPSK_Timing_and_Frequency_Synchronization
        title: 'PySDR: BPSK Timing and Frequency Synchronization'
    states:
        coordinate: [10, 10]
        rotation: 0
        state: enabled
blocks:
-   name: freq_offset
    id: variable_qtgui_range
    parameters:
        comment: ''
        label: Frequency offset (cycles/sample)
        min_len: '200'
        orient: QtCore.Qt.Horizontal
        rangeType: float
        start: '-0.03'
        step: '0.002'
        stop: '0.03'
        value: '0.005'
        widget: counter_slider
    states:
        coordinate: [610, 10]
        rotation: 0
        state: enabled
-   name: nfilts
    id: variable
    parameters:
        comment: ''
        value: '16'
    states:
        coordinate: [900, 10]
        rotation: 0
        state: enabled
-   name: noise_volt
    id: variable_qtgui_range
    parameters:
        comment: ''
        label: Noise voltage
        min_len: '200'
        orient: QtCore.Qt.Horizontal
        rangeType: float
        start: '0'
        step: '0.01'
        stop: '3'
        value: '0.1'
        widget: counter_slider
    states:
        coordinate: [1070, 10]
        rotation: 0
        state: enabled
-   name: rrc_taps
    id: variable
    parameters:
        comment: ''
        value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 11*sps*nfilts)
    states:
        coordinate: [1320, 10]
        rotation: 0
        state: enabled
-   name: samp_rate
    id: variable
    parameters:
        comment: ''
        value: '50000'
    states:
        coordinate: [10, 230]
        rotation: 0
        state: enabled
-   name: sps
    id: variable
    parameters:
        comment: ''
        value: '8'
    states:
        coordinate: [180, 230]
        rotation: 0
        state: enabled
-   name: time_offset
    id: variable_qtgui_range
    parameters:
        comment: ''
        label: Timing offset (epsilon)
        min_len: '200'
        orient: QtCore.Qt.Horizontal
        rangeType: float
        start: '0.999'
        step: '0.0001'
        stop: '1.001'
        value: '1.0002'
        widget: counter_slider
    states:
        coordinate: [350, 230]
        rotation: 0
        state: enabled
-   name: agc
    id: analog_agc2_xx
    parameters:
        affinity: ''
        alias: ''
        attack_rate: '0.06'
        comment: ''
        decay_rate: '0.001'
        gain: '1'
        max_gain: '65536'
        maxoutbuf: '0'
        minoutbuf: '0'
        reference: '1'
        type: complex
    states:
        coordinate: [80, 790]
        rotation: 0
        state: enabled
-   name: bpsk
    id: variable_constellation
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        const_points: '[-1, 1]'
        dims: '1'
        normalization: digital.constellation.AMPLITUDE_NORMALIZATION
        npwr: '1'
        precision: '8'
        rot_sym: '2'
        soft_dec_lut: None
        sym_map: '[0, 1]'
        type: bpsk
    states:
        coordinate: [630, 230]
        rotation: 0
        state: enabled
-   name: bpsk_mod
    id: digital_constellation_modulator
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        constellation: bpsk
        differential: 'False'
        excess_bw: '0.35'
        log: 'False'
        maxoutbuf: '0'
        minoutbuf: '0'
        samples_per_symbol: sps
        truncate: 'False'
        verbose: 'False'
    states:
        coordinate: [380, 510]
        rotation: 0
        state: enabled
-   name: channel
    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: '[1.0]'
    states:
        coordinate: [760, 520]
        rotation: 0
        state: enabled
-   name: clock_sync
    id: digital_pfb_clock_sync_xxx
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        filter_size: nfilts
        init_phase: '8'
        loop_bw: '0.0628'
        max_dev: '1.5'
        maxoutbuf: '0'
        minoutbuf: '0'
        osps: '1'
        sps: sps
        taps: rrc_taps
        type: ccf
    states:
        coordinate: [460, 770]
        rotation: 0
        state: enabled
-   name: const_rx
    id: qtgui_const_sink_x
    parameters:
        affinity: ''
        alias: ''
        alpha1: '1'
        alpha10: '1'
        alpha2: '1'
        alpha3: '1'
        alpha4: '1'
        alpha5: '1'
        alpha6: '1'
        alpha7: '1'
        alpha8: '1'
        alpha9: '1'
        autoscale: 'False'
        axislabels: 'True'
        color1: '"blue"'
        color10: '"dark blue"'
        color2: '"red"'
        color3: '"green"'
        color4: '"black"'
        color5: '"cyan"'
        color6: '"magenta"'
        color7: '"yellow"'
        color8: '"dark red"'
        color9: '"dark green"'
        comment: ''
        grid: 'True'
        label1: ''
        label10: ''
        label2: ''
        label3: ''
        label4: ''
        label5: ''
        label6: ''
        label7: ''
        label8: ''
        label9: ''
        legend: 'True'
        marker1: '0'
        marker10: '-1'
        marker2: '-1'
        marker3: '-1'
        marker4: '-1'
        marker5: '-1'
        marker6: '-1'
        marker7: '-1'
        marker8: '-1'
        marker9: '-1'
        name: '"1. Received (offset + noise)"'
        nconnections: '1'
        size: '1024'
        style1: '0'
        style10: '1'
        style2: '1'
        style3: '1'
        style4: '1'
        style5: '1'
        style6: '1'
        style7: '1'
        style8: '1'
        style9: '1'
        tr_chan: '0'
        tr_level: '0'
        tr_mode: qtgui.TRIG_MODE_FREE
        tr_slope: qtgui.TRIG_SLOPE_POS
        tr_tag: '""'
        update_time: '0.1'
        width1: '1'
        width10: '1'
        width2: '1'
        width3: '1'
        width4: '1'
        width5: '1'
        width6: '1'
        width7: '1'
        width8: '1'
        width9: '1'
        xmax: '2'
        xmin: '-2'
        ymax: '2'
        ymin: '-2'
    states:
        coordinate: [80, 950]
        rotation: 0
        state: enabled
-   name: const_synced
    id: qtgui_const_sink_x
    parameters:
        affinity: ''
        alias: ''
        alpha1: '1'
        alpha10: '1'
        alpha2: '1'
        alpha3: '1'
        alpha4: '1'
        alpha5: '1'
        alpha6: '1'
        alpha7: '1'
        alpha8: '1'
        alpha9: '1'
        autoscale: 'False'
        axislabels: 'True'
        color1: '"blue"'
        color10: '"dark blue"'
        color2: '"red"'
        color3: '"green"'
        color4: '"black"'
        color5: '"cyan"'
        color6: '"magenta"'
        color7: '"yellow"'
        color8: '"dark red"'
        color9: '"dark green"'
        comment: ''
        grid: 'True'
        label1: ''
        label10: ''
        label2: ''
        label3: ''
        label4: ''
        label5: ''
        label6: ''
        label7: ''
        label8: ''
        label9: ''
        legend: 'True'
        marker1: '0'
        marker10: '-1'
        marker2: '-1'
        marker3: '-1'
        marker4: '-1'
        marker5: '-1'
        marker6: '-1'
        marker7: '-1'
        marker8: '-1'
        marker9: '-1'
        name: '"3. After Costas loop"'
        nconnections: '1'
        size: '1024'
        style1: '0'
        style10: '1'
        style2: '1'
        style3: '1'
        style4: '1'
        style5: '1'
        style6: '1'
        style7: '1'
        style8: '1'
        style9: '1'
        tr_chan: '0'
        tr_level: '0'
        tr_mode: qtgui.TRIG_MODE_FREE
        tr_slope: qtgui.TRIG_SLOPE_POS
        tr_tag: '""'
        update_time: '0.1'
        width1: '1'
        width10: '1'
        width2: '1'
        width3: '1'
        width4: '1'
        width5: '1'
        width6: '1'
        width7: '1'
        width8: '1'
        width9: '1'
        xmax: '2'
        xmin: '-2'
        ymax: '2'
        ymin: '-2'
    states:
        coordinate: [1310, 730]
        rotation: 0
        state: enabled
-   name: const_timed
    id: qtgui_const_sink_x
    parameters:
        affinity: ''
        alias: ''
        alpha1: '1'
        alpha10: '1'
        alpha2: '1'
        alpha3: '1'
        alpha4: '1'
        alpha5: '1'
        alpha6: '1'
        alpha7: '1'
        alpha8: '1'
        alpha9: '1'
        autoscale: 'False'
        axislabels: 'True'
        color1: '"blue"'
        color10: '"dark blue"'
        color2: '"red"'
        color3: '"green"'
        color4: '"black"'
        color5: '"cyan"'
        color6: '"magenta"'
        color7: '"yellow"'
        color8: '"dark red"'
        color9: '"dark green"'
        comment: ''
        grid: 'True'
        label1: ''
        label10: ''
        label2: ''
        label3: ''
        label4: ''
        label5: ''
        label6: ''
        label7: ''
        label8: ''
        label9: ''
        legend: 'True'
        marker1: '0'
        marker10: '-1'
        marker2: '-1'
        marker3: '-1'
        marker4: '-1'
        marker5: '-1'
        marker6: '-1'
        marker7: '-1'
        marker8: '-1'
        marker9: '-1'
        name: '"2. After clock recovery"'
        nconnections: '1'
        size: '1024'
        style1: '0'
        style10: '1'
        style2: '1'
        style3: '1'
        style4: '1'
        style5: '1'
        style6: '1'
        style7: '1'
        style8: '1'
        style9: '1'
        tr_chan: '0'
        tr_level: '0'
        tr_mode: qtgui.TRIG_MODE_FREE
        tr_slope: qtgui.TRIG_SLOPE_POS
        tr_tag: '""'
        update_time: '0.1'
        width1: '1'
        width10: '1'
        width2: '1'
        width3: '1'
        width4: '1'
        width5: '1'
        width6: '1'
        width7: '1'
        width8: '1'
        width9: '1'
        xmax: '2'
        xmin: '-2'
        ymax: '2'
        ymin: '-2'
    states:
        coordinate: [880, 930]
        rotation: 0
        state: enabled
-   name: costas
    id: digital_costas_loop_cc
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        maxoutbuf: '0'
        minoutbuf: '0'
        order: '2'
        use_snr: 'False'
        w: '0.0628'
    states:
        coordinate: [880, 750]
        rotation: 0
        state: enabled
-   name: note_rx
    id: note
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        note: "Receiver: the same steps the chapter writes by hand in Python\n\nTransmitter: random bits -> BPSK -> RRC pulse shaping\n\nChannel: noise + carrier frequency offset + sample clock offset\n\nTry adding more noise or more frequency offset"
    states:
        coordinate: [950, 230]
        rotation: 0
        state: enabled
-   name: random_bits
    id: analog_random_uniform_source_x
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        maximum: '256'
        maxoutbuf: '0'
        minimum: '0'
        minoutbuf: '0'
        seed: '0'
        type: byte
    states:
        coordinate: [10, 550]
        rotation: 0
        state: enabled
-   name: throttle
    id: blocks_throttle2
    parameters:
        affinity: ''
        alias: ''
        comment: ''
        ignoretag: 'True'
        limit: auto
        maximum: '0.1'
        maxoutbuf: '0'
        minoutbuf: '0'
        samples_per_second: samp_rate
        type: complex
        vlen: '1'
    states:
        coordinate: [1120, 540]
        rotation: 0
        state: enabled
-   name: time_symbols
    id: qtgui_time_sink_x
    parameters:
        affinity: ''
        alias: ''
        alpha1: '1'
        alpha10: '1'
        alpha2: '1'
        alpha3: '1'
        alpha4: '1'
        alpha5: '1'
        alpha6: '1'
        alpha7: '1'
        alpha8: '1'
        alpha9: '1'
        autoscale: 'False'
        axislabels: 'True'
        color1: blue
        color10: dark blue
        color2: red
        color3: green
        color4: black
        color5: cyan
        color6: magenta
        color7: yellow
        color8: dark red
        color9: dark green
        comment: ''
        ctrlpanel: 'False'
        grid: 'True'
        label1: Signal 1
        label10: Signal 10
        label2: Signal 2
        label3: Signal 3
        label4: Signal 4
        label5: Signal 5
        label6: Signal 6
        label7: Signal 7
        label8: Signal 8
        label9: Signal 9
        legend: 'True'
        marker1: '0'
        marker10: '-1'
        marker2: '-1'
        marker3: '-1'
        marker4: '-1'
        marker5: '-1'
        marker6: '-1'
        marker7: '-1'
        marker8: '-1'
        marker9: '-1'
        name: '"Recovered symbols"'
        nconnections: '1'
        samp_rate: samp_rate/sps
        size: '256'
        stemplot: 'False'
        style1: '0'
        style10: '1'
        style2: '1'
        style3: '1'
        style4: '1'
        style5: '1'
        style6: '1'
        style7: '1'
        style8: '1'
        style9: '1'
        tr_chan: '0'
        tr_delay: '0'
        tr_level: '0'
        tr_mode: qtgui.TRIG_MODE_FREE
        tr_slope: qtgui.TRIG_SLOPE_POS
        tr_tag: '""'
        type: complex
        update_time: '0.1'
        width1: '1'
        width10: '1'
        width2: '1'
        width3: '1'
        width4: '1'
        width5: '1'
        width6: '1'
        width7: '1'
        width8: '1'
        width9: '1'
        ylabel: Amplitude
        ymax: '2'
        ymin: '-2'
        yunit: '""'
    states:
        coordinate: [1310, 870]
        rotation: 0
        state: enabled
-   name: wasm_gui_layout_0
    id: wasm_gui_layout
    parameters:
        affinity: ''
        alias: ''
        columns: '12'
        comment: ''
        layout: '{"const_rx":[0,2,4,3],"const_synced":[8,2,4,3],"const_timed":[4,2,4,3],"freq_offset":[0,0,5,1],"noise_volt":[0,1,12,1],"time_offset":[7,0,5,1],"time_symbols":[0,5,12,3]}'
        row_height: '60'
    states:
        coordinate: [320, 10]
        rotation: 0
        state: enabled
connections:
- [agc, '0', clock_sync, '0']
- [bpsk_mod, '0', channel, '0']
- [channel, '0', throttle, '0']
- [clock_sync, '0', const_timed, '0']
- [clock_sync, '0', costas, '0']
- [costas, '0', const_synced, '0']
- [costas, '0', time_symbols, '0']
- [random_bits, '0', bpsk_mod, '0']
- [throttle, '0', agc, '0']
- [throttle, '0', const_rx, '0']
metadata:
    file_format: 1
    grc_version: 3.11.0.0