Dlloydev / QuickPID

A fast PID controller with multiple options. Various Integral anti-windup, Proportional, Derivative and timer control modes.
MIT License
195 stars 50 forks source link

Should PoE and PoM have independent kP values? #30

Closed halmos closed 2 years ago

halmos commented 3 years ago

Sorry to make so many issues here - this one is more of a question / discussion / observation about the rational of the pOn implementation than it is a bug report:

When using mix of pOnM and pOnE, the two parameters share a single pK value, but track independent inputs: The pOnM is proportion to the relative change in input since that last reading (dInput). Since we are measuring the time base in microseconds, the pmTerm value is likely to be small, or at least, proportional to the sample time. The pOnE is an absolute measurement of the error without a time scale.

I believe that, maybe, it is necessary for kP to be split into two separate parameters for a mixed pOn value to work in most cases. It’s a bit complicated to try to explain the reasoning in prose, but I’ve written out an example below in which the error is proportionally much larger than the dInput to illustrate how a single kP is unable to produce workable values for both the pOnE and pOnM.

// SetTunings input values
void PID::SetTunings(double Kp, double Ki, double Kd, int POn) {
Kp = 10;
Ki = 1;
Kd = 0;
POn = .5;
DOn = 0;
sampleTimeUs = 100000;
outMax = 2000;
outMin = 0;

// SetTunings Output values
SampleTimeSec = .1; 100000 / 1000000;
Kp = 10;
Ki = 1; // 10 * .1 
Kd = 0;
Kpe = 5; // 10 x .5;
Kpm = 5; //  10 x (1 - .5)
}
…

// Compute
bool PID::Compute() {
input = 1000;
lastInput = 999;
setPoint = 1100;
outputSum = 100;

dInput = 1; // 1000 - 999
error = 100; // 1100 - 1000

pmTerm = 5; // 5 * 1; (kpm * dInput)
peTerm = 500; // 5* 100 (kpe * error)
iTerm = 100; // 1 * 100 (ki * 100)
dmTerm = 0;
deTerm = 0;

// accumulate i
outputSum += iTerm // outputSum = 100 + 100 = 200

// acculate pOnM
outputSum = outputSum - pmTerm; // outputSum = 200 - 5 = 195;

output = outputSum + 500 + 0 - 0 // outputSum = 195 + 500 = 695
}

In the above, you can see that the peTerm significantly out-ways the pmTerm in the final output.

I realize that the solution that has been implemented is what brettbeauregard proposed in his proposed "Setpoint Weighting" in the blog post on pOnM. However, I’m not sure that their solution was fully resolved.

I believe that for the pOn "Setpoint Weighting" to be practical, there would need to be separate parameters for the kP: one for the error and one for the measurement. eg. kPm and kPe. The pOn value would then serve as the proportional mix of those two values.

Input tuning values: 
Kpm = 100
Kpe = 10
pOn = .5

Output tuning values:
Kpm = 100 * .5 = 50;
Kpe = 10 * (1-.5) = 5;
…

Otherwise the two kP inputs (measurement and error) need to be on the same scale to work. This might happen in a few rare instance, but I believe that in most situations, those two values are most likely to be measured independently.

And again, many thanks for creating and maintaining this library!

Dlloydev commented 3 years ago

No problem with creating the issues, I welcome the discussion!

Yes, I can see how using separate gains (kPm and kPe) would offer an improvement to the "Setpoint Weighting" feature, because normally the proportional gain is tuned based on either error (P_ON_E) or measurement (P_ON_M) and the ideal kP value based on each method would be beneficial.

The rational of the pOn implementation was to offer a bit more user control over the system's response and overshoot. If the user prefers P_ON_E (POn=1) because of its faster response, but finds the overshoot too excessive, then they could dial back the POn setting until the overshoot meets their spec (at the tradeoff of the slower response of P_ON_M) ... or vise versa if they prefer using P_ON_M.

I suppose the user could determine the ideal kP for both POn=1 and POn=0 ... in your example Kpe=10 and Kpm=100, then they could use something like Kp=50 for POn=0.5.

Even so, I do like the suggestion to have the separate kPm and kPe parameters. I have some hardware on order that should arrived sometime soon (TCLab and a MAX31856) so I'll be able to run tests on a system based on heating and thermocouple(s).

There's been an interesting discussion here on P_ON_M vs P_ON_E and I wonder how using an adjustable POn with separate Kp values would have worked on that system.

halmos commented 3 years ago

I suppose the user could determine the ideal kP for both POn=1 and POn=0 ... in your example Kpe=10 and Kpm=100, then they could use something like Kp=50 for POn=0.5.

Yes, that's true. I guess it's a trade off between api complexity and control. The reason that I came to post this issue was that I had made the wrong assumption that the POn ratio would have a linear response - but that's not possible with a single kp value.

Also, it occurs to me that if you have two independent P_ON_M and P_ON_E parameters, you may not really need a POn parameter as you can adjust those inputs relative to each other... ?

halmos commented 3 years ago

Also, since we already opened this can of worms, I was wondering if the DOn might have a similar set of issues.

For DOn, I thought perhaps that the deTerm should be proportional to a dError value. ie. the D error should actually be a derivative of the error in the same way that the dmTerm is a derivative of the measurement. Currently deTerms is exactly the same value as the pmTerm which seems odd to me (but without a deep understanding of what a DOn ratio would be expected to do)

Dlloydev commented 3 years ago

My initial tests with POn and DOn were done with the RC filter example and an Arduino UNO. The idea for both ratios were to allow mixing of "error to measurement" in addition to just selecting one or the other. When some new hardware I ordered eventually arrives, I'll be able to do testing with a more conventional thermal / thermocouple system. At this point I'll re-visit POn and DOn and do more stringent testing ... will also be able to work on autoTune and expand its compatibility.