FPGA implements PID control algorithm (including simulation)

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
Please add a picture description

This is the case where D is set to 0, you can see the oscillation of the system

Please add a picture description
Welcome ━(`?′)ノ亻! Follow the WeChat public account FPGA Journey and related resources will be uploaded to it.