Программно-Конфигурируемое Радио – Как Это Работает? Часть 9

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

В предыдущая часть было рассмотрено декодирование сигналов RDS для FM-радиостанций, и идея следующей статьи возникла сама собой — нужно сделать свой FM-передатчик.

Будет два варианта — простой и более сложный, с RDS.

Программно-конфигурируемое радио – как это работает? Часть 9

Как и в предыдущих случаях, все это мы будем делать в GNU Radio, не написав ни единой строчки кода.

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

Итак, давайте начнем.

Конечно, для тестов нам понадобится SDR с возможностью передачи (HackRF, USRP, LimeSDR).



FM-передатчик

Схема простого передатчика сделана практически в два клика и, надеюсь, не представляет никаких сложностей в понимании.

В качестве источника я использую файл WAV, хотя при желании вы можете использовать другой источник, например вход звуковой карты.



Программно-конфигурируемое радио – как это работает? Часть 9

Собственно, в этой схеме есть два ключевых блока — WBFM-передатчик и Resampler, преобразующий частоту дискретизации потока.

Все частоты дискретизации должны совпадать друг с другом, иначе сэмплы будут пропущены, что будет слышно как щелчки.

Блок Multiply Const используется для регулировки входного уровня.

Также важно не запутаться; GNU Radio имеет два разных блока для FM — WBFM и NBFM. Нам нужен первый, Wide Band FM. Модуляция NFM используется в портативных радиостанциях.

В общем все просто, запускаем, работает. В схеме нет UI-блоков, поэтому использовать ее можно из командной строки (подробнее в 4-я часть ).

Кстати, если посмотреть на спектр, то видно, что передается простой моносигнал, без каких-либо каналов, пилот-тонов и т.п.



Программно-конфигурируемое радио – как это работает? Часть 9

Пришло время перейти к более сложному варианту.



Передатчик с RDS

Схема передатчика с RDS, конечно, будет сложнее.

Оригинал взят из примеров гр-рды с небольшими изменениями (оригинальная версия для Windows не работала, «правильная» версия находится внизу статьи), давайте посмотрим, из каких компонентов он состоит.

Программно-конфигурируемое радио – как это работает? Часть 9

(оригинал в полное разрешение ) Верхняя треть диаграммы — передача RDS. На входе имеется RDS-кодер, который на основе имеющихся данных (название станции, код страны и т. д.) формирует RDS-пакеты.

Затем битовый поток подвергается дифференциальное кодирование , идея которого заключается в удалении повторяющихся последовательностей вида 001000001. Затем сигнал обрабатывается и «несущая» модулируется частотой 57 КГц.

Центральная часть создает звук.

Здесь формируются каналы L+R и L-R. Ниже в качестве источника звука указан WAV-файл.

Наконец, блок «Добавить» объединяет все это, добавляя к сигналу пилот-тон с частотой 19 кГц и второй тон с частотой 38 кГц.

Весь этот суммарный сигнал поступает на частотный модулятор, все это передается в эфир с помощью SDR. Теоретически эта схема не на 100% завершена, например, нет блока предыскажения, не синхронизированы фазы тонов на 19, 38 и 57 КГц.

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

При запуске открывается окно; некоторые параметры можно изменить.



Программно-конфигурируемое радио – как это работает? Часть 9

Было желание протестировать RDS с реальным приёмником, но оказалось, что FM-радио — это уже атавизм, и у меня его дома нет. Его нет даже в смартфоне последней модели.

Поэтому в качестве приемника управления пришлось использовать RTL-SDR V3 и GQRX, в результате получился КДПВ.

Разумеется, перед тестированием необходимо выбрать свободную частоту, чтобы на ней не было станций и желательно не превышать разрешенную мощность.

Для тех, кто хочет получить максимальную дальность действия, можно купить дополнительный усилитель; антенну желательно сделать на нужную частоту так, чтобы был диполь хотя бы на 1/4 длины волны.



Заключение

