PiFmAdv:基于树莓派的FM-RDS发射器,支持立体声与实时数据生成

Advanced Raspberry Pi FM transmitter with RDS encoding

Branch1Tags0
FilesLast commitLast update
9 years ago
2 years ago
9 years ago
9 years ago
4 years ago

使用树莓派制作FM-RDS发射器

本程序生成带有实时RDS(无线电数据系统)数据的调频信号,可包含单声道或立体声音频。

PiFmAdv通过调制PLL控制器而非时钟分频器以实现更佳的信号纯净度,这意味着信号也更少噪声。这对立体声接收尤其重要,因为其效果显著改善。

为了使PLL调制稳定,需要额外一步操作。由于低电压检测可能导致PLL频率降低至安全值以防止崩溃。当这种情况发生时,载波频率会根据原始GPU频率变化。 为了避免这一情况,我们轻松地将GPU频率设置为与安全频率相同。这样一来,当因低电压检测而PLLC频率调整到安全值时,因为正常值和安全值相同,所以不会产生变化。

只需在/boot/config.txt中添加gpu_freq=250即可。

它基于Oliver Mattos和Oskar Weigl创建的FM发射器,并由Richard Hirst后续改进使用DMA。Christophe Jacquet进一步适配并加入了RDS数据生成器和调制器。该发射器利用树莓派的PWM发生器产生VHF信号。

兼容树莓派1代(初代)、树莓派2代和3代。

示意图

PiFmAdv仅供实验用途。它不是一个媒体中心,目的不是向你的音响系统广播音乐。请参考法律警告

如何使用?

PiFmAdv依赖于sndfile库。在如Raspbian这样的Debian类发行版上,运行sudo apt-get install libsndfile1-dev来安装此库。

PiFmAdv现在使用SoX重采样器进行高质量重采样。在基于Debian的系统上,运行sudo apt install libsoxr-dev安装这个依赖项。

PiFmAdv还需要Linux的rpi-mailbox驱动,因此需要一个较新的内核。从2015年8月起的Raspbian版本已包含这个驱动。

**重要:**编译好的树莓派1代用二进制文件与树莓派2/3代不兼容,反之亦然。切换模型时务必重新编译,切勿跳过以下步骤中的make clean

克隆源代码仓库并在src目录下运行make

git clone https://github.com/Miegl/PiFmAdv.git
cd PiFmAdv/src
make clean
make

之后你可以直接运行:

sudo ./pi_fm_adv

这将在87.6 MHz生成一个FM传输,默认情况下没有音频,但带有默认的电台名称(PS)、广播文本(RT)和PI码。无线电频率信号通过GPIO 4(P1接头上的第7针)发射。

要添加单声道或立体声音频,可以参照如下方式指定音频文件:

sudo ./pi_fm_adv --audio sound.wav

测试立体声音频时,可以尝试提供的stereo_44100.wav文件。

启动Pi-FM-RDS的一般语法如下:

pi_fm_adv

所有参数都是可选的:

  • --freq指定期望的载波频率(单位为MHz)。例如:--freq 87.6
  • --audio指定播放的音频文件路径。采样率无关紧要:PiFmAdv会重采样和滤波。提供立体声文件时,PiFmAdv会产生FM立体声信号。例如:--audio sound.wav。支持的格式取决于libsndfile,包括WAV和Ogg/Vorbis(但不限于)但不包括MP3。指定-作为文件名可以从标准输入读取音频数据(适合管道传输音频给PiFmAdv,参见下方说明)。
  • --pi设定RDS广播的PI码,由四位十六进制数字组成。例如:--pi FFFF
  • --ps设定广播的电台名称(节目服务名称,PS),限制为8个字符。例如:--ps RASP-PI
  • --rt设定待传输的广播文本(RT),限64个字符。例如:--rt 'Hello, world!'
  • --af设定替代频率(AF)。例如:--af 107.9 --af 99.2
  • --pty设定节目类型,范围0-31。例如:--pty 10(欧洲:流行音乐)。更多节目类型参见维基百科上的RDS条目
  • --tp指明节目是否包含交通信息。例如--tp 0
  • --dev设定频偏(单位Hz)。例如--dev 25000
  • --mpx设定输出的MPX功率,默认为30。例如--mpx 20
  • --power设定GPIO引脚的驱动强度,0=2mA...7=16mA,默认为7。例如--power 5
  • --gpclk设定使用的通用时钟(GPCLK),选项为0、1、2。
  • --gpio设定用于传输的GPIO引脚,可多次指定以同时在多个引脚上传输。默认为4。可与--gpclk结合使用。例如--gpio 20
  • --pll设定被调制的PLL,缺省为PLLC,在树莓派4上PLLA似乎不起作用。可用选项:ac
  • --cutoff设定PiFmAdv内部低通滤波器的截止频率(单位Hz)。大于15000的值不符合规范。使用时需谨慎。
  • --preemph指定了应使用的预加重,因为它根据不同地区有所不同。在欧洲选择'eu',在美国选择'us'。
  • --ctl设定命名管道(FIFO),用作控制通道以在运行时更改PS和RT(参见下方)。
  • --ppm指定您的树莓派晶振误差(百万分之一),详情见下文。
  • --rds开关以启用RDS广播。
  • --wait设定PiFmAdv是否等待音频管道或一旦没有音频就终止,默认为1。

