Jag har gjort en modell av en PID-regulator i ett open-office-calc dokument. Den exakta modellen av den externa processen känner jag inte till helt och hållet (fördröjning / förstärkning etc. är inte helt kända), men på ett ungefär.
Värdet jag ska reglera är en ström mellan 0 och 25 ampere. Utsignalen är en analog spänning på 2-5 volt som styr strömmen någorlunda proportionellt. Men det kan förekomma plötsliga avvikelser på flera ampere som måste kompenseras för. Modellen fungerar som jag önskar.
Men det jag undrar över är egentligen de tre parametrarna - P, I och D. Som det är nu så verkar det som om det är parametern I som har den viktigaste rollen - ja, man kan faktiskt helt ta bort de andra två och jag har en ungefär lika bra reglering ändå. Utan den så fungerar det inte alls. Kan det vara så? Jag funderar bara på om jag på något vis använd den här PID-algoritmen på ett udda eller felaktigt sätt på något vis? Jag trodde det var P-variabeln som var den viktigaste, "grunden", och de båda andra, I och D bara kompenserade för mindre fel.
Bifogar .ods filen samt en bild. Tar även med lite kod. (Har ej kunnat testa koden i praktiken än, då jag inte har all hårdvara tillgänglig).
X-axeln är tiden i sekunder. under 14-17 sek läggs en störning på utifrån (en last börjar dra ström som måste kompenseras för).
PID-formeln visas i inmatningsfönstret på bilden.
kod:
Kod: Markera allt
/// reglerar laddarens ut-ström. kompenserar mot snabba förändringar.
/// anropas 15 ggr/sek
/// set_point och measured_val är ampere*100. (25.00A = 2500)
void PID_regulator()
{
const u8 K_faktor = 5; // betyder att förstärkningen är 1 / 2^K_faktor
const u8 K = (1 << K_faktor);
static s32 Pold, I;
s32 P,D,out;
if (!PID.run)
{
/* stäng av - återställ värden */
I = 0;
Pold = 0;
PID.softstart = 0;
PID.set_curr = 0;
out = 0;
}
else
{
/*** sätt önskat värde ***/
s16 want = PID.set_curr;
if (want > PID.max_curr) want = PID.max_curr;
if (want > PID.softstart) want = PID.softstart;
if (PID.softstart < PID.max_curr) PID.softstart += 3; // öka 0.03*15 A / sek = 1 ampere på 2.22 sek eller 25A på 56 sek.
else if (PID.softstart > PID.max_curr) PID.softstart--;
/*** beräkna PID-variablerna ***/
P = PID.set_curr - PID.is_curr; // skillnad - Proportionell
I += Pold; // intregral del
D = P - Pold; // derivativ del
Pold = P; // minns tidigare skillnad
/*** begränsa I -delen ***/
if (I > 1200L * K) I = 1200L * K;
else if ( I < -1200L * K) I = -1200L * K;
/*** beräkna utsignal ***/
out = (P + I + D) >> K_faktor; // K = 0.03125
/*** justera utsignal till tillåtet område ***/
if (out < 0)
{
out = 0;
Pold = 0; // öka inte på integraldelen vid overflow!
}
out += 400; // botten PWM = 2.00 volt
if (out > 1023)
{
out = 1023; // max PWM
Pold = 0; // öka inte på integraldelen vid overflow!
}
}
/*** skicka ut signal ***/
SetPWM(out);
}