Как видите, в принципе, ничего сверхсложного в передаче FM-радио нет; в GNU Radio все вполне реализуемо (хотя без примеров повторить это было бы сложно, учитывая, что система вообще не документирована).

Что ж, теперь, по крайней мере, у читателей есть рабочий пример.

Исходники блоков находятся под спойлером.

fm_tx.grc

   

<Эxml version='1.0' encoding='utf-8'?> <Эgrc format='1' created='3.7.11'?> <flow_graph> <timestamp>Tue Jun 18 20:27:26 2019</timestamp> <block> <key>options</key> <param> <key>author</key> <value></value> </param> <param> <key>window_size</key> <value></value> </param> <param> <key>category</key> <value>[GRC Hier Blocks]</value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>description</key> <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>_coordinate</key> <value>(16, 20)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>generate_options</key> <value>wx_gui</value> </param> <param> <key>hier_block_src_path</key> <value>.

:</value> </param> <param> <key>id</key> <value>top_block</value> </param> <param> <key>max_nouts</key> <value>0</value> </param> <param> <key>qt_qss_theme</key> <value></value> </param> <param> <key>realtime_scheduling</key> <value></value> </param> <param> <key>run_command</key> <value>{python} -u {filename}</value> </param> <param> <key>run_options</key> <value>prompt</value> </param> <param> <key>run</key> <value>True</value> </param> <param> <key>thread_safe_setters</key> <value></value> </param> <param> <key>title</key> <value></value> </param> </block> <block> <key>analog_wfm_tx</key> <param> <key>audio_rate</key> <value>80000</value> </param> <param> <key>alias</key> <value></value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>affinity</key> <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>_coordinate</key> <value>(592, 76)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>id</key> <value>analog_wfm_tx_0</value> </param> <param> <key>max_dev</key> <value>75e3</value> </param> <param> <key>maxoutbuf</key> <value>0</value> </param> <param> <key>minoutbuf</key> <value>0</value> </param> <param> <key>fh</key> <value>-1.0</value> </param> <param> <key>quad_rate</key> <value>320000</value> </param> <param> <key>tau</key> <value>75e-6</value> </param> </block> <block> <key>blocks_multiply_const_vxx</key> <param> <key>alias</key> <value></value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>const</key> <value>0.45</value> </param> <param> <key>affinity</key> <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>_coordinate</key> <value>(248, 108)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>id</key> <value>blocks_multiply_const_vxx_0</value> </param> <param> <key>type</key> <value>float</value> </param> <param> <key>maxoutbuf</key> <value>0</value> </param> <param> <key>minoutbuf</key> <value>0</value> </param> <param> <key>vlen</key> <value>1</value> </param> </block> <block> <key>blocks_wavfile_source</key> <param> <key>alias</key> <value></value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>affinity</key> <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>file</key> <value>D:\MyProjects\GNURadio\sound.wav</value> </param> <param> <key>_coordinate</key> <value>(24, 100)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>id</key> <value>blocks_wavfile_source_0</value> </param> <param> <key>maxoutbuf</key> <value>0</value> </param> <param> <key>minoutbuf</key> <value>0</value> </param> <param> <key>nchan</key> <value>1</value> </param> <param> <key>repeat</key> <value>True</value> </param> </block> <block> <key>rational_resampler_xxx</key> <param> <key>alias</key> <value></value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>affinity</key> <value></value> </param> <param> <key>decim</key> <value>3</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>fbw</key> <value>0</value> </param> <param> <key>_coordinate</key> <value>(408, 84)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>id</key> <value>rational_resampler_xxx_0</value> </param> <param> <key>interp</key> <value>5</value> </param> <param> <key>maxoutbuf</key> <value>0</value> </param> <param> <key>minoutbuf</key> <value>0</value> </param> <param> <key>taps</key> <value></value> </param> <param> <key>type</key> <value>fff</value> </param> </block> <block> <key>uhd_usrp_sink</key> <param> <key>alias</key> <value></value> </param> <param> <key>ant0</key> <value></value> </param> <param> <key>bw0</key> <value>0</value> </param> <param> <key>center_freq0</key> <value>95.6e6</value> </param> <param> <key>norm_gain0</key> <value>False</value> </param> <param> <key>gain0</key> <value>30</value> </param> <param> <key>ant10</key> <value></value> </param> <param> <key>bw10</key> <value>0</value> </param> <param> <key>center_freq10</key> <value>0</value> </param> <param> <key>norm_gain10</key> <value>False</value> </param> <param> <key>gain10</key> <value>0</value> </param> <param> <key>ant11</key> <value></value> </param> <param> <key>bw11</key> <value>0</value> </param> <param> <key>center_freq11</key> <value>0</value> </param> <param> <key>norm_gain11</key> <value>False</value> </param> <param> <key>gain11</key> <value>0</value> </param> <param> <key>ant12</key> <value></value> </param> <param> <key>bw12</key> <value>0</value> </param> <param> <key>center_freq12</key> <value>0</value> </param> <param> <key>norm_gain12</key> <value>False</value> </param> <param> <key>gain12</key> <value>0</value> </param> <param> <key>ant13</key> <value></value> </param> <param> <key>bw13</key> <value>0</value> </param> <param> <key>center_freq13</key> <value>0</value> </param> <param> <key>norm_gain13</key> <value>False</value> </param> <param> <key>gain13</key> <value>0</value> </param> <param> <key>ant14</key> <value></value> </param> <param> <key>bw14</key> <value>0</value> </param> <param> <key>center_freq14</key> <value>0</value> </param> <param> <key>norm_gain14</key> <value>False</value> </param> <param> <key>gain14</key> <value>0</value> </param> <param> <key>ant15</key> <value></value> </param> <param> <key>bw15</key> <value>0</value> </param> <param> <key>center_freq15</key> <value>0</value> </param> <param> <key>norm_gain15</key> <value>False</value> </param> <param> <key>gain15</key> <value>0</value> </param> <param> <key>ant16</key> <value></value> </param> <param> <key>bw16</key> <value>0</value> </param> <param> <key>center_freq16</key> <value>0</value> </param> <param> <key>norm_gain16</key> <value>False</value> </param> <param> <key>gain16</key> <value>0</value> </param> <param> <key>ant17</key> <value></value> </param> <param> <key>bw17</key> <value>0</value> </param> <param> <key>center_freq17</key> <value>0</value> </param> <param> <key>norm_gain17</key> <value>False</value> </param> <param> <key>gain17</key> <value>0</value> </param> <param> <key>ant18</key> <value></value> </param> <param> <key>bw18</key> <value>0</value> </param> <param> <key>center_freq18</key> <value>0</value> </param> <param> <key>norm_gain18</key> <value>False</value> </param> <param> <key>gain18</key> <value>0</value> </param> <param> <key>ant19</key> <value></value> </param> <param> <key>bw19</key> <value>0</value> </param> <param> <key>center_freq19</key> <value>0</value> </param> <param> <key>norm_gain19</key> <value>False</value> </param> <param> <key>gain19</key> <value>0</value> </param> <param> <key>ant1</key> <value></value> </param> <param> <key>bw1</key> <value>0</value> </param> <param> <key>center_freq1</key> <value>0</value> </param> <param> <key>norm_gain1</key> <value>False</value> </param> <param> <key>gain1</key> <value>0</value> </param> <param> <key>ant20</key> <value></value> </param> <param> <key>bw20</key> <value>0</value> </param> <param> <key>center_freq20</key> <value>0</value> </param> <param> <key>norm_gain20</key> <value>False</value> </param> <param> <key>gain20</key> <value>0</value> </param> <param> <key>ant21</key> <value></value> </param> <param> <key>bw21</key> <value>0</value> </param> <param> <key>center_freq21</key> <value>0</value> </param> <param> <key>norm_gain21</key> <value>False</value> </param> <param> <key>gain21</key> <value>0</value> </param> <param> <key>ant22</key> <value></value> </param> <param> <key>bw22</key> <value>0</value> </param> <param> <key>center_freq22</key> <value>0</value> </param> <param> <key>norm_gain22</key> <value>False</value> </param> <param> <key>gain22</key> <value>0</value> </param> <param> <key>ant23</key> <value></value> </param> <param> <key>bw23</key> <value>0</value> </param> <param> <key>center_freq23</key> <value>0</value> </param> <param> <key>norm_gain23</key> <value>False</value> </param> <param> <key>gain23</key> <value>0</value> </param> <param> <key>ant24</key> <value></value> </param> <param> <key>bw24</key> <value>0</value> </param> <param> <key>center_freq24</key> <value>0</value> </param> <param> <key>norm_gain24</key> <value>False</value> </param> <param> <key>gain24</key> <value>0</value> </param> <param> <key>ant25</key> <value></value> </param> <param> <key>bw25</key> <value>0</value> </param> <param> <key>center_freq25</key> <value>0</value> </param> <param> <key>norm_gain25</key> <value>False</value> </param> <param> <key>gain25</key> <value>0</value> </param> <param> <key>ant26</key> <value></value> </param> <param> <key>bw26</key> <value>0</value> </param> <param> <key>center_freq26</key> <value>0</value> </param> <param> <key>norm_gain26</key> <value>False</value> </param> <param> <key>gain26</key> <value>0</value> </param> <param> <key>ant27</key> <value></value> </param> <param> <key>bw27</key> <value>0</value> </param> <param> <key>center_freq27</key> <value>0</value> </param> <param> <key>norm_gain27</key> <value>False</value> </param> <param> <key>gain27</key> <value>0</value> </param> <param> <key>ant28</key> <value></value> </param> <param> <key>bw28</key> <value>0</value> </param> <param> <key>center_freq28</key> <value>0</value> </param> <param> <key>norm_gain28</key> <value>False</value> </param> <param> <key>gain28</key> <value>0</value> </param> <param> <key>ant29</key> <value></value> </param> <param> <key>bw29</key> <value>0</value> </param> <param> <key>center_freq29</key> <value>0</value> </param> <param> <key>norm_gain29</key> <value>False</value> </param> <param> <key>gain29</key> <value>0</value> </param> <param> <key>ant2</key> <value></value> </param> <param> <key>bw2</key> <value>0</value> </param> <param> <key>center_freq2</key> <value>0</value> </param> <param> <key>norm_gain2</key> <value>False</value> </param> <param> <key>gain2</key> <value>0</value> </param> <param> <key>ant30</key> <value></value> </param> <param> <key>bw30</key> <value>0</value> </param> <param> <key>center_freq30</key> <value>0</value> </param> <param> <key>norm_gain30</key> <value>False</value> </param> <param> <key>gain30</key> <value>0</value> </param> <param> <key>ant31</key> <value></value> </param> <param> <key>bw31</key> <value>0</value> </param> <param> <key>center_freq31</key> <value>0</value> </param> <param> <key>norm_gain31</key> <value>False</value> </param> <param> <key>gain31</key> <value>0</value> </param> <param> <key>ant3</key> <value></value> </param> <param> <key>bw3</key> <value>0</value> </param> <param> <key>center_freq3</key> <value>0</value> </param> <param> <key>norm_gain3</key> <value>False</value> </param> <param> <key>gain3</key> <value>0</value> </param> <param> <key>ant4</key> <value></value> </param> <param> <key>bw4</key> <value>0</value> </param> <param> <key>center_freq4</key> <value>0</value> </param> <param> <key>norm_gain4</key> <value>False</value> </param> <param> <key>gain4</key> <value>0</value> </param> <param> <key>ant5</key> <value></value> </param> <param> <key>bw5</key> <value>0</value> </param> <param> <key>center_freq5</key> <value>0</value> </param> <param> <key>norm_gain5</key> <value>False</value> </param> <param> <key>gain5</key> <value>0</value> </param> <param> <key>ant6</key> <value></value> </param> <param> <key>bw6</key> <value>0</value> </param> <param> <key>center_freq6</key> <value>0</value> </param> <param> <key>norm_gain6</key> <value>False</value> </param> <param> <key>gain6</key> <value>0</value> </param> <param> <key>ant7</key> <value></value> </param> <param> <key>bw7</key> <value>0</value> </param> <param> <key>center_freq7</key> <value>0</value> </param> <param> <key>norm_gain7</key> <value>False</value> </param> <param> <key>gain7</key> <value>0</value> </param> <param> <key>ant8</key> <value></value> </param> <param> <key>bw8</key> <value>0</value> </param> <param> <key>center_freq8</key> <value>0</value> </param> <param> <key>norm_gain8</key> <value>False</value> </param> <param> <key>gain8</key> <value>0</value> </param> <param> <key>ant9</key> <value></value> </param> <param> <key>bw9</key> <value>0</value> </param> <param> <key>center_freq9</key> <value>0</value> </param> <param> <key>norm_gain9</key> <value>False</value> </param> <param> <key>gain9</key> <value>0</value> </param> <param> <key>clock_rate</key> <value>0.0</value> </param> <param> <key>comment</key> <value></value> </param> <param> <key>affinity</key> <value></value> </param> <param> <key>dev_addr</key> <value>""</value> </param> <param> <key>dev_args</key> <value>""</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> <key>_coordinate</key> <value>(848, 68)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> <param> <key>id</key> <value>uhd_usrp_sink_0</value> </param> <param> <key>type</key> <value>fc32</value> </param> <param> <key>clock_source0</key> <value></value> </param> <param> <key>sd_spec0</key> <value></value> </param> <param> <key>time_source0</key> <value></value> </param> <param> <key>clock_source1</key> <value></value> </param> <param> <key>sd_spec1</key> <value></value> </param> <param> <key>time_source1</key> <value></value> </param> <param> <key>clock_source2</key> <value></value> </param> <param> <key>sd_spec2</key> <value></value> </param> <param> <key>time_source2</key> <value></value> </param> <param> <key>clock_source3</key> <value></value> </param> <param> <key>sd_spec3</key> <value></value> </param> <param> <key>time_source3</key> <value></value> </param> <param> <key>clock_source4</key> <value></value> </param> <param> <key>sd_spec4</key> <value></value> </param> <param> <key>time_source4</key> <value></value> </param> <param> <key>clock_source5</key> <value></value> </param> <param> <key>sd_spec5</key> <value></value> </param> <param> <key>time_source5</key> <value></value> </param> <param> <key>clock_source6</key> <value></value> </param> <param> <key>sd_spec6</key> <value></value> </param> <param> <key>time_source6</key> <value></value> </param> <param> <key>clock_source7</key> <value></value> </param> <param> <key>sd_spec7</key> <value></value> </param> <param> <key>time_source7</key> <value></value> </param> <param> <key>nchan</key> <value>1</value> </param> <param> <key>num_mboards</key> <value>1</value> </param> <param> <key>samp_rate</key> <value>320000</value> </param> <param> <key>hide_cmd_port</key> <value>False</value> </param> <param> <key>hide_lo_controls</key> <value>True</value> </param> <param> <key>stream_args</key> <value></value> </param> <param> <key>stream_chans</key> <value>[]</value> </param> <param> <key>sync</key> <value></value> </param> <param> <key>len_tag_name</key> <value></value> </param> <param> <key>otw</key> <value></value> </param> </block> <connection> <source_block_id>analog_wfm_tx_0</source_block_id> <sink_block_id>uhd_usrp_sink_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> <source_block_id>blocks_multiply_const_vxx_0</source_block_id> <sink_block_id>rational_resampler_xxx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> <source_block_id>blocks_wavfile_source_0</source_block_id> <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> <source_block_id>rational_resampler_xxx_0</source_block_id> <sink_block_id>analog_wfm_tx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> </flow_graph>

Теги: #Научно-популярная #Электроника для начинающих #программирование #Гаджеты #sdr #Разработка систем связи #радио #rds #GNU Radio #transmit #lime sdr #hack rf
Вместе с данным постом часто просматривают: