Software Defined Radio — как это работает? Часть 10
Привет, Хабр.
В «юбилейной» части цикла про SDR хочется рассказать об одном из протоколов, благодаря которому многие радиолюбители «невольно» приобщились к миру цифровых широкополосных сигналов. Этот стандарт также являлся первой (и насколько известно, единственной) попыткой передачи цифрового звука на коротких волнах.
Как многие наверное уже догадались, речь пойдет о стандарте DRM — Digital Radio Mondiale (не путать с другим DRM, Digital Rights Management).
Ну и т.к. мы будем говорить об SDR, то посмотрим не только как принимать DRM, но и как его передавать. Продолжение под катом.
История
История стандарта DRM весьма непроста. Впервые он был представлен в 2003 м году, а тестовые передачи производились с 2007 г, и с переменным успехом продолжаются периодически и до сих пор.
В основу DRM было заложено две основные идеи.
- Передача звука на коротких волнах с «цифровым качеством», без шумов и замираний, с битрейтом от 6 до 34КБит/с. Впрочем, «цифровое качество» тут можно написать лишь в кавычках, т.к. при битрейте в 12КБит звук получается весьма от… относительно низкого качества. К тому же, сигнал на КВ действительно подвержен и помехам, и замираниям, и чтобы «цифра» могла декодироваться, нужно весьма высокое соотношение сигнал/шум — такое, при котором обычный аналоговый сигнал будет звучать даже лучше. В общем, достаточно хоть раз попробовать в реале принять DRM, чтобы понять что идея «не взлетит». Но вещание все же периодически проводилось, в том числе и из России (см. КДПВ), а некоторые радиостанции иногда транслируют в DRM до сих пор.
- Передача звука в FM-диапазоне. Этот стандарт был назван DRM+. Здесь идея была в экономии частотного ресурса — благодаря цифровому сжатию, в полосе 100КГц можно передать сразу до 4х аудиопередач, что сулило неплохие плюсы в крупных городах типа Лондона, где свободных частот уже нет. С другой стороны, в Европе уже работал DAB, и еще один стандарт тут просто был не нужен. Если верить Википедии, тестовое вещание DRM+ осуществлялось в Шотландии в 2010 м году, о каких-то реальных случая вещания DRM+ пока слышать не доводилось.
Стандарт DRM по сути является несколько сюрреалистичным — годами работают радиостанции, транслируются радиопередачи… А приемников этого стандарта в продаже нет. Вообще. Никаких. Понятное дело, что раз стандарт цифровой, то обычным приемником можно услышать лишь шипение, да и декодировать QAM на слух пока еще никто не научился. Так что прием DRM являлся развлечением лишь для радиолюбителей. Вроде бы 1–2 приемника таки существовали, о чем есть даже пара видео в youtube (1 и 2), но ни на Ebay, ни на Amazon ничего в продаже сейчас нет.
Вторая проблема приема DRM состоит в том, что в городах КВ вещание де-факто мертво — помех от бытовой аппаратуры и блоков питания сейчас столько, что даже если включить КВ-радио, то будет слышен один треск и шум — декодирование в таких условиях работать не будет, в лучшем случае приемник сможет показать заставку станции, но без звука. Можно конечно поставить антенну на балкон или на крышу, тщательно ее настроить, и в принципе, принять и декодировать DRM из городской квартиры для радиолюбителей вполне реально. Обычные же люди этим 100% заморачиваться не будут, никто не полезет на крышу вешать антенну, чтобы принять аудиосигнал с битрейтом 12КБит/с.
В общем, приемников нет, аудитории нет. А вещание есть. Суслик из фильма отдыхает…
Кстати, прямо сейчас, на момент написания статьи (июль 2019) тестовое вещание DRM+ проводится в Петербурге, так что желающие побыть сусликом могут попробовать принять сигнал (только слушать его нечем, ни приемников, ни даже софтовых SDR-декодеров для DRM+ нет). Для приема можно воспользоваться RTL-SDR, и если повезет, то в FM-диапазоне можно будет увидеть цифровой сигнал шириной около 100КГц. Декодеров, впрочем, как уже говорилось, для него найти не удалось.
Прием DRM
Первые сообщения о приеме радиолюбителями DRM на сайте radioscanner датируются 2008 годом. Прием цифрового сигнала шириной 10КГц невозможен на обычный бытовой (и даже радиолюбительский) приемник, так что желающим тогда приходилось паять конвертор для вывода ПЧ приемника к звуковой карте. После появления SDR проблема решилась сама собой, там можно выбрать любую ширину полосы в пределах возможностей приемника (для первых SDR на базе звуковой карты это обычно было 48КГц, что более чем достаточно). Само декодирование осуществлялось с помощью весьма удобной и качественной программы Dream.
Как уже говорилось выше, DRM-станции работают довольно-таки регулярно, и найти их в эфире не так уж сложно. Например, на websdr такой сигнал очень легко различим на спектре — если в широковещательном диапазоне виден цифровой сигнал шириной 10КГц, то это он и есть. Пример скриншота станции, работающей на 15МГц, сделанного во время написания статьи:
Только декодировать его с помощью websdr не выйдет, ширина полосы у онлайн-приемника слишком мала. Впрочем послушать DRM может любой желающий, записанный с реального эфира файл можно скачать здесь. Для декодирования можно воспользоваться уже упомянутой программой Dream, рабочую версию со всеми необходимыми DLL можно взять на сайте radioscanner.
Если говорить о «железных» приемниках, то анонсировался, например, приемник Gospell GR-216, но «вживую» его нет ни на eBay, ни на Amazon.
Передача DRM
Теперь перейдем к не менее интересному — возможности передачи DRM-сигналов (и если не ошибаюсь, в рунете это описывается впервые). Сделать это можно с помощью GNU Radio и модуля gr-drm.
Технически, DRM использует QAM-модуляцию, и имеет довольно много настроек битрейта и занимаемой полосы. Также может передаваться не только звук (как моно, так и стерео), но и текст, логотип канала и другая служебная информация. Для КВ (режимы A-D) занимаемая полоса может варьироваться от 4.5 до 20КГц, впрочем, на практике, встречались только 10КГц сигналы. Для УКВ (режим E), как уже говорилось, используется полоса в 100КГц.
Таблица с www.drm.org/DRM_Handbook_2018.pdf:
Более подробное описание стандарта есть в PDF, кратко можно почитать на Signalwiki.
Вернемся к нашему графу соединений. Как можно видеть, DRM-кодер формирует сигнал из нескольких компонентов.
- Fast Access Channel (FAC). Содержит информацию о свойствах ODFM-сигнала и конфигурации SDC/MSC. Информация о канале передается каждые 0.4с, что позволяет приемнику довольно быстро начать прием сигнала станции. Параметры сигнала можно настроить в блоке DRM Configuration.
- Service Description Channel (SDC). Содержит описание канала передачи MSC.
- Main Service Channel (MSC). Содержит фреймы данных, для передачи может использоваться QAM16 или QAM64.
Ну и самое интересное то, что всё это без проблем можно запустить на обычном ПК. Gr-drm включен в пакет PothosSDR для Windows, но там он увы, не работает — сигнал есть, но декодирование происходит с ошибками. Под Ubuntu все запускается нормально.
В качестве выходного устройства в GNU Radio можно использовать WAV-файл или полноценный SDR-трансивер, например HackRF. Для тех, кто захочет поэкспериментировать самостоятельно, GRC-файл под спойлером.
Tue Apr 29 11:37:08 2014
options
author
Felix Wunsch
window_size
3000, 2000
category
Custom
comment
description
Generic DRM Transmitter. For the MSC, only SM and EEP is implemented.
_enabled
True
_coordinate
(1016, 16)
_rotation
0
generate_options
no_gui
hier_block_src_path
.:
id
drm_transmitter
max_nouts
0
qt_qss_theme
realtime_scheduling
run_command
{python} -u {filename}
run_options
run
run
True
thread_safe_setters
title
DRM Transmitter
variable
comment
_enabled
True
_coordinate
(240, 60)
_rotation
0
id
file_dest
value
"D:\\MyProjects\\GNURadio\\gr-drm-master\\apps\\sound_drm_out.wav"
variable
comment
_enabled
True
_coordinate
(56, 60)
_rotation
0
id
file_source
value
"D:\\MyProjects\\GNURadio\\gr-drm-master\\apps\\sound.wav"
variable_drm_config
audio_sample_rate
12000
comment
Before generating the flow graph, define the path
to a 24 kHz wav-file and change the parameters
of the UHD sink. Do not forget to set the correct
audio_sample_rate.
_enabled
1
_coordinate
(1208, 12)
_rotation
0
id
tp
long_interl
True
msc_mapping
2
msc_prot_level_2_16
1
msc_prot_level_2_64
0
RM
1
sdc_mapping
0
SO
3
station_label
"Radioscanner Test"
text_message
"DRM transmission with GNU Radio"
analog_sig_source_x
amp
1
alias
comment
affinity
_enabled
1
freq
7000
_coordinate
(576, 624)
_rotation
0
id
analog_sig_source_x_0
maxoutbuf
0
minoutbuf
0
offset
0
type
complex
samp_rate
drm.FS_SOUNDCARD
waveform
analog.GR_COS_WAVE
audio_sink
alias
comment
affinity
device_name
_enabled
0
_coordinate
(1184, 556)
_rotation
0
id
audio_sink_0
num_inputs
1
ok_to_block
True
samp_rate
48000
audio_source
alias
comment
affinity
device_name
_enabled
0
_coordinate
(56, 156)
_rotation
0
id
audio_source_0
maxoutbuf
0
minoutbuf
0
num_outputs
1
ok_to_block
True
samp_rate
44100
blocks_complex_to_real
alias
comment
affinity
_enabled
1
_coordinate
(1008, 640)
_rotation
0
id
blocks_complex_to_real_0
maxoutbuf
0
minoutbuf
0
vlen
1
blocks_multiply_const_vxx
alias
comment
const
32768
affinity
_enabled
1
_coordinate
(272, 236)
_rotation
0
id
blocks_multiply_const_vxx_0
type
float
maxoutbuf
0
minoutbuf
0
vlen
1
blocks_multiply_const_vxx
alias
comment
Prevent clipping
const
7e-3
affinity
_enabled
True
_coordinate
(688, 468)
_rotation
0
id
blocks_multiply_const_vxx_1
type
complex
maxoutbuf
0
minoutbuf
0
vlen
1
blocks_multiply_xx
alias
comment
affinity
_enabled
1
_coordinate
(864, 624)
_rotation
0
id
blocks_multiply_xx_0
type
complex
maxoutbuf
0
minoutbuf
0
num_inputs
2
vlen
1
blocks_wavfile_sink
bits_per_sample
16
alias
comment
affinity
_enabled
1
file
file_dest
_coordinate
(1200, 620)
_rotation
0
id
blocks_wavfile_sink_0
nchan
1
samp_rate
drm.FS_SOUNDCARD
blocks_wavfile_source
alias
comment
affinity
_enabled
1
file
file_source
_coordinate
(56, 228)
_rotation
0
id
blocks_wavfile_source_0
maxoutbuf
0
minoutbuf
0
nchan
1
repeat
False
cell_mapping_cc
alias
comment
Multiplex the three logical
channels and the pilot cells
and create transmission frames.
affinity
_enabled
True
_coordinate
(1184, 264)
_rotation
0
id
cell_mapping_cc_0
maxoutbuf
0
minoutbuf
0
tp
tp
digital_ofdm_cyclic_prefixer
alias
cp_len
tp.ofdm().nfft()*tp.ofdm().cp_ratio_enum()/tp.ofdm().cp_ratio_denom()
comment
affinity
_enabled
True
input_size
tp.ofdm().nfft()
_coordinate
(456, 448)
_rotation
0
id
digital_ofdm_cyclic_prefixer_1
tagname
maxoutbuf
0
minoutbuf
0
rolloff
0
drm_audio_encoder_sb
alias
comment
affinity
_enabled
True
_coordinate
(456, 240)
_rotation
0
id
drm_audio_encoder_sb_0
maxoutbuf
0
minoutbuf
0
len_out
tp.msc().L_MUX()
tp
tp
drm_generate_fac_b
alias
comment
affinity
_enabled
True
_coordinate
(56, 344)
_rotation
0
id
drm_generate_fac_b_0
maxoutbuf
0
minoutbuf
0
tp
tp
drm_generate_sdc_b
alias
comment
affinity
_enabled
True
_coordinate
(56, 296)
_rotation
0
id
drm_generate_sdc_b_0
maxoutbuf
0
minoutbuf
0
tp
tp
drm_interleaver_cc
alias
comment
Additional interleaving
affinity
_enabled
True
_coordinate
(952, 240)
_rotation
0
id
drm_interleaver_cc_0
depth
drm.INTL_DEPTH_DRM
interl_seq
tp.msc().cell_interl_seq()
long_interl
tp.cfg().long_interl()
maxoutbuf
0
minoutbuf
0
drm_scrambler_bb
alias
block_len
tp.msc().L_MUX()
comment
affinity
_enabled
True
_coordinate
(608, 240)
_rotation
0
id
drm_scrambler_bb_0
maxoutbuf
0
minoutbuf
0
drm_scrambler_bb
alias
block_len
tp.fac().L()
comment
affinity
_enabled
True
_coordinate
(608, 344)
_rotation
0
id
drm_scrambler_bb_0_0
maxoutbuf
0
minoutbuf
0
drm_scrambler_bb
alias
block_len
tp.sdc().L()
comment
affinity
_enabled
True
_coordinate
(608, 296)
_rotation
0
id
drm_scrambler_bb_0_1
maxoutbuf
0
minoutbuf
0
fft_vxx
alias
comment
affinity
_enabled
True
fft_size
tp.ofdm().nfft()
forward
False
_coordinate
(232, 440)
_rotation
0
id
fft_vxx_0
type
complex
maxoutbuf
0
minoutbuf
0
nthreads
1
shift
True
window
mlc_bc
alias
channel_type
"FAC"
comment
Apply channel coding
and interleaving
affinity
_enabled
True
_coordinate
(744, 340)
_rotation
0
id
mlc_bc_0
maxoutbuf
0
minoutbuf
0
tp
tp
mlc_bc
alias
channel_type
"MSC"
comment
affinity
_enabled
True
_coordinate
(744, 236)
_rotation
0
id
mlc_bc_0_0
maxoutbuf
0
minoutbuf
0
tp
tp
mlc_bc
alias
channel_type
"SDC"
comment
affinity
_enabled
True
_coordinate
(744, 292)
_rotation
0
id
mlc_bc_0_1
maxoutbuf
0
minoutbuf
0
tp
tp
rational_resampler_xxx
alias
comment
Ingoing sample rate is
assumed to be 48 kHz.
250 kHz is one of the
lowest achievable rates
of the USRP.
affinity
decim
drm.FS_SOUNDCARD / 1000
_enabled
0
fbw
0
_coordinate
(864, 448)
_rotation
0
id
rational_resampler_xxx_0
interp
250
maxoutbuf
0
minoutbuf
0
taps
type
ccc
rational_resampler_xxx
alias
comment
affinity
decim
441
_enabled
0
fbw
0
_coordinate
(248, 136)
_rotation
0
id
rational_resampler_xxx_0_0
interp
240
maxoutbuf
0
minoutbuf
0
taps
type
fff
virtual_source
comment
_enabled
True
_coordinate
(56, 468)
_rotation
0
id
sym_in
stream_id
symbols
virtual_sink
comment
_enabled
True
_coordinate
(1408, 292)
_rotation
0
id
sym_out
stream_id
symbols
uhd_usrp_sink
alias
ant0
TXA
bw0
0
center_freq0
5e6
norm_gain0
False
gain0
0
ant10
bw10
0
center_freq10
0
norm_gain10
False
gain10
0
ant11
bw11
0
center_freq11
0
norm_gain11
False
gain11
0
ant12
bw12
0
center_freq12
0
norm_gain12
False
gain12
0
ant13
bw13
0
center_freq13
0
norm_gain13
False
gain13
0
ant14
bw14
0
center_freq14
0
norm_gain14
False
gain14
0
ant15
bw15
0
center_freq15
0
norm_gain15
False
gain15
0
ant16
bw16
0
center_freq16
0
norm_gain16
False
gain16
0
ant17
bw17
0
center_freq17
0
norm_gain17
False
gain17
0
ant18
bw18
0
center_freq18
0
norm_gain18
False
gain18
0
ant19
bw19
0
center_freq19
0
norm_gain19
False
gain19
0
ant1
bw1
0
center_freq1
0
norm_gain1
False
gain1
0
ant20
bw20
0
center_freq20
0
norm_gain20
False
gain20
0
ant21
bw21
0
center_freq21
0
norm_gain21
False
gain21
0
ant22
bw22
0
center_freq22
0
norm_gain22
False
gain22
0
ant23
bw23
0
center_freq23
0
norm_gain23
False
gain23
0
ant24
bw24
0
center_freq24
0
norm_gain24
False
gain24
0
ant25
bw25
0
center_freq25
0
norm_gain25
False
gain25
0
ant26
bw26
0
center_freq26
0
norm_gain26
False
gain26
0
ant27
bw27
0
center_freq27
0
norm_gain27
False
gain27
0
ant28
bw28
0
center_freq28
0
norm_gain28
False
gain28
0
ant29
bw29
0
center_freq29
0
norm_gain29
False
gain29
0
ant2
bw2
0
center_freq2
0
norm_gain2
False
gain2
0
ant30
bw30
0
center_freq30
0
norm_gain30
False
gain30
0
ant31
bw31
0
center_freq31
0
norm_gain31
False
gain31
0
ant3
bw3
0
center_freq3
0
norm_gain3
False
gain3
0
ant4
bw4
0
center_freq4
0
norm_gain4
False
gain4
0
ant5
bw5
0
center_freq5
0
norm_gain5
False
gain5
0
ant6
bw6
0
center_freq6
0
norm_gain6
False
gain6
0
ant7
bw7
0
center_freq7
0
norm_gain7
False
gain7
0
ant8
bw8
0
center_freq8
0
norm_gain8
False
gain8
0
ant9
bw9
0
center_freq9
0
norm_gain9
False
gain9
0
clock_rate
0.0
comment
affinity
dev_addr
dev_args
""
_enabled
0
_coordinate
(1168, 424)
_rotation
0
id
uhd_usrp_sink_0
type
fc32
clock_source0
sd_spec0
time_source0
clock_source1
sd_spec1
time_source1
clock_source2
sd_spec2
time_source2
clock_source3
sd_spec3
time_source3
clock_source4
sd_spec4
time_source4
clock_source5
sd_spec5
time_source5
clock_source6
sd_spec6
time_source6
clock_source7
sd_spec7
time_source7
nchan
1
num_mboards
1
samp_rate
48000 * 250 / 48
hide_cmd_port
False
hide_lo_controls
True
stream_args
stream_chans
[]
sync
len_tag_name
otw
analog_sig_source_x_0
blocks_multiply_xx_0
0
1
audio_source_0
rational_resampler_xxx_0_0
0
0
blocks_complex_to_real_0
audio_sink_0
0
0
blocks_complex_to_real_0
blocks_wavfile_sink_0
0
0
blocks_multiply_const_vxx_0
drm_audio_encoder_sb_0
0
0
blocks_multiply_const_vxx_1
blocks_multiply_xx_0
0
0
blocks_multiply_const_vxx_1
rational_resampler_xxx_0
0
0
blocks_multiply_xx_0
blocks_complex_to_real_0
0
0
blocks_wavfile_source_0
blocks_multiply_const_vxx_0
0
0
cell_mapping_cc_0
sym_out
0
0
digital_ofdm_cyclic_prefixer_1
blocks_multiply_const_vxx_1
0
0
drm_audio_encoder_sb_0
drm_scrambler_bb_0
0
0
drm_generate_fac_b_0
drm_scrambler_bb_0_0
0
0
drm_generate_sdc_b_0
drm_scrambler_bb_0_1
0
0
drm_interleaver_cc_0
cell_mapping_cc_0
0
0
drm_scrambler_bb_0
mlc_bc_0_0
0
0
drm_scrambler_bb_0_0
mlc_bc_0
0
0
drm_scrambler_bb_0_1
mlc_bc_0_1
0
0
fft_vxx_0
digital_ofdm_cyclic_prefixer_1
0
0
mlc_bc_0
cell_mapping_cc_0
0
2
mlc_bc_0_0
drm_interleaver_cc_0
0
0
mlc_bc_0_1
cell_mapping_cc_0
0
1
rational_resampler_xxx_0
uhd_usrp_sink_0
0
0
rational_resampler_xxx_0_0
drm_audio_encoder_sb_0
0
0
sym_in
fft_vxx_0
0
0
Увы, USRP на КВ не передает, а HackRF у меня нет. Так что реальный эфирный тест сделать не удалось, впрочем могу подтвердить, что декодирование звука через Dream происходит без ошибок.
Заключение
Как ни странно, но несмотря на, казалось бы, 99% бесперспективность, стандарт DRM пока еще жив. Впрочем, вряд ли он будет успешным и уйдет дальше каких-либо локальных экспериментов — качество звука в DRM уже не отвечает современным нормам, да и приемников на рынке нет. С технической точки зрения, то, что казалось «прорывом» в 2003 м, сейчас уже мало актуально.
Но с другой стороны, стандарт DRM содержит немало интересных идей, его прием был (и есть) достаточно интересный для радиолюбителей опыт, приобщиться к которому, пока еще drm-станции есть в эфире, может любой желающий.
Всем удачных экспериментов.