在上一篇文章中,已经生成了一串封装好的二进制数据包。如果我们有声卡,或者有SDR终端,则可以着手让数据播放/发射出去了。
0,1是一个离散的值,而声卡的声强,SDR(如USRP B210)TX口的无线电磁波的功率,都是一个模拟的、连续的值。要用这种模拟量表示数字量,需要引入调制技术。当然,在接收方,也需要把声强或者感应电压转化为01, 此类过程叫做解调。调制与解调是专门的一门子学科,里面的理论背景很深,而且很多算法与衔接的纠错技术是一体化设计的,在这里很难搞深入了。
但一切复杂的事物,总有简单的一面。在最初的有线电传时代,曾经直接用摩尔斯类似的滴滴声表示01,或者用有无声音表示01. 这个实验里,我们使用前后两个时刻声音大小的起伏表示01.
差分幅度键控是使用前后两个时刻的电压的大小关系表示0或者1. 如果V0 > V1,则表示1,否则表示0. 这种调制方式被古老的飞机ADS-B收发机采用。在没有噪声的情况下,前后两个时刻必然有一个时刻有电平,另一个时刻无电平。但因为存在噪声,绝对的0V或者0mW的测量值是不可能达到的,因此主要采用比较大小的方法,而不是比较绝对的门限。
如,序列 0 1 1 0 ,表示为DASK波形,生成的各个时刻的理论值是这样的:
| 时刻: | 时刻0 | 时刻1 | 时刻2 | 时刻3 | 时刻4 | 时刻5 | 时刻6 | 时刻7 |
|---|---|---|---|---|---|---|---|---|
| 功率: | 0mW | 3mW | 3mW | 0mW | 3mW | 0mW | 0mW | 3mW |

不过,到了实验现场,还有一些因素需要考虑。AD/DA(数字-模拟,模拟-数字)过程中主要注意以下几个小问题。
有过《信号系统》背景知识的同学肯定知道,上述冲击波形的频谱是很宽的。经过SDR器件后,带宽一般都会限定在一定的范围内。即使实验中不考虑成型滤波的问题主动地降低带宽,硬件本身的通道滤波带来的影响也很可观。这种限制带来的特点直观上就是这些陡峭的冲击值变成了类似SINC函数的曲线。

由于SDR器件默认的波形是交流的,均值位于0mv处。我们产生的波形,如果只含有0,3这种正值,就会产生直流分量。为了避免这种问题,使用0,3,-3这样的值,来产生均值为0的波形。

时刻0,时刻1间隔多少合适呢?这取决于器件的性能,以及计算机的性能。间隔越短,1秒能发送的数据越多,当然对器件的要求也更高。一般的SDR、声卡都有采样率的限制。比如声卡的采样率是9600Hz,则1秒内,最多只能传输9600个功率值。USRP B210可以传输56M个采样点,但是要考虑接收方的处理压力。
一秒能够传输的状态个数,单位是波特,Bd。选择调制速率,不但要考虑发射通道的能力,更要考虑接收处理的压力。在接收处理时,由于接收通道的时间轴和发射通道不是同步的,因此,在A/D时,选择的时刻很可能和咱们发射波形的时刻是错开的。如果用很低的速率来采样,如果运气不好,采集到的就是如下蓝色的位置:
所以,一般都会采用比调制速率高的倍数采样率,比如4倍、5倍、15倍等, 得到类似下图的波形:

要保证主能量峰值上要有3-4个采样点为佳。这样,选择一个调制速率M,还要保证N倍的速率要能够满足接收方的处理计算极限K。
M N < K MN < K MN<K
所以,调制速率不能设置的太大。
在发射时,理论上可以直接使用发射速率M发射,用接收速率 MN接收。但是,由于M,MN这两个速率具有的公因数不同,导致SDR设备可能无法确切的工作在其中某些速率上。如M=300KHz,最接近的工作点为266.66666KHz,会造成困扰。在本次实验里,接收、发射都使用确切的、相同的采样率;在发射时,使用倍率补零的方式变相降低调制速率。
同时,为了有效限制带宽,采用汉明窗取代冲击进行成型,效果也很好,代码如下:
static const short hamm[15] = {2560, 4018, 8102,14004,20556,26458,30542,32000,30542,26458,20556,14004, 8102, 4018, 2560};
static const short phe[4][2] = {{1,1},{-1,1},{-1,-1},{1,-1}};
tag_tx_plain plan;
plan.tmstmp.frag = 0;
plan.tmstmp.sec = 0;
plan.length_left = packagedta.size() * 2 * 15;
std::vector<short> signal;
for (int i=0;i<packagedta.size();++i)
{
const short ni = phe[i % 4][0];
const short nq = phe[i % 4][1];
if (packagedta[i])
{
//1:15
for (int j=0;j<15;++j)
{
signal.push_back(hamm[j]*ni);
signal.push_back(hamm[j]*nq);
}
for (int j=0;j<15;++j)
{
signal.push_back(0);
signal.push_back(0);
}
}
else
{
for (int j=0;j<15;++j)
{
signal.push_back(0);
signal.push_back(0);
}
for (int j=0;j<15;++j)
{
signal.push_back(hamm[j]*ni);
signal.push_back(hamm[j]*nq);
}
}
}


相关代码和工程参考gitcode.