Algorytm regulatora PID

May 10, 2010 2 Replies

Znalazlem na stronie Atmel'a fragment programu realizujacy regulator PID dla uC. Czy w linii 93 nie ma aby bledu? Wedlug mnie powinna ona wygladac raczej tak



d_term = pid_st->D_Factor * (processValue - pid_st->lastProcessValue);



czy ktos moze potwierdzic poprawnosc ktores z wersji?


00060 {
00061 int16_t error, p_term, d_term;
00062 int32_t i_term, ret, temp;
00063
00064 error = setPoint - processValue;
00065
00066 // Calculate Pterm and limit error overflow
00067 if (error > pid_st->maxError){
00068 p_term = MAX_INT;
00069 }
00070 else if (error < -pid_st->maxError){
00071 p_term = -MAX_INT;
00072 }
00073 else{
00074 p_term = pid_st->P_Factor * error;
00075 }
00076
00077 // Calculate Iterm and limit integral runaway
00078 temp = pid_st->sumError + error;
00079 if(temp > pid_st->maxSumError){
00080 i_term = MAX_I_TERM;
00081 pid_st->sumError = pid_st->maxSumError;
00082 }
00083 else if(temp < -pid_st->maxSumError){
00084 i_term = -MAX_I_TERM;
00085 pid_st->sumError = -pid_st->maxSumError;
00086 }
00087 else{
00088 pid_st->sumError = temp;
00089 i_term = pid_st->I_Factor * pid_st->sumError;
00090 }
00091
00092 // Calculate Dterm
00093 d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue);
00094
00095 pid_st->lastProcessValue = processValue;
00096
00097 ret = (p_term + i_term + d_term) / SCALING_FACTOR;
00098 if(ret > MAX_INT){
00099 ret = MAX_INT;
00100 }
00101 else if(ret < -MAX_INT){
00102 ret = -MAX_INT;
00103 }
00104
00105 return((int16_t)ret);
00106 }


__________ Informacja programu ESET NOD32 Antivirus, wersja bazy sygnatur wirusow 5103 (20100510) __________



Wiadomosc zostala sprawdzona przez program ESET NOD32 Antivirus.



formatting link
lub
formatting link


Raczej jest dobrze

jesli wejscie jest ponizej wartosci zadanej - to mamy wyjscie dodatnie.

Jesli jednak sygnal wejsciowy [szybko] rosnie, to nalezy _zmiejszyc_ wartosc wyjsciowa.

i ten czlon bedzie wtedy ujemny.

J.

Albo tak: d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue); ret = (p_term + i_term + d_term)

Albo tak: d_term = pid_st->D_Factor * (processValue - pid_st->lastProcessValue); ret = (p_term + i_term - d_term)

W tym algorytmie PID część różniczkująca jest obliczana jako pochodna wartości wyjściowej z obiektu, a nie jako pochodna uchybu. Ta modyfikacja powoduje to, iż nie mamy w sygnale wyjściowym z PID dużego piku wartości w momencie zmiany wartości zadanej.

Gdybyśmy obliczali część różniczkującą "tradycyjnie" (pochodna uchybu) wtedy trzeba by zmienić znak (czyli tak jak ty chciałeś to zrobić).

SM

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required