默认情况下,PS会在“PiFmAdv”和一个从“00000000”开始的序列号之间交替变换,大约每秒转换一次。

时钟校准(仅在遇到困难时)

RDS标准要求57kHz副载波的误差小于±6Hz,即不超过105ppm。树莓派的晶振误差可能超过这一数值。这就需要用到--ppm参数:您指定树莓派的误差,PiFmAdv会相应调整时钟分频器。

实际上,我发现即使不使用--ppm参数,PiFmAdv也能工作得相当好。我猜测接收机对误差的容忍度比RDS规格所述更高。

测量ppm误差的一个方法是播放pulses.wav文件:它精确播放一秒脉冲,然后是一秒静音,如此循环。使用具有良好音频卡的收音机记录输出音频。假设你以44.1kHz采样。测量10个间隔的样本数:如果没有时钟误差,应当是441,000样本。在我的树莓派上,我得到441,132样本。因此,我的ppm误差是(441132-441000)/441000 * 1e6 = 299ppm,前提是假定我的采样设备(音频卡)没有时钟误差...

将音频输入到PiFmAdv

如果你使用参数--audio -,PiFmAdv会在标准输入上读取音频数据。这允许你将程序的输出管道传入PiFmAdv。例如,可以用来通过Sox播放MP3文件:

sox -t mp3 http://www.linuxvoice.com/episodes/lv_s02e01.mp3 -t wav -  | sudo ./pi_fm_adv --audio -

或者将声卡的辅助输入管道传输给PiFmAdv:

sudo arecord -fS16_LE -r 44100 -Dplughw:1,0 -c 2 -  | sudo ./pi_fm_adv --audio -

运行时更改PS、RT、TA和PTY

你可以使用命名管道(FIFO)在运行时控制PS(节目名称)、RT(无线电文本)、TA(交通公告标志)和PTY(节目类型)。为此,以--ctl参数运行PiFmAdv。

示例:

mkfifo rds_ctl
sudo ./pi_fm_adv --ctl rds_ctl

然后你可以发送“命令”来更改PS、RT、TA和PTY:

cat >rds_ctl
PS MyText
RT A text to be sent as radiotext
PTY 10
TA ON
PS OtherTxt
TA OFF
...

每行必须以PSRTTAPTY开始,并跟随一个空格字符及期望的值。其他格式的行会被默默忽略。“TA ON”会将交通公告标志切换到开启状态,任何其他值都会将其切换至关闭状态。

警告与免责声明

PiFmAdv是一个实验性程序,仅用于实验目的。它无意成为个人媒体中心或运营广播电台的工具,甚至不适合向自己的立体声音响系统广播声音。

在大多数国家,未经政府特定许可(针对频率、功率、带宽等的许可)而发射无线电波是非法的

因此,始终使用屏蔽传输线直接连接树莓派和收音接收器,以避免发射无线电信号。绝不能使用天线。

即使你是执照业余无线电操作员,在没有在树莓派与天线之间添加任何滤波的情况下,使用PiFmAdv在业余无线电频率上发射无线电信号很可能是违法的,因为方波载波含有丰富的谐波,不太可能满足所需的频谱宽度要求。

