最近在看ofdm相关的东西,发现matlab本身也有自带的调制函数,乍一看没搞懂是怎么个用法,写这个笔记的过程中把这个函数大概搞清楚了,也顺便复习一下ofdm的调制过程。
matlab的帮助文档中描述此函数有四种语法,分别是:
1.Y=ofdmmod(X,nfft,cplen);
2.Y=ofdmmod(X,nfft,cplen,nullidx);
3.Y=ofdmmod(X,nfft,cplen,nullidx,pilotidx,pilots);
4.Y=ofdmmod(X,nfft,cplen,___,OversamplingFactor=Value;
语法1:Y=ofdmmod(X,nfft,cplen)
对于语法1,X代表子载波上携带的数据,ofdmmod采用快速傅里叶变换的方式实现正交频分复用,nfft代表快速傅里叶变换长度,cplen即cyclic prefix length 循环前缀长度。
此代码为文档中对语法1的示例,描述的是,双天线发射,16QAM调制,128子载波,循环前缀长度16,每帧传输5个ofdm符号(我不知道此处的RE为何意,故理解为帧)的情况。
M = 16; % Modulation order for 16QAM
nfft = 128; % Number of data carriers
cplen = 16; % Cyclic prefix length
nSym = 5; % Number of symbols per RE
nt = 2; % Number of transmit antennas
dataIn = randi([0 M-1],nfft,nSym,nt);
qamSig = qammod(dataIn,M,'UnitAveragePower',true);
y1 = ofdmmod(qamSig,nfft,cplen);
y1输出的是一个720×2的复数数组,(128+16 )×5=720,没有问题。
调出其中一组数据的第一个符号来看一下循环前缀的效果:
plot(abs(y1(1:128+16,1)));
xlim([1,144]);
可以看到,1:16的符号其实就是129:144的符号。
语法2:Y=ofdmmod(X,nfft,cplen,nullidx);
比语法1多了一个参数nullindx,文档的描述是:
Y = ofdmmod(X,nfft,cplen,nullidx)
inserts null subcarriers into the frequency domain input data signal prior to performing OFDM modulation. The null subcarriers are inserted at index locations from 1 tonfft
, as specified bynullidx
. For this syntax, the number of rows in the inputX
must benfft
–length(
. Use null carriers to account for guard bands and DC subcarriers.nullidx
)
在进行OFDM调制之前在频域输入信号中插入空子载波,插入的位置可以是索引1到nfft(这里直译过来就是这样,其实我不太懂啥意思,看下面)。此时,输入的X行数长度必须为nfft-length(nullidx)。这些空载波是用来放置保护频带或是直流载波的。
给的代码是这样的:
M = 16; % Modulation order for 16QAM
nfft = 64; % FFT length
cplen = 16; % Cyclic prefix length
nSym = 10; % Number of symbols per RE
nullIdx = [1:6 33 64-4:64]';
numDataCarrs = nfft-length(nullIdx);
inSym = randi([0 M-1],numDataCarrs,nSym);
qamSig = qammod(inSym,M,'UnitAveragePower',true);
outSig = ofdmmod(qamSig,nfft,cplen,nullIdx);
16QAM调制,fft长度64,循环前缀16,每帧10个ofdm符号。
值得注意的是,根据代码中对子载波数据numDataCarrs的描述,此时nfft应该不是子载波个数,而是进行ifft的长度了,进行了ifft处理的数据除了16QAM符号应该还包含其他东西,也就保护间隔或直流载波。nullidx是为保护间隔和直流载波占了位置,在这里还没有加入数据。
因此这句语法对应的处理效果可以画图表示成这样:
语法3:Y=ofdmmod(X,nfft,cplen,nullidx,pilotidx,pilots);
又多了两个参数,pilotidx和pilots,很好理解,就是导频的位置和导频信号本身。
Y = ofdmmod(X,nfft,cplen,nullidx,pilotidx,pilots)
inserts null and pilot subcarriers into the frequency domain input data symbols prior to performing OFDM modulation. The null subcarriers are inserted at the index locations specified bynullidx
. The pilot subcarriers,pilots
, are inserted at the index locations specified bypilotidx
. For this syntax, the number of rows in the inputX
must benfft
–length(
–nullidx
)length(
. The function assumes pilot subcarrier locations are the same across each OFDM symbol and transmit antenna.pilotidx
)
和上面那个差不多,在频域插入了空载波和导频载波。前面提到空载波是为保护间隔和直流载波预留的,所以在这里,pilotidx和nullidx是两组数组,并不是包含关系。也就是除了前面的空载波外,又插入了一组空载波,但是新插入的空载波是用来放置导频信号的。相应的,QAM信号的长度又得削减一点,也就对应了导频的加入对信号造成了额外开销。最后一句话说,这个函数他就只能设置一种导频放置位置,如果像第一个例子中那种有俩天线发射,对不起,你们导频的位置一样。
同样地,看一下例子:
M = 16; % Modulation order
nfft = 64; % FFT length
cplen = 16; % Cyclic prefix length
nSym = 10; % Number of symbols per RE
nullIdx = [1:6 33 64-4:64]';
pilotIdx = [12 26 40 54]';
numDataCarrs = nfft-length(nullIdx)-length(pilotIdx);
dataSym = randi([0 M-1],numDataCarrs,nSym);
qamSig = qammod(dataSym,M,UnitAveragePower=true);
pilots = repmat(pskmod((0:3).',4),1,nSym);
y2 = ofdmmod(qamSig,nfft,cplen,nullIdx,pilotIdx,pilots);
在pilotidx处又加了导频之后be like:
但是这个图只是一个ofdm信号,要知道一帧里面是传输了10个ofdm信号的,并且通常是构建一个10列(nSym)的二维数组来表示一帧的,所以实际上应该是这样的一个图:
这也说明了为啥上面的pilot要进行repmat操作了。
语法4: Y=ofdmmod(X,nfft,cplen,___,OversamplingFactor=Value;
在前面这些语法的基础上,又给出了上采样因子这个参数,该值必须为正标量,也可以是分数。默认情况下上采样因子值为1。但是要注意不要四舍五入,例如对FFT长度为12的信号进行4/3上采样,结果本来应该是获得16个信号。如果这里输入写的不是4/3而是1.333,那么会报错,因为这么算的话应该输出15.9960个信号,这是不可能的。
给的示例代码是这个:
M = 64; % Modulation order
osf = 3; % Oversampling factor
nfft = 256; % FFT length
cplen = 16; % Cyclic prefix length
nullidx = [1:6 nfft/2+1 nfft-5:nfft]';
numDataCarrs = nfft-length(nullidx);
x = randi([0 M-1],numDataCarrs,1);
qamSig = qammod(x,M,UnitAveragePower=true);
y = ofdmmod(qamSig,nfft,cplen,nullidx,OversamplingFactor=osf);
运行了一下,竟然报错了:
数据长度、空载波长度和导频长度加起来不等于FFT长度;但是代码内是用fft长度减去空载波长度来定义数据长度的,不应该报这个错。我觉得和上采样因子的引入有关,于是把这一项去掉之后运行了一下代码,是没有问题的。
语法4中和报错中都提到了导频,但在此例子中我们并没有设置导频。
但是我加入导频之后仍然报错,显示输入参数过多。
这个问题目前还没有解决,欢迎大家探讨。