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

Привет Хабр.

В одной из предыдущих статей про Software Defined Radio был задан вопрос, как декодировать RDS с помощью GNU Radio. Декодер RDS является не таким уж простым для создания с нуля, но к счастью для нас, в GNU Radio он уже встроен, так что несложно посмотреть как он работает, не написав ни одной строчки кода, достаточно лишь приемника RTL-SDR.

Как это работает, продолжение под катом.

Про GNU Radio и его установку я повторяться не буду, это уже описывалось ранее. Если совсем кратко, дистрибутив под Windows можно взять здесь. Перейдем собственно к RDS. Декодер для GNU Radio был сделан примерно лет 10 назад, но ту версию смотреть уже бесполезно, названия многих блоков поменялись, и приведенные там примеры уже не работают. Обновленный форк можно взять отсюда.

Собрать gr-rds из исходников под Windows, кстати, не получилось — в cmake выдаются ошибки на отсутствие Boost, хотя он поставлен. Непонятно кстати, почему за годы существования cmake и boost, cmake так и не научили находить пути в Windows — вроде найти папку на диске это совсем не rocket science (если кто знает решение, напишите в комментариях, хотя судя по Stack Overflow, проблема существует годами и всем пофиг). Но это нам как оказалось, и не нужно — декодер RDS уже добавлен в GNU Radio, так что из проекта на github нам нужны только примеры, которые лежат в папке apps.

Блок-схема, прилагаемая в примерах, является довольно-таки монструозной, к тому же, при ее открытии выдаются ошибки (блоки помечены красным).

В реале, впрочем, все проще — 2/3 схемы это стерео-плеер для FM, где из исходного сигнала извлекаются L+R и L-R каналы, обрабатываются и подаются на звуковую карту. Нам это сейчас неактуально, так что эти блоки можно удалить (тем более, что «из коробки» оно почему-то и не заработало, а разбираться было лень). Ошибки возникают из-за параметра Grid Position, который видимо, не поддерживается Windows-версией, но его можно без проблем удалить, на функциональность не влияет.

После удаления «всего лишнего» работающая схема RDS декодера выглядит так:

Посмотрим, что тут есть.

Исходный сигнал поступает из RTL-SDR Source, частота задается параметром freq, имеющим тип WX GUI Slider (да, в GNU Radio можно создать свой UI, и есть базовые контролы). Чтобы избежать пика на нулевой частоте в центре, используется параметр freq_offset, блок Frequency Xlating сдвигает частоту на это значение. Блок WBFM Receive, как понятно из названия, выполняет FM-демодуляцию, затем частота сдвигается еще раз, чтобы выделить сам RDS на 57КГц. Блок Root Cosined Filter выделяет узкую частоту, ну а MPSK-декодер с параметром 2 выполняет BPSK декодирование (сам RDS передается с помощью фазовой модуляции с двумя состояниями). В RDS используется дифференциальное кодирование, поэтому вызывается соответствующий дифференциальный декодер, ну и наконец готовый бинарный поток подается на блок RDS Decoder (его исходники можно посмотреть на github). После декодера не менее важная часть это RDS-парсер — типов пакетов в RDS довольно-таки много, и парсер делает всю работу по их расшифровке.

Собственно и все. Результаты работы декодера на КДПВ и скриншотах.

Если кому-то необходимо использовать программу в no-UI режиме, можно использовать блок FR Tap, более подробное описание здесь, я лично его не пробовал. Если же интересен более низкий побитовый уровень RDS, я его рассматривал ранее, для общего интереса тоже может быть полезно.

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

Исходный GRC-файл, работающий под Windows, под спойлером (частоту радиостанции только придется поменять).