我对于你如何使用自己的树莓派造成的任何不当行为概不负责。所有实验均需自行承担责任。

测试

PiFmAdv已成功地在我的所有支持RDS设备上进行了测试,包括:

  • 1995年的索尼ICF-C20RDS闹钟,
  • 1998年的Sangean PR-D1便携式接收机和1999年的ATS-305,
  • 2011年的三星Galaxy S2手机,
  • 2012年的Philips MBD7020 Hi-Fi系统,
  • 配备Si4701芯片的Silicon Labs USBFMRADIO-RD USB棒,以及使用我的RDS Surveyor程序,
  • 一款名为“PCear Fm Radio”的中国克隆产品,同样使用了RDS Surveyor。

上述所有设备的接收效果完美。RDS Surveyor报告无组错误。

galaxy_s2.jpg

CPU使用率

CPU使用率如下:

  • 无音频:9%
  • 单声道音频:33%
  • 立体声音频:40%

添加音频后,CPU使用率急剧增加,因为在将输入音频文件的(未指定的)采样率上采样到228 kHz(其内部操作采样率)时,程序必须应用一个FIR滤波器,这是计算成本较高的过程。

设计

RDS数据生成器位于rds.c文件中。

该RDS数据生成器周期性地生成四个0A群组(用于传输PS),以及一个2A群组(用于传输RT)。此外,每分钟插入一个4A群组(用于传输CT,即时间)。get_rds_group生成一个群组,并利用crc计算CRC值。

为了获取RDS数据样本,调用get_rds_samples。它调用get_rds_group,对信号进行差分编码并生成成型的双相符号。连续的双相符号重叠,通过对一系列曼彻斯特编码脉冲应用(RDS标准规定的)根升余弦(RRC)滤波器得到的结果相加。

成型的双相符号由一个名为generate_waveforms.py的Python程序一次性生成,该程序使用了我的另一个软件无线电项目Pydemod。这个Python程序生成名为waveform_biphase的数组,它是将RRC滤波器应用于正负脉冲对的结果。注意,generate_waveforms.py的输出,两个名为waveforms.cwaveforms.h的文件,已包含在Git仓库中,因此无需自己运行Python脚本即可编译PiFmAdv。

程序内部,所有信号都以228 kHz的采样率进行采样,这是RDS副载波频率57 kHz的四倍。

FM多路复用信号(基带信号)由fm_mpx.c生成。这个文件处理输入音频文件的上采样到228 kHz,以及生成多路复用信号:未调制的左右声道信号(限制在15 kHz内),可能的19 kHz立体声导频,可能在38 kHz上幅度调制的左右声道信号(无载波抑制),以及来自rds.c的RDS信号。上采样通过零阶保持后跟一阶60的FIR低通滤波器完成。滤波器是以汉明窗截断的抽样sinc函数。滤波器系数在启动时生成,以便滤波器剪切高于以下两者中较小者的频率:

  • 输入音频文件的奈奎斯特频率(采样率的一半),以避免混叠,
  • 15 kHz,根据FM广播标准,左右声道和左右声道通道的带通。

pi_fm_adv.c播放样本,该文件改编自Richard Hirst的PiFmDma。程序修改以支持精确的228 kHz采样率。

参考文献

历史

  • 2015-09-05:支持Raspberry Pi 2
  • 2014-11-01:支持运行时切换交通公告(TA)标志
  • 2014-10-19:修复bug(当指定的文件不存在或无法从标准输入读取时,干净地停止DMA引擎)
  • 2014-08-04:修复bug(ppm现在使用浮点数)
  • 2014-06-22:生成CT(时间信号)信号,修复bug
  • 2014-05-04:运行时更改PS和RT的可能性
  • 2014-04-28:支持将音频文件数据管道传输到PiFmAdv的标准输入
  • 2014-04-14:新版本,支持任意采样率的音频输入,并能根据提供的立体声音频文件生成正确的FM立体声信号
  • 2014-04-06:初始发布,最初只支持228 kHz单声道音频输入文件

版权所有 © Miegl & Christophe Jacquet(F8FTK),2014-2017。在GNU GPL v3许可下发布。

Introduction

Advanced Raspberry Pi FM transmitter with RDS encoding

Customize your domain