首先还是把握大的系统框架:
我要实现的部分不包括DA以及AD的转换,主要是将SSP接收到的数据送入到FIFO中,然后经过FIR带通滤波器的处理后对该信号计算幅值并做PSD,然后处理的信号经过积分够一方面送入到FIFO一方面进行均值滤波(实际上就是在一定的积分门时间内做累加操作)。最后结果通过通信模块RS232 送入到上位机,此外信号源2经过缓冲放大然后AD转换后送入到FIFO,也是通过RS232送入到上位机。
二次谐波幅值计算
先计算二次谐波幅值。
二次谐波的计算主要利用的是正余弦信号的周期性;信号经FIR带通滤波后主要含有8kHz的二次谐波,可用公式表示为
(4.5.1)
其中,是二次谐波幅值,,
将各次采样的点编号为1,2,3,4,5,6,7,8,那么这8采样的表达式的相位之间满足相差90度
A/D转换器的采样频率为64kHz而二次谐波频率为8kHz,即一个周期采样8个点,所以有
A0^2+A2^2=A^2,而且A1^2+A3^2=A^2;
通过40次定时中断采样40个点,32阶的FIR带通滤波器滤波后的最后8个点作为计算二次谐波幅值的数据点,因此可求得二次谐波幅值实际上就是这8次采样点的数据分别平方求和以后开根号,然后除以2(右移一位)来实现的
检波与积分反馈
在调试试验阶段预先调整好传感器输出信号与定时器匹配输出的8kHz检波信号同相(通过设置定时器计数器的初值),而设计的FIR带通滤波器不改变8kHz二次谐波的相位,在以后的测量中通过检波程序判断这两个信号是否还同相,就可知道所测信号的方向。
具体检波过程:在二次谐波的一个周期8个点内,找出最大值x[count],如果对应的检波信号c[count]为1(同相)则信号为正,如果c[count]为0(反相)则信号为负。
系统的积分是对每次计算出的二次谐波幅值进行累加求和。本系统反馈的是8K的幅值。假定幅值也是有正负的,当通过检波判断信号为正时幅值也为正,反之为负。每循环一次,计算一次二次谐波幅值,接着进行累加,然后把累加量通过D/A转换器反馈出去,直至使二次谐波幅值小于一个很小的预定值反馈才中止。此时,最后一次反馈的积分值可代表信号大小与方向。
理想情况下,预定值为0,实际情况中预定值不可能设置为0,否则系统一直反馈下去。增大预定值可以减小每次测量的反馈次数,从而使系统的测量时间更短,但是预定值也不能太大,否则积分值不能真实反映实际大小。预定值大小可以在调试程序过程中根据系统要求进行选择。
总结:这里边涉及到的主要的FPGA设计的关键部分主要有
1)多个输入的平方和开根号的问题(cordic算法来实现开根号的处理)
2)FIR带通滤波器的FPGA实现()
3)SPI传输信号的FPGA实现(FPGA作为主机,往从机发送数据的过程)
4)系统在门控时间内积分的实现(累加的过程实际上可以达到均值滤波的效果)
5)FIFO做数据缓冲模块的实现。(主要用在AD转换以及DA转换的时候两个不同类型之间的数据的缓冲的问题)
关于cordic实现求幅值的计算(开方根)
module cordic ( //input signals clk, rst, Data_i, Data_q, //output signals Z_valid, Magnitude, y, Phase ); /*****************************************************/ /*------- Input and Output Ports declaration --------*/ /*****************************************************/ input clk; input rst; input [15:0] Data_i; input [15:0] Data_q; output Z_valid; output [17:0] Magnitude; output [17:0] Phase; output [17:0] y; /*****************************************************/ /*------- Ports Type declaration --------*/ /*****************************************************/ reg Z_valid; reg [17:0] Magnitude; wire [17:0] Phase; reg [17:0] y; /*****************************************************/ /*------- Parameters declaration --------*/ /*****************************************************/ parameter Coef0 = 20'h20000; //arctan(1/2^0 ) = 45 parameter Coef1 = 20'h12e40; //arctan(1/2^1 ) = 26.565051 parameter Coef2 = 20'h09fb4; //arctan(1/2^2 ) parameter Coef3 = 20'h05111; //arctan(1/2^3 ) parameter Coef4 = 20'h028b1; //arctan(1/2^4 ) parameter Coef5 = 20'h0145d; //arctan(1/2^5 ) parameter Coef6 = 20'h00a2f; //arctan(1/2^6 ) parameter Coef7 = 20'h00518; //arctan(1/2^7 ) parameter Coef8 = 20'h0028c; //arctan(1/2^8 ) parameter Coef9 = 20'h00146; //arctan(1/2^9 ) parameter Coef10 = 20'h000a3; //arctan(1/2^10) parameter Coef11 = 20'h00051; //arctan(1/2^11) parameter Coef12 = 20'h00029; //arctan(1/2^12) parameter Coef13 = 20'h00014; //arctan(1/2^13) parameter Coef14 = 20'h0000a; //arctan(1/2^14) parameter Coef15 = 20'h00005; //arctan(1/2^15) parameter Coef16 = 20'h00003; //arctan(1/2^16) parameter Coef17 = 20'h00001; //arctan(1/2^17) /***************************************************** ---- Variable declaration *****************************************************/ reg [4:0] Cnt; wire [15:0] Data_i_inv; wire [15:0] Data_q_inv; reg [19:0] X_in_reg; reg [19:0] Y_in_reg; reg [19:0] Data_in_reg; wire [19:0] X_in[17:0]; wire [19:0] Y_in[17:0]; wire [19:0] Z_in[17:0]; wire [19:0] a_in[17:0]; wire [19:0] X_out[17:0]; wire [19:0] Y_out[17:0]; wire [19:0] Z_out[17:0]; reg [20:0] Phase_reg0; reg [17:0] Phase_reg1; wire [20:0] Phase_carry; reg [17:0] Magnitude_reg; /*****************************************************/ /*------- Main Code --------*/ /*****************************************************/ assign a_in[0 ] = Coef0; assign a_in[1 ] = Coef1; assign a_in[2 ] = Coef2; assign a_in[3 ] = Coef3; assign a_in[4 ] = Coef4; assign a_in[5 ] = Coef5; assign a_in[6 ] = Coef6; assign a_in[7 ] = Coef7; assign a_in[8 ] = Coef8; assign a_in[9 ] = Coef9; assign a_in[10] = Coef10; assign a_in[11] = Coef11; assign a_in[12] = Coef12; assign a_in[13] = Coef13; assign a_in[14] = Coef14; assign a_in[15] = Coef15; assign a_in[16] = Coef16; assign a_in[17] = Coef17; always @ ( posedge clk or posedge rst ) begin if ( rst ) Cnt <= 5'b0; else if ( Cnt < 5'd20 ) Cnt <= Cnt + 1'b1; else ; end always @ ( posedge clk or posedge rst ) begin if ( rst ) Z_valid <= 1'b0; else if ( Cnt >= 5'd20 ) Z_valid <= 1'b1; else Z_valid <= 1'b0; end genvar i; generate for ( i = 0; i < 18; i = i + 1 ) begin : U_Cordic_pipe cordic_pipe cordic_pipe (//input signals .clk ( clk ), .rst ( rst ), .X_in ( X_in[i] ), .Y_in ( Y_in[i] ), .Z_in ( Z_in[i] ), .Iteration ( a_in[i] ), .Shiftbit ( i ), //output signals .X_out ( X_out[i] ), .Y_out ( Y_out[i] ), .Z_out ( Z_out[i] ) ); end endgenerate assign Data_i_inv = ~Data_i + 16'b01; assign Data_q_inv = ~Data_q + 16'b01; always @ ( posedge clk or posedge rst ) begin if ( rst ) begin X_in_reg <= 16'b0; Y_in_reg <= 16'b0; end else if ( Data_q[15] == 1'b1 ) begin X_in_reg <= { {4{Data_q_inv[15]}}, Data_q_inv }; Y_in_reg <= { {4{Data_i[15]}}, Data_i }; end else begin X_in_reg <= { {4{Data_q[15]}}, Data_q }; Y_in_reg <= { {4{Data_i_inv[15]}}, Data_i_inv }; end end assign Z_in[0] = 20'b0; assign X_in[0] = X_in_reg; assign Y_in[0] = Y_in_reg; genvar j; generate for ( j = 1; j < 18; j = j + 1 ) begin : XYZ_IN assign X_in[j] = X_out[j-1]; assign Y_in[j] = Y_out[j-1]; assign Z_in[j] = Z_out[j-1]; end endgenerate always @ ( posedge clk or posedge rst ) begin if ( rst ) Data_in_reg[0] = 1'b0; else Data_in_reg[0] = Data_q[15]; end genvar k; generate for ( k = 1; k < 20; k = k + 1 ) begin : Rotate_back always @ ( posedge clk or posedge rst ) begin if ( rst == 1'b1 ) Data_in_reg[k] <= 1'b0; else Data_in_reg[k] <= Data_in_reg[k-1]; end end endgenerate always @ ( posedge clk or posedge rst ) begin if ( rst ) Phase_reg0 <= 21'b0; else if ( Data_in_reg[19] == 1'b0 ) Phase_reg0 <= { Z_out[17][19], Z_out[17] } + 21'h40000; else Phase_reg0 <= { Z_out[17][19], Z_out[17] } - 21'h40000; end assign Phase_carry = ( Phase_reg0[20] == 1'b0 ) ? ( Phase_reg0 + 21'b010 ) : ( Phase_reg0 + 21'b00001 ); always @ ( posedge clk or posedge rst ) begin if ( rst) Phase_reg1 <= 18'b0; else if ( ( Phase_carry[20:19] == 2'b00 ) || ( Phase_carry[20:19] == 2'b11 ) ) Phase_reg1 <= Phase_carry[19:2]; else if ( Phase_carry[20] == 1'b0 ) Phase_reg1 <= 18'h3ffff; else Phase_reg1 <= 18'h20000; end assign Phase = ( Z_valid == 1'b1 ) ? Phase_reg1 : 18'b0; always @ ( posedge clk or posedge rst ) begin if ( rst ) Magnitude_reg <= 18'b0; else begin Magnitude_reg <= X_out[17][17:0]; y <=Y_out[17][17:0]; end end always @ ( posedge clk or posedge rst ) begin if ( rst) Magnitude <= 18'b0; else Magnitude <= Magnitude_reg; end endmodule module cordic_pipe ( //input signals clk, rst, X_in, Y_in, Z_in, Iteration, Shiftbit, //output signals X_out, Y_out, Z_out ); /*****************************************************/ /*------- Input and Output Ports declaration --------*/ /*****************************************************/ input clk; input rst; input [19:0] X_in; input [19:0] Y_in; input [19:0] Z_in; input [19:0] Iteration; input [4:0] Shiftbit; output [19:0] X_out; output [19:0] Y_out; output [19:0] Z_out; /*****************************************************/ /*------- Ports Type declaration --------*/ /*****************************************************/ reg [19:0] X_out; reg [19:0] Y_out; reg [19:0] Z_out; wire [19:0] X_in_shift; wire [19:0] Y_in_shift; /***************************************************** ---- Variable declaration *****************************************************/ /*****************************************************/ /*------- Main Code --------*/ /*****************************************************/ cordic_shift U_cordic_shift ( .X_in ( X_in ), .Y_in ( Y_in ), .Shiftbit ( Shiftbit ), .X_in_shift ( X_in_shift ), .Y_in_shift ( Y_in_shift ) ); always @ ( posedge rst or posedge clk ) begin if( rst ) begin X_out <= 20'b0; Y_out <= 20'b0; Z_out <= 20'b0; end else if ( Y_in[19] == 1'b0 ) begin X_out <= X_in + Y_in_shift; Y_out <= Y_in - X_in_shift; Z_out <= Z_in + Iteration; end else begin X_out <= X_in - Y_in_shift; Y_out <= Y_in + X_in_shift; Z_out <= Z_in - Iteration; end end endmodule module cordic_shift ( //input signals X_in, Y_in, Shiftbit, //output signals X_in_shift, Y_in_shift ); /*****************************************************/ /*------- Input and Output Ports declaration --------*/ /*****************************************************/ input [19:0] X_in; input [19:0] Y_in; input [4:0] Shiftbit; output [19:0] X_in_shift; output [19:0] Y_in_shift; /*****************************************************/ /*------- Ports Type declaration --------*/ /*****************************************************/ reg [19:0] X_in_shift; reg [19:0] Y_in_shift; always @ ( X_in or Shiftbit ) begin case ( Shiftbit ) 5'b0 : X_in_shift = X_in; 5'd1 : X_in_shift = { {1{X_in[19]}}, X_in[19:1] }; 5'd2 : X_in_shift = { {2{X_in[19]}}, X_in[19:2] }; 5'd3 : X_in_shift = { {3{X_in[19]}}, X_in[19:3] }; 5'd4 : X_in_shift = { {4{X_in[19]}}, X_in[19:4] }; 5'd5 : X_in_shift = { {5{X_in[19]}}, X_in[19:5] }; 5'd6 : X_in_shift = { {6{X_in[19]}}, X_in[19:6] }; 5'd7 : X_in_shift = { {7{X_in[19]}}, X_in[19:7] }; 5'd8 : X_in_shift = { {8{X_in[19]}}, X_in[19:8] }; 5'd9 : X_in_shift = { {9{X_in[19]}}, X_in[19:9] }; 5'd10 : X_in_shift = { {10{X_in[19]}}, X_in[19:10] }; 5'd11 : X_in_shift = { {11{X_in[19]}}, X_in[19:11] }; 5'd12 : X_in_shift = { {12{X_in[19]}}, X_in[19:12] }; 5'd13 : X_in_shift = { {13{X_in[19]}}, X_in[19:13] }; 5'd14 : X_in_shift = { {14{X_in[19]}}, X_in[19:14] }; 5'd15 : X_in_shift = { {15{X_in[19]}}, X_in[19:15] }; 5'd16 : X_in_shift = { {16{X_in[19]}}, X_in[19:16] }; 5'd17 : X_in_shift = { {17{X_in[19]}}, X_in[19:17] }; default : X_in_shift = 20'b0; endcase end always @ ( Y_in or Shiftbit ) begin case ( Shiftbit ) 5'b0 : Y_in_shift = Y_in; 5'd1 : Y_in_shift = { {1{Y_in[19]}}, Y_in[19:1] }; 5'd2 : Y_in_shift = { {2{Y_in[19]}}, Y_in[19:2] }; 5'd3 : Y_in_shift = { {3{Y_in[19]}}, Y_in[19:3] }; 5'd4 : Y_in_shift = { {4{Y_in[19]}}, Y_in[19:4] }; 5'd5 : Y_in_shift = { {5{Y_in[19]}}, Y_in[19:5] }; 5'd6 : Y_in_shift = { {6{Y_in[19]}}, Y_in[19:6] }; 5'd7 : Y_in_shift = { {7{Y_in[19]}}, Y_in[19:7] }; 5'd8 : Y_in_shift = { {8{Y_in[19]}}, Y_in[19:8] }; 5'd9 : Y_in_shift = { {9{Y_in[19]}}, Y_in[19:9] }; 5'd10 : Y_in_shift = { {10{Y_in[19]}}, Y_in[19:10] }; 5'd11 : Y_in_shift = { {11{Y_in[19]}}, Y_in[19:11] }; 5'd12 : Y_in_shift = { {12{Y_in[19]}}, Y_in[19:12] }; 5'd13 : Y_in_shift = { {13{Y_in[19]}}, Y_in[19:13] }; 5'd14 : Y_in_shift = { {14{Y_in[19]}}, Y_in[19:14] }; 5'd15 : Y_in_shift = { {15{Y_in[19]}}, Y_in[19:15] }; 5'd16 : Y_in_shift = { {16{Y_in[19]}}, Y_in[19:16] }; 5'd17 : Y_in_shift = { {17{Y_in[19]}}, Y_in[19:17] }; default : Y_in_shift = 20'b0; endcase end endmodule