1. Introduction
I believe that everyone is familiar with the PID control algorithm. The balance car is balanced by it, and the balance algorithm of the flight control is also based on it, and it is also used in the closed-loop control in FOC. It is not only simple, but also easy to use. understand. Then this article will briefly introduce the principle of the algorithm, and then take you to use FPGA to realize it (the C language implementation process is very simple).
2. PID algorithm
PID is taken from the initials of the three English letters proportional, integral, and differential. Means the algorithm consists of these three parts.
1. P ratio
The operation process is the expected value minus the current value, and then multiplied by a p coefficient to obtain a feedback value. The role of the ratio is mainly to make the expected value equal to the current value
2. I points
The error value is continuously accumulated, and then multiplied by an I coefficient to obtain a feedback value. The function of the integral is mainly to eliminate the static error, but when the current value is close to the expected value, at this time, the effect of the ratio is very small, and it may be close to 0, and the error value of two adjacent times is also approximately 0, D differential It doesn’t work much either. If the external resistance of the system and the PD feedback value offset at this time, it is necessary to continuously accumulate this error value to make the current value equal to the expected value.
3. D differential
The current error value is subtracted from the error value of the last operation, and then multiplied by a d coefficient to obtain a feedback value. The function of differentiation is mainly to reduce the shock of the system, and to apply a feedback in the opposite direction to the direction of system change, so that the system changes in this direction can be suppressed
It can be seen that the PID algorithm mainly involves three operations: addition, subtraction and multiplication. These three kinds of operations are also very easy to implement on the FPGA.
3. FPGA implementation
The first thing to note is that the three coefficients of PID are all floating-point numbers. For the convenience of implementation, the floating-point numbers are enlarged by 100 times and then rounded up. Then reduce the feedback result by 100 times.
1. P ratio realization
The implementation code is as follows, which only needs two clock cycles to complete. Here, the operation of zooming out by 100 is realized by shifting to the left, which is actually zooming out by 102. times, which will not affect the result very much. In order to be the same as I integral and D differential calculation cycles, here is a beat operation.
//P -------------------------------------------- ----- always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kp_fb <= 1'b0; else if(pid_en == 1'b1) Kp_fb <= (desired_value - current_value) * Kp; else Kp_fb <= Kp_fb; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kp_fb_reduce <= 'd0; else if( cal_delay_0 == 1'b1) Kp_fb_reduce <= (Kp_fb >>> 7) + (Kp_fb >>> 9); // /102.4 else Kp_fb_reduce <= Kp_fb_reduce; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kp_fb_reduce_d0 <= 'd0; else if( cal_delay_1 == 1'b1) Kp_fb_reduce_d0 <= Kp_fb_reduce; else Kp_fb_reduce_d0 <= Kp_fb_reduce; end //------------------------------------------------ ----------------------------
2. I points realization
The implementation code is as follows, which is slightly more assisted than the P ratio. A problem of integral limit is considered here. If the integral value keeps accumulating, it may cause the system to be unstable, so it is set to 3000 here.
//I -------------------------------------------- ------------ always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Ki_integral <= 'd0; else if(pid_en == 1'b1) if( Ki_integral > $signed('d3000) & amp; & amp; ( desired_value - current_value ) > $signed('d0) ) Ki_integral <= Ki_integral; else if( Ki_integral < $signed(-'d3000) & amp; & amp; ( desired_value - current_value ) < $signed('d0) ) Ki_integral <= Ki_integral; else Ki_integral <= Ki_integral + (desired_value - current_value); else Ki_integral <= Ki_integral; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0 ) Ki_fb <= 'd0; else if( cal_delay_1 == 1'b1 ) Ki_fb <= Ki_integral * Ki; else Ki_fb <= Ki_fb; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0 ) Ki_fb_reduce <= 'd0; else if( cal_delay_2 == 1'b1) Ki_fb_reduce <= (Ki_fb >>> 7) + (Ki_fb >>> 9); // /102.4 else Ki_fb_reduce <= Ki_fb_reduce; end //------------------------------------------------ ------------------------------
3. D differential implementation
D The differential operation is realized as follows, just follow the formula
//D --------------------------- always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kd_error <= 'd0; else if(pid_en == 1'b1) Kd_error <= (desired_value - current_value); else Kd_error <= Kd_error; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kd_fb <= 'd0; else if( cal_delay_0 == 1'b1) Kd_fb <= (Kd_error - Kd_last_error) * Kd; else Kd_fb <= Kd_fb; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kd_last_error <= 'd0; else if( cal_delay_0 == 1'b1) Kd_last_error <= Kd_error; else Kd_last_error <= Kd_last_error; end always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) Kd_fb_reduce <= 'd0; else if( cal_delay_1 == 1'b1) Kd_fb_reduce <= (Kd_fb >>> 7) + (Kd_fb >>> 9); // /102.4 else Kd_fb_reduce <= Kd_fb_reduce; end //-------------------------------
Four. Simulation verification
The test code is as follows, initialize the current value to 500, and then adjust the current value according to the expected value and the feedback value of the PID output.
always@(posedge clk or negedge rst_n) begin if( rst_n == 1'b0) current_value <= 'd500; else if(pid_ack == 1'b1) current_value <= current_value + out; else current_value <= current_value; end PID_Control PID_Control_i( .clk ( clk ), .rst_n ( rst_n), .pid_en( 1'b1), .pid_ack(pid_ack), .desired_value(desired_value), .current_value( current_value), .Kp ( 'd10), .Ki ( 'd1), .Kd ( 'd10), .out (out) );
The simulation waveform is as follows
This is the case where D is set to 0, you can see the oscillation of the system
Welcome ━(`?′)ノ亻! Follow the WeChat public account FPGA Journey and related resources will be uploaded to it.