Software Defined Radio — как это работает? Часть 10

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

В «юбилейной» части цикла про SDR хочется рассказать об одном из протоколов, благодаря которому многие радиолюбители «невольно» приобщились к миру цифровых широкополосных сигналов. Этот стандарт также являлся первой (и насколько известно, единственной) попыткой передачи цифрового звука на коротких волнах.

Software Defined Radio — как это работает? Часть 10

Как многие наверное уже догадались, речь пойдет о стандарте 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КГц. Более подробное описание стандарта есть в 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 все запускается нормально.

В качестве выхода можно использовать WAV-файл или полноценный SDR-трансивер, например HackRF. Для тех, кто захочет поэкспериментировать самостоятельно, GRC-файл под спойлером.

rdm_transmit.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 содержит немало интересных идей, это был (и есть) достаточно интересный опыт, приобщиться к которому (пока еще) может любой желающий.

 
Источник

Читайте также