DIYPNP install: inital tuning
#241
Let me try a different way of explaining.
Lets try a decrease in RPM over 2 samples:
1200
1000
900
pwmidle_deriv = PV - (2*PV_last[0]) + PV_last[1];
900 - 2000 + 1200 = 100
That's now positive and will react in the same direction as P and I. (P and I will still be negative in this example).
Lets try a decrease in RPM over 2 samples:
1200
1000
900
pwmidle_deriv = PV - (2*PV_last[0]) + PV_last[1];
900 - 2000 + 1200 = 100
That's now positive and will react in the same direction as P and I. (P and I will still be negative in this example).
The MS2 code effectively does this:
CO += CO_change
akaduty = duty + change_in_duty
Remember, the 2nd derivative, the above snippet, calculates the *change* in duty cycle, not the duty cycle. The MS2 code adds the Kd term, because it has a double negative:
tmp1 = IACmotor_pos - (((long)(Kp + Ki - Kd) * ...
Let's try that. I will add leading and trailing RPM numbers like this1200
1200
1200
1000
900
900
900
900
I will add the 2nd derivative calculation
PHP Code:
1200
1200
1200 0
1000 -200
900 100
900 100
900 0
900 0
<Jeezus how do you make a table with columns aligned?>
It looks strange, but now the numbers in the 2nd column, will be integrated into the duty cycle. I will assume that the above 2nd column (which is change in duty), is scaled by 0.1, and the starting duty cycle is 50%.
PHP Code:
1200 50%
1200 50%
1200 0 50%
1000 -200 30%
900 100 40%
900 100 50%
900 0 50%
900 0 50%
Let's try it where
duty = duty - change_in_duty
as I suggest.PHP Code:
1200 50%
1200 50%
1200 0 50%
1000 -200 70%
900 100 60%
900 100 50%
900 0 50%
900 0 50%
- If RPM is constantly increasing or constantly decreasing over time, D won't have a huge effect, but its effect will be in the same direction as P or I
The effect of D and P and I can be any combinations of positive or negative.
#242
Now let's try a case where the RPM begins to continuously drop
1000 50%
1000 50%
1000 0 50%
1000 0 50%
950 -50 55%
900 0 55%
850 0 55%
800 0 55%
There, duty cycle opens up and stays open due to the RPM's downward slope.
The difference between form A and form C is that C calculates the derivative of the setpoint as opposed to the derivative of the error. Because error = setpoint minus actual_RPM, if setpoint does not change, (e.g. always 1000 RPM), then the resulting D term is the same between type A and type C.
The fact that the code uses the 2nd derivative of RPM is irrelevant in regards to type A vs type C. The 2nd derivative technique is *not* to turn the calculation from type A to type C, it's to be able to do this as the last step:
BTW in the page quoted, the part about
1000 50%
1000 50%
1000 0 50%
1000 0 50%
950 -50 55%
900 0 55%
850 0 55%
800 0 55%
There, duty cycle opens up and stays open due to the RPM's downward slope.
So, the D term in ideal PID is the 1st derivative of the actual error. In my code, the derivative of the whole PID equation was taken (since I'm summing the end result of the whole equation instead of using a bias + the PID output), which results in the D term needing to be the 2nd derivative.
That 2nd derivative form of the D term can cause "interesting" (but still correct) behavior, but I don't necessarily think it can be directly compared to what happens in the ideal form of PID.
I do think that taking the 2nd derivative of the error and adding that instead of subtracting it (form A of PID) may have a response closer to what you're expecting though.
That 2nd derivative form of the D term can cause "interesting" (but still correct) behavior, but I don't necessarily think it can be directly compared to what happens in the ideal form of PID.
I do think that taking the 2nd derivative of the error and adding that instead of subtracting it (form A of PID) may have a response closer to what you're expecting though.
The fact that the code uses the 2nd derivative of RPM is irrelevant in regards to type A vs type C. The 2nd derivative technique is *not* to turn the calculation from type A to type C, it's to be able to do this as the last step:
duty = duty - change_in_duty
You could turn the MS code into type A simply by calculating the 2nd derivative of the error instead of the RPM:derivative_of_error = error - 2*error_last[0] + error_last[1]
where error = setpoint - RPM
and the difference would only appear when setpoint is changing (e.g. target suddenly changes from 1000 to 1100 RPM when say, the a/c turns on).BTW in the page quoted, the part about
"engineers don't like type A because ..."
is true for industrial processes where the process variable don't change quickly (e.g. smelting temperature) and you don't want valves or whatever to be quickly slamming open or shut (e.g. big valves that have a fixed cycle life). A type A loop would cause said valves to slam open or shut if the setpoint was changed by an operator. In the case of idle or *especially* boost control, type A will be superior to type C because the target *can* change suddenly, and the solenoid valves responding to sudden changes in target are *not* a problem. Additionally if the target changes abruptly you *do* want the solenoid to quickly react in order to speed up the response.
#243
You could turn the MS code into type A simply by calculating the 2nd derivative of the error instead of the RPM:
derivative_of_error = error - 2*error_last[0] + error_last[1]
where error = setpoint - RPM
and the difference would only appear when setpoint is changing (e.g. target suddenly changes from 1000 to 1100 RPM when say, the a/c turns on).
#246
You know I hate to admit it after arguing so hard about it, but just based on how the signs change for type A vs B and C, you might be right... (Jason). I can admit when I'm wrong when it happens. I was mainly just following the site, but I see where I went wrong when following the site.
My logic here has nothing to do with the shift right or left, but the differences between types A and B, and then the further differences between types B and C, and where I put parens:
In type A, we have:
duty = duty + P + I + D
B is:
duty = duty + P + I - D (because when you change from using error calculated as SP - PV, to just using change in PV, you have to reverse the sign).
C is currently listed as:
duty = duty - P + I - D,
but I originally read it as
duty = duty - (P + I - D), which turns into duty = duty - P - I + D
now when I originally wrote the code, I noticed that this made the I term act in the wrong direction, so my "fix" was to change the error from SP - PV to PV - SP. Doing things that way P and I act in the correct direction, but D apparently doesn't.
So I was wrong, you were right, I have arrived at that conclusion on a different path but gotten the same result, so I think that doubly proves it.
I'll fix it as soon as I get a chance both in ms2 and ms3 and we'll see if it actually solves the problem you (Greg) were trying to fix.
So what I should probably really do is change error to SP - PV, and invert the signs on the I term and the D term inside the parens.
Now, I will have to double check what I did for boost and EGO, I think based on having tuned boost and working out how the signs work with/without parens that boost is done correctly but EGO probably isn't.
Next time you want to tell me something is wrong, you won't get as much argument if you show me that the equations themselves are wrong like I just used to prove it to myself
Ken
My logic here has nothing to do with the shift right or left, but the differences between types A and B, and then the further differences between types B and C, and where I put parens:
In type A, we have:
duty = duty + P + I + D
B is:
duty = duty + P + I - D (because when you change from using error calculated as SP - PV, to just using change in PV, you have to reverse the sign).
C is currently listed as:
duty = duty - P + I - D,
but I originally read it as
duty = duty - (P + I - D), which turns into duty = duty - P - I + D
now when I originally wrote the code, I noticed that this made the I term act in the wrong direction, so my "fix" was to change the error from SP - PV to PV - SP. Doing things that way P and I act in the correct direction, but D apparently doesn't.
So I was wrong, you were right, I have arrived at that conclusion on a different path but gotten the same result, so I think that doubly proves it.
I'll fix it as soon as I get a chance both in ms2 and ms3 and we'll see if it actually solves the problem you (Greg) were trying to fix.
So what I should probably really do is change error to SP - PV, and invert the signs on the I term and the D term inside the parens.
Now, I will have to double check what I did for boost and EGO, I think based on having tuned boost and working out how the signs work with/without parens that boost is done correctly but EGO probably isn't.
Next time you want to tell me something is wrong, you won't get as much argument if you show me that the equations themselves are wrong like I just used to prove it to myself
Ken
Last edited by muythaibxr; 06-17-2011 at 12:04 PM.
#249
(BTW that also reads as, "my weenie is hard" as opposed to software weenies )
Good stuff. Bugs have creative ways of sneaking in and getting past testing!
Last edited by JasonC SBB; 06-17-2011 at 01:12 PM.
#250
Yeah, I've learned as much hardware as I need to in order to install the MS and design some basic circuits, but I'm much more of a software guy, so showing me that one of my equations is wrong usually gets an immediate result.
Actually, it's a bit funny, but I learned how engines work by reading other peoples' code to control them.
Ken
Actually, it's a bit funny, but I learned how engines work by reading other peoples' code to control them.
Ken
#254
Elite Member
iTrader: (10)
Join Date: Jun 2006
Location: Athens, Greece
Posts: 5,976
Total Cats: 355
So in other words, the correct would be to say:
rpm_error = SP - PV;
and then:
tmp1 = IACmotor_100 - (((long)(Kp - Ki + Kd) * (flash5.pwmidle_open_duty - flash5.pwmidle_closed_duty)) / 100000);
Right?
rpm_error = SP - PV;
and then:
tmp1 = IACmotor_100 - (((long)(Kp - Ki + Kd) * (flash5.pwmidle_open_duty - flash5.pwmidle_closed_duty)) / 100000);
Right?
#255
Elite Member
iTrader: (10)
Join Date: Jun 2006
Location: Athens, Greece
Posts: 5,976
Total Cats: 355
Btw, for EGO, I see:
egoerr = SP - PV;
and
*egostep = (long)(10L*(Kp - Ki + Kd)) / (PID_scale_factor*1000L);
Since egostep is added, and not subtracted, like this:
egotmpcor = outpc.egocor1 + ego1step;
Then can we assume that the EGO code is also wrong and needs to be converted to this:
*egostep = (long)(10L*(-Kp + Ki - Kd)) / (PID_scale_factor*1000L);
Thoughts?
egoerr = SP - PV;
and
*egostep = (long)(10L*(Kp - Ki + Kd)) / (PID_scale_factor*1000L);
Since egostep is added, and not subtracted, like this:
egotmpcor = outpc.egocor1 + ego1step;
Then can we assume that the EGO code is also wrong and needs to be converted to this:
*egostep = (long)(10L*(-Kp + Ki - Kd)) / (PID_scale_factor*1000L);
Thoughts?
#257
Supporting Vendor
iTrader: (33)
Join Date: Jul 2006
Location: atlanta-ish
Posts: 12,659
Total Cats: 134
Jason, Ken, Greg, et all, THANKS! I think this thread is a prime example of why MegaSquirt is win!
Ken, please let us know when you get a chance to brush that up, and I'll give it a test.
Ken, please let us know when you get a chance to brush that up, and I'll give it a test.