概述了数字变频的数学原理与实际使用情况,使用Matlab仿真,先构造频域连续的宽带信号模拟基带数字信号,如果利用傅里叶反变换构造了时域信号用于仿真.文章给出了仿真代码与结果图.

前言

在无线通信中,数据由核心网下传至基站,基站经过处理后变成电磁信号对外发送,最后到达用户端。在基站中,核心网下发的未被处理过的数字信号被称为基带信号。基带信号通常是零频宽/窄带信号。基带信号的采样率较低,不能满足射频发射的要求,所以基带信号往往经过滤波和内插转换成高采样率,从而调制到中频载波频率上.
此时若基站接收到两路不同的基带信号,则无法做模拟上变频到同一频段,因为从频谱上看两个基带信号频谱叠加了,相互干扰。若使用两个频段对外发送则过于浪费频谱资源了。在同一空间内,通信信道是有限的,因此需要在模拟上变频之前先做数字上变频,将两路基带信号调制到一起,成为在频谱上连续的基带信号后,做模拟上变频,调制到中高频后对外发送。这样就只会占用一条中频带,节约了无线资源。

具体可以看这篇博客[4G&5G专题-9]:RRU 数字上变频DUC与数字下变频DDC

数字上变频(DUC)数学原理

数字上变频本质是是将一个处于零频的宽带信号搬移至高于零频的频段。原理上就是信号的调制,数学原理可以参考:通信系统中的调制解调

从公式上看频谱搬移可以通过时域中的信号乘以一个单音信号实现,公式如下:
$$
y(t) = x(t)*cos(\omega_1t)
$$

其中$x(t)$为需要调制的信号,假设也为一个单音信号$sin(\omega_0t)$则:
$$
\begin{align}
y(t) &= sin(\omega_0t) * cos(\omega_1t) \nonumber\\
&= \frac{sin(\omega_0+\omega_1)+cos(\omega_0-\omega_1)}{2} \nonumber
\end{align}
$$
由上可以得出频谱搬移后会出现镜像分别为$\omega_0+\omega_1$和$\omega_0-\omega_1$这两个频率上。但在基带处理中基带信号一般为IQ信号,因此用于调制的信号也该是个复数信号。
所以有

$$
y(t) = x(t)*e^{j2\pi f_0 t}
$$

其中

  • $x(t)$是基带信号
  • $e^{j2\pi f_0 t}$是复指数信号,可以看作载波信号。
  • $f_0$是搬移的频率,决定了搬移的幅度和方向。

复指数信号的时域表达式为:

$$
e^{j2\pi f_0 t} = \cos(\omega_1t) + j \sin(\omega_1t)
$$

因此从时域上看:
$$
y(t) = x(t) * [cos(\omega_1t)+jsin(\omega_1t)]
$$

假设基带信号为单音信号,其时域上三角函数表达式为:

$$
x(t)=cos(\omega_0t)+jsin(\omega_0t)
$$

则时域的频谱搬移可以由下表示:
$$ \begin{align}
y(t) &= [cos(\omega_0t)+jsin(\omega_0t)]*[cos(\omega_1t)+jsin(\omega_1t)] \nonumber\\
&=[cos(\omega_0t)cos(\omega_1t)-sin(\omega_0t)sin(\omega_1t)]+j[cos(\omega_0t)sin(\omega_1t)+sin(\omega_0t)cos(\omega_1t)] \nonumber\\
&=cos[(\omega_0+\omega_1)t]+jsin[(\omega_0+\omega_1)t] \nonumber
\end{align}
$$
由上面的计算可以看出原信号被搬移到了$\omega_0+\omega_1$上,若想得到位于$\omega_0-\omega_1$的信号则对IQ信号做差运算即可因为在FPGA中基带信号的实部和虚部是存在不同的变量中,可以单独拿出来做运算。复数在变换完成后可以只留下一个频率,这对我们基带处理带来了很大的便利。

Matlab模拟

建立基带时域信号

基带信号一般为零频的宽带或窄带信号,一开始的想法是利用不同频率的正弦波时域叠加构造宽带信号,但是傅里叶变换以后的叠加信号在频域上不连续。于是我反着来,先构建连续的频谱,然后用傅里叶反变换得到时域信号。

首先创建一个长度为$N$的全0行向量,然后将带宽内的元素全部赋值为1.

1
2
spectrum = zeros(1, N);
spectrum(f <= bandwidth) = 1;

我们得到了一个在索引值小于bandwidth时值全为1的行向量,可以认定为信号频谱。于是可以构建两个这样的不同带宽的频谱如下图:

宽带信号

接着为了得到时域信号我们对其做傅里叶反变换,然后再做傅里叶变换得到时域信号的频谱(觉得麻烦这步可以省略):

1
2
signal = ifft(spectrum);
signal_fft = fft(signal);

做傅里叶变换后,在高频会出现镜像,我们舍弃掉高频的部分的数据只讨论基带信号本身。
然后将代码简单假工一下做成函数方便一会调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function y = broadband(varargin)
p = inputParser; % 函数的输入解析器
p.addParameter('fs',1000); % 设置变量名和默认参数
p.addParameter('T',1); % 设置变量名和默认参数
p.addParameter('bandwidth',50); % 设置变量名和默认参数
p.parse(varargin{:}); % 对输入变量进行解析,如果检测到前面的变量被赋值,则更新变量取值

