基于FPGA的混沌信号发生器系统介绍:
由于模拟电路元器件的参数会受温度、老化等环境原因影响,而混沌系统又是对初始值极度敏感的系统,因此使用模拟电路实现混沌系统的效果非常有限。而数字电路不存在器件温度、老化问题,器件参数不会影响其结果,实现效果较模拟电路更加理想,故现阶段使用数字点路实现混沌系统成为主流。目前有两种实现方法,一种是基于欧拉算法、龙格库塔的离散算法编写底层硬件代码实现混沌系统,另外一种是使用Matlab 的DSP BUILDER库搭建混沌数字电路,自动生成verilog代码。两种方法各有优点,前者设计更加灵活但编程复杂,后者不需要编程但往往受器件约束。本文详细介绍了使用的四阶龙格库塔算法实现混沌系统过程,实现了一个具有隐藏多稳态吸引子的混沌系统发生器。图1.1是该系统的整体硬件框架。PC端根据算法使用quartus II EDA软件编写硬件代码并生成下载文件,通过下载器下载至 CycloneⅣ的EP4CE10F17C8N FPGA核心板,FPGA控制并输送数字信息给ACM9767DAC模块,由该模块生成模拟信号再输送给示波器显示。
以洛伦兹系统为例,使用改进的欧拉算法实现 ,有不足的地方还望指正
module chaos_4D(
clk,
rst_n,
x,
y,
z
);
input clk;
input rst_n;
output signed [31:0]x,y,z;
parameter t= 12;//时间1/2^12
reg signed [31:0] x_0 = 32'b0_00000_00000100000000000000000000; //初始值,由定点数表示一位符号位,五位整数位和26位小数位,初始值已经被压缩
reg signed [31:0] y_0 = 32'b0_00000_00000010000000000000000000; //y_0=0
reg signed [31:0] z_0 = 32'b0_00000_00000010000000000000000000; //z_0=0
reg signed [31:0] c = 32'b0_00010_10101010101010101010101011; //8/3
reg signed [31:0] xz_extend_6;//比例压缩,由于怕计算过程内部出现比五位整数位大的数,导致内部计算溢出,x,y,z都压缩64。例如dx = xy +z,将x,y,z压缩64,原=原式变换为d64x = 64x*64y +64z等价于dx=32xy+z;即n项式要乘于32^(n-1)
reg signed [31:0] xy_extend_6;//同上
reg signed [31:0] fx ;//改进欧拉算法中间值
reg signed [31:0] fy ;
reg signed [31:0] fz ;
reg signed [31:0] x_n_temp ;//计算的中间值,用来存储x_n的值
reg signed [31:0] y_n_temp ;
reg signed [31:0] z_n_temp ;
reg signed [31:0] x_n ;//计算的中间值
reg signed [31:0] y_n ;
reg signed [31:0] z_n ;
reg signed [31:0] fx_temp ;//改进欧拉算法的中间值
reg signed [31:0] fy_temp ;
reg signed [31:0] fz_temp ;
reg [2:0]state;
reg cnt;
reg flag;
parameter s0=3'd0,
s1=3'd1,
s2=3'd2,
s3=3'd3;
wire signed [63:0]xz_64;//两个32位的数相乘是64位
wire signed [63:0]xy_64;
wire signed [63:0]cz_64;
wire signed [31:0]ay;//用移位寄存器来计算整数乘
wire signed [31:0]ax;
wire signed [31:0]bx;
wire signed [31:0]xz;/对xz_64位数进行截取后的结果
wire signed [31:0]xy;
wire signed [31:0]cz;
wire signed [31:0]x_temp;//结果,由于可能为负数,一般加上一个正数后才输出,保证输出全为正数
wire signed [31:0]y_temp;
wire signed [31:0]z_temp;
assign ay = (y_n<<<3) + (y_n<<<1);//y*a //移位寄存器来进行乘10操作
assign ax = (x_n <<< 3) + (x_n<<<1) ; //x*a 同时
assign bx = (x_n <<< 5) - (x_n <<< 2) ; // b*x//移位寄存器来进行乘28操作,先乘32减去乘4
assign xz_64 = x_n * z_n;//乘法
assign xy_64 = x_n * y_n;
assign cz_64 = c * z_n;
assign xz = {xz_64[63],xz_64[56:26]} ;//截取规则为保留符号位,摒弃低26位小数位(可忽略)和高6位整数位(一般做了压缩后,都是为0)
assign xy = {xy_64[63],xy_64[56:26]} ;
assign cz = {cz_64[63],cz_64[56:26]} ;
always@(posedge clk or negedge rst_n)
if(!rst_n)//复位
begin
flag <= 1;
xz_extend_6 <= 0;
xy_extend_6 <= 0;
fx <= 0;
fy <= 0;
fz <= 0;
x_n_temp <= 0;
y_n_temp <= 0;
z_n_temp <= 0;
x_n <= x_0;
y_n <= y_0;
z_n <= z_0;
fx_temp <= 0;
fy_temp <= 0;
fz_temp <= 0;
cnt <= 0;
state <= 0;
end
else
begin
case(state)
s0:begin
xz_extend_6 <= xz <<< 6; //乘64
xy_extend_6 <= xy <<< 6; //乘64
state <= state +1'b1;
flag <= 0;
end
s1:begin
fx <=-ax+ay;
fy <= -xz_extend_6 + bx - y_n ;
fz <= -cz + xy_extend_6;//改进欧拉第一步操作,根据cnt的值对fx,fy,fz进行更新
if( cnt == 1 )//若已完成两步操作,进入到最后一步
begin
state <= state + 2'd2 ;
cnt <= 0;
end
else//进入到下一步操作
state <= state + 1'b1 ;
end
s2:begin
x_n_temp <= x_n;//保存x_n的值
y_n_temp <= y_n;
z_n_temp <= z_n;
x_n <= x_n + (fx>>>(t-1));//对x_n进行关于改进欧拉算法的计算
y_n <= y_n + (fy>>>(t-1));
z_n <= z_n + (fz>>>(t-1));
cnt <= 1;
fx_temp <= fx;//保存fx的值
fy_temp <= fy;
fz_temp <= fz;
state <= s0;
end
s3:begin
x_n <= x_n_temp + (fx>>>t) + (fx_temp>>>t);//改进欧拉算法的结果
y_n <= y_n_temp + (fy>>>t) + (fy_temp>>>t);
z_n <= z_n_temp + (fz>>>t) + (fz_temp>>>t);
state <= s0;
flag <= 1;
end
default:
begin
x_n <= x_0;
y_n <= y_0;
z_n <= z_0;
state <= s0;
end
endcase
end
assign x_temp= (flag)?x_n:x_temp;//flag为1,x_n才能作为有效输出,其余时候都是中间值
assign y_temp= (flag)?y_n:y_temp;
assign z_temp= (flag)?z_n:z_temp;
assign x = x_temp+ 32'b0000_0100_0000_0000_0000_0000_0000_0000;//加个1保证输出为正
assign y = y_temp+ 32'b0000_0100_0000_0000_0000_0000_0000_0000;
assign z = z_temp+ 32'b0000_0100_0000_0000_0000_0000_0000_0000;
endmodule
//tb文件
`timescale 1ns/1ns
`define clock_period 20
module gaijin_euler_tb;
reg clock;
reg Rst_n;
wire [31:0]x,y,z;
wire [11:0]x_n,y_n,z_n;
assign x_n = x[27:16];
assign y_n = y[27:16];
assign z_n = z[27:16];
chaos_4D fourD0(
.clk(clock),
.rst_n(Rst_n),
.x(x),
.y(y),
.z(z)
);
integer handle_x,handle_y,handle_z;
integer i;
initial
begin
handle_x = $fopen("data_x.txt");
handle_y = $fopen("data_y.txt");
handle_z = $fopen("data_z.txt");
//handle_w = $fopen("data_w.txt");
end
initial clock = 1'b1;
always #(`clock_period/2) clock = ~clock;
initial
begin
Rst_n = 1'b0;
#(`clock_period*20+1)
Rst_n = 1'b1;
for(i=0;i<400000;i=i+1'b1)
begin
#(`clock_period)
begin
$fdisplay(handle_x,"%d",x);//将数据保存为txt文件,十六进制格式的数据,可以通过matlab观察相位图
$fdisplay(handle_y,"%d",y);
$fdisplay(handle_z,"%d",z);
// $fdisplay(handle_w,"%d",w);
end
end
$stop;
end
endmodule