Jump to content
PLC Forum


peppe855

Funzione PID della libreria DSP

Recommended Posts

peppe855

Buon giorno a tutti, sto' utilizzando un dspic30f6010a ed ho "scoperto" la libreria DSP che tra le altre cose contiene la funzione PID. Senza dilungarmi troppo vedo che il calcolo dell'OUTPUT viene cosi' implementato:

controlOutput[n] = controlOutput[n-1]
+ controlHistory[n] * abcCoefficient[0]
+ controlHistory[n-1] * abcCoefficient[1]
+ controlHistory[n-2] * abcCoefficient[2]
where,
abcCoefficient[0] = Kp + Ki + Kd
abcCoefficient[1] = -(Kp + 2*Kd)
abcCoefficient[2] = Kd
ControlHistory[n] =
MeasuredOutput[n] - ReferenceInput[n]

dove il calcolo di abcCoefficient se lo fa' lui richiamando una delle tre funzioni PID mentre a me tocca inserire Kp Ki e Kd (dichiarate come fractional) percui mi chiedo ma il Td è sottointeso nel valore da me inserito in Ki e Kd visto che nel calcolo di abcCoefficient non c'è traccia?

Inoltre aprendo un esempio microchip dove si fa uso delle tre funzioni PID noto che Kp Ki Kd sono forniti nel seguente modo:

kCoeffs[0] = Q15(0.7);
kCoeffs[1] = Q15(0.2);
kCoeffs[2] = Q15(0.07);

il vettore che contiene i kCoeffs è dichiarato fractional.
Aprendo l'Header file dsp.h mi accorgo che chiamando Q15(x) lui fa' questo calcolo:

#define Q15(X) \
((X < 0.0) ? (int)(32768*(X) - 0.5) : (int)(32767*(X) + 0.5))

che non ho assolutamente compreso, perchè se la interpreto come una divisione allora qualsiasi valore ci metta ad X il risultato mi viene sempre uguale ad 1 per via del casting int fatto al dividendo e divisore comunque facendo un debug vedo che ad esempio Q15(0.7) viene trasformato in un numero pari a 0.7x2^15 cioè nel formato Q15 PERO' visto che sicuramente il mio Kp sarà maggiore di 1 come lo si riporta in formato Q15? (Non credo si faccia ad esempio se Kp=30 allora 30x2^15)
Un saluto

Link to comment
Share on other sites


Ctec

Io i Pic non li conosco affatto.

Ti posso però dire che la #DEFINE sostituisce Q15(X) con l'operatore ternario (.. ? .. : ..).

E funziona così: se X <0.0, sostituisce con (int)(32768*(X) - 0.5) altrimenti con  (int)(32767*(X) + 0.5). In pratica effettua una moltiplicazione con arrotondamento per eccesso.

Poi che in una PID non possa essere Kp inferiore o uguale a 1, non è mica vero...

Link to comment
Share on other sites

peppe855

Ciao Ctec grazie per l'intervento molto chiaro, pero' non discuto che un Kp possa valere meno di 1 ma non capisco se vale piu' di uno come faccio a restare coerente con questo formato?? 

Link to comment
Share on other sites

Ctec

Supponiamo di avere il primo caso Q15(0.7).

Per quanto detto lo traduce in 

(int)(32768*(0.7)+0.5) => (int)(22937.6 + 0.5) => (int)(22938.1) => 22938

Il casting a (int) viene effettuato alla fine, mentre tutti i calcoli dentro la parentesi successiva al casting vengono fatti in float, essendo 0.5 di questo tipo.

Il compilatore nelle operazioni eleva sempre al tipo "più capiente" tutti gli elementi dell'espressione in gioco, fa le operazioni con questo tipo, poi se specificato esegue il casting specificato. E' il cosiddetto casting automatico.

Link to comment
Share on other sites

peppe855

Quello che pero' non mi risulta chiaro è se Kp invece di essere 0.7 è ad esempio 20 come lo trasformo in Q15??

Link to comment
Share on other sites

Ctec

La #define è una macro. Sostituisce letteralmente quello che è scritto con Q15(X) con quella specie di formuletta, mettendo il valore di X nella Q15(X) dentro la X che c'è nella definizione.

Pertanto, se te scrivessi Q15(20), il compilatore lo sostituirebbe con

(int)(32768*(20)+0.5) => (int)(655360 + 0.5) => (int)(655360.5) => 655360

Se hai ulteriori dubbi, consiglio una lettura al Kernigan Ritchie...

Link to comment
Share on other sites

peppe855

Ctec ancora grazie per la pazienza, pero' scusa 655360 non puo' piu' essere considerato in formato Q15 poichè non ci entra nei 16bit !

Io penso che andrebbe fatta una scalatura a monte mi spiego:

ho Kp=20; Ki'=Ki*Td=0.2; Kd'=Kd/Td=0.04; allora faccio Kp+Kd+Ki'=20.24; quindi assumo Base=20.24; e faccio Kp'=20/BASE

                                                                                                                                                                               Ki''=0.2/BASE

                                                                                                                                                                               Kd'=0.04/BASE

La funzione PID() nei suoi calcoli si va' a prendere Riferimento=Q15(x);

                                                                                 Output=Q15(x);

e quindi mi chiedo come scalo questi valori? usando Base=20.24 non avrei un valore <1 poichè il riferimento ad esempio viene dall'ADC e restituisce un valore da 0-1024;

Io farei una cosa del genere:

Scalo i parametri del regolatore come detto sopra invece per il setpoint (che proviene da adc a 10bit) e la misura dell'uscita (in questo caso velocità motore che esce con un numero compreso tra +- 600) farei cosi: La misura da adc me la faccio dare in formato Q15 cioè con il MSB in posizione [15] ovvero ad esempio 0111111111 000000;

                                                                La misura di velocità per confrontarla con il numero dell'adc la shifterei di 5 bit a sinistra esempio 0110001101 000000;

Il PID mi restituira' l'uscita a 16 bit in formato Q15 che io dovro' manipolare per darlo in pasto al mio PWM che per le scelte fatte accetta un valore da 0-4096, e questo lo faccio cosi: (uscitaPID<<1)>>4; (nella prima parentesi elimino il segno, con la seconda operazione scalo tra 0-4096) che chiaramente si puo' fare UscitaPID>>3;

Resta' pero' il fatto che i parametri del pid sono stati scalati con BASE e non avendo io accesso alle operazioni intermedie fatte dalla funzione PID che mi da' direttamente l'uscita come tengo conto di quella scalatura fatta prima? 

Spero si sia capito qualcosa.

        

Link to comment
Share on other sites

Ctec

Peppe, io stavo solo parlando della sintassi del C.

Come ho detto, i PIC non li conosco, uso altra roba (8051 derivati e ARM CORTEX). In particolare per questi ultimi, gli int sono a 32bit... Per i primi a 16bit..

Normalmente la dimensione dipende dal compilatore...

Non so assolutamente la dimensione di un int per un dspic...

Per il resto, mi sa che dovrai chiedere a chi si intende di tali micro e chi ha visto le librerie in questione...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...