I am having trouble understanding some PID code on an FPGA that is posted on github, by David Paquette.

I will paste it in at the bottom of the post.

It looks very compact and neat, and I understand the concept behind it, but I don't understand why the Kp, Ki and Kd constants are negative numbers. Kp as -300 and Ki as -2 for example.

Suppose I have two questions regarding this:

  1. Why the negative numbers? I am thinking it gives a broader spectrum to work with error values, as the output is capped at zero if the output calculates as a negative.

  2. I am assuming the hardware requires integers of 100, i.e. whatever sensor or motor pwm frequency, but what would the reasoning be behind the 1000 and 10000 integer sizes for the variables?

-- Company: 
-- Engineer: David Paquette
-- Create Date:    16:49:31 11/19/2015 
-- Design Name: 
-- Module Name:    PIDController - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
-- Dependencies: 
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
library IEEE;
use IEEE.numeric_std.all; 

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity PIDController is
    Port (  samplingRateClock : in std_logic;
                reset : in std_logic;
                setpoint: in integer range 0 to 100;
                sensorFeedbackValue : in integer range 0 to 100;
                controlOutput : out integer range 0 to 100
end PIDController;

architecture Behavioral of PIDController is
    signal controllerOutput : integer range 0 to 100:=0;
    constant kp : integer range -1000 to 0:=-300;
    constant ki : integer range -1000 to 0:=-2;
    constant kd : integer range -1000 to 0:=0;
    process(samplingRateClock, reset)
        variable error :  integer range -1000 to 1000:=0;
        variable previousError : integer range -1000 to 1000:=0;
        variable errorSum:  integer range -100000 to 100000:=0;
        variable errorChange:  integer range -1000 to 1000:=0;
        variable output:  integer range -1000 to 1000:=0;
        if(reset='0') then
            controllerOutput<= 0;
        elsif(samplingRateClock'event and samplingRateClock='1') then
            error := (setpoint - sensorFeedbackValue);
            errorSum    := errorSum + error;
            if(errorSum > 10000) then
                errorSum := 10000;
            elsif(errorSum < -10000) then
                errorSum := -10000;
            end if;
            errorChange := error - previousError;
            output := (kp*error + ki*errorSum + kd*errorChange)/100;
            previousError := error;
            if(output>100) then
                output := 100;
            end if;
            controllerOutput<= output;
        end if;
    end process;
end Behavioral;

  • 2
    \$\begingroup\$ Is it designed for cooling rather than heating, by any chance? \$\endgroup\$
    – Transistor
    Apr 22, 2021 at 20:00
  • 1
    \$\begingroup\$ This line errorSum := errorSum + error; can couses its value is higher than 100 because its a Sum incresing in every function call until it reaches demanded output. It can be probably rewritten better (smaller variable types) if the PID function call is less offen, i.e. higher iteration step or another words slower response regulation. \$\endgroup\$
    – user208862
    Apr 22, 2021 at 20:01
  • 1
    \$\begingroup\$ @Transistor Yeah, I think it is for cooling. Does that explain the negative values? \$\endgroup\$
    – David777
    Apr 22, 2021 at 20:05
  • 2
    \$\begingroup\$ And the output is clipped to 0..100 because you can't have a fan spinning backwards to heat up the FPGA when the PV falls below the SP. \$\endgroup\$
    – tim
    Apr 22, 2021 at 21:07
  • 3
    \$\begingroup\$ It could be to avoid fractional mathematics by multiplying the coefficients -3 and -0.02 by 100 then dividing the result by 100. An alternative would be to use Q notation, e.g. multiply them by 128 (or 2^7 or shift left by 7 bits) then divide the result by 2^7 (or shift right by 7 bits). \$\endgroup\$
    – tim
    Apr 23, 2021 at 7:21

1 Answer 1


I’m the author of the module and just came across this post.

All the comments made are pretty much correct. But if you want a full description of this PID module check out the document I wrote outlining its behavior: https://github.com/paquettedavid/FPGATemperaturePIDController/blob/master/Documentation/FinalProjectReportDavidPaquette.pdf

The PID module is described in section 8 (8.3 for the HDL overview). Hope this gives some clarity!

  • 1
    \$\begingroup\$ Wow, thank you! I will have a look at the document. \$\endgroup\$
    – David777
    Oct 9, 2021 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.