Делаем модем: передаем цифровые данные по воздуху с помощью OFDM и GNU Radio

от автора

Привет, Хабр.

Данный текст можно считать продолжением статьи "Разбираем звук Dial-up модема", в которой разбирался метод установки связи между модемами. Сегодня мы пойдем дальше, и посмотрим на практике как передаются данные, для чего создадим простую реализацию модема с помощью OFDM и GNU Radio.

Данные мы будем передавать по воздуху, в прямом смысле этого слова — для приема и передачи будет достаточно динамика и микрофона.

Для тех, кому интересно как это работает, продолжение под катом.

Итак, наша задача — сделать простейший модем, способный передать данные из точки А в точку Б. Существует много способов модуляции цифрового сигнала, мы воспользуемся OFDM — методом, широко используемым в современных системах связи. В OFDM цифровой сигнал с помощью преобразования Фурье преобразуется в несколько параллельных поднесущих, что обеспечивает высокую скорость и эффективность использования канала передачи. OFDM используется много где, от цифрового телевидения и радио, до LTE. Наш аудиоканал гораздо уже и скромнее по параметрам, так что и скорости будут поменьше, но принципиально суть, в общем, не меняется. Строго говоря, OFDM не предназначен для передачи данных по воздуху, хотя для небольших расстояний обычного микрофона и динамика будет вполне достаточно.

OFDM в GNU Radio

Минимальный граф для тестирования приема и передачи показан ниже:

Исходный код для GNU Radio 3.8:

