I am trying to apply PID theory to a real-world case. I understand that the following represents a typical PID method:

error = target_value – actual_value

integral += error

derivative = error – last_error

output = KPerror + KIintegral + KD*derivative

last_error = error

My question is how to handle the measurement data (actual_value) versus the control (target_value). For example, say my feedback is measured with a 10-bit ADC. My control is a PWM with a valid duty cycle range for my application of 55-172.

Do I scale linearly between the two ranges? Say my target is 756 ADC. I would set my PWM to 86 initially?

Should the error calculation take place in the ADC range or PWM range?

What if the PWM control was not linear?


3 Answers 3


... how to handle the measurement data versus the control (reference value).

Usually in a single-input single-output system your reference value, the one you want to achieve, and the measured value from your sensor should be in the same "unit", so when you write code to acquire the value from the sensor you can either convert it to actually intelligible units (V, m/s, ⁰C and so on) or use them all as plain bits. Converting them to the actual units is more intuitive and better to learn with. But eventually just using the actual binary value will be as easy to work with and will incur less numeric errors.

For example, say my feedback is measured with a 10-bit ADC. My control is a PWM with a valid duty cycle range for my application of 55-172. Do I scale linearly between the two ranges? Say my target is 756 ADC. I would set my PWM to 86 initially?

The range of the actuator (the PWM) will not change how you calculate the error, but, as you suggested the PWM having a valid duty in a certain range is a nonlinear problem such as integral windup, actuator non linearity and many more. I would suggest that you make the control signal, "the duty", something such as,

$$ u_{PWM} = u_0 + u(t),$$

where \$u_0\$ is the value that is either:

  • in the middle of the range, or
  • the common value during the operation of your system, or
  • a PWM that you know to cause vary little change in the system.

And \$ u(t)\$ is the control signal that comes out of your controller. For the PID case I would keep this as just the result of the PID itself. Though it is possible (but I do not recommend) to try to deal with the non linearity of the actuator by using some wacky function that makes the actuator have a "linear" response proportional to the PID controller output.

All those choices of \$u_0\$ can lead to different startup behaviors, so you should carefully evaluate the constrains you need to follow, overshoot limit, settling time and so on.

Should the error calculation take place in the ADC range or PWM range?

Whether you are using the raw ADC value or converting it to some unit/measurement you should use that and not the PWM range.

What if the PWM control was not linear?

Then the PID might solve your problem but the analysis of nonlinear systems is way more complicated, and using the linear PID (control theory) will only get you as far. What people usually do is:

  • Linearize around the stability point, get an approximate linear model and keep it stable at that point (and close to it!), with the actual startup control that takes the system to that operating point being different then the one that keeps it at that point. Or,

  • Have a controller that adapts to different points of operation, let's say that you make a PID that re-tunes every time it gets "far" from the previous linearization.


Suppose your ADC value measures a voltage. This voltage is related to an exponential decay due to a capacitor discharging and you are using the rate of decay to measure a capacitance. The capacitance is related to the compression of some substance, which is what you want to control. That compression is your "process variable."

To get from the ADC values to the process variable you have to write code that gathers some set of ADC measurements and then takes the logarithm of those ADC values (to avoid a more complicated exponential fit algorithm and to instead use a least squares linear fit, which is easy to find and use -- though it is MUCH better if you have the math skills to deal with the partial differentials needed to develop it on your own whenever you need to.) But before you do that you find you need to remove the ADC offset first. So you do that (using some reasonable means.) You may also have to deal with the gain of the system, but let's say you are only interested in the slope so you can avoid that part.

So now you take the log of the curve, apply a least squares fit algorithm, and work out the slope of the curve as the \$\tau\$. Now, you have something you can use to work out the capacitance, plus some other value which perhaps represents an uncertainty (if you care to do that.)

Now you look up the \$\tau\$ in a table that skips worrying about the capacitance itself and goes directly to the compression figure, which is your process variable.

This process variable can be formatted internally in any way you wish. A lot of people immediately turn it into a floating point value for PID. I almost never do that. But that's a separate story related to applying proper numerical methods techniques and I'm going to avoid it here.

Wow! You have the process variable now. Finally, you can compute your error term and do a step of the PID.

Of course, once you do that you will have a new PID output value. Depending upon the units (dimensional analysis is something you should definitely know cold here), there will be yet another mapping from this PID output value to what you are controlling. And the process for doing that could be as complex as what I just wrote about above. Or worse. Or easier.

There is no simple answer to your question. The above illustrates some of the difficulties. There is a process for conditioning your input(s) in order to arrive at a single process variable measurement. Then you can apply the PID and get a single output from the PID. Then there is another process that takes this output and yet again conditions it in order to generate output(s) from that to control something.

If you do it well, there will be an exact and unvarying time delay between measurements needed to generate a process variable value and the control outputs needed to respond. What makes a PID very frustrating to apply by an operator (and nearly worthless, as a result) are two things: (1) long delays; and, (2) varying delays. Tolerate neither of these, beyond what is absolutely required by the physics and electronic systems.

  • \$\begingroup\$ Hey jonk, thanks for the response. Sorry for the delay. I'm new here and need to be more active. And learn: like don't hit the Return key. \$\endgroup\$ Oct 10, 2017 at 12:54
  • \$\begingroup\$ @snapthensmoke Hope it helps. If so, there is a check mark (open, almost non-descript) near the left top of my answer. If you click that check mark it marks the answer "as an answer" for you. Do not use this, if you still want to wait for others to attempt an answer, though. You can also "up mark" an answer or also "down mark" an answer, by using the up and down pointing triangles in the same area. Just so you know. \$\endgroup\$
    – jonk
    Oct 10, 2017 at 17:23

The error can be at any scale as long as you are not clipping your digital range and will simply impact K to arrive at the gains desired for loop performance.

Further here is a simple technique to get to starting values for your P, I and D gains:

Start with I and D = 0 (proportional loop) and increase P until the threshold of instability. The threshold of instability is when your output just starts to oscillate but maintains a constant level (the oscillation does not slowly decay). Once you find P at this point reduce it’s value by half and move on to the next step. This is the initial setting for P.

Next with P set and D=0, increase I to find the threshold of instability and then reduce its value by half. This is the initial setting for I. It should rise quickly and ring down with oscillatory behavior but ultimately stabilize.

Finally increase D to eliminate the ring down to achieve desired response with fast rise time, some overshoot and then settling to final value. (Typically; in applications where a PID is the appropriate controller such as two low frequency poles where the PID can bring the response time of the system out to the higher of those two poles).

The loop components should be linearized as suggested in the other answer.


Your Answer

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

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