ch[j] & 255结果是什么

山东移动 真是缺德啊!百度网址后面跟?tn=_pg&ch=8 知道这是什么吗?运营商想赚百度钱绑架我们用户!真是缺德!
同时转发到微博《HackRF与GNURadio入门指南》 | HackRF.net
› 《HackRF与GNURadio入门指南》
《HackRF与GNURadio入门指南》
本文正在写作中
近年来,软件工程师的触角早已经慢慢地向传统硬件工程师的保留领地里伸去。例如FPGA的出现使得硬件设计从原来的”原理图-&PCB图-&制板-&焊接-&调试-&改板-&制板-&焊接”的长周期、慢节奏开发中解放出来。缩短了硬件开发的周期,等同于延长了硬件工程师的寿命。
软件行业的先进内容
软件行业中一些先进的理念正在被引入硬件设计中,例如版本控制。在软件行业中,我们使用如SVN和GIT等工具对软件代码进行管理,基本地思想是,将程序员每次对代码的改动,都做为一个版本提交到版本库中,不同的版本之间可以进行对比和合并。
而硬件设计中,由于大部分EDA软件不提供该功能,使得硬件工程师只能人工地管理电路的原理图和PCB图,经常出现版本混乱的情况。
开源的电路设计软件如KiCAD将所有的原理图和PCB图以纯文本的方式保存,这样硬件设计过程中也可以使用版本控制系统对每一次改动进行跟踪。
开源协议中最著名的是GPL(GNU Public License)。GPL最美妙的地方在于,你使用了或者说是“抄袭”了GPL代码并没有关系,但是只要你用了GPL的代码,你就必须要把你基于此做出的成果也按照GPL协议发布出来。
而GPL之外的软件世界,大家都在小心地维护着不被珍视的版权,敝帚自珍。开源的思想是鼓励你把你的作品发布出来,勇于接受其它的人学习以及批评。
在GPL等开源协议的引领下,开源软件世界已经形成了一整套有生命力、有活力的软件工具体系。Linux的成功证实了一点。
同样,在无线电这一发展了一个多世纪的行业中,软件设计模式的加入,使得近年来无线电的玩法出现了新的变化。人们不再需要为一种特定的调制解调方案而单独地设计对应的硬件,并耗巨大的精力和时间对硬件各部分进行调优。
于是,我们想到可以用数字的方法,以不变应万变的形式,使用一块射频前端板卡,将无线信号变频到基带部分,然后将全部带宽采样回电脑,所有原来由特定硬件来实现的功能如混频器、滤波器、放大器、衰减器都变成了计算机中的运算。
为什么我们需要开源软件无线电?
无线电行业已经逐渐被安捷伦(是德科技)和罗德施瓦茨等巨头公司垄断,他们造出一块又一块仪表,写出一摞又一摞让人看不懂的通信标准,把好好的功能拆分成一个又一个的选件(Option)来卖钱。如同早期玩电脑的人可以接触一些命令行、了解一些电脑的内部原理,现在玩电脑的人早就被360等公司包围的严严实实,让你无暇也无力去了解电脑及互联网的任何原理。
GNURadio就是开源世界中软件无线电的代表项目。它的出现,使得开源世界能够打破传统通信巨头的垄断,使得人们能够自由地了解整个通信系统的任何细节。
GNURadio实现了软件无线电所需要的大部分模块,并且完成了对于采样数据流的缓冲、调度,并由开源社区集体维护。值得一提的是,GNURadio不同于MATLAB等旨在仿真的工具,它生来就是准备玩真的,GNURadio对于软件无线电射频前端硬件的支持非常全面,例如USRP、HackRF、BladeRF等。
这篇仔细地分析了三者的区别和优缺点。给了一个中译版。总的说来,USRP B2X0 系列价格最贵、性能最好;bladeRF 支持频段没有那么宽,但优点在于可以脱机运行;HackRF 价格低廉、开放程度高,最适合黑客玩家。
特别值得一提的是,HackRF是完全开源的软件无线电射频前端。它从原理图到PCB图,从驱动程序到单片机固件,甚至连加工制板所需要的工艺要求,全部以GPL协议无保留地发布,这对于我们学习研究软件无线电无疑是一件非常值得庆幸的事情。
HackRF已经在KickStarter上卖出了2000多块板卡。而BladeRF只卖出了500块板卡。
在本书中,笔者试图以一个非通信科班出身的资深的Linux玩家的视角,浅显地解释无线电的一些基本知识,并以HackRF为基础,向大家介绍开源软件无线电框架GNURadio的基本用法及示例。期望有更多的软件工程师能够发现这一块尚未被开垦的大陆,从而为开源软件无线电贡献出更多更好的开源项目。
Hello, World. 快速上手
本章试图以几个简单易懂的示例,向大家不经证明地展示一些无线电及信号处理的一些有趣的事实。旨在使读者能够对我们所要研习的领域有一个全面、粗犷而不失准确的认识。
本章假定读者对于Linux有基本的操作能力,能读懂理解基本的Python语言,假定读者对于频率、载波、相位等概念有基本的认识,并接触过示波器等常见工科仪表。
HackRF的FM广播接收
在Windows系统
将HackRF与电脑连接,按一下HackRF的电源/Reset按钮使其开机
使用Zadig安装其驱动。
下载最新版本的
(可选)下载Windows平台的
需要安装Microsoft Visual C++ 2012 Redistributable Package
TODO: SDR#的截图 TODO: 加入Zadig截图
然后打开SDR#,即可尝试接收FM广播了。
参照gqrx.dk上的安装指南
安装GNURadio
在之前安装GNURadio是一件非常困难的事情,现在有了sbrac.org提供的GNURadio安装脚本,所有的事情变得非常简单。只需要执行以下几条命令就可以安装好。
特别需要注意的是,由于GNURadio软件包目前被各大发行版的支持还不是特别好,因此完全不建议使用apt-get等方式安装GNURadio。
$ wget http://www.sbrac.org/files/build-gnuradio
$ chmod +x build-gnuradio
$ ./build-gnuradio -v -ja
$ wget http://www.sbrac.org/files/build-gnuradio$ chmod +x build-gnuradio$ ./build-gnuradio -v -ja&
然后在Proceed?后面输入y回车。在Do you have SUDO privileges?提示后面依然输入y回车。
注意,执行build-gnuradio脚本的时候,不要预先使用sudo。
加入-ja的选项后,使用多核处理器的并行处理能力来编译GNURadio,加快编译速度。整个编译安装过程可能会持续2小时甚至更长的时间,取决于网络速度。因此建议使用比较快的Linux镜像源服务器。
然后build-gnuradio脚本会自动安装所需要的软件包,然后开始安装。
值得一提的是,build-gnuradio脚本会自动安装最新版本的hackrf软件。
编译安装gqrx
$ git clone /csete/gqrx.git gqrx.git
$ cd gqrx.git
$ mkdir build
$ cd build
$ qmake ..
$ git clone https:///csete/gqrx.git gqrx.git$ cd gqrx.git$ mkdir build$ cd build$ qmake ..$ make&
LiveCD试用
如果现在还没有时间和精力来编译安装gqrx甚至GNURadio环境,可以使用社区其它人已经搭建好的引导光盘试用GNURadio。
放入光盘,重启电脑,选择以光盘引导。
打开HackRF的电源按钮。
只需要打开终端,输入hackrf_info命令
$ hackrf_info
Found HackRF board.
Board ID Number: 2 (Unknown Board ID)
Firmware Version: git-f9ffe90
Part ID Number: 0xbc5f4f4a 0xbc5f4f4a
Serial Number: 0xxx261c63c8 0x26776d53
$ hackrf_info Found HackRF board.Board ID Number: 2 (Unknown Board ID)Firmware Version: git-f9ffe90Part ID Number: 0xbc5f4f4a 0xbc5f4f4aSerial Number: 0x 0x 0x261c63c8 0x26776d53&
证明HackRF已经被电脑所识别。然后输入
然后选择硬件为HackRF,然后按下左上角的开关按钮,并将HackRF调谐到103.9MHz,不出意外的话,你就可以听到FM广播了。
TODO: gqrx的照片
TODO: gqrx的照片&
osmocom_fft osmocom_siggen
使用osmocom_fft 即可开启一个简单的频谱仪
osmocom_siggen 则提供了一个简单的信号发生器
FM 广播的发射
随便找一个mp3文件什么的,转换成WAV文件。在此建议转换成44.1kHz,双声道。
例如使用ffmpeg转换:
ffmpeg -i source.mp3 music.wav
ffmpeg -i source.mp3 music.wav&
打开gnuradio-companion搭建一个框图
WAV Source
samp_rate采样率要设置为250kHz,这个与我们的wav文件采样率为44.1kHz有关。实际试验,如果samp_rate设置为500kHz,放出来的声音会加速一倍。
N Channels表示Wav文件的声道数,填2
File里填写你在上一步制备的Wav文件地址
Stream Mux
Stream Mux的作用是把两条数据流合并为一条流,例如N0是来自第一条流的采样点,N1来自第二条流采样点,则Stream Mux会将两条流以如下方式输出:
[N0, N1, N0, N1, N0, N1, ...]
[N0, N1, N0, N1, N0, N1, ...]&
值得注意的是此处的Type需要填为Float,GNURadio里的数据类型是以颜色表示的。
另外,同一主色的情况下,颜色越深表示它是一个Vector。TODO: 待仔细调查
Osmocom Sink
在GNURadio里,Sink表示信号输出,Source表示信号输入。
Device Arguments可以填上hackrf=0
sample rate设置为samp_rate*4
Ch0 Freq Corr (ppm)
HackRF的频率较正值,在没有经过仪表校正时,可以直接先填0,有条件的同学可以使用频谱仪或信号源进行标定。
Ch0 Frequency 要发射的频率,此处我填了93e6,表示93MHz
Ch0 RF Gain(dB)
表示HackRF放大器是否开启
尽管此处Gain可任意输入,但事实上只有两档,0和14dB,并不是连续可调的,在此我们填14
Ch0 IF Gain(dB)
表示HackRF的中频增益
从电路上来看,应试指的是进入MAX2837收发器后给的增益
在此我们填40
Ch0 BB Gain(dB)
表示HackRF的基带增益
可能指是的进入ADC/DAC芯片后给的增益
在此我们填20
Ch0 BandWidth,填250e3
另外,你自行尝试将上述框图中的Wav File Source改为Audio Source,即可实现语音的实时FM发射。注意要修改一下各个采样率。
警告: 请短时间尝试性的操作,切勿长时间干扰正常业务频率。
遥控小车的重放
市面上的遥控小车多使用27MHz或者40MHz等频率进行遥控。在此我们在不分析遥控信号的情况下,对信号进行录制和重放,使大家对HackRF的操作有一个简单的认识。
在本书的后续章节,我们会进一步地分析市面上一种常见的遥控小车的遥控器,并使用GNURadio编写信号处理模块,重新生成遥控小车的指令,最后简单实现一个电脑上具有图形界面的遥控小车的控制程序。
我们使用内嵌的hackrf_transfer指令来实现录制-回放。首先看一下hackrf_transfer的用法:
$ hackrf_transfer
receive -r and receive_wav -w options are mutually exclusive
-r &filename& # Receive data into file.
-t &filename& # Transmit data from file.
-w # Receive data into file with WAV header and automatic name.
# This is for SDR# compatibility and may not work with other software.
[-f set_freq_hz] # Set Freq in Hz between [5MHz, 6800MHz]. 设置中心频率
[-a set_amp] # Set Amp 1=Enable, 0=Disable. 设置10dB放大器是否打开
[-l gain_db] # Set lna gain, 0-40dB, 8dB steps 低噪声放大器增益
[-i gain_db] # Set vga(if) gain, 0-62dB, 2dB steps VGA放大器(中频)
[-x gain_db] # Set TX vga gain, 0-47dB, 1dB steps 发射的增益
[-s sample_rate_hz] # Set sample rate in Hz (8/10/12.5/16/20MHz, default 10MHz). 设置采样率
[-n num_samples] # Number of samples to transfer (default is unlimited). 传输的采样点数
[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in MHz. 设置基带滤波器带宽(MHz)
Possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default & sample_rate_hz.
1234567891011121314151617
$ hackrf_transfer receive -r and receive_wav -w options are mutually exclusiveUsage:&&&&-r <filename> # Receive data into file.&&&&-t <filename> # Transmit data from file.&&&&-w # Receive data into file with WAV header and automatic name.&&&&&& # This is for SDR# compatibility and may not work with other software.&&&&[-f set_freq_hz] # Set Freq in Hz between [5MHz, 6800MHz]. 设置中心频率&&&&[-a set_amp] # Set Amp 1=Enable, 0=Disable. 设置10dB放大器是否打开 &&&&[-l gain_db] # Set lna gain, 0-40dB, 8dB steps 低噪声放大器增益&&&&[-i gain_db] # Set vga(if) gain, 0-62dB, 2dB steps VGA放大器(中频)&&&&[-x gain_db] # Set TX vga gain, 0-47dB, 1dB steps 发射的增益&&&&[-s sample_rate_hz] # Set sample rate in Hz (8/10/12.5/16/20MHz, default 10MHz). 设置采样率&&&&[-n num_samples] # Number of samples to transfer (default is unlimited). 传输的采样点数&&&&[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in MHz. 设置基带滤波器带宽(MHz)&&&&Possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default < sample_rate_hz.&
需要注意几点: – 此处的VGA是指Variable Gain Amplifier,指可变增益的放大器。 – 虽然HackRF的宣传文档里写的是支持30MHz到6GHz,但是实际上驱动支持从5MHz到6800MHz
$ hackrf_transfer -r car.iq -f
-s 8000000 -i 60
call hackrf_sample_rate_set(8000000 Hz/8.000 MHz)
call hackrf_baseband_filter_bandwidth_set(7000000 Hz/7.000 MHz)
call hackrf_set_freq( Hz/27.000 MHz)
Stop with Ctrl-C
16.0 MiB / 1.000 sec = 16.0 MiB/second
16.0 MiB / 1.000 sec = 16.0 MiB/second
16.0 MiB / 1.000 sec = 16.0 MiB/second
^CCaught signal 2
4.2 MiB / 0.273 sec = 15.3 MiB/second
User cancel, exiting...
Total time: 3.27395 s
hackrf_stop_rx() done
hackrf_close() done
hackrf_exit() done
fclose(fd) done
12345678910111213141516171819
$ hackrf_transfer -r car.iq -f
-s 8000000 -i 60call hackrf_sample_rate_set(8000000 Hz/8.000 MHz)call hackrf_baseband_filter_bandwidth_set(7000000 Hz/7.000 MHz)call hackrf_set_freq( Hz/27.000 MHz)Stop with Ctrl-C16.0 MiB / 1.000 sec = 16.0 MiB/second16.0 MiB / 1.000 sec = 16.0 MiB/second16.0 MiB / 1.000 sec = 16.0 MiB/second^CCaught signal 2 4.2 MiB / 0.273 sec = 15.3 MiB/second&User cancel, exiting...Total time: 3.27395 shackrf_stop_rx() donehackrf_close() donehackrf_exit() donefclose(fd) doneexit&
然后使用玩具小车的遥控器靠近HackRF的天线,操作小车,完毕后按Ctrl-C结束程序
其中,-f参数是指采回的中心频率,在这里的意思是把27.0MHz为中心,共8M带宽的信号,下变频到0Hz为中心频率,并传输回计算机,保存成为car.iq。 -i 60参数是接收中频增益
$ hackrf_transfer -t car.iq -f
-s 8000000 -a 1 -l 30 -x 40
call hackrf_sample_rate_set(8000000 Hz/8.000 MHz)
call hackrf_baseband_filter_bandwidth_set(7000000 Hz/7.000 MHz)
call hackrf_set_freq( Hz/27.000 MHz)
call hackrf_set_amp_enable(1)
Stop with Ctrl-C
16.0 MiB / 1.000 sec = 16.0 MiB/second
16.0 MiB / 1.000 sec = 16.0 MiB/second
16.0 MiB / 1.000 sec = 16.0 MiB/second
4.7 MiB / 1.000 sec =
4.7 MiB/second
User cancel, exiting...
Total time: 4.00070 s
hackrf_stop_tx() done
hackrf_close() done
hackrf_exit() done
123456789101112131415161718
$ hackrf_transfer -t car.iq -f
-s 8000000 -a 1 -l 30 -x 40 call hackrf_sample_rate_set(8000000 Hz/8.000 MHz)call hackrf_baseband_filter_bandwidth_set(7000000 Hz/7.000 MHz)call hackrf_set_freq( Hz/27.000 MHz)call hackrf_set_amp_enable(1)Stop with Ctrl-C16.0 MiB / 1.000 sec = 16.0 MiB/second16.0 MiB / 1.000 sec = 16.0 MiB/second16.0 MiB / 1.000 sec = 16.0 MiB/second 4.7 MiB / 1.000 sec =&&4.7 MiB/second&User cancel, exiting...Total time: 4.00070 shackrf_stop_tx() donehackrf_close() donehackrf_exit() doneexit&
注意-a 1打开HackRF的功率放大器,使最终的信号提升10dB。-l参数设置了HackRF的LNA(Low Noise Amplifier,低噪声放大器的增益),-x参数设置了HackRF的发射中频增益。在此,我们选择这些参数,以使得HackRF的发射功率适当。
然后,你就会发现遥控小车按照你刚刚录制的动作跑起来了。
另外,关于hackrf_transfer的详细情况,可以参考代码hackrf/host/hackrf-tools/src/hackrf_transfer.c。
由于HackRF最大支持20MHz的采样率,于是我们可以一次把市面上的27MHz和40MHz的遥控车同时录制。
我们选取35MHz为采样的中心。
hackrf_transfer -r both.iq -f
hackrf_transfer -t both.iq -f
-a 1 -l 30 -x 40
hackrf_transfer -r both.iq -f
-i 60&hackrf_transfer -t both.iq -f
-a 1 -l 30 -x 40 &
本章试图以浅显而直观地方式简要地介绍在软件无线电中会经常遇到的一些常用名词。
章节末提供了一个使用声卡在示波器上打字的示例,以加深读者的理解。
CW / 莫尔斯码
Morse Code,又称CW,是最古老但是也最广泛的无线电通信方式了。由于CW通信方式所占用的带宽小、抗干扰能力强。作为一种信息编码标准,摩尔斯电码拥有其他编码方案无法超越的长久生命。摩尔斯电码在海事通讯中被作为国际标准一直使用到1999年。1997年,当法国海军停止使用摩尔斯电码时,发送的最后一条消息是:所有人注意,这是我们在永远沉寂之前最后的一声呐喊!
如果你想学习莫尔斯码,最简单的方式就是在手机上装一个Morse Code练习软件,例如笔者某天晚上,于学校的操场上一边练习一边散步,走了十几圈后,就可以不加参考地发送莫尔斯码了。
在Linux系统里,xcwcp和gMFSK两个程序可以帮助你做一些简单的莫尔斯码通讯训练。
Google曾经在2012年的愚人节推出了手机的。
美国NBC电视台有一期,同样一段文字,一组人使用手机发送,另一组人使用FT817便捷式短波发信机通过摩尔斯码自动键进行收发。结果摩尔斯码组明显获胜。
顺便提一句,此刻北京市仍然可以发电报,在出西单地铁站不远,出门右转的联通营业厅。有兴趣的同学可以去体验一下。
业余无线电
业余无线电是一种在全世界非常普遍的业余爱好。喜爱业余无线电的人也被称为业余无线电爱好者或HAM,在美国大约有一百多万人,日本大约有三百万人,中国大约有二十万人,在全世界总共大约四百多万人。他们必须学习相关知识并通过所在国家的测试才能领取到业余无线电执照,同时领取政府分配给的呼号。
例如在北京,获取业余无线电执照,需要向北京市无线电协会(www.)提交申请,然后参加培训、考试和验机,最后才可以获取操作能力证书和电台执照。
<提供了全球无线电爱好者的呼号查询服务。
业余无线电爱好者完成一次通联之后,会通过卡片收寄局或邮件方式双方互送QSL卡片。
例如下图即是清华集体业余电台(BY1QH)的台址和通联卡片,摘自
无线爱好者之间通常使用一种名为Q简语的三字符缩写来提升通信效率。例如: QTH代表台址,QRP代表减小发信机功率。
通联结束后,双方会互致73表达问候。73在摩尔斯码里的表示是&#8211;&#8230; &#8230;&#8211;,是一段非常对仗的声音。
更多关于业余无线电的知识,可以参阅望京集体业余电台(BY1WJ)的网站
ISM Band 免执照频段
gMFSK是一个非常强大的Linux平台下的业余无线电调制解调软件。
需要注意的是,由于最近的Linux发行版都使用ALSA做为声卡驱动,而gMFSK目前还只能使用旧的OSS声卡驱动。
但是我们可以使用alsa-oss这个软件包提供的aoss脚本,来为gMFSK伪造出一个/dev/dsp接口出来。
sudo apt-get install alsa-oss
aoss gmfsk
sudo apt-get install alsa-oss&aoss gmfsk&
以大提琴演奏家杜普蕾(Jacqueline Mary du Pré)为主题的电影《她比烟花寂寞》(英文片名: Hilary and Jackie)中有一个细节,杜普蕾用大提琴发出DTMF声音,拔通了电话。名侦探柯南剧场版第12部《战栗的乐谱》中也有类似的桥段。
DTMF(Dual-Tone Multi-Frequency, 双音多频)的原理是键盘上的所有按键由高音部分(1209Hz, 1336Hz, 1477Hz, 1633Hz)和低音部分(697Hz, 770Hz, 852Hz, 941Hz)
sudo apt-get install multimon
aoss multimon -a DTMF
sudo apt-get install multimon&aoss multimon -a DTMF&
然后拿起手机,打开拨号键盘,按下几个声音,然后multimon便可以解析出DTMF。
进一步地,我们使用gnuradio-companion搭建一个简单的声音频谱仪,直接对话筒输入的声音进行FFT。
当手机发出2的拨号音时的频谱697Hz,1336Hz
那么,最后我们再用gnuradio-companion搭建一个简单的生成DTMF中2键的框图
值得一提有两点:
注意各个模块的端口颜色,代表了不同的数据类型。黄色表示float,搭建的时候需要做修改。
最后加入Multipy Const来减小声音的响度
然后先开启multimon,然后再执行我们的框图。multimon便解析出我们生成的2了。
另外,multimon也是一个非常有趣的项目,不止可以完成DTMF的解调,还可以完成AX.25信号的解调。此外,multimon-ng项目为multimon增加了更多的解调模式。
声卡示波器
上图中,我们使用声卡的左右声道输出分别接到示波器的X-Y两路,使得示波器显示了汉字。
示波器的X-Y模式可以理解为,把X路输入的电压值反映为示波器电子枪对于电子横向的偏转,把Y路输入的电压值反映为示波器电子枪对于电子纵向的偏转。 于是,我们只需要生成一系列X,Y的数值组合,就可以操控示波器的显示了。
我们使用画图软件生成一幅黑白图片,然后使用Python编写一段小脚本将上述图片转换成为声音。
import wave
import struct
import Image
WHITE = 255
def getImage():
im = Image.open('startest.bmp') #black and white 1000 x 270
pix = im.load() #black is 0; white is 255
print im.size
return pix
def main():
im = Image.open('startest.bmp') #black and white 1000 x 270
pix = im.load() #black is 0; white is 255
print im.size #
f = wave.open('startest.wav','w')
f.setsampwidth(2)
f.setnchannels(2)
f.setframerate(192000)
max_x = im.size[0]
max_y = im.size[1]
for i in range(im.size[0]):
for j in range(im.size[1]):
if pix[i,j] == BLACK:
x = -(65535.0 * i*1.0/max_x - 32767.0) * 0.8
y = (65535.0 * j*1.0/max_y - 32767.0) * 0.8
d = struct.pack('hh',y,x)
data.append(d)
for v in range(10): #重复10遍,以延长WAV文件时间,使效果更明显
for d in data:
f.writeframes(d)
if __name__ == "__main__":
1234567891011121314151617181920212223242526272829303132333435363738394041
import waveimport structimport Image&BLACK = 0WHITE = 255&def getImage():&&&&im = Image.open('startest.bmp') #black and white 1000 x 270&&&&pix = im.load() #black is 0; white is 255&&&&print im.size&&&&return pix&def main():&&&&im = Image.open('startest.bmp') #black and white 1000 x 270&&&&pix = im.load() #black is 0; white is 255&&&&print im.size # &&&&&f = wave.open('startest.wav','w')&&&&f.setsampwidth(2)&&&&f.setnchannels(2)&&&&f.setframerate(192000)&&&&&max_x = im.size[0]&&&&max_y = im.size[1]&&&&data = []&&&&for i in range(im.size[0]):&&&&for j in range(im.size[1]):&&&&&&&&if pix[i,j] == BLACK:&&&&&&&&&&&&x = -(65535.0 * i*1.0/max_x - 32767.0) * 0.8&&&&&&&&&&&&y = (65535.0 * j*1.0/max_y - 32767.0) * 0.8&&&&&&&&&&&&d = struct.pack('hh',y,x)&&&&&&&&&&&&data.append(d)&&&&for v in range(10): #重复10遍,以延长WAV文件时间,使效果更明显&&&&for d in data:&&&&&&&&f.writeframes(d)&&&&f.close()&&&&&&&&&if __name__ == "__main__":&&&&main()&
最后,找到一根废旧耳机,断之。把里面的导线剥出来,然后用示波器的X路表笔勾住耳机线的地和左声道,用示波器的Y路表笔勾住耳机线的地和右声道。将耳机线的另一头接到电脑的声音输出上。
TODO:接线图?
打开任意一个音频播放器,播放刚刚我们生成的WAV文件,在示波器上即可显示我们的文字。
有趣的是,当你调整音量时,示波器上显示的图形会随之进行缩放。另外,如果发现显示的文字有虚化的现象,有可能是我们生成的示波器上的点的位置变化太快,可以尝试每个采样点重复地多生成几遍。TODO: 待验证
让我们回想一下,刚刚我们做了哪些事情。我们写了一段程序,按照192kHz的采样速率,按照我们的要求生成了WAV文件里的每一个采样点。
那么,如果我们合理的选择一些点的位置,让这些点代表不同的含意,例如把示波器的屏幕等分成四个区域,点落在各区域里分别代表数字00,01,10,11。那么,我们就可以用声音来传播数字信息了。
TODO: 补充QPSK的示意图
事实上,这种思路就是通信系统里常用的QPSK(Quadrature Phase Shift Keying,正交相移键控)的方案。
更进一步,如果我们对于打出的点的精确度有足够的信心,我们可以把区域分的更多,例如分成16个区域。点落在每个区域里分别表示
1234567891011121314151617
0000000100100011010001010110011110001001101010111100110111101111&
这样,我们只需要打出一个点便可以表示更多的数据,这便是16QAM的基本想法。
实际上BPSK、QPSK、16QAM、64QAM都使用了这种想法,不过在细节上有更多关于实际通信系统实现上的考虑,例如使用改变相位的方式来打出点。
其它常用的通信概念
dB(decibel)是一个表征相对值的单位。计算方法为
$10 \times \log_{10}{(\frac{A}{B})}$
一辆卡车的重量是1000Kg,一只背包的重量是1Kg。那么卡车的重量比背包的重量大30dB
$10 \times \log_{10}{\frac{1000Kg}{1Kg}} = 30 dB $
同样,A信号的功率是100W,B信号的功率是1W。那么A信号比B信号功率大20dB
在无线通信领域里经常会遇到成千上万倍的比例,引入dB的概念之后,工程师们可以免于抄写长串0的苦恼。
同时,引入dB之后,我们可以把原来的乘法运算变成了加法运算。例如一个可以放大1000倍的功率放大器,我们可以记为30dB放大器;一个把信号衰减一半的衰减器,我们可以记为-3dB衰减器。
dBm则是将被衡量的功率值与1mW的功率进行比较,30dBm也即1W。
$30 dBm = 10 * \log_{10}{\frac{1W}{1mW}} $
在工程中经常用一些估算方法来求概略值,例如:增加3dB = 乘2倍; 减少3dB = 变成1/2 ;增加10dB =乘10倍
这样便可以直接进行快速运算来求得概略值:
(+10dB-3dB = 10/2)
+4dB= *2.5
(+10dB-6dB = 10/4)
+1dB= *1.25 (+4dB-3dB=2.5/2)
+2dB= *1.6
(+6dBm-4dBm=4/2.5=1.6)
+3dB= *2+6dB= *4&&&&(2*2)+7dB= *5&&&&(+10dB-3dB = 10/2)+4dB= *2.5&&(+10dB-6dB = 10/4)+1dB= *1.25 (+4dB-3dB=2.5/2)+2dB= *1.6&&(+6dBm-4dBm=4/2.5=1.6)&
举个例子,计算47dBm时,40dBm = $10^4$mW,再多7dBm = 5 * $10^4$mW = 50W。
以下的计算读者可以验算一下并把它记忆。
0 dBm = 1 mW
10 dBm = 10 mW
14 dBm = 25 mW
15 dBm = 32 mW
16 dBm = 40 mW
17 dBm = 50 mW
20 dBm = 100 mW
30 dBm = 1000 mW = 1W
0 dBm = 1 mW10 dBm = 10 mW14 dBm = 25 mW15 dBm = 32 mW16 dBm = 40 mW17 dBm = 50 mW20 dBm = 100 mW30 dBm = 1000 mW = 1W&
IQ采样 / 复采样
I 指的是 in-phase(同相)数据, Q指的是quadrature(正交)data (because the carrier is offset by 90 degrees)
IQ Data for dummies:
为什么直接对波形的幅度进行采样不满足要求?而一定要使用IQ采样?
硬件设计上的考虑
大部分的通讯系统都使用了调相(PM, Phase Modulation)的调制方式,但是由于硬件设计上的考虑,直接操作一个波形的相位是困难的。
为了避免直接操作波形的相位,我们使用了以下的想法:
$A\sin(2 \pi f_c t + \phi) = A\cos(\phi)\cos(2\pi f_c t) &#8211; A\sin(\phi)(2\pi f_c t)$
其中,我们令
$I = A\cos(\phi) $
$Q = A\sin(\phi) $
这其中使用了和差化积公式:
$\cos(\alpha+\beta) = \cos(\alpha)\cos(\beta) &#8211; \sin(\alpha)\sin(\beta)$
于是,要想改变$A\sin(2 \pi f_c t + \phi) $波形的相位$\phi$,我们只需要同时改变I和Q之值即可, 然后将I作为幅度乘以$\cos(2\pi f_c t)$,将Q作为幅度乘以$\sin(2\pi f_c t)$,最后将两者相加,即可完成相位的调制。
这样的做法使得硬件电路上的设计变得简单多了,把对时间的操作变为了对电压的操作,在电路中对时间的精确控制不易,但对电压的精确操作却是容易的。
在此有一个假定,我们认为所有的真实信号(也就是I)都可以被表示为 当我们取得了一组I,Q之值时,我们不只得到了我们信号的瞬时值,还知道了生成这个信号的函数:
有一点需要明确,任何发射到空中的信号或者说真实信号都是不存在虚部的。
采样率的考虑
另外,采用IQ采样可以降低每个支路的采样率,如果用幅度检波后的采样率将是其两倍,降低了对ADC(Analog to Digital Converter)的要求。
本振(LO, Local Oscillator)
本振频率,英文Local Oscillator。 就是LC振荡器。用在超外差接收机中。超外差接收机中有一个振荡器叫本机振荡器。它产生的高频电磁波与所接收的高频信号混合而产生一个差频,这个差频就是中频。如要接收的信号是900KHZ.本振频率是1365KHZ.两频率混合后就可以产生一个465KHZ或者2265KHZ的差频。接收机中用LC电路选择465KHZ作为中频信号。因为本振频率比外来信号高465KHZ所以叫超外差。
TODO: FIXME!!
$\cos(\omega_1 t) * \cos(\omega_2 t) = $ TODO
FFT(Fast Fourier Transform, 快速傅里叶变换)
GNURadio及HackRF介绍
FIXME: 参考
FIXME: 参考kickstarter的介绍
HackRF是一款由Michael Ossmann发起的开源软件无线电外设,旨在从30MHz到6GHz,于2012年从DARPA处拿了一笔经费,制作了500块测试版本Jawbreaker,并向社会分发测试。在经过用户对Jawbreaker的反馈后,作者对硬件板卡做了重新布线,改善了射频性能,这一点我们将会在后文详细讨论。 随后于日至9月4日共计35天的时间,在著名的社会化融资平台Kickstarter上,迅速地获得多达1991人的预订,共预订出价值为$602,960的HackRF One。
现在已经被gqrx和osmocom-sdr等支持
全面支持GNURadio
30MHz – 6GHz
与RTL2832U(RTLSDR)不同,HackRF可以进行发射
比USRP更廉价
最大采样率: 20 Msps (10倍于电视棒RTLSDR)
接口: High Speed USB
硬件/软件全部开源
获得了DARPA的Cyber Fast Track项目的支持
已经在KickStarter上拿到投资
测试版本Jawbreaker已经不被最新版的固件所支持。
HackRF 的硬件原理
TODO: 插图 硬件主要由以下几部分组成
RFFC5072: 混频器提供80MHz到4200MHz的本振
MAXGHz to 2.7GHz 无线宽带射频收发器
MAX5864: ADC/DAC, 22MHz采样率 8bit
LPC: ARM Cortex M4处理器, 主频204MHz
Si5351B: I2C可编程任意CMOS时钟生成器,由800MHz分频提供40MHz 50MHz 及采样时钟
MGA-8–6GHz 3V, 14 dBm 放大器
SKY13317: 20 MHz-6.0 GHz 射频单刀三掷(SP3T)开关
SKY1-6.0 GHz 射频单刀双掷(SPDT)开关
以接收过程为例,信号由天线进入后流程如下
由射频开关决定是否经由14dB的放大器进行放大
经过镜像抑制滤波器对信号进行高通或低通滤波
信号进行RFFC5072芯片混频到2.6GHz固定中频
信号送入MAX2837芯片混频到基带,输出差分的IQ信号
其间MAX2837芯片可以对信号进行带宽限制
MAX5864芯片对基带信号进行数字化后送入CPLD和单片机 TODO FIXME
CPLD干了什么?
LPC处理器将采样数据通过USB送至计算机
HackRF One针对Jawbreaker做了哪些改进
删除了板载废柴微带天线
将RFFC5072和MAX2837放入屏蔽罩内保护起来,防止外界及板上其它芯片的干扰,并试图防止静电击穿部分芯片
重新布局,使得射频连线更紧凑
实际测试过程中,我们发现Jawbreaker中由于布线问题造成的全频谱范围内1MHz为周期出现的小信号干扰,在HackRF One中完全消除。
TODO: 上对比图
本章节介绍如何在Linux环境中搭建GNURadio和HackRF的开发调试平台。
不要使用发行版自带的GNURadio软件包,因为发行版的维护者比较懒,或者说GNURadio的开发者们没有主动向发行版里发布版本。
$ wget http://www.sbrac.org/files/build-gnuradio
$ chmod +x build-gnuradio
$ ./build-gnuradio -v -ja
$ wget http://www.sbrac.org/files/build-gnuradio$ chmod +x build-gnuradio$ ./build-gnuradio -v -ja&
然后在Proceed?后面输入y回车。在Do you have SUDO privileges?提示后面依然输入y回车。
注意,执行build-gnuradio脚本的时候,不要预先使用sudo。
加入-ja的选项后,使用多核处理器的并行处理能力来编译GNURadio,加快编译速度。整个编译安装过程可能会持续2小时甚至更长的时间,取决于网络速度。因此建议使用比较快的Linux镜像源服务器。
然后build-gnuradio脚本会自动安装所需要的软件包,然后开始安装。
值得一提的是,build-gnuradio脚本会自动安装最新版本的hackrf软件。
HackRF 环境搭建
另参考/viewtopic.php?f=9&t=16
遥控小车信号解析
NOAA卫星接收
GSM信号解调
HackRF LTE-Cell-Scanner
/v_show/id_XNjc1MjIzMDEy.html
解析Pocsag Pagers
/viewtopic.php?f=9&#038;t=8
Washington DC HackRF
/2013/using-a-hackrf-to-capture-an-entire-radio-system/
There is a lot going on behind this simple looking website. Here is a high level overview of how it works, but shot me an email if you want details.
The radio signals are received using the HackRF Software Defined Radio (SDR). The SDR receives a wide swath of radio spectrum and passes it to a computer to process and decode. Using this approach, it is possible to receive all of the transmission from the radio system and decode them simultaneously. Without the SDR a separate radio receiver would be need for each channel.
In a Trunking system, one of the radio channels is set aside for to manage the assignment of radio channels to talkgroups. When someone wants to talk, they send a message on the control channel. The system then assigns them a channel and sends a Channel Grant message on the control channel. This lets the talker know what channel to transmit on and anyone who is a member of the talkgroup know that they should listen to that channel.
In order to follow all of the transmissions, this system constantly listens to and decodes the control channel. When a channel is granted to a talkgroup, the system creates a monitoring process. This process will start to process and decode the part of the radio spectrum for that channel which the SDR is already pulling in.
No message is transmitted on the control channel when a talkgroup&#8217;s conversation is over. So instead the monitoring process keeps track of transmissions and if there has been no activity for 5 seconds, it ends the recording and uploads to the webserver.
The monitoring and recording is being run off of a laptop in my apartment and uses a crappy antenna. The website is run off a VPS I have running up in the magical cloud.
The webserver is pretty simple. It is written in NodeJs. The audio is stored as WAV files and indexed using MongoDB. The server simply watches for new files being placed in a directory and then moves them and adds them to the DB. Socket.io is used to updated all of the browsers visiting the site that a new transmission has been added. See &#8211; Easy, Peasy!
解析大车的信号
/viewtopic.php?f=3&t=20 http://blog.kismetwireless.net/2013/08/playing-with-hackrf-keyfobs.html
解析FLEX信号
Kismet教程
http://blog.kismetwireless.net/2013/08/hackrf-pt-2-gnuradio-companion-and.html
船 161.975MHz or 162.025MHz
Bluetooth monitoring
wireless microphones
RFID (Radio Freq Identification)
Cellular GSM base station
GPS receiver
AM/FM Radio TX/RX, APCO-25 (USA) / TETRA (EU) Digital Radio
Digital Television (ATSC/DVB-T)
Passive radar
gr-air-modes osmocom modes_gui
-d, &#8211;dcblock Use a DC blocking filter (best for HackRF Jawbreaker) [default=False]
通过网络传输IQ数据
GNURadio模块编写示例 &#8211; 遥控小车的信号分析与生成
可以参阅http://gnuradio.org/redmine/projects/gnuradio/wiki/OutOfTreeModules
首先使用频谱仪或者查资料获知其频率在27.145MHz,所以我们取中心频率为27MHz,以8M采样率采回16M个点,时长2秒
hackrf_transfer -r car.iq -f
-s 8000000 -n
hackrf_transfer -r car.iq -f
-s 8000000 -n &
重放,注意优化它的发射增益
hackrf_transfer -t car.iq -f
-s 8000000 -a 1 -l 30 -i 30 -x 40
hackrf_transfer -t car.iq -f
-s 8000000 -a 1 -l 30 -i 30 -x 40 &
使用GNURadio对采集到的iq进行分析
控制信号分析结果
27.145MHz的遥控小车的信号大致可以认为是如下的PPM/AM波形:
PPM意为Pulse Position Modulation,脉冲位置调制
+---------+
+--------- ... -------+
12345678910
&&&&&&&&&&&&&&&&&&&&&&TIME3&&&&&&&& TIME4&&&&&&--------+&&&&+---------+&&&&+-------+&&&&+--------- ... -------+&&&&+---.....&&&&&&&&&&&&&&|&&&&|&&&&&&&& |&&&&|&&&&&& |&&&&|&&&&&&&&&&&&&&&&&&&& |&&&&|&&&&&&&&&&&&&&|&&&&|&&&&&&&& |&&&&|&&&&&& |&&&&|&&&&&&&&&&&&&&&&&&&& |&&&&|&&&&&&&&&&&&&&|&&&&|&&&&&&&& |&&&&|&&&&&& |&&&&|&&&&&&&&&&&&&&&&&&&& |&&&&|&&&&&&&&&&&&&&|&&&&|&&&&&&&& |&&&&|&&&&&& |&&&&|&&&&&&&&&&&&&&&&&&&& |&&&&|&&&&&&&&&&&&&&+----+&&&&&&&& +----+&&&&&& +----+&&&&&&&&&&&&&&&&&&&& +----+&&&&&&&&&&&&&&TIME0&&&&&&&&&&TIME0&&&&&&&&TIME0&&&&&&&&&& --&gt;|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&TIME2&&&&&&&&&&&&&&&& |&lt;---&
其中的典型值为 TIME0 = 520us TIME2 = 20ms TIME3,TIME4 = [300us,1.3ms]
TIME3的时间长度控制了小车的左右 TIME4的时间长度控制了小车的油门量
用Python生成基带进行原理验证
import struct
SAMP_RATE=8e6
TIME_TOTAL = int(1 * SAMP_RATE) #s
TIME0 = int(520e-6 * SAMP_RATE)
TIME10 = int(300e-6 * SAMP_RATE)
TIME11 = int(1.3e-3 * SAMP_RATE)
TIME2 = int(20e-3 * SAMP_RATE)
Control0 = 0 #[0,1] 0.5 = stop orientation
Control1 = 1#speed
TIME3 = (TIME11-TIME10) * Control0 + TIME10
TIME4 = (TIME11-TIME10) * Control1 + TIME10
TIME_REST = TIME2-TIME0*3-TIME3-TIME4
MIN=struct.pack('B',128)
MAX=struct.pack('B',255)
def WriteFrame(value,quantity,f):
while j & quantity:
f.write(value) #i
f.write(value) #q
def main():
f = open('w.iq','wb')
WriteFrame(MAX,1e-3*SAMP_RATE,f)
i += 1e-3*SAMP_RATE
while i & TIME_TOTAL:
WriteFrame(MIN,TIME0,f)
i += TIME0
WriteFrame(MAX,TIME3,f)
i += TIME3
WriteFrame(MIN,TIME0,f)
i += TIME0
WriteFrame(MAX,TIME4,f)
i += TIME4
WriteFrame(MIN,TIME0,f)
i += TIME0
WriteFrame(MAX,TIME_REST,f)
i += TIME_REST
if __name__ == "__main__":
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
import struct&SAMP_RATE=8e6TIME_TOTAL = int(1 * SAMP_RATE) #s&TIME0 = int(520e-6 * SAMP_RATE)TIME10 = int(300e-6 * SAMP_RATE)TIME11 = int(1.3e-3 * SAMP_RATE)TIME2 = int(20e-3 * SAMP_RATE)&Control0 = 0 #[0,1] 0.5 = stop orientationControl1 = 1#speed&TIME3 = (TIME11-TIME10) * Control0 + TIME10TIME4 = (TIME11-TIME10) * Control1 + TIME10&TIME_REST = TIME2-TIME0*3-TIME3-TIME4&MIN=struct.pack('B',128)MAX=struct.pack('B',255)&def WriteFrame(value,quantity,f):&&&&j = 0&&&&while j &lt; quantity:&&&&f.write(value) #i&&&&f.write(value) #q&&&&j += 1&def main():&&&&f = open('w.iq','wb')&&&&&i = 0&&&&WriteFrame(MAX,1e-3*SAMP_RATE,f)&&&&i += 1e-3*SAMP_RATE&&&&while i &lt; TIME_TOTAL:&&&&WriteFrame(MIN,TIME0,f)&&&&i += TIME0&&&&WriteFrame(MAX,TIME3,f)&&&&i += TIME3&&&&WriteFrame(MIN,TIME0,f)&&&&i += TIME0&&&&WriteFrame(MAX,TIME4,f)&&&&i += TIME4&&&&WriteFrame(MIN,TIME0,f)&&&&i += TIME0&&&&WriteFrame(MAX,TIME_REST,f)&&&&i += TIME_REST&&&&f.close()&&&&&&&&&if __name__ == "__main__":&&&&main()&
然后生成了w.iq的原始基带数据.
如何查看它是否正确呢?让我们打开gnuradio-companion来做出一个简单的信号流程来调试一下。
写GNURadio模块: 第二种车
信号原理分析
使用gnuradio-companion搭建AM解调,然后输出到WX GUI Scope Sink里,发现信号在27MHz是如下情形:
+----------+
+----------+
+----------+
+----------+
1234567891011
+----------+&&&& +----------+&&&& +----------+&&&& +----------+&&&& +-----+&&&& +-----+&&&&&&&&&&&&&&&&&&&&&&&&|&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&&&&&&&&|&&&& |&&&& |&&&& |&&&& |&&&&&&&&&&&&&&&& +&&&&&&&&&&+-----+&&&&&&&&&&+-----+&&&&&&&&&&+-----+&&&&&&&&&&+-----+&&&& +-----+&&&& +-...&&&&&&&&&&&&&&&&&&&& &|&lt;-&&3t&&-&gt;|&&t&&|&lt;-&&3t&&-&gt;|&&t&&|&lt;-&&3t&&-&gt;|&&t&&|&lt;-&&3t&&-&gt;|&&t&&|&&t&&|&&t&&|&&t&&|&&&&&&&& &
每个控制帧都由4个长脉冲和n个短脉冲组成
经过测试,找到n的值如下:
1档前进: n=10
2档前进: n=22
后退: n=40
1档左前: n=28
1档右前: n=34
左后: n=46
右后: n=52
12345678910
左: n=58右: n=641档前进: n=102档前进: n=22后退: n=401档左前: n=281档右前: n=34左后: n=46右后: n=52&
$ gr_modtool new remotecar
$ gr_modtool add RemoteCarIIBaseBand -t sync
GNU Radio module name identified: remotecar
Language: C++
Block/code identifier: RemoteCarIIBaseBand
Enter valid argument list, including default arguments: double samp_rate,bool run, int command
Add Python QA code? [Y/n] n
Add C++ QA code? [Y/n] n
Adding file 'RemoteCarIIBaseBand_impl.h'...
Adding file 'RemoteCarIIBaseBand_impl.cc'...
Adding file 'RemoteCarIIBaseBand.h'...
Editing swig/remotecar_swig.i...
Adding file 'remotecar_RemoteCarIIBaseBand.xml'...
Editing grc/CMakeLists.txt...
12345678910111213141516
$ gr_modtool new remotecar&$ gr_modtool add RemoteCarIIBaseBand -t syncGNU Radio module name identified: remotecarLanguage: C++Block/code identifier: RemoteCarIIBaseBandEnter valid argument list, including default arguments: double samp_rate,bool run, int commandAdd Python QA code? [Y/n] nAdd C++ QA code? [Y/n] nAdding file 'RemoteCarIIBaseBand_impl.h'...Adding file 'RemoteCarIIBaseBand_impl.cc'...Adding file 'RemoteCarIIBaseBand.h'...Editing swig/remotecar_swig.i...Adding file 'remotecar_RemoteCarIIBaseBand.xml'...Editing grc/CMakeLists.txt...&
写io_signature
在lib/RemoteCarIIBaseBand_impl.cc文件中:
RemoteCarIIBaseBand_impl::RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command)
: gr::sync_block("RemoteCarIIBaseBand",
gr::io_signature::make(0,0,0),
gr::io_signature::make(1,1,sizeof(float)))
RemoteCarIIBaseBand_impl::RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command)&&&&&&: gr::sync_block("RemoteCarIIBaseBand",&&&&&&&&&&gr::io_signature::make(0,0,0),&&&&&&&&&&gr::io_signature::make(1,1,sizeof(float)))&
添加所需变量
在lib/RemoteCarBaseBand_impl.h里加入
namespace gr {
namespace remotecar {
class RemoteCarIIBaseBand_impl : public RemoteCarIIBaseBand
double d_samp_
bool bool_
int current_
int current_
int current_sample_
RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command);
~RemoteCarIIBaseBand_impl();
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
} // namespace remotecar
} // namespace gr
12345678910111213141516171819202122232425262728293031
namespace gr {&&namespace remotecar {&&&&&class RemoteCarIIBaseBand_impl : public RemoteCarIIBaseBand&&&&{&&&& private:&&&&&&&& double d_samp_rate;&&&&&&&& bool bool_run;&&&&&&&&& int n_pre;&&&&&&&& int n_command;&&&&&&&&& int current_pre;&&&&&&&& int current_command;&&&&&&&&& int current_sample_index;&&&&& public:&&&&&&RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command);&&&&&&~RemoteCarIIBaseBand_impl();&&&&&&&// Where all the action really happens&&&&&&int work(int noutput_items,&&&&&&&&&& gr_vector_const_void_star &amp;input_items,&&&&&&&&&& gr_vector_void_star &amp;output_items);&&&&};&&&} // namespace remotecar} // namespace gr&&&&....&
整个类的生命周期内一直存在, GNURadio的调度器会调用work函数,索取noutput_items个结果
$ gr_modtool makexml RemoteCarIIBaseBand
GNU Radio module name identified: remotecar
Warning: This is an experimental feature. Don't expect any magic.
Searching for matching files in lib/:
Making GRC bindings for lib/RemoteCarIIBaseBand_impl.cc...
Overwrite existing GRC file? [y/N] y
$ gr_modtool makexml RemoteCarIIBaseBandGNU Radio module name identified: remotecarWarning: This is an experimental feature. Don't expect any magic.Searching for matching files in lib/:Making GRC bindings for lib/RemoteCarIIBaseBand_impl.cc...Overwrite existing GRC file? [y/N] y&
grc中On Off的设置
参考: gnuradio/gr-wxgui/grc/wxgui_scopesink2.xml
&name&Remotecariibaseband&/name&
&key&remotecar_RemoteCarIIBaseBand&/key&
&category&REMOTECAR&/category&
&import&import remotecar&/import&
&make&remotecar.RemoteCarIIBaseBand($samp_rate,$run, $command)&/make&
&name&Sample Rate&/name&
&key&samp_rate&/key&
&type&real&/type&
&name&Run&/name&
&key&run&/key&
&value&True&/value&
&type&bool&/type&
&name&Off&/name&
&key&False&/key&
&name&On&/name&
&key&True&/key&
&name&Command&/name&
&key&command&/key&
&type&int&/type&
&name&out&/name&
&type&float&/type&
123456789101112131415161718192021222324252627282930313233343536
&lt;block&gt;&&&lt;name&gt;Remotecariibaseband&lt;/name&gt;&&&lt;key&gt;remotecar_RemoteCarIIBaseBand&lt;/key&gt;&&&lt;category&gt;REMOTECAR&lt;/category&gt;&&&lt;import&gt;import remotecar&lt;/import&gt;&&&lt;make&gt;remotecar.RemoteCarIIBaseBand($samp_rate,$run, $command)&lt;/make&gt;&&&lt;param&gt;&&&&&lt;name&gt;Sample Rate&lt;/name&gt;&&&&&lt;key&gt;samp_rate&lt;/key&gt;&&&&&lt;type&gt;real&lt;/type&gt;&&&lt;/param&gt;&&&lt;param&gt;&&&&&lt;name&gt;Run&lt;/name&gt;&&&&&lt;key&gt;run&lt;/key&gt;&&&&&lt;value&gt;True&lt;/value&gt;&&&&&lt;type&gt;bool&lt;/type&gt;&&&&&lt;option&gt;&&&&&lt;name&gt;Off&lt;/name&gt;&&&&&lt;key&gt;False&lt;/key&gt;&&&&&lt;/option&gt;&&&&&lt;option&gt;&&&&&lt;name&gt;On&lt;/name&gt;&&&&&lt;key&gt;True&lt;/key&gt;&&&&&lt;/option&gt;&&&lt;/param&gt;&&&lt;param&gt;&&&&&lt;name&gt;Command&lt;/name&gt;&&&&&lt;key&gt;command&lt;/key&gt;&&&&&lt;type&gt;int&lt;/type&gt;&&&lt;/param&gt;&&&lt;source&gt;&&&&&lt;name&gt;out&lt;/name&gt;&&&&&lt;type&gt;float&lt;/type&gt;&&&lt;/source&gt;&lt;/block&gt;&
RemoteCarIIBaseBand_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
float *out = (float *) output_items[0];
for (int i = 0;i & noutput_ i++){
out[i] = 1.5;
// Tell runtime system how many output items we produced.
return noutput_
123456789101112131415
&&&&int&&&&RemoteCarIIBaseBand_impl::work(int noutput_items,&&&&&&&&&&&&&&gr_vector_const_void_star &amp;input_items,&&&&&&&&&&&&&&gr_vector_void_star &amp;output_items)&&&&{&&&&float *out = (float *) output_items[0];&&&&&for (int i = 0;i &lt; noutput_items; i++){&&&&&&&&&&&&out[i] = 1.5;&&&&}&&&&&// Tell runtime system how many output items we produced.&&&&return noutput_items;&&&&}&
加入基带信号生成部分
在lib/RemoteCarBaseBand_impl.cc里加入代码
RemoteCarIIBaseBand_impl::RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command)
: gr::sync_block("RemoteCarIIBaseBand",
gr::io_signature::make(0,0,0),
gr::io_signature::make(1,1,sizeof(float)))
bool_run = // output on off
d_samp_rate = samp_
n_command = // command code
n_pre = 4; // pre pulse number
current_command = 0;
current_pre = 0;
current_sample_index = 0;
RemoteCarIIBaseBand_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
float *out = (float *) output_items[0];
for (int i = 0;i & noutput_ i++){
if (bool_run) {
if (current_pre & n_pre) {
if (current_sample_index & d_samp_rate * 0.00055 * 3) {
out[i] = 1;
current_sample_index += 1;
else if (current_sample_index & d_samp_rate * 0.00055 * 4){
out[i] = 0;
current_sample_index += 1;
} else { // a long pre pulse generated.
current_sample_index = 0;
current_pre += 1;
else if (current_command & n_command) {
// 4 pre long pulse generated, then generate other short pulse.
if (current_sample_index & d_samp_rate * 0.00055 ) {
out[i] = 1;
current_sample_index += 1;
else if (current_sample_index & d_samp_rate * 0.00055 * 2){
out[i] = 0;
current_sample_index += 1;
} else { // a short command pulse generated
current_sample_index = 0;
current_command += 1;
// 1 frame generated
current_pre = 0;
current_command = 0;
current_sample_index = 0;
} else { // muted
out[i] = 0;
// Tell runtime system how many output items we produced.
return noutput_
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
RemoteCarIIBaseBand_impl::RemoteCarIIBaseBand_impl(double samp_rate,bool run, int command)&&&&&&: gr::sync_block("RemoteCarIIBaseBand",&&&&&&&&&&gr::io_signature::make(0,0,0),&&&&&&&&&&gr::io_signature::make(1,1,sizeof(float)))&&&&{&&&&bool_run = run; // output on off&&&&d_samp_rate = samp_rate; &&&&&n_command = command; // command code &&&&n_pre = 4; // pre pulse number&&&&&current_command = 0;&&&&current_pre = 0;&&&&&current_sample_index = 0;&&&&&}&&&&&...&&&&&int&&&&RemoteCarIIBaseBand_impl::work(int noutput_items,&&&&&&&&&&&&&&gr_vector_const_void_star &amp;input_items,&&&&&&&&&&&&&&gr_vector_void_star &amp;output_items)&&&&{&&&&float *out = (float *) output_items[0];&&&&&for (int i = 0;i &lt; noutput_items; i++){&&&&&&&&&&&&if (bool_run) {&&&&&&&&&&&&&&&&&&&&if (current_pre &lt; n_pre) {&&&&&&&&&&&&&&&&&&&&&&&&if (current_sample_index &lt; d_samp_rate * 0.00055 * 3) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&out[i] = 1;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index += 1;&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&else if (current_sample_index &lt; d_samp_rate * 0.00055 * 4){&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&out[i] = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index += 1;&&&&&&&&&&&&&&&&&&&&&&&&} else { // a long pre pulse generated.&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_pre += 1;&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&else if (current_command &lt; n_command) {&&&&&&&&&&&&&&&&&&&&&&&&// 4 pre long pulse generated, then generate other short pulse.&&&&&&&&&&&&&&&&&&&&&&&&if (current_sample_index &lt; d_samp_rate * 0.00055 ) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&out[i] = 1;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index += 1;&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&else if (current_sample_index &lt; d_samp_rate * 0.00055 * 2){&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&out[i] = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index += 1;&&&&&&&&&&&&&&&&&&&&&&&&} else { // a short command pulse generated&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&current_command += 1;&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&else {&&&&&&&&&&&&&&&&&&&&&&&&&&&&// 1 frame generated&&&&&&&&&&&&&&&&&&&&&&&&&&current_pre = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&current_command = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&current_sample_index = 0;&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&} else { // muted&&&&&&&&&&&&&&&&&&&&out[i] = 0;&&&&&&&&&&&&}&&&&&}&&&&&// Tell runtime system how many output items we produced.&&&&return noutput_items;&&&&}&
如果没有回调函数,那么生成的模块不能在gnuradio-companion里被WX GUI Slider实时的修改参数。
为了能够实时地控制小车,我们需要加入两个回调函数。
在lib/RemoteCarBaseBand_impl.h里加入set_run和set_command函数的声明
namespace gr {
namespace remotecar {
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
void set_run(bool run);
void set_command(int command);
} // namespace remotecar
} // namespace gr
1234567891011121314151617
namespace gr {&&namespace remotecar {&&&&&....&&&&&&&// Where all the action really happens&&&&&&int work(int noutput_items,&&&&&&&&&& gr_vector_const_void_star &amp;input_items,&&&&&&&&&& gr_vector_void_star &amp;output_items);&&&&&&void set_run(bool run);&&&&&&void set_command(int command);&&&&};&&&} // namespace remotecar} // namespace gr&&&&....&
还需要在include/remotecar/RemoteCarIIBaseBand.h加入set_run和set_command的声明
class REMOTECAR_API RemoteCarIIBaseBand : virtual public gr::sync_block
typedef boost::shared_ptr&RemoteCarIIBaseBand&
static sptr make(double samp_rate,bool run, int command);
virtual void set_run(bool run) = 0;
virtual void set_command(int command) = 0 ;
12345678910
&& class REMOTECAR_API RemoteCarIIBaseBand : virtual public gr::sync_block&&&&{&&&& public:&&&&&&typedef boost::shared_ptr&lt;RemoteCarIIBaseBand&gt; sptr;&&&&&&&static sptr make(double samp_rate,bool run, int command);&&&&&&virtual void set_run(bool run) = 0;&&&&&&virtual void set_command(int command) = 0 ;&&&&};&
在lib/RemoteCarIIBaseBand_impl.cc里加入set_run和set_command的实现
void RemoteCarIIBaseBand_impl::set_run(bool run) {
bool_run =
void RemoteCarIIBaseBand_impl::set_command(int command) {
n_command =
&&&&void RemoteCarIIBaseBand_impl::set_run(bool run) {&&&&&&&&bool_run = run;&&&&}&&&&&void RemoteCarIIBaseBand_impl::set_command(int command) {&&&&&&&&n_command = command;&&&&}&
最后,在grc/remotecar_RemoteCarIIBaseBand.xml文件里加入
&make&remotecar.RemoteCarIIBaseBand($samp_rate,$run, $command)&/make&
&callback&set_run($run)&/callback&
&callback&set_command($command)&/callback&
&&&lt;make&gt;remotecar.RemoteCarIIBaseBand($samp_rate,$run, $command)&lt;/make&gt;&&&lt;callback&gt;set_run($run)&lt;/callback&gt;&&&lt;callback&gt;set_command($command)&lt;/callback&gt;&&....&
mkdir build
cmake ../ && make && sudo make install && sudo ldconfig
mkdir buildcd buildcmake ../ &amp;&amp; make &amp;&amp; sudo make install &amp;&amp; sudo ldconfig&
然后重启gnuradio-companion即可搭建一个简单的示例来跑通小车
加入一个简单的GUI
如果觉得这样操作不舒服,我们可以用Qt写一个简单的键盘控制的方向盘。
gr_modtool 用法概览
gr_modtool newmod blahblah
gr_modtool add -t general square_ff
make test / ctest -V -R blahblah
gr_modtool add -t sync square2_ff
set_history()
input_items.size()
/ output_items.size()
Sync Interpolator
gr_modtool makexml square2_ff
forecast()
gr::sync_block, gr::sync_interpolator or gr::sync_decimator instead of gr::block
set_output_multiple() 攒够固定倍数才输出
Hierarchical Block
gr_modtool.py add -t hier hierblockcpp_ff
Delete blocks from the source tree: gr_modtool rm REGEX
Disable blocks by removing them from the CMake files: gr_modtool disable REGEX
Python: gr_modtool add -t sync -l python square3_ff
1234567891011121314151617
gr_modtool newmod blahblahgr_modtool add -t general square_ffmake test / ctest -V -R blahblahgr_modtool add -t sync square2_ffset_history()input_items.size()&&/ output_items.size()Sync Interpolatorgr_modtool makexml square2_ffforecast()gr::sync_block, gr::sync_interpolator or gr::sync_decimator instead of gr::blockset_output_multiple() 攒够固定倍数才输出Hierarchical Block&&&&gr_modtool.py add -t hier hierblockcpp_ff&&&&Delete blocks from the source tree: gr_modtool rm REGEX Disable blocks by removing them from the CMake files: gr_modtool disable REGEXPython: gr_modtool add -t sync -l python square3_ff&
HackRF硬件分析及射频指标测试
HackRF硬件分析
Product Description The RFFC5071 and RFFC5072 are re-configurable frequency conversion devices with integrated fractional-N phased locked loop (PLL) synthesizer, voltage con- trolled oscillator (VCO) and either one or two high linearity mixers. The fractional-N synthesizer takes advantage of an advanced sigma-delta modulator that delivers ultra-fine step sizes and low spurious products. The PLL/VCO engine combined with an external loop filter allows the user to generate local oscillator (LO) signals from 85MHz to 4200MHz. The LO signal is buffered and routed to the integrated RF mix- ers which are used to up/down-convert frequencies ranging from 30MHz to 6000MHz. The mixer bias current is programmable and can be reduced for applica- tions requiring lower power consumption. Both devices can be configured to work as signal sources by bypassing the integrated mixers. Device programming is achieved via a simple 3-wire serial interface. In addition, a unique programming mode allows up to four devices to be controlled from a common serial bus. This eliminates the need for separate chip-select control lines between each device and the host controller. Up to six general purpose outputs are provided, which can be used to access internal signals (the LOCK signal, for example) or to control front end components. Both devices operate with a 2.7V to 3.3V power supply
The MAX2837 direct-conversion zero-IF RF transceiver is designed specifically for 2.3GHz to 2.7GHz wireless broadband systems. The MAX2837 completely inte- grates all circuitry required to implement the RF trans- ceiver function, providing RF-to-b and baseband-to-RF transmit path, VCO, frequency synthesizer, crystal oscillator, and baseband/control interface. The device includes a fast-settling sigma- delta RF synthesizer with smaller than 20Hz frequency steps and a crystal oscillator, which allows the use of a low-cost crystal in place of a TCXO. The transceiver IC also integrates circuits for on-chip DC offset cancella- tion, I/Q error, and carrier-leakage detection circuits. Only an RF bandpass filter (BPF), crystal, RF switch, PA, and a small number of passive components are needed to form a complete wireless broadband RF radio solution. The MAX2837 completely eliminates the need for an external SAW filter by implementing on-chip monolithic filters for both the receiver and transmitter. The baseband filters along with the Rx and Tx signal paths are optimized to meet stringent noise figure and linearity specifications. The device supports up to 2048 FFT OFDM and imple- ments programmable channel filters for 1.75MHz to 28MHz RF channel bandwidths. The transceiver requires only 2μs Tx-Rx switching time, which includes frequency transient settling. The IC is available in a small, 48-pin thin QFN package measuring only 6mm x 6mm x 0.8mm.
The MAX5864 ultra-low-power, highly integrated analog front end is ideal for portable communication equipment such as handsets, PDAs, WLAN, and 3G wireless termi- nals. The MAX5864 integrates dual 8-bit receive ADCs and dual 10-bit transmit DACs while providing the high- est dynamic performance at ultra-low power. The ADCs’ analog I-Q input amplifiers are fully differential and accept 1V P-P full-scale signals. Typical I-Q channel phase matching is ±0.1° and amplitude matching is ±0.03dB. The ADCs feature 48.5dB SINAD and 69dBc spurious-free dynamic range (SFDR) at f IN = 5.5MHz and f CLK = 22Msps. The DACs’ analog I-Q outputs are fully differential with ±400mV full-scale output, and 1.4V com- mon-mode level. Typical I-Q channel phase match is ±0.15° and amplitude match is ±0.05dB. The DACs also feature dual 10-bit resolution with 71.7dBc SFDR, and 57dB SNR at f OUT = 2.2MHz and f CLK = 22MHz. The ADCs and DACs operate simultaneously or indepen- dently for frequency-division duplex (FDD) and time-divi- sion duplex (TDD) modes. A 3-wire serial interface controls power-down and transceiver modes of opera- tion. The typical operating power is 42mW at f CLK = 22Msps with the ADCs and DACs operating simultane- ously in transceiver mode. The MAX5864 features an internal 1.024V voltage reference that is stable over the entire operating power-supply range and temperature range. The MAX5864 operates on a +2.7V to +3.3V ana- log power supply and a +1.8V to +3.3V digital I/O power supply for logic compatibility. The quiescent current is 5.6mA in idle mode and 1μA in shutdown mode. The MAX5864 is specified for the extended (-40°C to +85°C) temperature range and is available in a 48-pin thin QFN package.
射频指标概述
HackRF 射频指标
最大发射功率 ~ 10dBm 64QAM发射EVM ~ 1.5% 复采样带宽 20MHz
如何使用两个HackRF
Here&#8217;s a tricky method about duplex.
If you plug in two hackrf device, hackrf_info will only show one hackrf device.
But, if you plug in one first, run something with this hackrf to occupy it. Then plug in another hackrf device, then run another program , and the &#8216;duplex&#8217; works.
f = scipy.fromfile(open("myFile.bin"), plex64)
f = scipy.fromfile(open("myFile.bin"), dtype=scipy.complex64)&
手工打造HackRF
大约需要2天造一块
如何对HackRF进行刷机
对HackRF做贡献
/mossmann/hackrf/pull/108
HackRF One外壳设计
Grid Positioning
http://gnuradio.org/redmine/projects/gnuradio/wiki/GNURadioCompanion#Grid-Positioning
message source
http://gnuradio.org/redmine/projects/gnuradio/wiki/TutorialsCoreConcepts#Streams-vs-Messages-Passing-PDUs
简单的方法: 找一个已知的FM频率,在gqrx直接修改ppm,直到该FM电台的标称频率刚好与实际值一致
kalibrate_rtl
kalibrate_rtl&
KiCAD 图形Diff
compare image1 image2 -compose src diff.png compare image1 image2 -compose src diff.pdf
另: 由pdf提取png convert example.pdf -density 300 example.png 其中300为DPI数值
经常会在FM收听时发现某台(例如103.9MHz),在103.9M+采样频率,例如103.9+8 = 111.9MHz处有一个镜像台
It looks like you&#8217;re getting the hang of it, but here is an answer to your earlier question about how to predict the bad spurs.
The IF is the intermediate frequency the MAX2837 is tuned to. The RF is the radio frequency of interest at the antenna port. The LO is the local oscillator frequency of the RFFC5072. (Technically there is another LO in the MAX2837, but it is the same frequency as IF. When I refer to LO, I am talking about the LO in the RFFC5072.)
RF = |IF+LO| or RF = |IF &#8211; LO|
Which one (the sum or the difference) depends on the configuration of the image reject filter stage.
Bad spurs occur when LO or an integer multiple of LO is within 10 MHz (or half of your baseband filter bandwidth) of RF. This happens due to leakage of the LO into the RF side of the RFFC5072.
Bad spurs occur when LO or an integer multiple of LO is within 10 MHz (or half of your baseband filter bandwidth) of IF. This happens due to leakage of the LO into the IF side of the RFFC5072.
To be safe, it is probably best to keep LO harmonics 20 MHz or further away from RF or IF. Right now our automatic tuning code (which is already fairly complicated) does not take LO leakage into account.
DC Removal
DC Blocker
osmocom source: DC OFFSET
DC Blocker
HackRF Jawbreaker性能分析
GNURadio Scheduler 调度
gcc-arm-none-eabi
HackRF开发环境搭建
gcc-arm-none-eabi
GNURadio写模块
gr-modtool
osmocom模块分析
HackRF One vs Jawbreaker
gqrx代码分析
hackrf usb代码分析
gqrx代码分析
hackrf usb代码分析
手工制造/制造工艺
QFN封装及介绍
QFN封装及介绍
osmocom source: DC OFFSET
Raspberry Pi / ARMv6h
嵌入式系统跑
Raspberry Pi / ARMv6h
ODroid /ARMv7h
ODroid /ARMv7h
kalibrate_rtl
HackRF on Android平板
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
&&&&DC Removal&&&&&&&&DC Blocker&&&&&&&&osmocom source: DC OFFSET&&&&DC Blocker&&&&&HackRF Jawbreaker性能分析&&&&GNURadio Scheduler 调度&&&&gcc-arm-none-eabi&&&&HackRF开发环境搭建&&&&&&&&gcc-arm-none-eabi&&&&&&&&DFU&&&&DFU&&&&GNURadio写模块&&&&&&&&gr-modtool&&&&osmocom模块分析&&&&HackRF One vs Jawbreaker&&&&&gqrx代码分析&&&&hackrf usb代码分析&&&&&&&&opencm3&&&&KiCAD&&&&代码分析&&&&&&&&gqrx代码分析&&&&&&&&hackrf usb代码分析&&&&&&&&&&&&opencm3&&&&SMT贴装&&&&手工制造/制造工艺&&&&&&&&KiCAD&&&&&&&&SMT贴装&&&&&&&&QFN封装及介绍&&&&&&&&PCB工艺&&&&QFN封装及介绍&&&&PCB工艺&&&&PyBombs&&&&&osmocom source: DC OFFSET&&&&rtlsdr&&&&Raspberry Pi / ARMv6h&&&&嵌入式系统跑&&&&&&&&Raspberry Pi / ARMv6h&&&&&&&&ODroid /ARMv7h&&&&ODroid /ARMv7h&&&&&kalibrate_rtl&&&&HackRF on Android平板&
RF IF 干扰
并参阅files/WhySpurExists
example: Center = 1277MHz IF = 2560MHz
1283 &# = 6
When Sampling Rate = 20M: Spur = 1283MHz = 2560 &#
When Sampling Rate = 8M: 1277 + 8/2 = 1281 & 1283 so it is sub sampling: Spur = 1277 &#8211; [ 8 &#8211; (1283 &#) ]= 1277 &#8211; 2 = 1275 M
NOTE: the spur can be filtered by MAX2837 bandwidth filter.
When Sampling Rate = 10M: 1277 + 10/2 = 1282 & 1283 sub sampling: Spur = 1277 &#8211; [10 &#8211; (1283 &#)] = 1277 &#8211; 4 = 1273
- 36,592 次阅读 - 26,016 次阅读 - 23,899 次阅读 - 22,349 次阅读 - 21,156 次阅读 - 20,690 次阅读 - 19,371 次阅读 - 15,836 次阅读 - 11,733 次阅读 - 11,015 次阅读
Recent Posts
powered by}

我要回帖

更多关于 www.6688ampj.com 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信