ofdm1.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: ofdm_test_1     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: OFDM Test 1     window_size: ''   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [8, 8]     rotation: 0     state: enabled  blocks: - name: fft_len   id: variable   parameters:     comment: ''     value: '64'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [448, 12.0]     rotation: 0     state: enabled - name: packet_len   id: variable   parameters:     comment: ''     value: '12'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [336, 12.0]     rotation: 0     state: enabled - name: samp_rate   id: variable   parameters:     comment: ''     value: '2400'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [216, 12.0]     rotation: 0     state: enabled - name: blocks_file_source_0   id: blocks_file_source   parameters:     affinity: ''     alias: ''     begin_tag: pmt.PMT_NIL     comment: ''     file: D:\Temp\1\data2.txt     length: '0'     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     repeat: 'True'     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [32, 128.0]     rotation: 0     state: enabled - name: blocks_stream_to_tagged_stream_0   id: blocks_stream_to_tagged_stream   parameters:     affinity: ''     alias: ''     comment: ''     len_tag_key: '"key"'     maxoutbuf: '0'     minoutbuf: '0'     packet_len: packet_len     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [488, 156.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: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [272, 168.0]     rotation: 0     state: enabled - name: blocks_udp_sink_0   id: blocks_udp_sink   parameters:     affinity: ''     alias: ''     comment: ''     eof: 'True'     ipaddr: 127.0.0.1     port: '40868'     psize: '128'     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [424, 476.0]     rotation: 180     state: enabled - name: channels_channel_model_0   id: channels_channel_model   parameters:     affinity: ''     alias: ''     block_tags: 'True'     comment: ''     epsilon: '1.0'     freq_offset: 0 * 1.0/fft_len     maxoutbuf: '0'     minoutbuf: '0'     noise_voltage: '0.1'     seed: '0'     taps: 1.0 + 1.0j   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1112.0, 280]     rotation: 270     state: enabled - name: digital_ofdm_rx_0   id: digital_ofdm_rx   parameters:     affinity: ''     alias: ''     comment: ''     cp_len: fft_len//4     fft_len: fft_len     header_mod: '"BPSK"'     log: 'False'     maxoutbuf: '0'     minoutbuf: '0'     occupied_carriers: ((-4,-3,-2,-1,1,2,3,4),)     packet_len_key: '"key"'     payload_mod: '"QPSK"'     pilot_carriers: ((-6,-5,5,6),)     pilot_symbols: ((-1,1,-1,1),)     scramble_bits: 'False'     sync_word1: None     sync_word2: None   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [776, 428.0]     rotation: 180     state: enabled - name: digital_ofdm_tx_0   id: digital_ofdm_tx   parameters:     affinity: ''     alias: ''     comment: ''     cp_len: fft_len//4     fft_len: fft_len     header_mod: '"BPSK"'     log: 'False'     maxoutbuf: '0'     minoutbuf: '0'     occupied_carriers: ((-4,-3,-2,-1,1,2,3,4),)     packet_len_key: '"key"'     payload_mod: '"QPSK"'     pilot_carriers: ((-6,-5,5,6),)     pilot_symbols: ((-1,1,-1,1),)     rolloff: '0'     scramble_bits: 'False'     sync_word1: None     sync_word2: None   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [776, 80.0]     rotation: 0     state: enabled - name: qtgui_freq_sink_x_0   id: qtgui_freq_sink_x   parameters:     affinity: ''     alias: ''     alpha1: '1.0'     alpha10: '1.0'     alpha2: '1.0'     alpha3: '1.0'     alpha4: '1.0'     alpha5: '1.0'     alpha6: '1.0'     alpha7: '1.0'     alpha8: '1.0'     alpha9: '1.0'     autoscale: 'False'     average: '1.0'     axislabels: 'True'     bw: samp_rate     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'     fc: '0'     fftsize: '1024'     freqhalf: 'True'     grid: 'False'     gui_hint: ''     label: Relative Gain     label1: Rx Spectrum     label10: ''     label2: ''     label3: ''     label4: ''     label5: ''     label6: ''     label7: ''     label8: ''     label9: ''     legend: 'True'     maxoutbuf: '0'     minoutbuf: '0'     name: Rx Spectrum     nconnections: '1'     showports: 'True'     tr_chan: '0'     tr_level: '0.0'     tr_mode: qtgui.TRIG_MODE_FREE     tr_tag: '""'     type: complex     units: dB     update_time: '0.10'     width1: '1'     width10: '1'     width2: '1'     width3: '1'     width4: '1'     width5: '1'     width6: '1'     width7: '1'     width8: '1'     width9: '1'     wintype: firdes.WIN_BLACKMAN_hARRIS     ymax: '10'     ymin: '-140'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1232, 92.0]     rotation: 0     state: enabled  connections: - [blocks_file_source_0, '0', blocks_throttle_0, '0'] - [blocks_stream_to_tagged_stream_0, '0', digital_ofdm_tx_0, '0'] - [blocks_throttle_0, '0', blocks_stream_to_tagged_stream_0, '0'] - [channels_channel_model_0, '0', digital_ofdm_rx_0, '0'] - [digital_ofdm_rx_0, '0', blocks_udp_sink_0, '0'] - [digital_ofdm_tx_0, '0', channels_channel_model_0, '0'] - [digital_ofdm_tx_0, '0', qtgui_freq_sink_x_0, '0']  metadata:   file_format: 1 

В качестве источника данных используется обычный текстовый файл (в моем случае он содержит строку «Hello Habr!!»), затем данные разбиваются на блоки, которые подаются на OFDM Transmitter. OFDM это достаточно сложный вид модуляции, в настройках OFDM-кодера нужно указать достаточно много не совсем очевидных параметров.

Более детальный разбор значений можно найти здесь. Разумеется, параметры блока OFDM Receiver должны совпадать с параметрами передачи.

Блок Channel Model используется для симуляции канала связи, блок QT GUI Frequency Sink используется для визуализации спектра. Также стоит обратить внимание на невысокую частоту дискретизации (sample rate = 2400), это специально сделано для того, чтобы сигнал занимал небольшую полосу спектра, пригодную для передачи по аудиоканалу.

К сожалению, встроенного блока для отображения принимаемых данных в GNU Radio я не нашел, так что приходится использовать UDP. Блок UDP Sink используется для вывода данных, для их приема используется программа на языке Python:

