Costas环的设计与实现

最近浩哥给我布置了一个FPGA实现QPSK解调的任务,其中最重要的一步便是载波同步——Costas环技术的实现,老大也基于了一些思想上的指导。已经布置了好长时间了,不能让老大失望。

载波同步中的性能参数

  • 同步带(Hold range)
    在锁定状态下,缓慢地改变输入信号频率来增加固有频差,若环路随着频差增大而最终失锁,那么失锁时对应的最大固有频差成为同步带。
    同步带是环路可以维持静态相位跟踪的频偏范围,锁相环路在此范围内可以保持静态的条件稳定。同步带代表了锁相环的静态稳定极限。
  • 快捕带(Lock range)
    锁相环不经过跳周而达到锁定的最大固有频差称为快捕带。
  • 失锁带(Pull-out range)
    如果锁相环的输入信号的频率阶跃超过一定范围,那么锁相环将失锁,这个频率的范围称为失锁带。
  • 捕获带(Pull-in range)
    在锁相环初始时刻就处于失锁状态的情况下,环路最终能锁定的最大固有频差成为锁相环的捕获带。只要环路失锁时的频偏在这一范围里,环路总会再次锁定,但时间可能会很长。
  • 捕获时间(Pull-in time)
    环路从某个起始状态频差开始,经历周期跳跃达到频率锁定所需的时间。即初始频差在锁相环的捕获带内,锁相环从失锁状态到锁定状态所需的时间。
  • 快捕时间(Lock time)
    环路从某个起始状态频差开始,不经历周期跳跃达到频率锁定所需的时间。即初始频差在锁相环的快捕带内,锁相环从失锁状态到锁定状态所需的时间。

  • 环路前置带宽 $B_i$ 通常需要计算输入端叠加的高斯白噪声的带宽,即$N_0 B_i$

  • 环路单边噪声带宽 $B_L$
    对于理想二阶环,$B_L$的计算方法是:
    $$ B_L=\frac{\omega_n}{8\xi}(1+4\xi^2) $$

  • 环路自然角频率 $\omega_n$
    $\omega_n$的值越小,环路锁定时的信噪比条件越低,环路更容易在恶劣的条件下锁定,并且锁定之后的稳态相差越小。
    $\omega_n$的值越大,环路的快捕带越宽,捕获约迅速。

注:此节引用lifejustdoit的博客

参数的计算

  • 环路滤波器的系数
    $$ C_1 = \dfrac{2\xi\omega_n T}{K} $$
    $$ C_2 = \dfrac{(\omega_n T)^2}{K} $$
    其中环路自然角频率$\omega_n$
    $$ \begin{equation}\begin{split}
    \omega_n &= \dfrac{8\xi(S/N)_i B_i}{(S/N)_L(1+4\xi^2)}
    \end{split}
    \end{equation}
    $$

Costas环实现框图

环路滤波器模型

$$H(z)=C_1 + \dfrac{C_2 z^{-1}}{1-z^{-1}}$$

matlab 仿真

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
clear;clc
%% 设置参数
load('lpf.mat','Num');
fs = 50e6; %采样频率
sim_time = 0.05; %仿真时长
real_fc = 1000050; %实信号载波频
local_fc = 10000; %初始本地振荡频率
SampleBit_len = 8;
LocalBit_len = 8;
DDS_PhaseBit_len = 32;

C1 = power(2,-31);
C2 = power(2,-15);

t = 1 / fs : 1 / fs : sim_time;
sampled_data = sin(2 * pi * real_fc * t) ;
Data_length = length(sampled_data);

%变量申请空间
% DDS_CtrlWord= zeros(1,Data_length);
% DDS_Phase = zeros(1,Data_length);
% nco_cos = zeros(1,Data_length);
% nco_sin = zeros(1,Data_length);

t = power(2,DDS_PhaseBit_len);

% for k = 1 : Data_length - 1

% DDS_CtrlWord(k) = 1024;

% nco_sin(k) = sin(2 * pi * DDS_Phase(k) / t);

% nco_cos(k) = cos(2 * pi * DDS_Phase(k) / t);

% DDS_Phase(k+1) = DDS_Phase(k) + DDS_CtrlWord(k);

% end
% lpf_out_i = zeros(1,length(Num));
% lpf_out_q = zeros(1,length(Num));
mult_i = zeros(1,Data_length + length(Num));
mult_q = zeros(1,Data_length + length(Num));

DDS_Phase = 0;

figure;

for k = 1 : Data_length - 1

% DDS_CtrlWord = 1024;

nco_sin = sin(2 * pi * DDS_Phase / t) * power(2,LocalBit_len);

nco_cos = cos(2 * pi * DDS_Phase / t) * power(2,LocalBit_len);

mult_i(k + length(Num) - 1) = nco_sin * sampled_data(k);

mult_q(k + length(Num) - 1) = nco_sin * sampled_data(k);

lpf_out_i = mult_i(k + length(Num) - 1 : -1 : k) * Num';

lpf_out_q = mult_q(k + length(Num) - 1 : -1 : k) * Num';

PhaseDetect = lpf_out_i * lpf_out_q;

LoopFilter_out = PhaseDetect;

DDS_CtrlWord = LoopFilter_out;

DDS_Phase = DDS_Phase + DDS_CtrlWord;
end
0%