本节主要介绍了一维CFAR的基本原理以及它的MATLAB仿真与Verilog硬件实现的思路。
一维CFAR的基本原理
- 毫米波雷达中,CFAR(Constant False Alarm Rate)算法是一种常用的目标检测和跟踪算法。它的主要作用是在背景噪声(杂波)中检测出目标信号,同时保证误检概率不变。
- CFAR算法的步骤如下:
- 确定检测窗口的大小和形状,例如矩形、圆形等。
- 在检测窗口内计算信号功率的平均值和方差,可以使用不同的方法来计算,例如对数变换、线性平均、动态平均等。
- 将检测窗口划分为若干个子窗口,每个子窗口的大小和形状可以根据实际应用进行调整。
- 根据期望的误检概率和背景噪声的统计特性,计算每个子窗口的阈值,例如高斯分布下的阈值可以通过计算高斯分布的概率密度函数得到。
- 对于每个子窗口,比较信号功率与阈值的大小关系,判断该子窗口内是否存在目标信号。
- 对于检测到的目标信号,可以进行后续的处理和跟踪,例如目标分离、速度估计等。
- CFAR算法分为两类:一类是均值类CFAR(CA-CFAR)算法,该类算法应用的前提是假设背景杂波是均匀分布的;另一类是有序统计类CFAR(OS-CFAR)算法,这类算法是为了应对邻域内多目标情况而设计的
- 我的理解就是一个滑动窗口,其在不断滤波,类似深度学习中的卷积(但不一样,只是都是滤波的感觉)
1.均值类CFAR
$$ \alpha =N(P_{FA}^{-\frac 1N}-1),P_{FA}为虚警概率 $$1.1 CA-CFAR
1 | function [ index, XT ] = cfar_ca( xc, N, pro_N, PAD) |
1.2 GO-CFAR
1 | function [ index, XT ] = cfar_go( xc, N, pro_N, PAD) |
1.3 SO-CFAR
1 | function [ index, XT ] = cfar_so( xc, N, pro_N, PAD) |
2.统计类CFAR
2.1 OS-CFAR
1 | function [ index, XT ] = cfar_os( xc, N, k, pro_N, PAD) |
CFAR算法的MATLAB建模
1 | % 函数名:CFAR_1D_Compute |
CFAR算法的Verilog硬件实现
1.基本思路
目前还只是初步优化思路,还没考虑量化以及参数可配置的问题,后续有时间再继续优化
其大致思路是通过时钟计数,并对计数器进行判断,从而对数据进行不同的计算,此外,数据是进到保护单元长度的时候就开始计算
首先,在时序电路中得想明白一个事,也就是我们在抓取寄存器输出的值时,它总是在时钟上升沿结束之后才更新的,所以我们在时钟上升沿开始去抓取数据时,只能抓取到旧值,只有在再下一个时钟时,才能抓取到上一个时钟更新的值
同理,可推导出在第12个时钟上升沿到来时,有:
当cnt>11时,则可以进行加一个新移进来的数以及减一个最旧的数的操作了。对了,同样,还是得寄存左窗口最旧的那个值
此外,需要设置一个完成标志位,其意味着所有窗口左右两侧的和均算出
- 简单计算一下:
- 在cnt == 11时,第一个滑窗左右的和被计算出
- 此后每个周期都能计算出一此和,这里先不考虑补零问题,那么意味着还需要做100-10-1 = 89次cfar
- 故当cnt == 11+89(即100时),所有滑窗求和均算出,此时将finished标志位置高
- 简单计算一下:
而最终二者左基本单元和右基本单元的求和计算,会晚一个时钟周期计算出来,道理其实与前面解释的一样,获取时序电路的输出再计算,均会导致晚一个周期,而不是立马被计算出来
2.源代码
CA_cfar.v
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132module CA_cfar #(
parameter N_reg = 11
)(
input clk,
input rst,
input start, //启动信号
input [6:0] SF, //输入的FFT后的频谱幅度
input [4:0] alpha, //与cfar后Z值相乘的alpha
output [8:0] XT, //最终阈值
output reg finished //一次cfar完成的标志位
);
integer i, j;
reg [6:0] shift_reg [N_reg - 1 : 0]; //这里的shift_reg右边的位宽实际代表N_reg
reg [6:0] Ncount; //时钟计数
reg [6:0] temp; //寄存左侧窗口移出的值
//移位寄存器实现
always @(posedge clk or negedge rst) begin
if(~rst) begin
for(i = 0; i < N_reg - 1; i = i + 1) begin
shift_reg[i] <= 0;
end
temp <= 0;
end
else if(start) begin
for(i = 0; i < N_reg - 1; i = i + 1) begin
shift_reg[i] <= 0;
end
temp <= 0;
end
else begin
for(j = 0; j < N_reg - 1; j = j + 1) begin
shift_reg[j + 1] <= shift_reg[j];
end
shift_reg[0] <= SF;
end
end
//时钟计数器
always @(posedge clk or negedge rst) begin
if(~rst) begin
Ncount <= 0;
end
else if(start) begin
Ncount <= 0;
end
else begin
Ncount <= Ncount + 1;
end
end
reg valid_flag; //数据全部移进来的标志信号
always @(posedge clk or negedge rst) begin
if(~rst) begin
valid_flag <= 0;
end
else begin
if(Ncount == 11) begin
valid_flag <= 1;
end
else begin
valid_flag <= 0;
end
end
end
//计算完成标志位
always @(posedge clk or negedge rst) begin
if(~rst) begin
finished <= 0;
end
else begin
if(Ncount == 100) begin
finished <= 1;
end
else begin
finished <= 0;
end
end
end
//加法求和
//1.左侧
reg [8:0] Adder_left;
always @(posedge clk or negedge rst) begin
if(~rst) begin
Adder_left <= 9'b0;
end
else begin
if(Ncount == 4) begin
Adder_left <= shift_reg[0] + shift_reg[1] + shift_reg[2] + shift_reg[3];
temp <= shift_reg[3];
end
if(Ncount > 11) begin
Adder_left <= Adder_left + shift_reg[7] - temp;
temp <= shift_reg[10];
end
end
end
//2.右侧
reg [8:0] Adder_right;
always @(posedge clk or negedge rst) begin
if(~rst) begin
Adder_right <= 9'b0;
end
else begin
if(Ncount == 11) begin
Adder_right <= shift_reg[0] + shift_reg[1] + shift_reg[2] + shift_reg[3];
end
if(Ncount > 11) begin
Adder_right <= Adder_right + shift_reg[0] - shift_reg[4];
end
end
end
//左右两侧求和
reg [9:0] sum_mean;
always @(posedge clk or negedge rst) begin
if(~rst) begin
sum_mean <= 10'b0;
end
else if(start) begin
sum_mean <= 10'b0;
end
else begin
sum_mean <= Adder_left + Adder_right;
end
end
endmodule
3.Testbench
CA_cfar_tb.v
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
module CA_cfar_tb;
reg clk;
reg rst;
reg start;
reg [6:0] SF;
reg [4:0] alpha;
wire [8:0] XT;
wire finished;
CA_cfar #(.N_reg(11)) ca_U1(
.clk(clk),
.rst(rst),
.start(start),
.SF(SF),
.alpha(alpha),
.XT(XT),
.finished(finished)
);
initial clk = 1;
always #(`CLOCK_PERIOD/2) clk = ~clk;
initial begin
rst = 0;
start = 0;
#21 rst = 1;
#20 start = 1;
#10 start = 0;
end
reg [6:0] dataI[99:0];
initial begin
$readmemb("D:\\App_Data_File\\Vivado_data\\Vivado_project\\DSP_design\\CFAR_project\\cfar_test_data.txt",dataI);
end
reg [6:0] ncount;
always @(posedge clk or negedge rst) begin
if(~rst) begin
ncount <= 7'b0;
end
else if(start) begin
ncount <= 0;
end
else begin
ncount <= ncount + 1;
end
end
always @(*) begin
if(~rst) begin
SF <= 7'b0;
end
else begin
if(ncount < 100) begin
SF = dataI[ncount];
end
else begin
SF = 7'b0;
end
end
end
endmodule结果如下:
4.更新
- 目前一维CFAR可以做到CA、GO、SO、OS四种CFAR可选、保护单元和基本单元可调,等项目结束后将有偿提供代码,着急需要代码的可邮箱联系(2024.3.22)