import socket  UDP_IP = "127.0.0.1" UDP_PORT = 40868  sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((UDP_IP, UDP_PORT)) sock.settimeout(0.5)  while True:     try:         data, addr = sock.recvfrom(128)          print("Msg:", data, 'Hex:', ' '.join('{:02x}'.format(x) for x in data))     except socket.timeout:         pass 

Это позволяет выводить принимаемые данные в консоли, что достаточно удобно. Возможно есть более простой способ вывода в GNU Radio, если кто знает, напишите в комментариях.

Если все было сделано правильно, мы можем запустить GNU Radio и наш скрипт для приема, результат должен выглядеть примерно так:

Казалось бы, тему можно закрывать? Нет, все интересное только начинается.

Выходим в эфир

В вышеприведенном примере все довольно просто. Но есть одно «но» — GNU Radio работает с так называемым «комплексным сигналом», фактически представляющим собой пары чисел, сдвинутых по фазе на 90 градусов. Это удобно для компьютерной обработки, но мы не можем просто взять и передать в эфир комплексное число.

И тут есть два варианта. Владельцы SDR-трансмиттеров (HackRF, LimeSDR, USRP и пр) могут дальше не читать, а просто взять готовый блок для GNU Radio, в котором все делается «автоматом». Но т.к. мы собираемся передать сигнал с помощью звуковой карты, мы должны сделать преобразование самостоятельно, для чего воспользуемся блок-схемой, которая есть в любой статье по ЦОС:

Здесь OFDM это наш передатчик, Fc частота несущей, мы зададим её равной 4КГц, чтобы сигнал попадал в максимум чувствительности колонок и микрофона. Блок-схема графа для передачи также соответственно, усложняется:

Для удобства тестирования я использую WAV File Sink, чтобы сохраненный файл можно было записать и воспроизводить отдельно. Также мы можем открыть файл и посмотреть его спектр, можно убедиться что центральная частота действительно равна 4КГц:

Прием

И наконец, последний шаг: создадим блок-схему для приема сигнала. Тут фактически все то же самое, только в обратном порядке.

Мы домножаем исходный сигнал на сдвинутые по фазе опорные сигналы, затем с помощью LPF отсекаем высокочастотные компоненты. На выходе получается комплексный сигнал, который может использоваться для дальнейшей обработки.

Граф для приема в GNU Radio имеет следующий вид:

Стоит отметить блок Audio Source для приема данных из звуковой карты, блок QT GUI Frequency Sink используется для визуализации принимаемого сигнала.

Для тестирования, я записал WAV-файл на смартфон, при поднесении его к микрофону компьютера, на экране появляется декодированный текст:

Заключение

Как можно видеть, прием и передача сигналов с помощью GNU Radio достаточно интересен и нагляден. OFDM имеет достаточно большое число параметров, желающие могут поэспериментировать самостоятельно с размером блока FFT, числом несущих, частотой передачи и пр.

Всем спасибо за внимание, и удачных экспериментов.

Для желающих, исходник под спойлером.

odfm2.grc

