50行实现C语言FM收音机-Taskbus Stdio封装器在SDR课程中的应用
自从学校引入SDR教学以来,总觉得学生的实验课上的很吃力——还不如学习Matlab仿真算了。原因是编程基础不是很扎实的学生,可能只会使用C语言课上介绍的最基础的知识,这些知识往往无法支持其完成完整的SDR收音机接收实验。
之前为了避免学生学习太多的周边知识,对其造成困扰,我和几个老师共同建立了TaskBus工程。工程的初衷很好,旨在提供一种基于stdio(就是进程默认的键盘和回显句柄)的数据吞吐策略,把SDR的发射、接收、处理、播放串起来。关于这个工程,可以参考我的系列文章。
但这个框架还是没有顺利推进,主要原因:
- stdio需要封包、拆包,封包本身显著提高了学习曲线。即使用工具函数可以完成,但跟踪到函数内部,一些复杂性让学生望而却步。(实际不是很复杂)
- 在构造工程时,引入不少的 if else 判断,使得代码变长。
- 一些模块必须使用多线程。多线程是学生不希望接触的。
因此,能够使用C语言为TaskBus开发模块的同学屈指可数。这个项目苟延残喘到本学期,把新来的实验老师弄毛了。我们提出了一个想法——能不能进一步简化,就在C语言教科书上的例子里,直接解决问题呢?折腾了几个礼拜,还真的实现了。
1 学生开发的FM最简收音机
学生根据课本内容,实现FM广播单声道解调。输入的是调制信号,采样率200KHz,基带复数形式。大部分学生都能够通过测量前后两个样点的相位差,来估算频率。频率与相位是积分关系,对相位求微分,获得频率。求atan后,得到声音。
这个程序没有用到任何难以接受的知识点。唯一的美中不足,是在windows下要开启stdio句柄的二进制模式,防止Windows下的回车+换行代换破坏数据。这点在树莓派和Linux下不需要。但让我想不到的是,耽误时间最多的,是atan(y/x)的0除和象限问题。这个问题困扰不少学生很久。
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#define Pi 3.14159265354
//仿matlab Angle
double angle(int x, int y)
{double angle = 0;//计算角度if (x==0)angle = (y>0)? Pi/2:-Pi/2;else if (x >0 )angle = atan(y*1.0/x);else if (y >=0)angle = atan(y*1.0/x)+Pi;elseangle = atan(y*1.0/x)-Pi;return angle;
}
int main()
{short buf[128][2];int nPts = 0;int last_i = 0, last_q = 0;//老师加的两行。用于在windows下吞吐二进制数据。setmode(fileno(stdout), O_BINARY);setmode(fileno(stdin), O_BINARY);//算法while ((nPts = fread(buf,4,128,stdin))){short out[128];for (int j=0;j<nPts;++j){//d(phase)/d(t) = freqint curr_i = buf[j][0];int curr_q = buf[j][1];int diff_i = last_i * curr_i + last_q * curr_q;int diff_q = last_q * curr_i - last_i * curr_q; last_i = curr_i;last_q = curr_q;out[j] = angle(diff_i,diff_q)/Pi*4096;}//输出到stdoutfwrite(out,2,nPts,stdout);fflush(stdout);}return 0;
}
这个程序可以用离线的文件来测试,并把结果导入AudaCity里播放。学生写好了这个程序,直接放在taskBus里,就能使用。可以看到,与不使用封装器的 TaskBus FM解调模块代码相比,上面的代码更为聚焦算法,大大降低了篇幅。
2. 用Qt建立stdio封装器
Stdio封装器要把上面这个普通的使用标准输入输出的可执行文件封装起来,完成stdio输入输出的格式化组包。说到进程的封装,Qt的Process很棒。只要给定可执行文件的名字,就能作为子进程启动,并用QIODevie接口吞吐数据。
QProcess * m_process = new QProcess(this);
connect(m_process,&QProcess::readyReadStandardOutput,this,&DlgWrpStdio::slot_readyReadStandardOutput,Qt::QueuedConnection);
connect(m_process,&QProcess::readyReadStandardError,this,&DlgWrpStdio::slot_readyReadStandardError,Qt::QueuedConnection);
//...
const QString exe = ui->lineEdit_prgPath->text();
const QString args= ui->lineEdit_parasec->text();
m_process->startCommand(exe + " " + args);
一旦进程启动,在 slot_readyReadStandardOutput 和 slot_readyReadStandardError里,就能顺序读取进程的输出了:
void DlgWrpStdio::slot_readyReadStandardOutput()
{QByteArray arred = m_process->readAllStandardOutput();//...
}
void DlgWrpStdio::slot_readyReadStandardError()
{QByteArray arred =m_process->readAllStandardError();//...
}
同时,想发往子进程数据,直接调用write即可:
QByteArray arr(somedata,length);
m_process->write(arr);
//立刻送到
m_process->flush();
这个封装器作为Taskbus的新插件,在这里可以找到源码。其界面如下:
3.引入Taskbus
在Taskbus里,拖入封装器模块,把路径设置到学生自己的exe上,并连接管脚:这样,学生的模块就嵌入到FM解调工程中去了。FM的接收与解调,主要分为:
- 设置USRP B210工作在电台频率。
- 接收500KHz或1MHz等采样率的信号。
- 滤波与下采样到200KHz
- 解调。(这一步学生做)
- 声波下采样到44100Hz
- 声卡播放。
- 同时,分一路信号去fftw和进行实时谱分析显示。
学生能够直观感觉到自己的程序竟可以参与到实时的接收处理中,成就感很高!并且,通过开发类似的模块,可以逐步取代老师们开发的范例模块,并对比其性能。比如老师通过^V Github写的仿Matlab 分数倍采样率变换,使用了浮点,速率不高。如果能变成定点,性能肯定更好。
4.测试结果
通过测试,这个小模块可以很好的播放本地广播电台的音乐。
有学生非常兴奋,有事没事都开着。
5 衍生应用
封装EXE的标准输入输出,并不要求EXE一定是C语言写的。使用python、node.js甚至标准的命令程序,如grep,都可以引进来处理。
有了这种技术,即使是没有多线程、数据库、动态链接库、COM、消息队列等知识的新手,也能够根据教科书上的内容迅速尝试向实时处理系统中输出自己的知识。
Taskbus目前支持鼠标的动态连线了,进一步方便了学生的操作。加入的USRP UHD 定时突发发射模块仍在测试中。相关程序的运行、软件使用文档尚不完善。发行版见这里。
50行实现C语言FM收音机-Taskbus Stdio封装器在SDR课程中的应用相关推荐
- 50行以上c语言程序代码,C语言非常简单的字符统计程序50行
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 该程序用于实现linux系统中wc命令的最简单模式 wc 命令用于统计文件中字符信息. [xx@localhost 1.5]$ wc 01.c 02.c ...
- C语言程序设计50行以上,C语言程序设计100例——都卡会了,2级绝对没问题了---2...
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 gotoxy(1,10);printf("| | | | |"); gotoxy(1,11);printf("| ----- ...
- html语言的编译器,50 行代码的 HTML 编译器
虚拟 DOM 几乎已经是现代 JS 框架的标配了.那么该怎样将 HTML 字符串编译为虚拟 DOM 呢?这样的编译器并不是什么黑科技,这里只用了不到 50 行 JS 就实现了一个. Demo 在 HT ...
- 50 岁的 C 语言,掌控 Windows、Linux、macOS 等操作系统半边天
[CSDN 编者按]诞生于1972年的C语言已经50岁了,目前来看,它还像20岁的小伙一样活力四射,似乎永不会退休,并且正在赋能全世界重量级应用系统的运行. 作者 | Daniel Munoz 编译 ...
- 50行的python游戏代码_50行代码实现贪吃蛇(具体思路及代码)
[下载文档: 50行代码实现贪吃蛇(具体思路及代码).txt ] (友情提示:右键点上行txt文档名->目标另存为) 50行代码实现贪吃蛇(具体思路及代码) 最近一直在准备用来面试的几个小de ...
- 如何用50行代码构建情感分类器
选自Toward Data Science,作者:Rohith Gandhi,机器之心编译. 本文介绍了如何构建情感分类器,从介绍自然语言处理开始,一步一步讲述构建过程. 自然语言处理简介 语言把人类 ...
- linux上听FM程序,安装和使用Odio在Linux上收听FM收音机的方法
Linux平台上有一些很棒的无线电应用程序可用于在Linux上收听FM Radio(收音机),本文介绍Odio,包括安装和使用它来收听FM收音机的方法. 启用Snap支持和安装Odio 由于Sna ...
- 《USRP B210》制作FM收音机
一.环境描述:Ubuntu18.04 虚拟机 PC:I5 8250 8G 硬件设备:USRP B210 LTE胶棒天线 总的工作环境如下图 二.流图介绍: 具体描述 1.Osmocom Source ...
- 车载FM收音机的性能测试
商用汽车AM/FM收音机必须能在各种环境下可靠地工作.因为这些收音机的设计师采用数字信号处理(DSP)算法来克服反射.信号多径和衰落等效应,所以他们经常要去现场花数周的时间分析不同信号条件下的效果.而 ...
最新文章
- 使用 XML 时尽量避免使用的技术
- setHasOptionsMenu
- ETSI GS MEC 015,MEP 带宽管理 API
- rssi室内定位算法原理_智慧定位系统之蓝牙网关在室内定位技术的原理浅析
- poj 1011 Sticks 搜索
- 工作112:vue路由跳转错误:Error: Redirected when going from “/login“ to “/home“ via a navigation guard.
- coddenomicon工具
- 授予数据库账号dba权限_深入理解 MySQL 用户和权限
- Windows Phone 7知识锦分享【第二季】
- python操作日期和时间的方法
- ArcGIS Pro 简明教程(3)数据编辑
- linux目录结构和份文件系统
- weblogic调整多个服务启动顺序方法
- spring揭秘_「死磕 Spring」—– IOC 之深入理解 Spring IoC
- ES index not_analyzed
- windows Git Gui 汉化
- influxdb java api使用_Influxdb入门使用
- Arrays.copyOf 编译器提示 Usage of API documented as @since 1.6+ less... (Ctrl+F1) This inspection finds
- 字符串转成可计算的数学表达式
- Deep Learning 最优化方法
热门文章
- 计算机办公软件应用英文,办公软件用英语怎么说英文表达
- Nginx启动报错: could not open error log file: open() q unable to find local peer: 192.168.10.102:8848,
- 【两天搞定小米商城】【第九步】小米商城之尾部部分
- DELETE * FROM和DELETE FROM的区别
- mysql log-update 错误_记一次修复MySQL socker 错误
- PTC Creo 5.0.2.0 + HelpCenter Win64 中文破解版
- 研究区分onbeforeunload事件是刷新还是关闭
- ant pro-table点击表格行高亮显示
- Windows编程(2)
- 2-SAT问题,一个神奇的东西