% 生成频谱
N = p.Results.fs*p.Results.T; % 信号长度
f = linspace(0, p.Results.fs, N); % 频率范围
spectrum = zeros(1, N);
spectrum(f <= p.Results.bandwidth) = 1; % 在带宽内设置频谱幅度为1
% 生成时域信号
signal = ifft(spectrum);
%傅里叶变换
signal_fft = fft(signal);

y.fft = signal_fft(1:end/2);
y.f=f(1:end/2);
y.real = signal;
y.t=linspace(0, p.Results.T, N);
y.n=N;
end

建立载波时域信号

直接生成特定频率的正弦波即可,注意为了一会与基带信号进行运算,要保证生成的信号长度与基带信号相同。函数代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function y = wave_init(varargin)
p = inputParser; % 函数的输入解析器
p.addParameter('fs',1000); % 设置变量名和默认参数
p.addParameter('L',1000); % 设置变量名和默认参数
p.addParameter('a1',0); % 设置变量名和默认参数
p.addParameter('f1',0); % 设置变量名和默认参数
p.parse(varargin{:}); % 对输入变量进行解析,如果检测到前面的变量被赋值,则更新变量取值

% 定义参数
T = 1/p.Results.fs; % 采样间隔
t = (0:p.Results.L-1)*T; % 时间向量

% 生成正弦波信号
reslut = p.Results.a1*sin(2*pi*p.Results.f1*t);
temp_fft=abs(fft(reslut));
f = linspace(0, p.Results.fs, p.Results.L); % 频率范围

y.fft = temp_fft(1:end/2);
y.f = f(1:end/2);
y.real = reslut;
y.t = t;
end

值得注意,这里是直接使用正弦信号进行快速傅里叶变换,傅里叶变换会将信号从时域转换到频域,得到频谱。频谱是一个复数,包含幅度和相位信息。取绝对值操作后,我们得到了频谱的幅度,这表示了在不同频率下信号的能量分布情况,当然也可以直接对信号进行平方运算,我们就可以的得到信号在频域上的能量分布情况,对信号的功率谱密度进行分析。利用以上函数构造两个频率为100Hz和130Hz的载波信号。

频谱搬移

根据前文的计算,想要实现频谱搬移需要将基带信号与载波信号相乘。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
% 宽带信号
wave_0 = broadband('fs',1000,'T',1,'bandwidth',30);
wave_1 = broadband('fs',1000,'T',1,'bandwidth',50);

%载波信号
c_wave = wave_init('a1',1,'f1',100);
c_wave_1 = wave_init('a1',1,'f1',130);

% 搬移
s_wave = c_wave.real.*wave_0.real;
s_wave_fft = abs(fft(s_wave));

s_wave_1 = c_wave_1.real.*wave_1.real;
s_wave_fft_1 = abs(fft(s_wave_1));

随后我们再将调制波时域上相加,即可得到一个宽带信号。

1
2
wave = s_wave + s_wave_1;
wave_fft = abs(fft(wave));

若不进行搬移直接叠加会发生干扰,信号无法解调,如图:

这是主函数调试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
figure(1);

% 宽带信号
wave_0 = broadband('fs',1000,'T',1,'bandwidth',30);
wave_1 = broadband('fs',1000,'T',1,'bandwidth',50);

%载波信号
c_wave = wave_init('a1',1,'f1',100);
c_wave_1 = wave_init('a1',1,'f1',130);

% 搬移
s_wave = c_wave.real.*wave_0.real;
s_wave_fft = abs(fft(s_wave));

s_wave_1 = c_wave_1.real.*wave_1.real;
s_wave_fft_1 = abs(fft(s_wave_1));

wave = s_wave + s_wave_1;
wave_fft = abs(fft(wave));

% s_wave_2 = wave_0.real + wave_1.real;
% s_wave_2_fft = abs(fft(s_wave_2));
% subplot(1,1,1);
% plot(wave_0.f, s_wave_2_fft(1:end/2));
% title("叠加频谱");

subplot(7,1,1);
plot(wave_0.f, wave_0.fft);
title("信号α频谱");

subplot(7,1,2);
% subplot(2,1,2);
plot(wave_1.f, wave_1.fft);
title("信号β频谱");

subplot(7,1,3);
plot(c_wave.f, c_wave.fft);
title("载波频谱i");

subplot(7,1,4);
plot(c_wave.f, c_wave_1.fft);
title("载波频谱ii");

subplot(7,1,5);
plot(c_wave.f, s_wave_fft(1:end/2));
title("调制波(α*i)频谱");

subplot(7,1,6);
plot(c_wave.f, s_wave_fft_1(1:end/2));
title("调制波(β*ii)频谱");

subplot(7,1,7);
plot(c_wave.f, wave_fft(1:end/2));
title("调制波叠加((α*i)+(β*ii))频谱");