BLE 學習筆記_1(CORDIC演算法)
在BLE的物理層實現中,會發現在調製解調的過程中上變頻,下變頻以及混頻等操作需要將訊號和正弦訊號(餘弦訊號)做乘積,這就需要在晶片裡實現一個數字訊號發生器模組(DDS),假設這些部分都透過模擬來實現,在BLE receiver端還需要根據I Q訊號來計算相位值,即進行反三角函式運算(arctan)。在一些不怎麼關係memory資源的片子中,查表法是一個很實用的方法,效率高且簡單。但是有些片子的memory資源不是那麼的豐富,這就需要利用CORDIC演算法來實現了。
CORDIC演算法的核心原理是透過將
旋轉角度 #FormatImgID_1# 分成多個連續的小偏轉角,透過逐次搖擺逼近目標旋轉角度的過程
。如圖所示:
目標旋轉過程
從向量(x1,y1)旋轉到(x2,y2)的過程可以表示為:
(1)
對上式提取公因式:
(2)
CORDIC演算法將目標的旋轉角度變為如下形式:
(3)
上式中的
表示旋轉的方向,另外為了硬體的實現簡單,令:
則公式(2)可以表示為:
(4)
上式中
稱為縮放因子,N趨於無窮大的時候,該值接近於0。607253。因此在硬體上實現的時候可以採用常數表示。因此,CORDIC演算法在硬體上實現的核心公式如下所示:
(5)
至此,我們就可以編寫程式碼來驗證CORDIC演算法了,這裡我用matlab編寫了基於CORDIC的訊號發生器程式碼和相位計算程式碼。
首先驗證DDS產生一個餘弦波:
DDS
在看下相位計算:
arctan cal
其matlab程式碼分別如下:
dds:
function
cosa
=
dds_cordic
(
angle,Iterate
)
if
angle
<
-
pi
/
2
||
angle
>
pi
/
2
if
angle
<
0
cosa
=
dds_cordic
(
angle
+
pi
,
Iterate
);
else
cosa
=
dds_cordic
(
angle
-
pi
,
Iterate
);
end
cosa
=
-
cosa
;
% v = -v; % flip the sign for second or third quadrant
return
end
% Iterate = 16;%迭代次數
x
=
zeros
(
Iterate
+
1
,
1
);
y
=
zeros
(
Iterate
+
1
,
1
);
z
=
zeros
(
Iterate
+
1
,
1
);
x
(
1
)
=
0。607253
;
%初始設定
z
(
1
)
=
angle
;
%待求角度θ
for
i
=
1
:
Iterate
if
z
(
i
)
>
=
0
d
=
1
;
else
d
=
-
1
;
end
x
(
i
+
1
)
=
x
(
i
)
-
d
*
y
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
y
(
i
+
1
)
=
y
(
i
)
+
d
*
x
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
z
(
i
+
1
)
=
z
(
i
)
-
d
*
atan
(
2
^
(
-
(
i
-
1
)));
end
cosa
=
x
(
Iterate
+
1
);
end
arctan:
function
arctan
=
arctan_cordic
(
sin_data,cos_data,Iterate
)
% Iterate = 16;%迭代次數
x
=
zeros
(
Iterate
+
1
,
1
);
y
=
zeros
(
Iterate
+
1
,
1
);
z
=
zeros
(
Iterate
+
1
,
1
);
x
(
1
)
=
cos_data
;
y
(
1
)
=
sin_data
;
k
=
0。607253
;
for
i
=
1
:
Iterate
if
y
(
i
)
>
=
0
d
=
-
1
;
else
d
=
1
;
end
x
(
i
+
1
)
=
x
(
i
)
-
d
*
y
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
y
(
i
+
1
)
=
y
(
i
)
+
d
*
x
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
z
(
i
+
1
)
=
z
(
i
)
-
d
*
atan
(
2
^
(
-
(
i
-
1
)));
end
arctan
=
z
(
Iterate
+
1
);
end
要注意的是arctan函式的輸入必須限制在第一和第四象限,如果不在的話要旋轉變換過來。
編寫完matlab程式碼後我們就可以考慮用FPGA去實現了。我這裡編寫了一個pipeline實現的CORDIC演算法來實現DDS的功能,程式碼如下:
`timescale
1
ns
/
1
ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2020/06/19 15:22:59
// Design Name:
// Module Name: cordic_dds_pipe_line
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0。01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module
cordic_dds_pipe_line
(
input
clk
,
input
rst_n
,
input
phase_vaild
,
input
signed
[
32
-
1
:
0
]
phase
,
output
reg
cordic_vaild
,
output
signed
[
32
-
1
:
0
]
cordic_cos_data
);
//51471 30385 16054 8149 4090 2047 1023 511 255 127 63 31 15 7 3 1
`define arctan1 32‘d51471
// floor(arctan(2^(0)) * 2^16)
`define arctan2 32’d30385
// floor(arctan(2^(-1)) * 2^16)
`define arctan3 32‘d16054
// floor(arctan(2^(-2)) * 2^16)
`define arctan4 32’d8149
// floor(arctan(2^(-3)) * 2^16)
`define arctan5 32‘d4090
// floor(arctan(2^(-4)) * 2^16)
`define arctan6 32’d2047
// floor(arctan(2^(-5)) * 2^16)
`define arctan7 32‘d1023
// floor(arctan(2^(-6)) * 2^16)
`define arctan8 32’d511
// floor(arctan(2^(-7)) * 2^16)
`define arctan9 32‘d255
// floor(arctan(2^(-8)) * 2^16)
`define arctan10 32’d127
// floor(arctan(2^(-9)) * 2^16)
`define arctan11 32‘d63
// floor(arctan(2^(-10)) * 2^16)
`define arctan12 32’d31
// floor(arctan(2^(-11)) * 2^16)
`define arctan13 32‘d15
// floor(arctan(2^(-12)) * 2^16)
`define arctan14 32’d7
// floor(arctan(2^(-13)) * 2^16)
`define arctan15 32‘d3
// floor(arctan(2^(-14)) * 2^16)
`define arctan16 32’d1
// floor(arctan(2^(-15)) * 2^16)
parameter
K
=
32
‘d39796
;
//K=floor(0。607253*2^16)
reg
signed
[
32
-
1
:
0
]
x_0
,
y_0
,
z_0
;
reg
signed
[
32
-
1
:
0
]
x_1
,
y_1
,
z_1
;
reg
signed
[
32
-
1
:
0
]
x_2
,
y_2
,
z_2
;
reg
signed
[
32
-
1
:
0
]
x_3
,
y_3
,
z_3
;
reg
signed
[
32
-
1
:
0
]
x_4
,
y_4
,
z_4
;
reg
signed
[
32
-
1
:
0
]
x_5
,
y_5
,
z_5
;
reg
signed
[
32
-
1
:
0
]
x_6
,
y_6
,
z_6
;
reg
signed
[
32
-
1
:
0
]
x_7
,
y_7
,
z_7
;
reg
signed
[
32
-
1
:
0
]
x_8
,
y_8
,
z_8
;
reg
signed
[
32
-
1
:
0
]
x_9
,
y_9
,
z_9
;
reg
signed
[
32
-
1
:
0
]
x_10
,
y_10
,
z_10
;
reg
signed
[
32
-
1
:
0
]
x_11
,
y_11
,
z_11
;
reg
signed
[
32
-
1
:
0
]
x_12
,
y_12
,
z_12
;
reg
signed
[
32
-
1
:
0
]
x_13
,
y_13
,
z_13
;
reg
signed
[
32
-
1
:
0
]
x_14
,
y_14
,
z_14
;
reg
signed
[
32
-
1
:
0
]
x_15
,
y_15
,
z_15
;
reg
signed
[
32
-
1
:
0
]
x_16
,
y_16
,
z_16
;
reg
[
17
-
1
:
0
]
cordic_en
;
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
cordic_en
<=
17
’d0
;
end
else
begin
cordic_en
<=
{
cordic_en
[
17
-
2
:
0
],
phase_vaild
};
end
end
reg
[
32
-
1
:
0
]
phase_r
;
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
phase_r
<=
32
‘d0
;
end
else
begin
phase_r
<=
phase
;
end
end
// 0次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_0
<=
32
’d0
;
y_0
<=
32
‘d0
;
z_0
<=
32
’d0
;
end
else
if
(
cordic_en
[
0
])
begin
x_0
<=
K
;
y_0
<=
32
‘d0
;
z_0
<=
phase_r
;
end
end
// 1次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_1
<=
32
’d0
;
y_1
<=
32
‘d0
;
z_1
<=
32
’d0
;
end
else
if
(
cordic_en
[
1
])
begin
x_1
<=
(
!
z_0
[
32
-
1
]
)
?
(
x_0
-
(
y_0
))
:
(
x_0
+
(
y_0
));
y_1
<=
(
!
z_0
[
32
-
1
]
)
?
(
y_0
+
(
x_0
))
:
(
y_0
-
(
x_0
));
z_1
<=
(
!
z_0
[
32
-
1
]
)
?
(
z_0
-
`arctan1
)
:
(
z_0
+
`arctan1
);
end
end
// 2次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_2
<=
32
‘d0
;
y_2
<=
32
’d0
;
z_2
<=
32
‘d0
;
end
else
if
(
cordic_en
[
2
])
begin
x_2
<=
(
!
z_1
[
32
-
1
]
)
?
(
x_1
-
(
y_1
>>
1
))
:
(
x_1
+
(
y_1
>>
1
));
y_2
<=
(
!
z_1
[
32
-
1
]
)
?
(
y_1
+
(
x_1
>>
1
))
:
(
y_1
-
(
x_1
>>
1
));
z_2
<=
(
!
z_1
[
32
-
1
]
)
?
(
z_1
-
`arctan2
)
:
(
z_1
+
`arctan2
);
end
end
// 3次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_3
<=
32
’d0
;
y_3
<=
32
‘d0
;
z_3
<=
32
’d0
;
end
else
if
(
cordic_en
[
3
])
begin
x_3
<=
(
!
z_2
[
32
-
1
]
)
?
(
x_2
-
(
y_2
>>
2
))
:
(
x_2
+
(
y_2
>>
2
));
y_3
<=
(
!
z_2
[
32
-
1
]
)
?
(
y_2
+
(
x_2
>>
2
))
:
(
y_2
-
(
x_2
>>
2
));
z_3
<=
(
!
z_2
[
32
-
1
]
)
?
(
z_2
-
`arctan3
)
:
(
z_2
+
`arctan3
);
end
end
// 4次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_4
<=
32
‘d0
;
y_4
<=
32
’d0
;
z_4
<=
32
‘d0
;
end
else
if
(
cordic_en
[
4
])
begin
x_4
<=
(
!
z_3
[
32
-
1
]
)
?
(
x_3
-
(
y_3
>>
3
))
:
(
x_3
+
(
y_3
>>
3
));
y_4
<=
(
!
z_3
[
32
-
1
]
)
?
(
y_3
+
(
x_3
>>
3
))
:
(
y_3
-
(
x_3
>>
3
));
z_4
<=
(
!
z_3
[
32
-
1
]
)
?
(
z_3
-
`arctan4
)
:
(
z_3
+
`arctan4
);
end
end
// 5次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_5
<=
32
’d0
;
y_5
<=
32
‘d0
;
z_5
<=
32
’d0
;
end
else
if
(
cordic_en
[
5
])
begin
x_5
<=
(
!
z_4
[
32
-
1
]
)
?
(
x_4
-
(
y_4
>>
4
))
:
(
x_4
+
(
y_4
>>
4
));
y_5
<=
(
!
z_4
[
32
-
1
]
)
?
(
y_4
+
(
x_4
>>
4
))
:
(
y_4
-
(
x_4
>>
4
));
z_5
<=
(
!
z_4
[
32
-
1
]
)
?
(
z_4
-
`arctan5
)
:
(
z_4
+
`arctan5
);
end
end
// 6次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_6
<=
32
‘d0
;
y_6
<=
32
’d0
;
z_6
<=
32
‘d0
;
end
else
if
(
cordic_en
[
6
])
begin
x_6
<=
(
!
z_5
[
32
-
1
]
)
?
(
x_5
-
(
y_5
>>
5
))
:
(
x_5
+
(
y_5
>>
5
));
y_6
<=
(
!
z_5
[
32
-
1
]
)
?
(
y_5
+
(
x_5
>>
5
))
:
(
y_5
-
(
x_5
>>
5
));
z_6
<=
(
!
z_5
[
32
-
1
]
)
?
(
z_5
-
`arctan6
)
:
(
z_5
+
`arctan6
);
end
end
// 7次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_7
<=
32
’d0
;
y_7
<=
32
‘d0
;
z_7
<=
32
’d0
;
end
else
if
(
cordic_en
[
7
])
begin
x_7
<=
(
!
z_6
[
32
-
1
]
)
?
(
x_6
-
(
y_6
>>
6
))
:
(
x_6
+
(
y_6
>>
6
));
y_7
<=
(
!
z_6
[
32
-
1
]
)
?
(
y_6
+
(
x_6
>>
6
))
:
(
y_6
-
(
x_6
>>
6
));
z_7
<=
(
!
z_6
[
32
-
1
]
)
?
(
z_6
-
`arctan7
)
:
(
z_6
+
`arctan7
);
end
end
// 8次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_8
<=
32
‘d0
;
y_8
<=
32
’d0
;
z_8
<=
32
‘d0
;
end
else
if
(
cordic_en
[
8
])
begin
x_8
<=
(
!
z_7
[
32
-
1
]
)
?
(
x_7
-
(
y_7
>>
7
))
:
(
x_7
+
(
y_7
>>
7
));
y_8
<=
(
!
z_7
[
32
-
1
]
)
?
(
y_7
+
(
x_7
>>
7
))
:
(
y_7
-
(
x_7
>>
7
));
z_8
<=
(
!
z_7
[
32
-
1
]
)
?
(
z_7
-
`arctan8
)
:
(
z_7
+
`arctan8
);
end
end
// 9次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_9
<=
32
’d0
;
y_9
<=
32
‘d0
;
z_9
<=
32
’d0
;
end
else
if
(
cordic_en
[
9
])
begin
x_9
<=
(
!
z_8
[
32
-
1
]
)
?
(
x_8
-
(
y_8
>>
8
))
:
(
x_8
+
(
y_8
>>
8
));
y_9
<=
(
!
z_8
[
32
-
1
]
)
?
(
y_8
+
(
x_8
>>
8
))
:
(
y_8
-
(
x_8
>>
8
));
z_9
<=
(
!
z_8
[
32
-
1
]
)
?
(
z_8
-
`arctan9
)
:
(
z_8
+
`arctan9
);
end
end
// 10次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_10
<=
32
‘d0
;
y_10
<=
32
’d0
;
z_10
<=
32
‘d0
;
end
else
if
(
cordic_en
[
10
])
begin
x_10
<=
(
!
z_9
[
32
-
1
]
)
?
(
x_9
-
(
y_9
>>
9
))
:
(
x_9
+
(
y_9
>>
9
));
y_10
<=
(
!
z_9
[
32
-
1
]
)
?
(
y_9
+
(
x_9
>>
9
))
:
(
y_9
-
(
x_9
>>
9
));
z_10
<=
(
!
z_9
[
32
-
1
]
)
?
(
z_9
-
`arctan10
)
:
(
z_9
+
`arctan10
);
end
end
// 11次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_11
<=
32
’d0
;
y_11
<=
32
‘d0
;
z_11
<=
32
’d0
;
end
else
if
(
cordic_en
[
11
])
begin
x_11
<=
(
!
z_10
[
32
-
1
]
)
?
(
x_10
-
(
y_10
>>
10
))
:
(
x_10
+
(
y_10
>>
10
));
y_11
<=
(
!
z_10
[
32
-
1
]
)
?
(
y_10
+
(
x_10
>>
10
))
:
(
y_10
-
(
x_10
>>
10
));
z_11
<=
(
!
z_10
[
32
-
1
]
)
?
(
z_10
-
`arctan11
)
:
(
z_10
+
`arctan11
);
end
end
// 12次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_12
<=
32
‘d0
;
y_12
<=
32
’d0
;
z_12
<=
32
‘d0
;
end
else
if
(
cordic_en
[
12
])
begin
x_12
<=
(
!
z_11
[
32
-
1
]
)
?
(
x_11
-
(
y_11
>>
11
))
:
(
x_11
+
(
y_11
>>
11
));
y_12
<=
(
!
z_11
[
32
-
1
]
)
?
(
y_11
+
(
x_11
>>
11
))
:
(
y_11
-
(
x_11
>>
11
));
z_12
<=
(
!
z_11
[
32
-
1
]
)
?
(
z_11
-
`arctan12
)
:
(
z_11
+
`arctan12
);
end
end
// 13次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_13
<=
32
’d0
;
y_13
<=
32
‘d0
;
z_13
<=
32
’d0
;
end
else
if
(
cordic_en
[
13
])
begin
x_13
<=
(
!
z_12
[
32
-
1
]
)
?
(
x_12
-
(
y_12
>>
12
))
:
(
x_12
+
(
y_12
>>
12
));
y_13
<=
(
!
z_12
[
32
-
1
]
)
?
(
y_12
+
(
x_12
>>
12
))
:
(
y_12
-
(
x_12
>>
12
));
z_13
<=
(
!
z_12
[
32
-
1
]
)
?
(
z_12
-
`arctan13
)
:
(
z_12
+
`arctan13
);
end
end
// 14次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_14
<=
32
‘d0
;
y_14
<=
32
’d0
;
z_14
<=
32
‘d0
;
end
else
if
(
cordic_en
[
14
])
begin
x_14
<=
(
!
z_13
[
32
-
1
]
)
?
(
x_13
-
(
y_13
>>
13
))
:
(
x_13
+
(
y_13
>>
13
));
y_14
<=
(
!
z_13
[
32
-
1
]
)
?
(
y_13
+
(
x_13
>>
13
))
:
(
y_13
-
(
x_13
>>
13
));
z_14
<=
(
!
z_13
[
32
-
1
]
)
?
(
z_13
-
`arctan14
)
:
(
z_13
+
`arctan14
);
end
end
// 15次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_15
<=
32
’d0
;
y_15
<=
32
‘d0
;
z_15
<=
32
’d0
;
end
else
if
(
cordic_en
[
15
])
begin
x_15
<=
(
!
z_14
[
32
-
1
]
)
?
(
x_14
-
(
y_14
>>
14
))
:
(
x_14
+
(
y_14
>>
14
));
y_15
<=
(
!
z_14
[
32
-
1
]
)
?
(
y_14
+
(
x_14
>>
14
))
:
(
y_14
-
(
x_14
>>
14
));
z_15
<=
(
!
z_14
[
32
-
1
]
)
?
(
z_14
-
`arctan15
)
:
(
z_14
+
`arctan15
);
end
end
// 16次迭代計算
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
x_16
<=
32
‘d0
;
y_16
<=
32
’d0
;
z_16
<=
32
‘d0
;
end
else
if
(
cordic_en
[
16
])
begin
x_16
<=
(
!
z_15
[
32
-
1
]
)
?
(
x_15
-
(
y_15
>>
15
))
:
(
x_15
+
(
y_15
>>
15
));
y_16
<=
(
!
z_15
[
32
-
1
]
)
?
(
y_15
+
(
x_15
>>
15
))
:
(
y_15
-
(
x_15
>>
15
));
z_16
<=
(
!
z_15
[
32
-
1
]
)
?
(
z_15
-
`arctan16
)
:
(
z_15
+
`arctan16
);
end
end
// 迭代結束
assign
cordic_cos_data
=
x_16
;
always
@(
posedge
clk
or
negedge
rst_n
)
begin
if
(
!
rst_n
)
begin
cordic_vaild
<=
0
;
end
else
begin
cordic_vaild
<=
(
cordic_en
[
16
])
?
1
:
0
;
end
end
endmodule
模擬結果如下所示:
當輸入相位’d51471和‘d34314的時候分別輸出的cos值為:’d46340和‘d56758。我們在到matlab中進行量化驗證一下:
%% FPGA test
Iterate
=
16
;
%迭代次數
x
=
zeros
(
Iterate
+
1
,
1
);
y
=
zeros
(
Iterate
+
1
,
1
);
z
=
zeros
(
Iterate
+
1
,
1
);
% x(1) = 0。607253;%初始設定
x
(
1
)
=
39796
;
%K=floor(0。607253*2^16)
% z(1) = 51471; % floor((pi/4)*2^16);%待求角度θ
z
(
1
)
=
34314
;
for
i
=
1
:
Iterate
if
z
(
i
)
>
=
0
d
=
1
;
else
d
=
-
1
;
end
x
(
i
+
1
)
=
x
(
i
)
-
d
*
y
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
y
(
i
+
1
)
=
y
(
i
)
+
d
*
x
(
i
)
*
(
2
^
(
-
(
i
-
1
)));
z
(
i
+
1
)
=
z
(
i
)
-
d
*
(
Quat_atan
(
i
));
end
cosa
=
x
(
Iterate
+
1
)
real_cosa
=
cosa
/
2
^
16
結果如下:
和FPGA計算的數值基本一樣。
值得注意的是需要控制好輸入的象限,不然會出錯的。
參考文獻
[1]陳志強。 基於CORDIC演算法的BLE4。0發射機數字基帶的設計與實現[D]。東南大學,2016