options:   parameters:     author: ''     category: Custom     cmake_opt: ''     comment: ''     copyright: ''     description: Transmit a pre-defined signal (a complex sine) as OFDM packets.     gen_cmake: 'On'     gen_linking: dynamic     generate_options: qt_gui     hier_block_src_path: '.:'     id: ofdm_test_2     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: OFDM Test 2     window_size: 1280, 1024   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [8, 12.0]     rotation: 0     state: enabled  blocks: - name: audio_samp_rate   id: variable   parameters:     comment: ''     value: '24000'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [648, 20.0]     rotation: 0     state: true - name: carrier_freq   id: variable   parameters:     comment: ''     value: '4000'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [792, 20.0]     rotation: 0     state: true - name: fft_len   id: variable   parameters:     comment: ''     value: '64'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [448, 20.0]     rotation: 0     state: enabled - name: len_tag_key   id: variable   parameters:     comment: ''     value: '"packet_len"'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [320, 20.0]     rotation: 0     state: enabled - name: packet_len   id: variable   parameters:     comment: ''     value: '12'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [216, 20.0]     rotation: 0     state: enabled - name: samp_rate   id: variable   parameters:     comment: ''     value: '2400'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [536, 20.0]     rotation: 0     state: enabled - name: analog_sig_source_x_0   id: analog_sig_source_x   parameters:     affinity: ''     alias: ''     amp: '1'     comment: ''     freq: carrier_freq     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     phase: '0'     samp_rate: audio_samp_rate     type: float     waveform: analog.GR_COS_WAVE   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1080, 88.0]     rotation: 0     state: true - name: analog_sig_source_x_0_0   id: analog_sig_source_x   parameters:     affinity: ''     alias: ''     amp: '1'     comment: ''     freq: carrier_freq     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     phase: '0'     samp_rate: audio_samp_rate     type: float     waveform: analog.GR_SIN_WAVE   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1080, 344.0]     rotation: 0     state: true - name: analog_sig_source_x_0_0_0   id: analog_sig_source_x   parameters:     affinity: ''     alias: ''     amp: '1'     comment: ''     freq: carrier_freq     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     phase: '0'     samp_rate: audio_samp_rate     type: float     waveform: analog.GR_SIN_WAVE   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1376, 824.0]     rotation: 180     state: true - name: analog_sig_source_x_0_1   id: analog_sig_source_x   parameters:     affinity: ''     alias: ''     amp: '1'     comment: ''     freq: carrier_freq     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     phase: '0'     samp_rate: audio_samp_rate     type: float     waveform: analog.GR_COS_WAVE   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1376, 672.0]     rotation: 180     state: true - name: audio_sink_0   id: audio_sink   parameters:     affinity: ''     alias: ''     comment: ''     device_name: ''     num_inputs: '1'     ok_to_block: 'True'     samp_rate: audio_samp_rate   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1608, 224.0]     rotation: 0     state: disabled - name: audio_source_0   id: audio_source   parameters:     affinity: ''     alias: ''     comment: ''     device_name: ''     maxoutbuf: '0'     minoutbuf: '0'     num_outputs: '1'     ok_to_block: 'True'     samp_rate: audio_samp_rate   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1376, 584.0]     rotation: 180     state: enabled - name: blocks_add_xx_0   id: blocks_add_xx   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     num_inputs: '2'     type: float     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1480, 264.0]     rotation: 0     state: true - name: blocks_complex_to_float_0   id: blocks_complex_to_float   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1128, 256.0]     rotation: 0     state: true - name: blocks_file_source_0   id: blocks_file_source   parameters:     affinity: ''     alias: ''     begin_tag: pmt.PMT_NIL     comment: ''     file: D:\Temp\1\data2.txt     length: '0'     maxoutbuf: '0'     minoutbuf: '0'     offset: '0'     repeat: 'True'     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [32, 224.0]     rotation: 0     state: enabled - name: blocks_float_to_complex_0   id: blocks_float_to_complex   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [744, 768.0]     rotation: 180     state: true - name: blocks_multiply_xx_0   id: blocks_multiply_xx   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     num_inputs: '2'     type: float     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1336, 176.0]     rotation: 0     state: true - name: blocks_multiply_xx_0_0   id: blocks_multiply_xx   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     num_inputs: '2'     type: float     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1336, 344.0]     rotation: 0     state: enabled - name: blocks_multiply_xx_0_1   id: blocks_multiply_xx   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     num_inputs: '2'     type: float     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1168, 696.0]     rotation: 180     state: true - name: blocks_multiply_xx_0_1_0   id: blocks_multiply_xx   parameters:     affinity: ''     alias: ''     comment: ''     maxoutbuf: '0'     minoutbuf: '0'     num_inputs: '2'     type: float     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1176, 864.0]     rotation: 180     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: [1608, 168.0]     rotation: 0     state: true - name: blocks_stream_to_tagged_stream_0   id: blocks_stream_to_tagged_stream   parameters:     affinity: ''     alias: ''     comment: ''     len_tag_key: '"key"'     maxoutbuf: '0'     minoutbuf: '0'     packet_len: packet_len     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [424, 252.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: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [248, 264.0]     rotation: 0     state: enabled - name: blocks_udp_sink_0   id: blocks_udp_sink   parameters:     affinity: ''     alias: ''     comment: ''     eof: 'True'     ipaddr: 127.0.0.1     port: '40868'     psize: '128'     type: byte     vlen: '1'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [104, 748.0]     rotation: 180     state: enabled - name: blocks_wavfile_sink_0   id: blocks_wavfile_sink   parameters:     affinity: ''     alias: ''     bits_per_sample: '16'     comment: ''     file: D:\Temp\1\ofdm.wav     nchan: '1'     samp_rate: audio_samp_rate   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [1608, 308.0]     rotation: 0     state: disabled - name: digital_ofdm_rx_0   id: digital_ofdm_rx   parameters:     affinity: ''     alias: ''     comment: ''     cp_len: fft_len//4     fft_len: fft_len     header_mod: '"BPSK"'     log: 'False'     maxoutbuf: '0'     minoutbuf: '0'     occupied_carriers: ((-4,-3,-2,-1,1,2,3,4),)     packet_len_key: '"key"'     payload_mod: '"QPSK"'     pilot_carriers: ((-6,-5,5,6),)     pilot_symbols: ((-1,1,-1,1),)     scramble_bits: 'False'     sync_word1: None     sync_word2: None   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [440, 700.0]     rotation: 180     state: enabled - name: digital_ofdm_tx_0   id: digital_ofdm_tx   parameters:     affinity: ''     alias: ''     comment: ''     cp_len: fft_len//4     fft_len: fft_len     header_mod: '"BPSK"'     log: 'False'     maxoutbuf: '0'     minoutbuf: '0'     occupied_carriers: ((-4,-3,-2,-1,1,2,3,4),)     packet_len_key: '"key"'     payload_mod: '"QPSK"'     pilot_carriers: ((-6,-5,5,6),)     pilot_symbols: ((-1,1,-1,1),)     rolloff: '0'     scramble_bits: 'False'     sync_word1: None     sync_word2: None   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [664, 176.0]     rotation: 0     state: enabled - name: low_pass_filter_0   id: low_pass_filter   parameters:     affinity: ''     alias: ''     beta: '6.76'     comment: ''     cutoff_freq: carrier_freq     decim: audio_samp_rate//samp_rate     gain: '1'     interp: '1'     maxoutbuf: '0'     minoutbuf: '0'     samp_rate: audio_samp_rate     type: fir_filter_fff     width: '1000'     win: firdes.WIN_HAMMING   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [960, 648.0]     rotation: 180     state: true - name: low_pass_filter_0_0   id: low_pass_filter   parameters:     affinity: ''     alias: ''     beta: '6.76'     comment: ''     cutoff_freq: carrier_freq     decim: audio_samp_rate//samp_rate     gain: '1'     interp: '1'     maxoutbuf: '0'     minoutbuf: '0'     samp_rate: audio_samp_rate     type: fir_filter_fff     width: '1000'     win: firdes.WIN_HAMMING   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [960, 816.0]     rotation: 180     state: true - name: qtgui_freq_sink_x_0   id: qtgui_freq_sink_x   parameters:     affinity: ''     alias: ''     alpha1: '1.0'     alpha10: '1.0'     alpha2: '1.0'     alpha3: '1.0'     alpha4: '1.0'     alpha5: '1.0'     alpha6: '1.0'     alpha7: '1.0'     alpha8: '1.0'     alpha9: '1.0'     autoscale: 'False'     average: '1.0'     axislabels: 'True'     bw: samp_rate     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'     fc: '0'     fftsize: '1024'     freqhalf: 'True'     grid: 'False'     gui_hint: ''     label: Relative Gain     label1: Rx Spectrum     label10: ''     label2: ''     label3: ''     label4: ''     label5: ''     label6: ''     label7: ''     label8: ''     label9: ''     legend: 'True'     maxoutbuf: '0'     minoutbuf: '0'     name: Rx Spectrum     nconnections: '1'     showports: 'True'     tr_chan: '0'     tr_level: '0.0'     tr_mode: qtgui.TRIG_MODE_FREE     tr_tag: '""'     type: complex     units: dB     update_time: '0.10'     width1: '1'     width10: '1'     width2: '1'     width3: '1'     width4: '1'     width5: '1'     width6: '1'     width7: '1'     width8: '1'     width9: '1'     wintype: firdes.WIN_BLACKMAN_hARRIS     ymax: '10'     ymin: '-140'   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [728, 612.0]     rotation: 0     state: enabled - name: rational_resampler_xxx_0   id: rational_resampler_xxx   parameters:     affinity: ''     alias: ''     comment: ''     decim: '1'     fbw: '0'     interp: audio_samp_rate//samp_rate     maxoutbuf: '0'     minoutbuf: '0'     taps: ''     type: ccf   states:     bus_sink: false     bus_source: false     bus_structure: null     coordinate: [912, 236.0]     rotation: 0     state: true  connections: - [analog_sig_source_x_0, '0', blocks_multiply_xx_0, '0'] - [analog_sig_source_x_0_0, '0', blocks_multiply_xx_0_0, '1'] - [analog_sig_source_x_0_0_0, '0', blocks_multiply_xx_0_1_0, '1'] - [analog_sig_source_x_0_1, '0', blocks_multiply_xx_0_1, '1'] - [audio_source_0, '0', blocks_multiply_xx_0_1, '0'] - [audio_source_0, '0', blocks_multiply_xx_0_1_0, '0'] - [blocks_add_xx_0, '0', audio_sink_0, '0'] - [blocks_add_xx_0, '0', blocks_null_sink_0, '0'] - [blocks_add_xx_0, '0', blocks_wavfile_sink_0, '0'] - [blocks_complex_to_float_0, '0', blocks_multiply_xx_0, '1'] - [blocks_complex_to_float_0, '1', blocks_multiply_xx_0_0, '0'] - [blocks_file_source_0, '0', blocks_throttle_0, '0'] - [blocks_float_to_complex_0, '0', digital_ofdm_rx_0, '0'] - [blocks_float_to_complex_0, '0', qtgui_freq_sink_x_0, '0'] - [blocks_multiply_xx_0, '0', blocks_add_xx_0, '0'] - [blocks_multiply_xx_0_0, '0', blocks_add_xx_0, '1'] - [blocks_multiply_xx_0_1, '0', low_pass_filter_0, '0'] - [blocks_multiply_xx_0_1_0, '0', low_pass_filter_0_0, '0'] - [blocks_stream_to_tagged_stream_0, '0', digital_ofdm_tx_0, '0'] - [blocks_throttle_0, '0', blocks_stream_to_tagged_stream_0, '0'] - [digital_ofdm_rx_0, '0', blocks_udp_sink_0, '0'] - [digital_ofdm_tx_0, '0', rational_resampler_xxx_0, '0'] - [low_pass_filter_0, '0', blocks_float_to_complex_0, '0'] - [low_pass_filter_0_0, '0', blocks_float_to_complex_0, '1'] - [rational_resampler_xxx_0, '0', blocks_complex_to_float_0, '0']  metadata:   file_format: 1 

ссылка на оригинал статьи https://habr.com/ru/post/497638/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *