如何从 Gnuradio 元文件接收器中提取原始 IQ 数据?

How to extract raw IQ data from Gnuradio meta file sink?

系统:debian 11,Gnuradio 3.8.10,python 3.8.10

我尝试使用meta file sink块来记录带有元数据的原始IQ数据。
grc文件如下:

options:
  parameters:
    author: ''
    category: '[GRC Hier Blocks]'
    cmake_opt: ''
    comment: ''
    copyright: ''
    description: ''
    gen_cmake: 'On'
    gen_linking: dynamic
    generate_options: qt_gui
    hier_block_src_path: '.:'
    id: meta_sink
    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: Not titled yet
    window_size: ''
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [8, 8]
    rotation: 0
    state: enabled

blocks:
- name: samp_rate
  id: variable_qtgui_range
  parameters:
    comment: ''
    gui_hint: ''
    label: ''
    min_len: '200'
    orient: Qt.Horizontal
    rangeType: float
    start: '0'
    step: '1'
    stop: 128e3
    value: 32e3
    widget: counter_slider
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [384, 60.0]
    rotation: 0
    state: true
- name: strobe_value
  id: variable_qtgui_chooser
  parameters:
    comment: ''
    gui_hint: ''
    label: ''
    label0: str=0
    label1: str=1
    label2: ''
    label3: ''
    label4: ''
    labels: '[]'
    num_opts: '2'
    option0: '0'
    option1: '1'
    option2: '2'
    option3: '3'
    option4: '4'
    options: '[0, 1, 2]'
    orient: Qt.QVBoxLayout
    type: int
    value: '0'
    widget: combo_box
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [616, 20.0]
    rotation: 0
    state: true
- name: analog_sig_source_x_0
  id: analog_sig_source_x
  parameters:
    affinity: ''
    alias: ''
    amp: '1'
    comment: ''
    freq: '100'
    maxoutbuf: '0'
    minoutbuf: '0'
    offset: '0'
    phase: '0'
    samp_rate: samp_rate
    type: complex
    waveform: analog.GR_SAW_WAVE
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [80, 140.0]
    rotation: 0
    state: enabled
- name: blocks_file_meta_sink_0
  id: blocks_file_meta_sink
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    detached: 'False'
    extra_dict: pmt.make_dict()
    file: /home/laozi/meta.bin
    max_seg_size: '1000000'
    rel_rate: '1'
    samp_rate: samp_rate
    type: complex
    unbuffered: 'False'
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [632, 220.0]
    rotation: 0
    state: enabled
- 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: [448, 244.0]
    rotation: 0
    state: enabled
- name: import_0
  id: import
  parameters:
    alias: ''
    comment: ''
    imports: import pmt
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [1224, 320.0]
    rotation: 0
    state: true

connections:
- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
- [blocks_throttle_0, '0', blocks_file_meta_sink_0, '0']

metadata:
  file_format: 1

然后,使用python脚本提取原始IQ数据进行进一步处理:

from gnuradio import gr,blocks
import pmt
import sys
from gnuradio.blocks import parse_file_metadata
import numpy as np

filename ='./meta.bin'
max_data_segments_to_read = 3
print_output = True
fh = open(filename, "rb")
for ii in range(max_data_segments_to_read):
    header_str = fh.read(parse_file_metadata.HEADER_LENGTH)
    header = pmt.deserialize_str(header_str)

    print(f"\n===Data segment {ii} ===")

    header_info = parse_file_metadata.parse_header(header, print_output)
    if(header_info["extra_len"] > 0):
        extra_str = fh.read(header_info["extra_len"])
        if(len(extra_str) != 0):
            extra = pmt.deserialize_str(extra_str)
            extra_info = parse_file_metadata.parse_extra_dict(extra, header_info, print_output)

    data=np.fromfile(file=fh, dtype=np.float32, count=int(header_info['nitems']), sep='', offset=0)
    print(f"{len(data)} data elements read")
fh.close()

但是我失败了如下:

===Data segment 0 ===
Version Number: 0
Sample Rate: 32000.00 sps
Seconds: 0.000000
Item size: 8
Data Type: float (5)
Complex? True
Header Length: 150 bytes
Extra Length:  1
Extra Header?  True
Size of Data: 8000000 bytes
              1000000.0 items
1000000 data elements read
Traceback (most recent call last):
  File "/home/laozi/a.py", line 13, in <module>
    header = pmt.deserialize_str(header_str)
  File "/usr/lib/python3/dist-packages/pmt/pmt_swig.py", line 2898, in deserialize_str
    return _deserialize_str_u8(tuple(x for x in pmt_str))
  File "/usr/lib/python3/dist-packages/pmt/pmt_swig.py", line 2871, in _deserialize_str_u8
    return _pmt_swig._deserialize_str_u8(py_str)
RuntimeError: pmt::deserialize: malformed input stream, tag value = : 91

问题出在哪里?

Item size: 8
Size of Data: 8000000 bytes
             1000000.0 items

一个可能的解释是您没有读取所有数据。元数据表明一项的大小为 8 个字节(两个 float32 数字 - 一个用于 I,一个用于 Q)并且有 1000000 个项目(8000000 字节)。

data=np.fromfile(file=fh, dtype=np.float32, count=int(header_info['nitems']), sep='', offset=0)

您已将 dtype 指定为 np.float32(即 4 个字节)并且 count 是项目数 (1000000),因此仅读取 4000000 个字节。

尝试阅读两倍 - count=2*int(header_info['nitems'])