Данный текст можно считать продолжением статьи "Разбираем звук Dial-up модема", в которой разбирался метод установки связи между модемами. Сегодня мы пойдем дальше, и посмотрим на практике как передаются данные, для чего создадим простую реализацию модема с помощью OFDM и GNU Radio.
Данные мы будем передавать по воздуху, в прямом смысле этого слова — для приема и передачи будет достаточно динамика и микрофона.
Для тех, кому интересно как это работает, продолжение под катом.
Итак, наша задача — сделать простейший модем, способный передать данные из точки А в точку Б. Существует много способов модуляции цифрового сигнала, мы воспользуемся OFDM — методом, широко используемым в современных системах связи. В OFDM цифровой сигнал с помощью преобразования Фурье преобразуется в несколько параллельных поднесущих, что обеспечивает высокую скорость и эффективность использования канала передачи. OFDM используется много где, от цифрового телевидения и радио, до LTE. Наш аудиоканал гораздо уже и скромнее по параметрам, так что и скорости будут поменьше, но принципиально суть, в общем, не меняется. Строго говоря, OFDM не предназначен для передачи данных по воздуху, хотя для небольших расстояний обычного микрофона и динамика будет вполне достаточно.
OFDM в GNU Radio
Минимальный граф для тестирования приема и передачи показан ниже:
Исходный код для GNU Radio 3.8:
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, числом несущих, частотой передачи и пр.
Всем спасибо за внимание, и удачных экспериментов.
Для желающих, исходник под спойлером.
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
siryoshka
Вася включай магнитофон!!!111 Сейчас усилитель включу, данные перешлю
aafin
Когда-то давно игры для компов передавали по FM радио. Так что…
DmitrySpb79 Автор
Радио я не застал (пишут что было в 83м www.kotaku.co.uk/2014/10/13/people-used-download-games-radio), а вот магнитофонные кассеты для Спектрума покупал, было дело :)
drWhy
Для спектрума и на местных телеканалах передавали игры в не прайм-тайм.