rds_rx.grc

     Thu Aug 28 08:24:49 2014        options            author                        window_size       1600, 1600                 category       Custom                 comment                        description                        _enabled       True                 _coordinate       (14, 9)                 _rotation       0                 generate_options       wx_gui                 hier_block_src_path       .:                 id       rds_rx                 max_nouts       0                 qt_qss_theme                        realtime_scheduling                        run_command       {python} -u {filename}                 run_options       prompt                 run       True                 thread_safe_setters                        title       Stereo FM receiver and RDS Decoder                variable            comment                        _enabled       True                 _coordinate       (8, 156)                 _rotation       0                 id       audio_decim                 value       5                variable            comment                        _enabled       True                 _coordinate       (112, 156)                 _rotation       0                 id       audio_decim_rate                 value       baseband_rate/audio_decim                variable            comment                        _enabled       True                 _coordinate       (112, 92)                 _rotation       0                 id       baseband_rate                 value       samp_rate/bb_decim                variable            comment                        _enabled       True                 _coordinate       (240, 156)                 _rotation       0                 id       bb_decim                 value       4                variable_slider            comment                        converver       float_converter                 value       100.7e6                 _enabled       True                 _coordinate       (448, 4)                 _rotation       0                 grid_pos                        id       freq                 label       Freq                 max       107.9e6                 min       88.1e6                 notebook                        num_steps       99                 style       wx.SL_HORIZONTAL                variable            comment                        _enabled       True                 _coordinate       (448, 132)                 _rotation       0                 id       freq_offset                 value       250000                variable            comment                        _enabled       True                 _coordinate       (224, 92)                 _rotation       0                 id       freq_tune                 value       freq - freq_offset                variable_slider            comment                        converver       float_converter                 value       20                 _enabled       True                 _coordinate       (336, 4)                 _rotation       0                 grid_pos                        id       gain                 label       RF Gain                 max       49.6                 min       0                 notebook                        num_steps       124                 style       wx.SL_HORIZONTAL                variable            comment                        _enabled       True                 _coordinate       (8, 92)                 _rotation       0                 id       samp_rate                 value       1000000                variable            comment                        _enabled       True                 _coordinate       (336, 132)                 _rotation       0                 id       xlate_bandwidth                 value       100000                analog_wfm_rcv            audio_decimation       bb_decim                 alias                        comment                        affinity                        _enabled       True                 _coordinate       (576, 356)                 _rotation       0                 id       analog_wfm_rcv_0                 maxoutbuf       0                 minoutbuf       0                 quad_rate       samp_rate                blocks_complex_to_real            alias                        comment                        affinity                        _enabled       True                 _coordinate       (792, 632)                 _rotation       0                 id       blocks_complex_to_real_0                 maxoutbuf       0                 minoutbuf       0                 vlen       1                blocks_keep_one_in_n            alias                        comment                        affinity                        _enabled       True                 _coordinate       (280, 788)                 _rotation       0                 id       blocks_keep_one_in_n_0                 maxoutbuf       0                 minoutbuf       0                 n       2                 type       byte                 vlen       1                digital_binary_slicer_fb            alias                        comment                        affinity                        _enabled       True                 _coordinate       (112, 792)                 _rotation       0                 id       digital_binary_slicer_fb_0                 maxoutbuf       0                 minoutbuf       0                digital_diff_decoder_bb            alias                        comment                        affinity                        _enabled       True                 _coordinate       (424, 788)                 _rotation       0                 id       digital_diff_decoder_bb_0                 maxoutbuf       0                 minoutbuf       0                 modulus       2                digital_mpsk_receiver_cc            alias                        comment                        affinity                        _enabled       True                 _coordinate       (528, 488)                 _rotation       0                 gain_mu       0.05                 gain_omega       0.001                 id       digital_mpsk_receiver_cc_0                 w       1*cmath.pi/100.0                 M       2                 fmax       0.06                 maxoutbuf       0                 fmin       -0.06                 minoutbuf       0                 mu       0.5                 omega_relative_limit       0.005                 omega       samp_rate/bb_decim/audio_decim/ 2375.0                 theta       0                freq_xlating_fir_filter_xxx            alias                        center_freq       freq_offset                 comment                        affinity                        decim       1                 _enabled       True                 _coordinate       (279, 296)                 _rotation       0                 id       freq_xlating_fir_filter_xxx_0                 maxoutbuf       0                 minoutbuf       0                 samp_rate       samp_rate                 taps       firdes.low_pass(1, samp_rate, xlate_bandwidth, 100000)                 type       ccc                freq_xlating_fir_filter_xxx            alias                        center_freq       57e3                 comment                        affinity                        decim       audio_decim                 _enabled       True                 _coordinate       (72, 532)                 _rotation       0                 id       freq_xlating_fir_filter_xxx_1                 maxoutbuf       0                 minoutbuf       0                 samp_rate       baseband_rate                 taps       firdes.low_pass(2500.0,baseband_rate,2.4e3,2e3,firdes.WIN_HAMMING)                 type       fcc                gr_rds_decoder            alias                        comment                        affinity                        debug       False                 _enabled       True                 _coordinate       (632, 780)                 _rotation       0                 id       gr_rds_decoder_0                 log       False                 maxoutbuf       0                 minoutbuf       0                gr_rds_panel            alias                        comment                        affinity                        _enabled       True                 freq       freq                 _coordinate       (984, 792)                 _rotation       0                 grid_pos                        id       gr_rds_panel_0                 notebook                       gr_rds_parser            alias                        comment                        affinity                        debug       False                 _enabled       True                 _coordinate       (800, 772)                 _rotation       0                 id       gr_rds_parser_0                 log       True                 maxoutbuf       0                 minoutbuf       0                 pty_locale       0                 reset       0                import            alias                        comment                        _enabled       True                 _coordinate       (576, 4)                 _rotation       0                 id       import_0                 import       import math                notebook            alias                        comment                        _enabled       True                 _coordinate       (184, 6)                 _rotation       0                 grid_pos                        id       nb                 labels       ['BB', 'Demod', 'L+R', 'Pilot', 'DSBSC', 'RDS', 'L-R', 'RDS constellation','Waterfall']                 notebook                        style       wx.NB_TOP                root_raised_cosine_filter            alpha       1                 alias                        comment                        affinity                        decim       1                 _enabled       True                 type       fir_filter_ccf                 _coordinate       (304, 516)                 _rotation       0                 gain       1                 id       root_raised_cosine_filter_0                 interp       1                 maxoutbuf       0                 minoutbuf       0                 ntaps       100                 samp_rate       samp_rate/bb_decim/audio_decim                 sym_rate       2375                rtlsdr_source            alias                        ant0                        bb_gain0       20                 bw0       0                 dc_offset_mode0       0                 corr0       0                 freq0       freq_tune                 gain_mode0       False                 if_gain0       20                 iq_balance_mode0       0                 gain0       gain                 ant10                        bb_gain10       20                 bw10       0                 dc_offset_mode10       0                 corr10       0                 freq10       100e6                 gain_mode10       False                 if_gain10       20                 iq_balance_mode10       0                 gain10       10                 ant11                        bb_gain11       20                 bw11       0                 dc_offset_mode11       0                 corr11       0                 freq11       100e6                 gain_mode11       False                 if_gain11       20                 iq_balance_mode11       0                 gain11       10                 ant12                        bb_gain12       20                 bw12       0                 dc_offset_mode12       0                 corr12       0                 freq12       100e6                 gain_mode12       False                 if_gain12       20                 iq_balance_mode12       0                 gain12       10                 ant13                        bb_gain13       20                 bw13       0                 dc_offset_mode13       0                 corr13       0                 freq13       100e6                 gain_mode13       False                 if_gain13       20                 iq_balance_mode13       0                 gain13       10                 ant14                        bb_gain14       20                 bw14       0                 dc_offset_mode14       0                 corr14       0                 freq14       100e6                 gain_mode14       False                 if_gain14       20                 iq_balance_mode14       0                 gain14       10                 ant15                        bb_gain15       20                 bw15       0                 dc_offset_mode15       0                 corr15       0                 freq15       100e6                 gain_mode15       False                 if_gain15       20                 iq_balance_mode15       0                 gain15       10                 ant16                        bb_gain16       20                 bw16       0                 dc_offset_mode16       0                 corr16       0                 freq16       100e6                 gain_mode16       False                 if_gain16       20                 iq_balance_mode16       0                 gain16       10                 ant17                        bb_gain17       20                 bw17       0                 dc_offset_mode17       0                 corr17       0                 freq17       100e6                 gain_mode17       False                 if_gain17       20                 iq_balance_mode17       0                 gain17       10                 ant18                        bb_gain18       20                 bw18       0                 dc_offset_mode18       0                 corr18       0                 freq18       100e6                 gain_mode18       False                 if_gain18       20                 iq_balance_mode18       0                 gain18       10                 ant19                        bb_gain19       20                 bw19       0                 dc_offset_mode19       0                 corr19       0                 freq19       100e6                 gain_mode19       False                 if_gain19       20                 iq_balance_mode19       0                 gain19       10                 ant1                        bb_gain1       20                 bw1       0                 dc_offset_mode1       0                 corr1       0                 freq1       100e6                 gain_mode1       False                 if_gain1       20                 iq_balance_mode1       0                 gain1       10                 ant20                        bb_gain20       20                 bw20       0                 dc_offset_mode20       0                 corr20       0                 freq20       100e6                 gain_mode20       False                 if_gain20       20                 iq_balance_mode20       0                 gain20       10                 ant21                        bb_gain21       20                 bw21       0                 dc_offset_mode21       0                 corr21       0                 freq21       100e6                 gain_mode21       False                 if_gain21       20                 iq_balance_mode21       0                 gain21       10                 ant22                        bb_gain22       20                 bw22       0                 dc_offset_mode22       0                 corr22       0                 freq22       100e6                 gain_mode22       False                 if_gain22       20                 iq_balance_mode22       0                 gain22       10                 ant23                        bb_gain23       20                 bw23       0                 dc_offset_mode23       0                 corr23       0                 freq23       100e6                 gain_mode23       False                 if_gain23       20                 iq_balance_mode23       0                 gain23       10                 ant24                        bb_gain24       20                 bw24       0                 dc_offset_mode24       0                 corr24       0                 freq24       100e6                 gain_mode24       False                 if_gain24       20                 iq_balance_mode24       0                 gain24       10                 ant25                        bb_gain25       20                 bw25       0                 dc_offset_mode25       0                 corr25       0                 freq25       100e6                 gain_mode25       False                 if_gain25       20                 iq_balance_mode25       0                 gain25       10                 ant26                        bb_gain26       20                 bw26       0                 dc_offset_mode26       0                 corr26       0                 freq26       100e6                 gain_mode26       False                 if_gain26       20                 iq_balance_mode26       0                 gain26       10                 ant27                        bb_gain27       20                 bw27       0                 dc_offset_mode27       0                 corr27       0                 freq27       100e6                 gain_mode27       False                 if_gain27       20                 iq_balance_mode27       0                 gain27       10                 ant28                        bb_gain28       20                 bw28       0                 dc_offset_mode28       0                 corr28       0                 freq28       100e6                 gain_mode28       False                 if_gain28       20                 iq_balance_mode28       0                 gain28       10                 ant29                        bb_gain29       20                 bw29       0                 dc_offset_mode29       0                 corr29       0                 freq29       100e6                 gain_mode29       False                 if_gain29       20                 iq_balance_mode29       0                 gain29       10                 ant2                        bb_gain2       20                 bw2       0                 dc_offset_mode2       0                 corr2       0                 freq2       100e6                 gain_mode2       False                 if_gain2       20                 iq_balance_mode2       0                 gain2       10                 ant30                        bb_gain30       20                 bw30       0                 dc_offset_mode30       0                 corr30       0                 freq30       100e6                 gain_mode30       False                 if_gain30       20                 iq_balance_mode30       0                 gain30       10                 ant31                        bb_gain31       20                 bw31       0                 dc_offset_mode31       0                 corr31       0                 freq31       100e6                 gain_mode31       False                 if_gain31       20                 iq_balance_mode31       0                 gain31       10                 ant3                        bb_gain3       20                 bw3       0                 dc_offset_mode3       0                 corr3       0                 freq3       100e6                 gain_mode3       False                 if_gain3       20                 iq_balance_mode3       0                 gain3       10                 ant4                        bb_gain4       20                 bw4       0                 dc_offset_mode4       0                 corr4       0                 freq4       100e6                 gain_mode4       False                 if_gain4       20                 iq_balance_mode4       0                 gain4       10                 ant5                        bb_gain5       20                 bw5       0                 dc_offset_mode5       0                 corr5       0                 freq5       100e6                 gain_mode5       False                 if_gain5       20                 iq_balance_mode5       0                 gain5       10                 ant6                        bb_gain6       20                 bw6       0                 dc_offset_mode6       0                 corr6       0                 freq6       100e6                 gain_mode6       False                 if_gain6       20                 iq_balance_mode6       0                 gain6       10                 ant7                        bb_gain7       20                 bw7       0                 dc_offset_mode7       0                 corr7       0                 freq7       100e6                 gain_mode7       False                 if_gain7       20                 iq_balance_mode7       0                 gain7       10                 ant8                        bb_gain8       20                 bw8       0                 dc_offset_mode8       0                 corr8       0                 freq8       100e6                 gain_mode8       False                 if_gain8       20                 iq_balance_mode8       0                 gain8       10                 ant9                        bb_gain9       20                 bw9       0                 dc_offset_mode9       0                 corr9       0                 freq9       100e6                 gain_mode9       False                 if_gain9       20                 iq_balance_mode9       0                 gain9       10                 comment                        affinity                        args                        _enabled       1                 _coordinate       (24, 272)                 _rotation       0                 id       rtlsdr_source_0                 maxoutbuf       0                 clock_source0                        time_source0                        clock_source1                        time_source1                        clock_source2                        time_source2                        clock_source3                        time_source3                        clock_source4                        time_source4                        clock_source5                        time_source5                        clock_source6                        time_source6                        clock_source7                        time_source7                        minoutbuf       0                 nchan       1                 num_mboards       1                 type       fc32                 sample_rate       samp_rate                 sync                       wxgui_fftsink2            avg_alpha       0.8                 average       True                 baseband_freq       0                 alias                        comment                        affinity                        _enabled       True                 fft_size       1024                 freqvar       None                 _coordinate       (1056, 56)                 _rotation       0                 grid_pos                        id       wxgui_fftsink2_0                 notebook       nb, 0                 peak_hold       False                 ref_level       -30                 ref_scale       2.0                 fft_rate       15                 samp_rate       samp_rate                 title       Baseband                 type       complex                 win_size                        win       None                 y_divs       10                 y_per_div       10                wxgui_fftsink2            avg_alpha       0.8                 average       True                 baseband_freq       0                 alias                        comment                        affinity                        _enabled       True                 fft_size       1024                 freqvar       None                 _coordinate       (1056, 280)                 _rotation       0                 grid_pos                        id       wxgui_fftsink2_0_0                 notebook       nb, 1                 peak_hold       False                 ref_level       0                 ref_scale       2.0                 fft_rate       15                 samp_rate       baseband_rate                 title       FM Demod                 type       float                 win_size                        win       None                 y_divs       10                 y_per_div       10                wxgui_scopesink2            ac_couple       False                 alias                        comment                        affinity                        _enabled       True                 _coordinate       (1056, 500)                 _rotation       0                 grid_pos                        id       wxgui_scopesink2_1                 notebook       nb,7                 num_inputs       1                 samp_rate       2375                 t_scale       0                 title       Scope Plot                 trig_mode       wxgui.TRIG_MODE_AUTO                 type       complex                 v_offset       0                 v_scale       0.4                 win_size                        xy_mode       True                 y_axis_label       Counts                analog_wfm_rcv_0     freq_xlating_fir_filter_xxx_1     0     0           analog_wfm_rcv_0     wxgui_fftsink2_0_0     0     0           blocks_complex_to_real_0     digital_binary_slicer_fb_0     0     0           blocks_keep_one_in_n_0     digital_diff_decoder_bb_0     0     0           digital_binary_slicer_fb_0     blocks_keep_one_in_n_0     0     0           digital_diff_decoder_bb_0     gr_rds_decoder_0     0     0           digital_mpsk_receiver_cc_0     blocks_complex_to_real_0     0     0           digital_mpsk_receiver_cc_0     wxgui_scopesink2_1     0     0           freq_xlating_fir_filter_xxx_0     analog_wfm_rcv_0     0     0           freq_xlating_fir_filter_xxx_0     wxgui_fftsink2_0     0     0           freq_xlating_fir_filter_xxx_1     root_raised_cosine_filter_0     0     0           gr_rds_decoder_0     gr_rds_parser_0     out     in           gr_rds_parser_0     gr_rds_panel_0     out     in           root_raised_cosine_filter_0     digital_mpsk_receiver_cc_0     0     0           rtlsdr_source_0     freq_xlating_fir_filter_xxx_0     0     0     

 
Источник

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