• DIY调频(FM) MP3电台-基于增强管道数据流转(EPDR)的taskBus实时水位控制技术


    0. 背景介绍

    增强管道数据流转(EPDR, Enhanced Pipeine Data Routing)彩鹰工作室提出的多进程合作架构。此架构通过各个进程的标准输入输出管道(stdio)吞吐数据,平台按照生产消费关系进行流转,联合多个子进程实现数据合作处理。EPDR主要的特点是低耦合性,特别适用于小规模工坊的跨语言、跨编译器合作开发。

    taskBus 开源软件无线电平台将此架构运用于SDR领域。非计算机专业的工程师受惠于此平台,可迅速整合每个人最熟悉的开发语言、开发环境,让不同知识背景、教育层次的工程师共同完成实时波形处理软件。

    在SDR软件开发中,水位控制是保证硬件及时获取数据,并防止数据堆积的有效手段。本文章基于taskBus平台,演示带水位控制的FM音乐电台的搭建技术,直接播放MP3文件到空中频率,主要流程如下:

    Mp3文件夹
    Lame.exe在线解码
    FM调制
    UHD发射

    1. 水位反馈控制

    对于含有实时硬件系统的波形生成设备来说,硬件逻辑的优先级总是高于软件逻辑。如一个把MP3音乐变成调频广播的简单播放机,可存在4个模块。

    1. 文件读取模块:负责从音乐文件夹读取MP3数据,是系统里的生产者。
    2. lame解码模块:直接使用开源MP3解码器LAME.exe实现stdio管道解码。
    3. FM调制模块:负责把 lame.exe 音乐的振幅调制为FM的频率变化。
    4. SDR发射机。如USRP B210,负责把基带波形搬移到射频并发射出去,是最终消费者。

    此时,为了保持音乐的连续性,需要注意几个问题:

    1. 无法确切控制mp3解码的节奏。Lame.exe解码速度很快,大大超过FM的自然速率。
    2. 如果上位机送入音乐的速度高于SDR发射机消费音乐的速度,则会出现数据堆积。
    3. 如果上位机送入音乐的速度低于SDR发射机消费音乐的速度,则会出现数据中断。

    由于生产者和消费者的时钟不统一,而消费者是硬件,不好调整节奏,因此需要引入一种反馈机制,让生产者通过软件适时调整输出的速率,让消费者的缓存处于健康的状态(40-60%充盈率)。

    这相当于生产者往一个水箱里注水,消费者在用水。生产者生产速度大于消费速度,但无法精确保持一致。此时,通过反馈水位给注水者,通知其调整进水的速率,使得水箱始终有水,又不至于溢出。

    反馈
    对应到SDR软件中,关键在于负责Tx(发射)的代码要不断地输出当前发射缓存中的水位,如下图所示:

    在这里插入图片描述

    2. taskBus UHD 模块的水位实现

    水位就是一个整数,用来指示当前环状缓存器还有多少样点节的数据尚未发射出去。

    2.1 消费者水位播报

    在 taskBus 的UHD模块里,设置一个 waterMark 专题(topic/Subject),用于汇报水位。其核心逻辑如下:

    	//初始化环状缓存器
    	const quint64 sz_buffer_all = 128 * 1024 * 1024;
    	std::vector<SPTYPE> buf_tx_array(sz_buffer_all,0);
    	//In IQ Samples, RF io
    	quint64 tx_pos = 0, stdin_pos = 0;
    	
    	//...
    	qint64 watM = stdin_pos[0] - tx_pos;							
    	TASKBUS::push_subject(
    				i_txWaterMark,
    				instance,
    				sizeof(qint64),
    				(unsigned char *) &watM);
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    通过不断向stdout输出当前的缓存状态,可以让生产者及时知道缓存的盈亏。

    2.2 生产者水位控制

    在生产者(这里是文件读取器)里,检查当前水位是不是充盈,如果充盈,则降速或者停止生产:

    int i_watermark =0;
    std::atomic<long long> g_watermark (0);
    //刷新水位
    while (false==bfinished)
    	{
    		subject_package_header header;
    		std::vector<unsigned char> packagedta = pull_subject(&header);
    		if (header.subject_id==i_watermark)
    		{			
    					long long * ptr = (long long *)packagedta.data();
    					g_watermark = *ptr;
    		}
    }
    //......
    
    
    //水位控制
    	if (minmark > 0 && i_watermark > 0)
    	{
    		while(g_watermark > minmark)
    		{
    			QThread::msleep(20);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3. 范例工程搭建

    3.1 下载 lame.exe

    去网上下载mp3解码器 lame.exe,放在当前文件夹。这个解码器可以直接接受 stdin的输入,并输出到 stdout (这简直就是为了管道应用而设计的!优雅!)。其参数:

    C:\> lame.exe --decode   --flush -S --mp3input  - -
    
    • 1

    解释:

    LAME 32bits version 3.98.4 (http://www.mp3dev.org/)
    
    usage: f:\lame.exe [options]  [outfile]
    
         and/or  can be "-", which means stdin/stdout.
         --flush         flush output stream as soon as possible
         -S              don't print progress report, VBR histograms
         --decode        input=mp3 file, output=wav
         --mp3input      input file is a MPEG Layer III file
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    该工具通过封装器模块直接引入工程。封装器模块使得所有支持stdio的程序都可以直接放进来用。

    Wrapper注意:如果运行时没有声音,而弹出了配置栏,那很可能是lame.exe路径不对。

    3.2 设置文件源,并连接反馈

    设置文件源 source_files, 监视音乐文件夹,文件类型mp3,生产速率每秒50次,每次10000字节。这个生产速率高于绝大多数Mp3文件的速率。同时,设置关键水位门限为1MB。当水位小于1MB时,会触发生产。注意,这个1MB是解码后的WAV的大小,并不是mp3的大小。

    水位反馈
    注意,这种反馈是级联的反馈,源头生产者生产的数据,经过2层处理后,才给消费者。

    4. 执行效果

    我们把文件夹中放入mp3文件,就可以直接用收音机收听了!整个过程稳定、连续。

    TaskBus Good
    相关源码参考代码仓库。

  • 相关阅读:
    初级篇—第六章创建和管理表
    vue-pdf(v4.3.0)
    EF Core 7.0 新特性之批量修改
    什么是架构,架构的本质是什么
    设计模式之抽象工厂模式
    现货白银有哪些优势
    leetcode-09(下一个排列+快乐数+全排列)
    【Mysql】表的约束
    wordpress建网站主题案例推荐
    编程技术对网络社会的益作用?
  • 原文地址:https://blog.csdn.net/goldenhawking/article/details/127569293