Sei sulla pagina 1di 115

M ODELLISTICA E PROGETTO DI REGOLATORI PI E

PID ORIENTATI ALLO SVILUPPO SU


MICRO - CONTROLLORE
Calzoni Pietro
Francesco Castelli Dezza
17 gennaio 2007

Questa dispensa cercher di modellizzare un regolatore PI e, successivamente, PID per il controllo di un


sistema stabile e instabile. Lobiettivo realizzare i modelli di simulazione tempo-continui, discreti e, infine,
digitali. Questi ultimi in particolare verranno anche simulati in modo che si possa studiare il comportamento di
un regolatore digitale allinterno della catena di regolazione e il codice scritto sar in linea di massima quello
riportabile allinterno del micro-controllore.
Per quanto riguarda la modellistica tutto verr fatto con S IMULINK 6 fornito nel pacchetto M ATLAB 7 SP1
sotto sistema GNU/Linux Slackware 10.2. Si noti comunque che esistono tools molto simili (gratuiti e opensource) come S HILAB che eseguono esattamente le stesse funzioni. La scelta di M ATLAB ricaduta sul fatto che
presente nella stragrande maggioranza dei laboratori informatizzati del Politecnico di Milano e che attualmente
lo stato dellarte per la modellistica dei sistemi.
Tutta la trattazione orientata alla realizzazione vera e propria del controllore prendendo come riferimento
i micro-controllori di MICROCHIPT M ; la scelta di questi prodotti non dettata da particolari motivazioni tecniche, bens da motivi pratici. Questi processori infatti cono distribuiti con package di tipo DIP ossia possono
essere montati e saldati agevolmente anche su millefori in modo da dare la possibilit a chiunque di effettuare
sperimentazioni a basso costo. Inoltre tutti i tools di sviluppo e compilazione sono forniti gratuitamente insieme
allambiente di sviluppo direttamente da MICROCHIPT M comune a tutti i processori.

Indice
1

Problematiche di calcolo digitale

1.1

Basi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

Operazioni tra numeri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3

Velocizzare le operazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4

Flusso del programma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.5

Scrivere un programma C orientato al micro controllore . . . . . . . . . . . . . . . . . . . . . .

1.6

Integrazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Progetto di un regolatore PI

15

2.1

Regolatore tempo-continuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

2.1.1

Cenni riguardo la trasformata di Laplace . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.1.2

Progetto del regolatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.1.3
2.2

Anti wind-up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

Regolatore Discreto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.2.1

Cenni riguardo la trasformazione Z . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.2.2

Mappatura dei poli da s a z . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

2.2.3

Risposta in frequenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

Modellistica del regolatore PI

25

3.1

Regolatore tempo-continuo classico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

3.2

Regolatore Z ottenuto dal tempo-continuo classico . . . . . . . . . . . . . . . . . . . . . . . .

29

3.3

Regolatore Digitale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

3.3.1

Modello C-S IMULINK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

3.3.1.1

Metodo 1: Separazione parte proporzionale e integrale . . . . . . . . . . . . .

34

3.3.1.2

Metodo 2: Rielaborazione del PI ottenuto dalle funzioni z . . . . . . . . . . .

37

3.3.1.3

Metodo 3: Rielaborazione del PI ottenuto dalla configurazione anti wind-up .

40

3.3.1.4

Osservazioni e Confronti . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

3.3.2

Simulazione del Duty-Cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

3.3.3

Regolatore Digitale con metodo di integrazione dei resti . . . . . . . . . . . . . . . .

47

Implementazione di un regolatore PI

49

4.1

Regolatore PI su processori dsPIC30F . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.1

Sviluppo del regolatore in codice C . . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

Controllo di tensione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

60

4.2.1

61

4.2

Progetto e implementazione del regolatore . . . . . . . . . . . . . . . . . . . . . . . . .


3

INDICE

Regolatore PID
5.1 Regolatore tempo-continuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73
73

5.2

Regolatore Discreto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

5.3

Regolatore PID di corrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


5.3.1 Progetto del regolatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

78
80

5.3.2
5.3.3

81
86

Simulazione del regolatore digitale . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Implementazione su micro-processore dsPIC30F . . . . . . . . . . . . . . . . . . . . .

A Breviario sulla sintassi C

93

A.1 Tipi di dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

93

A.2 Dichiarazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

B Validit del regolatore PI


103
B.1 Discretizzazione del regolatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
B.2 Modellistica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

Capitolo 1

Problematiche di calcolo digitale


Prima di affrontare il progetto e la realizzazione del regolatore vero e proprio, verranno affrontate alcune problematiche tipiche del calcolo digitale con micro processori dedicati i quali normalmente non hanno potenzialit di
calcolo molto elevate. Prima di proseguire con la trattazione viene brevemente introdotta la tabella dei simboli
usati in questo capitolo:
a

lettera minuscola: indica il valore reale della grandezza

arif

grandezza reale di riferimento

bitbase

numero di bit che identifica la base

indica il valore in per-unit della grandezza

#Ap

indica il valore normalizzato in base p. Per esempio: #A10 un valore in base 10bit

indica il processo di normalizzazione, tipicamente 2bitbase /arif

Verranno poi descritte le linee guida per la scrittura di un programma C.

1.1

Basi

Il micro calcolatore deve in primo luogo effettuare calcoli in un intervallo temporale ben definito. Le ridotte
capacit di calcolo normalmente non permettono di operare con variabili di dimensioni e/o struttura complesse
e non ci si riferisce al formato float o double (doppia precisione), ma, spesso, neppure agli interi a 16bit! Un
esempio sono i molti micro controllori PIC di M ICROCHIP o HC di F REESCALE che lavorano con parole a 8bit1 .
chiaro quindi che, per rendere lesecuzione veloce (spesso in modo determinante), occorre fare in modo che
il processore esegua i conti con numeri interi. Per rappresentare numeri reali si rende quindi necessario scegliere
una base. Questo riporto non complesso da gestire; in linea teorica infatti sufficiente fissare un valore di
riferimento per una determinata grandezza, prendere il valore reale, dividerlo per il riferimento (ossia riportare
il valore in per-unit) e quindi moltiplicarlo per la base scelta. Per esempio: si supponga di avere un valore di
corrente reale che al massimo raggiunga i 20A e il processore riesca a gestire parole a 16bit; si ipotizzi di usare
1 Si

noti che tipicamente riescono a gestire parole a 16bit o multipli al costo di un maggiore carico computazionale.

CAPITOLO 1. PROBLEMATICHE DI CALCOLO DIGITALE

una base pari a 4096 (212 ). Allora, indicando con i la corrente reale e con #I la corrente digitalizzata, si pu
asserire che
4096
#I12 = i
20
In questo esempio si scelto come riferimento della corrente il suo valore massimo. Non necessario operare
in questo modo; infatti il valore di riferimento viene normalmente scelto in funzione delle caratteristiche del
sensore.
Per quanto riguarda la base scelta, il numero 4096 non casuale! Esso infatti una potenza di 2. Ci render
molto pi comodo eseguire operazioni tra basi, come si vedr in seguito. per evidente che si scelto di operare
con variabili a 16 bit e che con tale base si possono rappresentare numeri in [p.u.] compresi tra -8 e 8. Potrebbe
sembrare esagerato ma tali valori permettono di eliminare il problema delloverflow a seguito dellesecuzione di
operazioni. Per esempio se una grandezza a 16bit (ma in base 12bit) viene calcolata come somma di qualche
variabile (per esempio 3) in base 12bit (e supponiamo limitate a 4095) il risultato sarebbe contenuto in 14 bit
senza bisogno di effettuare controlli sulle soglie che costano in termini computazionali e possono quindi essere
differiti alla fine dei calcoli. Si noti che i bit a disposizione sono s 16, ma il sedicesimo bit di segno.
Variabilit della base
Una base non deve necessariamente rimanere la stessa durante tutta lesecuzione del programma. Essa non
solo pu variare, ma pu essere anche diversa tra variabili che concorrono a generare lo stesso risultato, come
per esempio il termine integrale in alcuni PI (sezioni 3.3.1 e 4.1.1); se infatti il termine molto minore di 1,
conviene prevedere degli accorgimenti necessari a non perdere dati significativi. Il problema dellintegrazione
verr affrontato pi avanti, ma per ora basti sapere che spesso (e se possibile) conviene usare una variabile al
doppio della base (pari a 24bit, quindi in una variabile tipo long int) ed effettuare conversioni di base quando
verr richiesto il valore in una base differente.

1.2

Operazioni tra numeri

Le operazioni di somma e sottrazione tra numeri interi non presentano grossi problemi (escludendo loverflow
descritto poco prima) e il risultato, qualunque valore abbia, nella stessa base dei due addendi. Moltiplicazione
e divisione invece hanno qualche problema.
Moltiplicazione: la moltiplicazione tra due numeri della stessa base pari al prodotto dei due diviso la base dei
due numeri:
#Cbitbase = #(A B)bitbase =

#Abitbase #Bbitbase
2bitbase

ma avendo scelto basi con potenze di 2, loperazione si semplifica e si velocizza in quanto la divisione per
potenze di 2 equivale a uno shift logico dei bit verso destra:
#Cbitbase = #(A B)bitbase = (#Abitbase #Bbitbase )  bitbase
Questa operazione risulta molto pi agevole per il micro processore, mentre una divisione molto pi
pesante. La moltiplicazione tra basi differenti invece avviene allopposto:
#C10 = #(A B)10 =

#A12 #B9
= (#A12 #B9 )  11
212+910

1.3. VELOCIZZARE LE OPERAZIONI

Divisione: la divisione analoga. In questo caso per conviene premoltiplicare il numeratore per non perdere in
precisione:
 
A
#Abitbase  bitbase
#Cbitbase = #
=
B bitbase
#Bbitbase

1.3

Velocizzare le operazioni

Come si accennato le operazioni matematiche come moltiplicazioni e somme sono molto pesanti per il microcontrollore. Per guadagnare tempo quindi si definiscono una serie di shift, normalmente pi veloci da gestire i
quali possono aiutare a velocizzare lesecuzione del programma. Se loperazione tra un valore e una costante
conviene riportare tutto alloperazione di moltiplicazione, per esemio #A = #B/0.3125 = #B 3.2. In questo
esempio si vede come il secondo termine non sia un numero intero. Grazie agli shift possiamo tenerne conto
scomponendolo: 3.2 ' 21 + 20 + 23 + 24 + 25 da cui ne deriva #A = (#B  1) + (#B) + (#B 
3) + (#B  4) + (#B  5).
Le operazioni matematiche per non sono le uniche pesanti. Altre operazioni di rilievo sono le chiamate
(CALL) di funzione le quali sono tanto pi pesanti quanti pi parametri vengono passati in quanto vanno normalmente salvati nello stack; evidente quindi che in un sistema a micro-controllore sono da evitare funzioni
di tipo ricorsivo. Per ovviare a questo inconveniente pu risultare utile definire la funzione tramite la direttiva
__inline__ come segue:
void __inline__ callback(int, int, int);

Lo svantaggio di usare questa formulazione che il codice normalmente diventa molto voluminoso.
Una alternativa alla direttiva __inline__ la definizione di una macro, ma lutilizzo consigliabile solo se
le operazioni sono relativamente poche o relative alla analisi di una struttura (ottimi esempi nel codice sorgente
dei dispositivi a caratteri del kernel Linux). La definizione di una macro :
#define NOME_MACRO(var1, var2, varN)(var1*5-(var2> >4)-3*varN)

Da porre attenzione al fatto che la macro non fa altro che sostituire lespressione che segue la definizione
degli argomenti in parentesi con quanto gli veine passato. Quindi, quando la macro viene chiamata, i parametri
devono essere o numerici o contenuti in parentesi per precauzione. Se allinterno del programma la macro venisse
chiamata nel modo seguente:
x = NOME_MACRO(2-1, 0, 1+1)

x assumerebbe il valore x=2-5-2*1+1=-4 al posto del valore desiderato ossia x=(2-1)*5-2*(1+1)=1.


Quindi il metodo corretto per scrivere una macro ricorrere il pi possibile alle parentesi:
#define NOME_MACRO(var1, var2, varN)((var1)*5-((var2)> >4)-3*(varN))

Altri errori di calcolo sono legati al metodo di scrittura degli shift logici i quali come precedenza sono inferiori
alla somma, ossia una macro del tipo:
#define MACRO(var1)(var1< <2 + var1> >1)

il primo shift (a sinistra) avr come numero di bit da shiftare un valore pari a (2 + var1). Per esempio con
var1=4 il risultato di MACRO effettua il calcolo (4(2+4))1=128 mentre il risultato atteso (42)+(41)=18.
Per questo anche in questo caso occorre usare il maggior numero di parentesi.

CAPITOLO 1. PROBLEMATICHE DI CALCOLO DIGITALE

Le macro possono introdurre anche un altro problema legato alla castizzazione2 ; infatti una macro del tipo
seguente:
#define NOME_MACRO(var1)((var1)< <10)

se chiamata allinterno del programma in modo che e sia una variabile per esempio di tipo int, ma il risultato
sia da porre in una di tipo long int, il valore verr prima calcolato in int e, se ci causa un overflow, il risultato
verr troncato e successivamente assegnato a long int. Questo un errore frequente quanto grave. Per porvi
rimedio o si castizza largomento della macro quando essa viene chiamata nel programma, o lo si castizza nel
codice della macro.
Le macro che realizzano shift verso destra (ossia divisioni per potenze di 2) hanno un grande inconveniente
se lavorano su numeri con segno. Si consideri a tal proposito la seguente macro:
#define SHIFT_DX(e)((e> >4)+(e> >5)+(e> >6))

Si supponga ora che venga passato come ingresso il numero intero (ossia definito int) pari a 10 che in binario
a 16bit si esprime come 0b0000000000001010: il risutltato chiaramente 0 perch ogni shift sposta i vari bit di
una posizione sostituendo il vecchio valore con il valore del bit pi significativo, ossia il bit di segno. Se per il
numero -10 (che in binario risulta 0b1111111111110110) il risultato -3!3 Questo perch gli shift di numeri
negativi sostituiscono i bit spostati con il valore 1 ossia il valore del bit di segno. Quindi se la macro ha shift
negativi (soprattutto se la macro realizza un integrale) la corretta sintassi la seguente:

if(input>=0) output=SHIFT_DX(input)
else output=-(SHIFT_DX((-input)))

1.4

Flusso del programma

Lesecuzione del programma non lineare come invece avviene nei normali programmi4 . Il programma normalmente parte chiamando la funzione main la quale provveder a compiere tutte le inizializzazioni di variabili e
dispositivi. Fatto ci il micro passa in un loop infinito. Il programma, quindi, continuer ad eseguire le operazioni definite in questo loop il quale potr essere interrotto da determinati eventi (interrupt) legati ai dispositivi
presenti sul processore e alle condizioni di I/O. Normalmente infatti non si gestisce la richiesta di un evento
in polling (ossia controllando ciclicamente che sia avvenuto un evento) in quanto si perde tempo di CPU per
eseguire operazioni che il pi delle volte danno risultato nullo (come per esempio la gestione dei pulsanti).
Gli interrupt, per, possono essere asserviti anche ad eventi interni al micro-processore generati da sistemi
come timer, PWM, convertitori, ecc. Ci fondamentale perch nei sistemi embedded normalmente richiesto
il real-time5 , ossia occorre essere sicuri che entro determinate scadenze temporali il sistema abbia effettuato tutte
le operazioni necessarie per effettuare la regolazione.
A titolo di esempio si consideri il sistema di controllo della corrente in un regolatore. prassi fare in modo
che la routine di regolazione (per esempio PI) venga asservita alla richiesta di interruzione dovuta allevento di
fine conversione del convertitore analogico-digitale. Le temporizzazioni invece possono essere date con timer o
PWM (come si vedr in seguito).
2 Questo problema in realt sarebbe da imputare al compilatore. Si noti che nel compilatore C30 e C18 di M ICROCHIP questo problema
esiste, mentre, per esempio, nel compilatore gcc Linux (da cui i compilatori menzionati derivano) non vi questo problema.
3 Si ricorda che 0b1111111111111111 = -1.
4 Sempre che non ricorrano a fork o thread.
5 Spesso si intende implicitamente hard real-time ossia che se non vengono garantite determinati risultati entro certe scadenze, viene
compromesso il funzionamento del dispositivo sotto controllo (per esempio i sistemi intrinsecamente instabili); viceversa per il soft real-time.

1.5. SCRIVERE UN PROGRAMMA C ORIENTATO AL MICRO CONTROLLORE

Priorit
Le funzioni di interrupt sono prioritarie ed interrompono lesecuzione normale del programma, dove per normale si intende tutto ci che viene seguito dalla funzione main. Gli interrupt per, vengono a loro volta gestiti con
determinate priorit in funzione del processore. A titolo di esempio si considerino le seguenti famiglie:
PIC16F

fino alla versione 16F i pic hanno una sola chiamata di interrupt. Per capire quale dispositivo ha
invocato linterruzione, occorre esaminare specifici flags.

PIC18F

sono pi evoluti e tra le altre migliorie hanno introdotto anche due funzioni di interrupt: una a
bassa priorit e una ad alta priorit. In questo caso la funzione di interrupt ad alta priorit in
grado di interrompere quella a bassa priorit. Rimane comunque da capire quale evento ha scatenato
linterrupt e ci viene fatto sempre esaminando determinati flags.

dsPIC30F hanno interrupt per ogni dispositivo con una priorit variabile tra 0 e 7. Le routine a pi alta priorit possono interrompere quelle a pi bassa priorit e sono normalmente pi veloci per evitare di
occupare troppo tempo di CPU che dovrebbe essere destinato ad altre routines. Infatti questo sistema di gestione delle priorit si molto versatile ma pu rendere difficoltoso lanalisi del flusso
di programma. In questi processori esistono comunque flags che indicano lavvenuta richiesta di
interrupt, anche se normalmente vengono usati solo dai dispositivi che generano la stessa richiesta di
interruzione a fronte di propri eventi interni differenti (come per esempio la ricezione, trasmissione,
generazione errori, ecc nel modulo CAN).

1.5

Scrivere un programma C orientato al micro controllore

Un programma C costituito normalmente da files .h e .c. I primi sono detti di intestazione (header) e sono files in cui vengono definite le funzioni, macro, variabili, tipi, ecc; i secondi sono i files che contengono
limplementazione delle funzioni definite nei files .h.

Struttura di un file header


buona norma che tutto il codice definito in un file header sia posto allinterno di una macro di precompilazione
#if come segue:
#ifndef __NOMEFILE_H__
# define __NOMEFILE_H__
//TODO
#endif //__NOMEFILE_H__

il che serve per comunicare al compilatore che durante la compilazione di un file .c se linclusione del file
nomefile.h viene fatta pi volte (per esempio da altri file .h) questo file gia stato incluso. In caso contrario il
compilatore restituirebbe dei warnings (o degli error) a causa di definizioni multiple di tipi, define, ecc.
Per quanto riguarda le definizioni di funzioni e variabili allinterno del file header, tipicamente occorre
definirle come extern:
extern void CallBack(int, int); //funzione
extern int error; //variabile

10

CAPITOLO 1. PROBLEMATICHE DI CALCOLO DIGITALE

Questo implica che esister un file .c in cui queste label vengono riprese e, se funzioni, implementate. In caso
contrario in fase di linking, il linker restituir un errore simile al seguente:
/tmp/ccgbPtiF.o(.text+0x16): In function main:
: undefined reference to CallBack
collect2: ld returned 1 exit status

e analogamente per le variabili. La keyword extern ha anche un altro utilizzo, ossia permette al linker di collegare
funzioni che non sono state implementate in un apposito file .c, ma passate tramite dei files oggetto o librerie
precompilate.
Nei files .h vengono spesso definite anche le grandezze const:
const int X[LENGTH_X] = {
//TODO, x es: 1, 2, 3
};

Questa non la scelta pi oculata in quanto potrebbero accadere errori dovuti alla multipla inclusione, ma normalemente queste costanti vengono usate solo da uno specifico file quindi incluse una volta sola. Nel micro
controllore la keyword const implica che la variabile andr scritta nellarea codice (.code) e non nellarea dati (.text), quindi non potr essere scritta in run-time. Un tentativo di scrittura comporta normalmente un reset
del processore. Si noti che normalmente larea .text nettamente pi piccola dellarea .code. Per maggiori
informazioni su questo argomento si veda [3] o il manuale del compilatore C del processore specifico.

Struttura dei files C


Come detto il file .c pi importate quello che contiene la funzione main. Essistono per i file che contengono
limplementazione delle funzioni C definite negli header files. Tali funzioni non devono ovviamente ripetersi.
Un file C che contiene la funzione main normalmente strutturato come segue:
#include <p30fxxxx.h> //inclusioni di file contenuti nelle directory del compilatore
#include localfile.h //inclusione di un file nella directory di progetto
//definizione macro
#define MUL2(in)(((int)in< <1))
//definizione variabili globali
long int integrale=10, derivata;
//definizione di funzioni a visibilit globale, x es:
int moltiplicazione(int x, int y);
//implementazione del main: definita una volta sola allinterno del progetto
int main () {
//TODO
while(1) { //loop infinito
//TODO
}
}
//implementazione delle funzioni locali
int moltiplicazione(int x, int y) {
return x*y;
}
//Eventuale implementazione delle routine i interrupt.
//La sintassi varia da micro a micro; qui riportata quella per dsPIC30F
void _ISR _T1Interrupt(){
//TODO
}

Come si nota allinterno della funzione main deve esserci un ciclo infinito. Questo perch il micro non deve
terminare il programma altrimenti si resetterebbe. Allinterno del ciclo while non strettamente necessario che

1.6. INTEGRAZIONE

11

vengano svolte operazioni. Una volta entrati in questo ciclo tutto il controllo affidato di norma alle routine di
interrupt; solo routine di minore importanza vengono gestite in polling allinterno del ciclo.
Un ciclo infinito pu essere definito anche nei seguenti modi:

Ciclo do ... while:


do {
// TODO
} while (1);

Ciclo FOR:
for(;;){
// TODO
}

GOTO:
goto_label:
// TODO
goto goto_label;

1.6

Integrazione

Lintegrazione in un micro controllore viene tipicamente fatta con il metodo dei rettangoli o con il metodo dei
trapezi (detto anche di Eulero) il quale pi preciso del precedente. Lintegrazione di una grandezza tipicamente
problematica in quanto il coefficiente di integrazione normalmente molto piccolo e ci implica che spesso il
piccolo errore non venga valutato. Per esempio si consideri un coefficiente Ki =10 e un tempo di integrazione
Ts =50106 s. Supponendo ora una variabile errore e intera, la quota parte di integrale allistante n-esimo sar
pari a
Ki

Ts
(e(n) + e(n 1)) = 2, 4 104 (e(n) + e(n 1))
2

Non entriamo per il momento nel merito di come si realizzi il parametro floating poit 2.4 104 , ma noto che il
microprocessore elabori variabili intere e perci il risultato di questa operazione dovr essere un numero intero.
Considerando ora la variabile errore e di tipo intero che, per esempio, assume valori tra 0 e 4096, chiaro che
perch il risultato della moltiplicazione dia almeno il valore 1 occorre che e(n) + e(n 1) valga almeno 4000.
Per questo occorre gestire opportunamente la grandezza integrale. Di seguito sono proposti alcuni metodi.
Il codice che verr presentato nelle sezioni seguenti da considerarsi pseudo codice nel senso che serve
solo per dare unidea di come tradurre in C il problema formalizzato.
Variabili a 32 bit
Scelta la base di conversione delle grandezze fisiche (per esempio 12 bit) si suppone di lavorare con una base
dellintegrale diversa, tipicamente il doppio dei bit della base delle grandezze fisiche (quindi 24 bit). Questo
vuol dire che il valore del coefficiente Ki T2s verr calcolato come Ki T2s 212 = 1, 024. A questo punto possibile
valutare il piccolo errore tenendone memoria nella variabile di integrazione. Chiaramente la variabile risultante
in base 24 bit quindi occorre un intero a 32 bit per poterla gestire (long int nel micro controllore).
Per quanto riguarda limplementazione possibile seguire il metodo degli shift introdotto nella sezione 1.3.
Volendo realizzare il parametro 2.4 104 risulta:
#define INTEGRALE(e)((e> >12))

12

CAPITOLO 1. PROBLEMATICHE DI CALCOLO DIGITALE

il che implica praticamente la perdita di tutti i valori minori di 4095, come ci si poteva aspettare. Portando invece
il valore di Ki in base 24 nit si ha che la macro pu essere definita come:
#define INTEGRALE(e)((e)+(e> >6)+(e> >7)+(e> >11))

il che permette di tenere conto del piccolo errore anche in fase di integrazione. Allinterno del programma
lintegrale verr gestito come segue:
long int integrale; //variabile a 32 bit
...
error_i=error+error_1; //calcolo error_i come lerrore attuale+lerrore precedente
if(error_i>=0)
integrale+=INTEGRALE_L(error_i);
else
integrale-=INTEGRALE_L((-error_i));

Pro e contro di questo metodo sono evidenti: sicuramente favorevole il fatto che tutte le operazioni si riducano
a degli shift le quali sono operazioni di norma eseguite con un bassissimo numero di cicli di clock e quindi
molto performanti anche con grandezze di notevole dimensione come le variabili long int. Di contro si ha
che le operazioni su grandezze di tipo long restano comunque pesanti dal punto di vista computazionale per
processori a 8 bit (come i PIC) perch occorre ricordare che tale grandezza andr poi riscalata alla base scelta per
poter essere omogenea con le altre grandezze del regolatore per esempio per calcolare luscita:
out=proporzionale+derivativo+((int)(integrale> >12));

dove out, proporzionale e derivativo in questo caso sono da considerarsi variabili in base 12 bit.
Ci nonostante in questa dispensa, questo metodo sar quello pi utilizzato.
Gestione dei resti
La gestione dei resti utile per micro processori con scarse capacit computazionali o in quei casi in cui il
metodo precedentemente descritto non funzioni correttamente. Un metodo per eseguire ci pu essere quello di
tenere in considerazione lelaborazione del piccolo errore e del grande errore; a tal proposito si supponga
di essere nelle condizioni del caso precedente, ossia di avere un Ki =10 e Ts =50106 s. Si consideri ora di
avere due variabili che tengano conto della componente pi significativa e meno significativa di un integrale
(rispettivamente indicate con intH e intL). La gestione del resto pu quindi essere espressa in questo modo:
#define UNITA_INTEGRALE 4095
#define INTEGRALE_H(e)((e))
#define INTEGRALE_L(e)((e> >6)+(e> >7)+(e> >11))
int intH, intL, error_i; //int da intendersi a 16 bit, ma i valori sono in base 12bit!
...
//nella routine si ha
error_i=error+error_1; //calcolo error_i come lerrore attuale+lerrore precedente
intH+=INTEGRALE_H(error_i); //non faccio controlli su error_i perch non ho shift destri
if(error_i>=0)
intL+=INTEGRALE_L(error_i);
else
intL-=INTEGRALE_L((-error_i));
//Controllo del superamento dellunit (UNITA_INTEGRALE)
if(intL>UNITA_INTEGRALE) {
intH++; //aumento di 1 la parte integrale pi significativa
//riduco di una unit intL che ha superato il valore massimo positivo
intL-=UNITA_INTEGRALE;
} else if(intL<-UNITA_INTEGRALE) {
intH--; //diminuisco di 1 la parte integrale pi significativa
//aumento di una unit intL che ha superato il valore massimo negativo

1.6. INTEGRAZIONE

13

intL+=UNITA_INTEGRALE;
}
...
out=proporzionale+derivativo+intH;

Come di pu notare lintegrale diviso in due e la somma pari a quella del caso precedente solo che questa
volta vengono calcolati separatamente e i risultati posti in variabili in base 12 bit. La parte minore (intL) viene
trattata in modo tale che non superi mai il valore 4095, ossia il valore corrispondente allunit. Qualora questo
valore venisse superato, intL avr sicuramente il 13 bit a 1 che corrisponde allunit da aggiungere a intH,
operazione che viene fatta subito dopo; quindi intL viene ridimensionata sottraendo il valore 4095. Per quanto
detto evidente che la variabile intL dopo la sottrazione si porta ad un valore minore di UNITA_INTEGRALE.
Tutto quello che stato appena detto ripetibile anche nel caso in cui la soglia superata sia quella negativa. Si
osservi che quando occorre utilizzare la variabile integrale (come per il calcolo di out) sufficiente utilizzare la
parte pi significativa del valore dellintegrale espressa nella stessa base delle altre grandezze. Il metodo appena
descritto non ha nessun pregio significativo rispetto al precedente in quanto evidente che la precisione resta la
stessa a fronte di un carico computazionale maggiore.
possibile introdurre un altro modo per gestire il problema agendo direttamente sulla variabile error_i.
Per fare questo si considera il valore reale del termine integrale Ki T2s 212 = 1, 024 il che scomponibile come
Ki T2s 212 = 1, 024 = 1 + 0, 024 = H + L, do ve chiaramente H = 1 e L = 0, 024. La parte maggiore di
zero continuer ad essere gestita come in precedenza, mentre la parte inferiore verr gestita in un altro modo.
Ora occorre valutare quale valore della variabile error_i fa in modo che si raggiunga lunit; tale valore chiaramente 0, 0241 = 41, 6 arrotondato sempre per eccesso, quindi 42. Quindi isolando i bit che compongono il
numero 42 nella variabile error_i e sommandoli ad oni ciclo di integrazione, quando lintegrale intL raggiunger
(o superer) il valore 42 occorrer aumentare di una unit il valore intH e ridimensionare intL. Assumendo che
per poter esprimere il numero 42 occorrono 6 bit6 , lo stralcio di codice seguente d unidea di come realizzare
quanto detto:
#define UNITA_INTEGRALE 42
#define MASK_INTL 0x3F //maschera separare i 6 bit necessari al calcolo di intL
#define INTEGRALE_H(e)((e))
#define INTEGRALE_L(e)(((e)&MASK_INTL))
int intH, error_i; //int da intendersi a 16 bit, ma i valori sono in base 12bit!
short int intL; //short int da considerarsi a 8 bit
...
//nella routine si avr...
error_i=error+error_1; //calcolo error_i come lerrore attuale+lerrore precedente
intH+=INTEGRALE_H(error_i); //non faccio controlli su error_i perch non ho shift destri
if(error_i>=0)
intL+=INTEGRALE_L(error_i);
else
intL-=INTEGRALE_L((-error_i));
//Controllo del superamento dellunit (UNITA_INTEGRALE)
if(intL>=UNITA_INTEGRALE) { // questa volta devo verificare che sia >=
intH++; //aumento di 1 la parte integrale pi significativa
//riduco di una unit intL che ha superato il valore massimo positivo
intL-=UNITA_INTEGRALE;
} else if(intL<=-UNITA_INTEGRALE) {
intH--; //diminuisco di 1 la parte integrale pi significativa
//aumento di una unit intL che ha superato il valore massimo negativo
intL+=UNITA_INTEGRALE;
}
...
out=proporzionale+derivativo+intH;
66

bit ottenuti arrotondando per eccesso il risultato di log2 (42); in Matlab: ceil(log2(42))

14

CAPITOLO 1. PROBLEMATICHE DI CALCOLO DIGITALE

Come si nota non cambia molto nella struttura del programma anche se il carico computazionale si abbassato.
Inoltre intL ora a 8 bit quindi pi facilmente gestibile da micro processori come i PIC. Come si nota la
precisione aumentata in quanto nei casi descritti precedentemente tutti i valori di error_i minori di 26 1 = 63
venivano scartati, mentre ora vengono considerati.

Capitolo 2

Progetto di un regolatore PI
In questo primo capitolo verr trattato il progetto di un semplice regolatore PI per il controllo di un sistema del
primo ordine, come per esempio la funzione di trasferimento tra corrente e tensione in un induttore. Verr quindi
presentato come realizzare un regolatore partendo dallo studio delle funzioni continue nella variabile tempo t
(ossia si progetter il regolatore analogico) per poi portare i risultati nel tempo discreto. Il passo successivo sar
realizzare il codice vero e proprio che un microprocessore possa eseguire. Ci verr fatto restando inizialmente
in ambiente Simulink.

2.1

Regolatore tempo-continuo

Il regolatore tempo-continuo, come noto, viene definito studiando il sistema da controllare nel dominio della
frequenza, ossia applicando la trasformazione di Laplace alle equazioni di stato.

Figura 2.1: Retroazione di un sistema con regolatore PI.


Banalmente un sistema controllato con un regolatore PI rappresentato in figura 2.1; in particolare questo
regolatore PI controlla un sistema stabile di tipo R-L. In questo caso il regolatore permette di migliorare la risposta
del sistema cercando di seguire il pi fedelmente possibile il riferimento di corrente in ingresso. In questo schema
sono volontariamente eliminati i ritardi e le funzioni di trasferimento degli azionamenti e dei sensori. comunque
chiaro che la corrente in un sistema reale dovr essere retroazionata tramite un sensore apposito e che il regolatore
comprensivo dellazionamento vero e proprio (ossia dellalimentatore ideale1 di tensione).
I due blocchi in figura verranno indicati in seguito come R(s) per quanto riguarda il regolatore PI e G(s) per
quanto riguarda la funzione del sistema in esame.
Negli esempi seguenti il regolatore PI verr applicato su sistemi intrinsecamente stabili.
1 Per ideale non si intende solo il fatto che i ritardi introdotti siano nulli, ma anche che il sistema pu dare un valore di tensione continuo
e illimitato istantaneamente.

15

16

CAPITOLO 2. PROGETTO DI UN REGOLATORE PI

2.1.1

Cenni riguardo la trasformata di Laplace

La trasformata di Laplace una funzione lineare che permette di studiare una funzione reale (normalmente
funzioni temporali) tramite una corrispondente funzione complessa.
Definita una funzione reale (f : (0, +) R) si ottiene lintegrale di Laplace come
T

est F f (t)dt

F (s) = {Lf } (s) = lim lim

T + 0

o nella foma generalizzata


Z

est F (t)dt

F (s) = {Lf } (s) =


0

Questa relazione lineare ed molto comoda per lo studio dei sistemi come regolatori e filtri per i quali non
vi motivo di effettuarne lo studio per valori temporali negativi.
Per quanto riguarda la convergenza della serie, questa legata sia alla funzione f (t) sia alla variabile s. Infatti
se la funzione f (t) , come precedentemente definito, una funzione reale ed anche s una funzione reale, si ha
che la trasformata di Laplace restituisce come risultato un numero reale; quindi indicando con A il dominio della
trasformata di Laplace


est f (t)dt

sR:

A :=

si ha
Z
F : A R,

F (s) =

est f (t)dt

(2.1)

per tanto si ha convergenza se esiste ed funito lintegrale reale della funzione f (t).
Se invece la funzione s un numero complesso

B :=

Z
sC:

+
st


f (t)dt

come per esempio s = x + iy , allora la trasformata si esprime come


Z
F (s) =

ext (cos(yt) + i sin(yt)) f (t)dt

(2.2)

da cui deriva che la convergenza sia assicurata se convergono i due integrali reali in cui si scompone la funzione.
Il principale vantaggio introdotta da questa trasformazione riguarda la risoluzione delle equazioni differenziali
le quali diventano di tipo algebrico e consentono di studiare un sistema fisico come funzione fratta. La stabilit
del sistema assicurata dal fatto che le soluzioni che annullano il polinomio a denominatore (ossia i poli) devono
essere tutti a parte reale negativa.

2.1.2

Progetto del regolatore

Il progetto del regolatore PI normalmente abbastanza semplice in quanto vengono definite due equazioni in due
incognite. Le incognite sono i coefficienti del regolatore, mentre le due equazioni vengono definite fissando il
margine di fase e banda passante. Il problema come scegliere tali valori. Il margine di fase si fissa normalmente pari a 90 . Ci permette di non avere sovra-elongazioni nella risposta al gradino. Per quanto riguarda la
banda passante, la cosa pi complessa in quanto dipende tutto da come verr implementato il regolatore reale.

2.1. REGOLATORE TEMPO-CONTINUO

17

Infatti per il teorema del campionamento si sa che scelta la massima armonica campionabile senza aliasing, la
frequenza di campionamento dovr essere doppia di quella di tale armonica. Nei casi pratici, per, questo non
avviene praticamente mai soprattutto se non vengono implementati filtri di ordine elevato in uscita al trasduttore2 .
Tipicamente quindi si sceglie una frequenza di circa 1020 volte inferiore a quella di campionamento la quale
viene decisa in funzione delle capacit elaborative dei micro-controllori e viene data in termini di pulsazione; ci
verr trattato pi avanti nel dettaglio, quindi per ora si consideri la scelta (tipica) di 10001500 rad/s.
Definito il sistema in termini di banda passante (t 3 ) e margine di fase (m ) possibile ottenere le due
equazioni di cui sopra esprimendo in modulo e fase la funzione danello L(s) :
(

|R(j) G(j)|
=
1
]R(j) + ]G(j) = 180 + m

(2.3)

da cui si pu isolare lespressione del regolatore in termini di modulo e fase:


(

1
|G(j)|

|R(jt )|

]R(jt )

= 180 m ]G(jt ) =

(2.4)

Luscita di un regolatore PI nel dominio del tempo funzione dellerrore in ingresso ed la seguente:
Z
uP I (t) = KP e(t) + KI


e(x)dx = KP

1
e(t) +
Ti


e(x)dx

(2.5)

la quale portata nel dominio di Laplace diventa:



UP I =

KI
KP +
s


E(s) = P I(s) E(s) = R(s) E(s)

(2.6)

Esprimendo il regolatore in funzione della frequenza si ha:


R(j) = KP +

KI
KI
= KP j
= |R(j)|ej = |R(j)| (cos() + jsin())
j

(2.7)

Detto questo, dalle equazioni 2.4, 3.2 e 2.7 si ottengono le due equazioni in due incognite che permettono la
determinazione i parametri del regolatore:
(

2.1.3

KP

= |R(jt )| cos() =

KI

= |R(jt )| sin()

cos()
|G(jt )|
sin()
= |G(j
t
t )|

(2.8)

Anti wind-up

Normalmente tutti i regolatori (ma anche i sistemi in esame) vengono muniti di opportune soglie in uscita in modo
da impedire che le azioni di un determinato blocco (ossia le loro uscite) raggiungano valori poco realistici a causa
dei dispositivi fisici a disposizione per realizzare lazionamento vero e proprio. Ci per normalmente non basta
ad evitare il problema di wind-up. Tale problema legato normalmente allazione integrale4 la quale, a fronte
di un errore non nullo, tende a divergere anche se luscita del sistema viene saturata. Questo causa una notevole
2 Tali filtri possono anche essere di tipo digitale implementati sul microcontrollore applicati ai segnali campionati prima che esegua le
routine di controllo e regolazione.
3 Si noti che la pulsazione relativa alla banda passante si assume coincidente con la pulsazione di taglio in quanto la funzione danello
definita come L(s) = R(s)G(g) in retroazione, deve restituire una funzione di trasferimento risultante tra ingresso e uscita ( i i ) di modulo
rif

unitario (0 in dB nel diagramma di Bode) fino al punto di intersezione di L(s) con lasse 0 dB, ossa fino alla pulsazione t .
4 Si vedr in seguito che anche la componente derivativa pu avere problemi di questo tipo.

18

CAPITOLO 2. PROGETTO DI UN REGOLATORE PI

perdita di reattivit da parte del controllo e, soprattutto, si pu incorrere in spiacevoli conseguenze dipendenti dai
tipi di integratori (sia analogici che digitali). Lo schema tipico di un sistema anti wind-up riportato in figura
2.2.
Non ci si dilungher oltre in questa descrizione in quanto questo sistema di anti wind-up (come anche altri pi
complessi) serve solo per modellizare il sistema nel dominio del tempo, mentre nel digitale le cose si risolvono
molto pi semplicemente (sezione 3.3). Inoltre in [1] viene descritto dettagliatamente tutto il il processo di
digitalizzazione.

Figura 2.2: Schema a blocchi di un tipico sistema anti wind-up per regolatori PI.

2.2

Regolatore Discreto

I regolatori di tipo discreto sono regolatori che elaborano ingressi di tipo reale, discretizzando il tempo, ossia prelevando le valori ad intervalli regolari. immediato intuire che questo sistema si avvicina molto al
comportamento del regolatore reale il quale per presenta ulteriori complicazioni che verranno mostrate in
seguito.

2.2.1

Cenni riguardo la trasformazione Z

La trasformata z di una sequenza x(n) generica definita secondo le espressioni seguenti:


x(z) =

x(n)z n

x(z) =

n=

x(n)z n

(2.9)

n=0

rispettivamente dette bilatera e unilatera, dove la variabile z una variabile esprimibile in forma polare:
z = rej
Da ci ne consegue che la trasformazione si pu esprimere come prodotto della trasformata di Fourier per la
sequenza esponenziale:

X
X
x(rei ) =
x(n)(rej )n =
rn ejn
n=

n=

chiaro che perch la funzione converga deve risultare finita la sommatoria

|x(n)rn | <

n=

Tale espressione deriva direttamente dalla seguente

X
n=

x(n)z n <

2.2. REGOLATORE DISCRETO

19

dalla quale immediato intuire che, data la natura della variabile z, la regione di convergenza di questa funzione
sia una regione circolare (o anulare) del piano complesso.
Dal punto di vista dei controlli/filtri digitali, lo studio delle funzioni tempo-discrete viene fatto normalmente ricorrendo alla Z-Trasformata. Con questo tipo di funzioni normalmente possibile realizzare una approssimazione della funzione regolatore R(s) che permetter poi di passare alla definizione di un modello
digitale.

(a) schema a blocchi

(b) segnale e(t)

(c) segnale capionato e(n)

Figura 2.3: Campionamento di una funzione continua.


In figura 2.3 rappresentato lo schema di campionamento di una funzione continua (come per esempio la
funzione errore) i cui campioni sono presi a intervalli regolari Ts , da cui e (n) = e(kTs ) con k N; e (n) una
sequenza di campioni. Un grande vantaggio che deriva da questa formalizzazione che ogni grandezza variabile
definita nel dominio z moltiplicata per z n equivale a considerare ln-esimo campione della sequenza associata
alla grandezza; per esempio:
y = xz 1 + 2xz y (n) = x(n 1) + x(n + 1)

2.2.2

Mappatura dei poli da s a z

Come detto, per ottenere una funzione digitale implementabile su micro controllore, occorre passare per la trasformata z in modo da approssimare al meglio la funzione tempo-continua. Per fare questo occorre quindi mappare i
poli e gli zeri in s nel corrispondente dominio z.
Dalla figura 2.4 subito chiaro che, essendo le due aree di convergenza una un semipiano e laltra una zona
anulare, occorre determinare una funzione che degradi il meno possibile la risposta del regolatore in z. Per fare ci
si ricorre tipicamente alle trasformazioni bilineari le quali derivano dalla considerazione che lo scopo ultimo della
progettazione del regolatore digitale di descrivere il sistema tempo-continuo tramite opportune equazioni alle
differenze ossia discretizzando la funzione continua R(s). Per fare ci quindi si parte da semplici considerazioni
riguardo lintegrazione numerica, la quale deve approssimare quella nel continuo.

20

CAPITOLO 2. PROGETTO DI UN REGOLATORE PI

Figura 2.4: Dominio di convergenza della funzione s e z.

(a) tempo-continuo

(b) discreto

Figura 2.5: Integratori.

Prendendo in considerazione quanto riportato in figura 2.5-a, un puro integratore costituito da una semplice
equazione di stato
dy(t)
= u(t)
dt
Se ora venisse richiesto di realizzare un algoritmo di integrazione della funzione u(t), le soluzioni immediate e
pi semplici che probabilmente vengono in mente, una volta definito che la funzione viene campionata a intervalli
Ts regolati, sono lapprossimare la funzione con una serie di rettangoli identificabili tra due intervalli successivi,
ossia

y(kTs ) = Ts u(kTs ) + y((k 1)Ts )

(2.10)

y(kTs ) = Ts u((k 1)Ts ) + y((k 1)Ts )

(2.11)

o anche

detto appunto metodo dei rettangoli. Questo metodo chiaramente molto approssimato anche se lerrore commesso tanto pi piccolo quanto pi piccolo il periodo Ts ; ci fa comprendere che questo metodo molto
comodo per il controllo quando le potenze di calcolo a disposizione non sono molto elevate e/o i tempi di integrazione sono stringenti. Una soluzione pi brillante il metodo dei trapezi il quale non fa altro che considerare rettilineo il tratto tra due istanti (di campionamento) successivi sommando quindi le aree dei vari trapezi
identificabili in ogni istante Ts
y(kTs ) =

Ts
(u(kTs ) + u((k 1)Ts ) + y((k 1)Ts )
2

(2.12)

2.2. REGOLATORE DISCRETO

21

Concentrandosi ora su questa seconda soluzione immediato formulare il problema in termini di sequenze
y (n) =

Ts
2

(u (n) + u (n 1)) + y (n 1)
equivalente a

y (n + 1) =

Ts
2

(u (n + 1) + u (n)) + y (n)

Come gi detto, chiaro che questo metodo di calcolo una approssimante del sistema tempo-continuo, quindi
cercando di utilizzare una formula che approssimi al meglio lintegrazione, si pu formulare il problema come in
2.5-b, ossia definendo un coefficiente a tale che
y (n + 1) = Ts ((1 a) u (n) + a u (n + 1)) + y (kn)

con

a [0, 1]

da cui deriva la funzione di trasferimento dellintegratore che mette in relazione la formulazione tempo-continua
con quella digitale
1
a z + (1 a)
Ts
s
z1
e quindi la definizione della variabile s che permetter di mappare le funzioni tempo-continue nelle corrispettive
digitali:
s=

z1
1
Ts a z + (1 a)

Dal fatto che la trasformazione sia bilineare deriva una importante considerazione ossia che se la funzione
R(s) una funzione razionale fisicamente realizzabile (cio il grado del polinomio a denominatore maggiore o
uguale al grado del numeratore) e senza poli in 1/(aTs ) , allora R(z) razionale con denominatore di grado pari
a quello di R(s) e maggiore o uguale al grado del numeratore.
A questo punto risulta chiaro che il regolatore digitale possa essere ottenuto sostituendo a s la variabile
definita in z. Il problema ora valutare i valori che a pu assumere; tipicamente i valori assegnabili sono tre:
a=0

equivale ad adottare come metodo di integrazione la formula di Eulero detta in avanti o del
rettangolo destro. La funzione di mappatura del piano s diventa quindi
s=

1
(z 1)
Ts

(2.13)

e sostituendola alla funzione di trasferimento dellintegrale si ottiene


y=u

Ts
z1

da cui

yz = Ts u y

e dividendo tutto per z si ottiene


y = Ts uz 1 yz 1

da cui

y (n) = Ts u (n 1) + y (n 1)

ossia la stessa relazione definita precedentemente (equazione 2.11).


a=1

equivale ad adottare come metodo di integrazione la formula di Eulero detta in indietro o del
rettangolo sinistro. La funzione di mappatura del piano s diventa quindi
s=

1 z1
Ts z

(2.14)

22

CAPITOLO 2. PROGETTO DI UN REGOLATORE PI

ed effettuando le stesse considerazioni del punto precedente si ottiene


y = Ts u yz 1

da cui

y (n) = Ts u (n) + y (n 1)

ossia la stessa relazione definita precedentemente (equazione 2.10).


a=

1
2

ossia il metodo di integrazione detto di Tustin o dei trapezi. La variabile s si definisce come
s=

2 z1
Ts z + 1

(2.15)

da cui deriva il metodo di integrazione dei trapezi definito in precedenza osservando semplicemente
i campioni del segnale:
y=

2.2.3


Ts
u 1 + z 1 + yz 1
2

da cui

y (n) =

Ts
(u (n) + u (n 1)) + y (n 1)
2

Risposta in frequenza

Per diagrammare la risposta in frequenza di una funzione z, non si pu considerare tutto il semipiano delle
frequenze come per il diagramma di Bode per i sistemi tempo-continui; le funzioni in z infatti sono funzioni
periodiche nellintervallo [ Ts , Ts ]. Tuttavia possibile ottenerne la risposta sostituendo alla variabile z la
forma polare ejTs . Si intuisce per che le trasformazioni bilineari, non essendo trasformazioni lineari, tendono
a distorcere la risposta in frequenza della funzione in z rispetto a quella della funzione tempo-continua in s (si
veda [2] per maggiori informazioni).
Dal punto di vista teorico quindi possibile determinare il minimo valore di frequenza oltre il quale la distorsione trascurabile, ma dal punto di vista pratico ci non molto significativo in quanto le frequenze di
campionamento sono normalmente molto elevate e comunque dipendenti anche dallhardware a disposizione. A
titolo di esempio si consideri ora un regolatore con Ki=10 e Kp=0.01 e tempo di campionamento di 1kHz (ossia
Ts = 1ms); eseguendo i seguenti comandi M ATLAB si ottengono i risultati in figura 2.6. La frequenza a cui
limitata la funzione in z chiaramente 1kHz (Ts1 ) che in termini di pulsazione 3141.6 rad/sec; a questo punto
facile intuire che se il tempo di campionamento aumenta, anche la distorsione si riduce (figura 2.7); lecito
quindi aspettarsi che il sistema tempo-discreto risponda in modo pressoch identico al sistema tempo-continuo a
patto che le frequenze di campionamento siano molto alte.

2.2. REGOLATORE DISCRETO

Ki=10; Kp=0.01; Ts=1e-3;


filtroS = tf([Kp Ki],[1 0]);
filtroZ = tf([Ts*Ki/2+Kp Ki*Ts/2-Kp],[1 -1],Ts,variable,z);
bode(filtroS, filtroZ);

Figura 2.6: Diagramma di Bode della funzione del regolatore di esempio s e z con Ts = 1ms.

Figura 2.7: Diagramma di Bode della funzione del regolatore di esempio s e z con Ts = 100s.

23

24

CAPITOLO 2. PROGETTO DI UN REGOLATORE PI

Capitolo 3

Modellistica del regolatore PI


In questo capitolo verr modellizzato il regolatore nella forma classica e con anti wind-up. Lobiettivo di
ottenere tre regolatori (continuo, discreto e digitale) che restituiscano gli stessi risultati in termini di prestazioni
dinamiche e precisione statica. Il sistema preso in considerazione un induttore R-L lineare la cui equazione di
stato

d
1
i(t) = (v(t) Ri(t))
dt
L

(3.1)

Si consideri a titolo di esempio per le simulazioni successive L = 50 mH e R = 0.11 . La prima


formulazione del regolatore sar quella classica senza strutture anti wind-up.
Si consideri inizialmente un sistema come quello riportato in figura 3.1. Come si nota la relazione banalmente un guadagno che moltiplicato per lingresso restituisce il valore della tensione applicabile. chiaro che
questo presuppone una perfetta conoscenza del modello del dispositivo sotto controllo e comunque anche in questo caso questa soluzione ha una dinamica legata ai poli dellinduttore. Questo schema permetter di confrontare
i risultati che seguiranno per verificare i miglioramenti apportati da un regolatore PI.

(a) Schema Simulink

(b) Tensione applicata

(c) Corrente di riferimento e reale

Figura 3.1: Schema in anello aperto per il controllo della corrente in un induttore.
25

26

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

3.1

Regolatore tempo-continuo classico

Il sistema in esame un sistema intrinsecamente stabile. Introdurre un PI quindi in linea teorica non far altro
che modificare la dinamica del sistema. In particolare quello che si vuole fare accelerare il sistema in esame.
Per fare ci si ipotizza inizialmente che lattuatore (ossia in questo caso il generatore di tensione) sia ideale,
cio non abbia una uscita teoricamente illimitata; inoltre non deve introdurre nessun ritardo addizionale1 , cos
come il regolatore. Si applichino quindi le considerazioni fatte al paragrafo 2.1. Solo a scopo didattico la banda
passante non verr posta intorno ai 1000 rad/s, ma pari a 50 rad/s: si ricorda infatti che lobiettivo realizzare
tre regolatori (tempo-continuo, tempo-discreto e infine C) che abbiano la stessa risposta; lo scopo principale
infatti quello di mostrare semplicemente che il regolatore migliora landamento della corrente. Da ci per
nasce anche una considerazione di tipo pratico: la tensione imposta (almeno in termini di picco) dal regolatore
ha un valore tanto pi alto quanto pi alta la banda passante. Ci abbastanza intuitivo: pi il regolatore
prestante, maggiore sar la forzante che generer in ingresso al sistema sotto controllo, chiaramente entro i
limiti dellalimentatore. Problematiche di questo tipo rientrano nellambito della cos detta moderazione del
controllo; il caso limite quello in cui a fronte del pi piccolo errore si ha la massima variazione delluscita,
ossia il raggiungimento istantaneo della soglia di saturazione (superiore o inferiore). Tornando al caso in esame,
la pulsazione scelta permette di avere, a fronte di un errore massimo, una tensione massima di poco superiore
a 120V. Nel caso in cui il regolatore possa dare tensioni di riferimento in uscita pi elevate di quelle gestibili
dellattuatore, si deve necessariamente prevedere una saturazione. Per quanto riguarda il margine di fase, viene
impostato a 90 .

In figura 3.2 riportato il PI con coefficienti pari a Kp = 2.5 e Ki = 5.5. Come si nota non vi sovraelongazione e il sistema risponde pi prontamente anche se la tensione applicata ora molto pi alta, quantomeno
come valore di picco.

Per quanto riguarda la risposta in frequenza, in fgura 3.3 rappresentata la risposta del regolatore PI, del
circuito R-L (G(s)), della funzione danello (L(s) = P I(s) G(s)) e della funzione di trasferimento totale, ossia
con F (s) = L(s)/(1 + L(s)) la quale ha un andamento di tipo passa-basso. Come si pu notare la funzione
danello una retta di pendenza 20dB/dec e ci corretto perch avendo impostato il margine di fase a 90 il PI
assume valori tali da avere uno zero in corrispondenza del polo della funzione in esame G(s). Il sistema L(s) si
riduce semplicemente ad un integrale moltiplicato per un guadagno.

Applicando come riferimento una sinusoide di pulsazione 10rad/s e una di 100rad/s si deve trovare la prima
inseguita con un leggero ritardo e poco attenuata in modulo, mentre la seconda attenuata e con sfasamento intorno
ai 70 . Ci verificato dalla figura 3.4.

1I

regolatori reali infatti possono introdurre ritardi legati ai filtri dei segnali, al campionamento, al tempo di elaborazione, ecc.

3.1. REGOLATORE TEMPO-CONTINUO CLASSICO

27

(a) Schema Simulink

(b) Correnti

(c) Tensioni applicate

I colori sono, rispettivamente per ogni componente del vettore in ingresso al blocco scope, giallo-porpora-azzurro.
Il riferimento di corrente stato messo per ultimo per avere corrispondenza tra i colori relativi a ogni regolatore.
I diagrammi sono ottenuti dal modello R_L_01.mdl.
Figura 3.2: PI tempo-continuo.

28

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

Figura 3.3: Diagramma di Bode dei vari blocchi del sistema tempo-continuo.

(a) Corrente (riferimento a 10rad/s)

(b) Tensione (riferimento 10rad/s)

(c) Corrente (riferimento 100rad/s)

(d) Tensione (riferimento 100rad/s)

Figura 3.4: PI tempo-continuo con ingresso sinusoidale.

3.2. REGOLATORE Z OTTENUTO DAL TEMPO-CONTINUO CLASSICO

3.2

29

Regolatore Z ottenuto dal tempo-continuo classico

Anche in questo caso si applicano le considerazioni precedentemente fatte nella sezione 2.2.2. Si ricorda che
la trasformata Z discretizza solo il tempo, mentre lingresso reale. Conseguenza di ci il fatto che neppure
S IMULINK accetta come ingresso ai blocchi in z-trasformata variabili intere (a 16 o 32 bit) se non opportunamente
castizzate.

La funzione di trasferimento del PI


Vrif (s)
Ki
sKp + Ki
= Kp +
=
E(s)
s
s

(3.2)

e applicando la trasformazione bilineare di Tustin si ottiene la funzione di trasferimento del regolatore discreto,
ossia
vrif (z)
e(z)

KP (z 1) + Ki T2s (z + 1)
Ts (z + 1)
=
=
2 (z 1)
(z 1)


+ Kp z + Ki T2s Kp
z1

= Kp + Ki
=

Ki T2s

(3.3)
(3.4)

Introducendo questo nel modello Simulink si hanno i risultati mostrati in figura 3.5. Si noti che per effettuare
la simulazione occorre cambiare le impostazioni settando i parametri di simulazione con passo fisso. In particolare stato fissato un passo di integrazione pari a 50s. In figura 3.5-a e 3.5-b si osserva che sia la corrente in
uscita che la tensione dovuta al regolatore digitale e a quello analogico, si sovrappongono perfettamente.

30

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

(a) Schema simulink

(b) Corrente.

(c) Tensione applicata.

I colori sono, rispettivamente per ogni componente del vettore in ingresso al blocco scope, giallo-porpora-azzurrorosso.
Figura 3.5: PI tempo-discreto con Ts = 50s.
In realt se si ingrandisse notevolmente si noterebbe un piccolo scostamento della funzione discreta rispetto
a quella continua. Se alzassimo il valore del passo di integrazione (per esempio a 50ms), questo scostamento si
farebbe pi marcato, come mostrato in figura 3.6. Si nota che la risposta cambiata e sembrerebbe in meglio,
ma questo leggero miglioramento lo si pagato in termini di moderazione del controllo. Inoltre il sistema
tendenzialmente pi instabile; infatti se si aumentasse oltre una certa soglia il passo di integrazione, il sistema
divergerebbe e, comunque, un aumento del passo di integrazione riduce la prontezza del regolatore. Ad ogni
modo il sistema non si discostato molto dalla risposta che ci si attendeva partendo dal progetto del regolatore
tempo-continuo.
Anche in questo caso a fronte di un andamento sinusoidale il riferimento viene seguito con la stessa dinamica
come mostrato in figura 3.7-a. Anche la risposta a 5ms non presenta sensibili variazioni (3.7-b)
NOTA: a queste considerazioni si pu giungere anche in termini matematici. Se infatti si osservano i risultati
con uno sguardo al futuro ponendo lattenzione su come si comporter il regolatore digitale, diventa chiaro
fin dora che il sistema digitale dovr effettuare un campionamento e un controllo prima di restituire i

3.3. REGOLATORE DIGITALE

31

(a) Correnti.

(b) Tensioni applicate.

Figura 3.6: Risposta del PI continuo e discreto con Ts = 5ms.

(a) Ts=50us

(b) Ts=5ms

Figura 3.7: PI tempo-discreto con riferimento sinusoidale.


risultati e quindi agire sul sistema. Di questo ritardo normalmente se ne deve tenere conto con un tempo
di campionamento e uno di elaborazione. Tipicamente per si assume che questi due tempi siano pari
allintervallo Ts in quanto tra un campionamento e laltro si cercher di effettuare tutti i calcoli necessari al
controllo. Si tiene conto di tale ritardo normalmente nella parte tempo-continua del modello definendolo
come esTs . immediato capire che in termini di margine di fase si ha una riduzione pari a
m = c

Ts
2

il che equivale a rendere meno robusto il sistema. Ad ogni modo non se ne terr conto in questi primi
modelli.

3.3

Regolatore Digitale

Il modello del regolatore digitale verr anchesso sviluppato in S IMULINK, ma ora ci si trova a dover analizzare
su quale struttura hardware il sistema dovr essere implementato e ci va oltre alla sola scelta del processore, ma

32

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

riguarda anche i sensori (e quindi la loro caratterizzazione) e gli attuatori.


La famiglia di processori per la quale verr plasmato il codice la dsPIC30F. La scelta del processore in
linea teorica scorrelata dal codice S IMULINK tranne per alcuni fattori:
1. si deve sempre verificare che il codice S IMULINK reimplementato sul processore scelto rispetti perfettamente le scadenze temporali, soprattutto se stringenti (hard real-time)
2. soglie e variabili in S IMULINK vanno espresse tenendo conto dei limiti di calcolo del processore. I
dsPIC30F, per esempio, hanno parole a 16bit con ALU, MCU per calcoli come moltiplicazioni e divisioni e anche una DSP unit che, anche se non performanti come un vero DSP, permette di eseguire calcoli
di somma e moltiplicazione contemporaneamente (multiply and accumulate), mente i PIC12/16 hanno solo
la ALU (Arithmetic/Logic Unit).
3. occorre riadattare gli ingressi per simulare la perdita di precisione legata ad ADC, PWM (e altre periferiche
se necessario). Gli ADC sono a 10bit.
Il secondo punto fondamentale il sensore; prendendo in esame un sensore LEM di corrente e valutando la
portata massima da rilevare si sceglie il modello. La caratteristica dei LEM espressa in figura 3.8.

Vout = 2.5 + 0.625

IP max
IP N

dove IP max la corrente passante per il


numero di spire avvolte.
Si noti che il LEM satura a 4.5V

Figura 3.8: Caratteristica LEM.


Dai grafici la corrente da retroazionare ha un valore massimo nominale pari a 50A. La scelta quindi ricade
sul LEM LTS-25-NP con una spira. Questo implica che a fronte di una tensione massima in uscita dal sensore di
4,5V, la corrente massima che pu circolare nel conduttore pari a 80A. Il LEM inoltre ha una tensione in uscita
con un offset di 2,5V.
Il terzo punto di cui occorre tener presente luscita. Occorre infatti pensare alla tensione massima applicabile
la quale sarebbe meglio fosse maggiore (o al pi uguale) alla tensione di picco ottenuta dalle simulazioni. Per
semplicit si supponga di avere a disposizione una sorgente di tensione continua di valore 150V. Il sistema di
parzializzazione della tensione pu quindi essere un chopper o un ponte ad H. Per completezza verr considerato
un ponte ad H in quanto sar possibile verificare le risposte in frequenza in quanto questo dispositivo permette di
avere sul carico sia tensioni positive che negative2 .
Da queste considerazioni si procede col modellizzare il regolatore Simulink e quello del micro processore.
2 Questa affermazione acquisir importanza nel momento in cui il codice verr adattato al micro-controllore, sul quale occorrer introdurre
i registri di PWM ed effettuare i debiti riscalamenti delle grandezze.

3.3. REGOLATORE DIGITALE

3.3.1

33

Modello C-S IMULINK

In questo esempio il sensore+convertitoreAD verranno sviluppati al di fuori del codice C in modo che il codice
scritto sia il pi vicino possibile a quello del micro processore. Per quanto appena detto occorre modellizzare
prima di tutto il blocco sensore-ADC. Per fare ci si considera la formula riportata in figura 3.8. Inoltre si sa
che la conversione digitale ad opera del micro processore ha una sensibilit di 5V/1024. Il blocco di conversione
eseguir

Vdigit = round

2.5 + 0.625

IP N

1024
5

Si noti che sia il riferimento che il valore reale vengono campionati, mentre la loro differenza verr calcolata
allinterno del codice C.
Detto ci, in figura 3.9 riportato il componente aggiuntivo a cui si far riferimento per il test del codice
del regolatore riportato in seguito. Come si nota il blocco di campionamento stato posto al di fuori del blocco
che simula il micro controllore vero e proprio per fare in modo che il codice sia il pi possibile simile a quello
del micro controllore. Anche il riferimento viene digitalizzato in questo caso e non implementato sul controllore
vero e proprio. Ci verosimile se si pensasse di avere la possibilit di settare il riferimento dallesterno. I due
AD riportati non fanno altro che convertire la corrente in un valore compreso tra 0-512 corrispondenti a 0-80A in
quanto, come gi detto, il LEM ha un offset di 2.5V e il micro acquisisce ingressi in 0-5V.

Figura 3.9: Blocco PI digitale.


Il blocco programma C in figura 3.9 un S-Function Builder. Lhelp di M ATLAB completo e spiega
perfettamente tutte le caratteristiche del blocco, ma per poter gi scrivere e testare i programmi basti ricordare
che:
1. Nella scheda Initialization, Sample mode deve essere settato su Discrete con un passo di 50e-6 (pari
a Ts ). Si sconsiglia di fare ereditare al blocco il tempo di sample impostato in simulazione, anche se questa
fosse configurata (come deve essere) con un passo di integrazione fisso.
2. Nella Scheda Data Properties lingresso u0 un vettore di due elementi, cos come luscita y0.
3. In Libraries nel riquadro External Function Declaration verranno settate costanti e variabili globali.
4. In Outputs verr scritto il codice.
Si noti inoltre che la base scelta per i calcoli 4096 (12bit).
Il resto dellhardware non modellizzato per il momento. Si tenga per conto che il regolatore dovr andare
a pilotare delle valvole (per esempio un ponte H) e, in generale, il pic introdurr dei ritardi. Tutto ci verr tenuto
in considerazione pi avanti.

34

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

3.3.1.1

Metodo 1: Separazione parte proporzionale e integrale

Il regolatore pu essere scritto tranquillamente separando il termine proporzionale e quello integrale secondo
quanto riportato nellequazione 2.12. Secondo molti, compreso chi scrive, questo metodo molto comodo per la
scrittura di un PI perch evitando di mettere in relazione il termine proporzionale e quello integrale, diventa molto
pi agevole modificare i parametri per affinare il controllo in fase di test e collaudo sul campo del regolatore
stesso.
Algorithm 1 Variabili e definizioni globali.
#define I_REALE u0[1]
#define I_RIF u0[0]
#define IUP 8400000
#define IDW -8400000
#define KP(e)((e< <1)+(e> >1))
#define KI(e)((e> >1)+(e> >4))
#define KIS 12 // extra shift per ltergale
int error, error_1=0;
int proporzionale;
int integrale=0;
int first_scan=0;

Algorithm 2 Codice C del regolatore (S IMULINK)


int error_i;
error = ((I_RIF - I_REALE)< <3); /* errore riportato a 12bit */
error_i=error+error_1; /*errore da passare alla macro integrale*/
proporzionale = KP(error)
if(error_i>=0) /* calcolo integrale */
integrale += KI(error_i);
else
integrale -= KI((-error_i));
error_1=error; /* memorizzo lerrore per il passo successivo */
/*Ci che segue la satrazione dellintegrale, ossia lanti wind-up.

Introdurre ci a questo punto

solo per completezza; ai fini dellesempio ininfluente in quanto lanti wind-up verr trattato in
seguito*/
if(integrale>IUP) /* Limito lintegrale (anti wind-up) */
integrale=IUP;
else if(integrale<IDW)
integrale=IDW;
y0[0]=proporzionale+(integrale> >KIS);
y0[1]=round(y0[0]*100)/4096;

Analizzando il programma si vede che subito i dati in ingresso vanno riportati alla base scelta ossia moltiplicati per 8 mediante uno shift logico a sinistra di 3 bit; successivamente viene calcolata la componente proporzionale
del regolatore la quale non viene limitata perch il prodotto dellerrore massimo per il termine proporzionale non
potr mai dare un overflow della variabile intera a 16bit3 : per comprendere meglio quanto appena detto si consideri che lerrore massimo teorico di corrente pari a 511 (=29 1) che moltiplicato per 8 restituisce 4088
che ancora moltiplicato per il coefficiente Kp pari a 2,5 d come risultato 10220 <215 1=32767. Lintegrale
3 15

bit se si considera anche il bit di segno.

3.3. REGOLATORE DIGITALE

35

invece viene calcolato tramite la variabile error_i data dalla somma dei valori errore attuale (error) ed errore
al passo precedente (error_1); questo far in modo che la macro sia ottimizzata perch, come detto al capitolo
1, una macro tende a riscrivere il codice passatogli come parametro. Quindi la macro definita KI definita nellalgoritmo 1 prendesse come argomento la somma dei due errori, tale operazione verrebbe richiamata tutte le volta
che compare il simbolo e nella macro aumentando il carico computazionale. Oltre a ci viene fatto un check
sulla variabile error_i per evitare il problema legato agli shift logici a destra. Attenzione poi per quanto riguarda la conversione delluscita: la conversione in tensione reale data dalla costante 100/4096, ossia il reciproco
del coefficiente di conversione analogico-digitale del sensore di corrente. Attenzione quindi a non confondere il
valore 100A con il massimo teorico della tensione in uscita dal generatore!
La dimostrazione di ci relativamente semplice e la si pu fare per analogia. Lespressione seguente:
out_i(n) = e(n) Kp + Ki

Ts
(e(n) + (e(n 1))
2

(3.5)

rappresenta il valore delluscita senza tenere conto del valore accumulato dallintegrale espressa con grandezze
reali. Tale funzione possibile riscriverla digitalizzando lingresso; come noto la costante di conversione del convertitore AD 4096/100 da cui si pu esprimere che il valore digitale della grandezza sar E(n) = e(n) 4096
100 =
e(n) kAD . Lequazione 3.5 pu quindi essere scritta in digitale come:
OU T _I(n) = E(n) Kp + Ki

Ts
(E(n) + (E(n 1))
2

(3.6)

A questo punto non resta da chiedersi qual il valore della costante che moltiplicata per il valore digitale
delluscita restituisce il valore reale dellingresso:
k=

e(n) Kp + Ki T2s (e(n) + (e(n 1))


e(n) Kp + Ki T2s (e(n) + (e(n 1))
out_i
1
=
=
=
T
T
s
s
OU T _I
kAD
E(n) Kp + Ki 2 (E(n) + (E(n 1))
kAD e(n) Kp + Ki 2 (e(n) + (e(n 1))

Con questo dimostrato che per ottenere luscita y0[0] reale occorre moltiplicare per il reciproco del fattore di
conversione del convertitore analogico digitale.
Si noti che per essere precisi occorrerebbe limitare luscita alla tensione massima di DC bus: senza questa
limitazione si assume lalimentatore ideale e in grado di erogare qualsiasi valore di tensione e corrente.
Per quanto riguarda la regolazione vera e propria, i parametri Kp e Ki vengono realizzati tramite una macro. Il
KP come si vede resta uguale e pari a 2.5, mentre KI tiene conto anche del tempi di campionamento (KI Ki T2s ).
Cos facendo il nuovo coefficiente risulta 1.375104 il quale troppo piccolo per poter essere applicato ad una
variabile che al massimo raggiunge il valore 4096. Per questo la macro viene applicata ad una variabile a 32
bit (int in M ATLAB) e limitata a 224 (=212 212 ), mentre il coefficiente verr moltiplicato per 4096 (il che
diventa 0,5632). Ora lintegrale pu tenere conto di tutti i valori maggiori o uguali di 2 perch 20,5632=1,1264
che arrotondato allintero pi vicino 1, aumentando decisamente la precisione. Mantenendo invece il valore
dellintegrale pari a 1.375104 la macro sarebbe stata scritta come KI(e)((e> >13)+(e> >16)) il che implica
che perch il risultato di KI sia maggiore di 1, occorre che error_i sia almeno pari a 213 . Lintegrale per
viene utilizzato per calcolare grandezze in base 12 bit come y0[0] e quindi occorre riportarne il valore nella base
corretta applicando uno shift logico a destra di 12 bit.
La risposta seguita perfettamente, come mostrato in figura 3.10.

36

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

(a) Corrente.

(b) Tensione

Figura 3.10: Risposta PI digitale (metodo 1).

Anche in questo caso la risposta alla sinusoide segue il comportamento voluto (figura 3.11 e 3.11), ma con un
particolare: infatti osservando le figure 3.11-b e 3.12-b si vede che la forzante appare un po frastagliata. I valori
per sono accettabili come ordine di grandezza e andamento; questi andamenti discontinui sono da imputare alla
quantizzazione del segnale in ingresso. E chiaro poi che la corrente in uscita abbia un comportamento buono a
causa delleffetto filtrante dellinduttanza.

(a) Corrente

(b) Tensione

Figura 3.11: PI digitale con forzante sinusoidale a 10rad/s.

3.3. REGOLATORE DIGITALE

37

(a) Corrente

(b) Tensione

Figura 3.12: PI digitale con forzante sinusoidale a 100rad/s.


3.3.1.2

Metodo 2: Rielaborazione del PI ottenuto dalle funzioni z

Esaminiamo ora un altro modo per ottenere il regolatore PI digitale. Considerando lequazione 3.3, ne deriva che

(z 1) vrif =

KP (z 1) + Ki


Ts
(z + 1) e
2

e dividento tutto per z e facendo gli opportuni passaggi, si ottiene




vrif = Kp 1 z 1 Ki T2s 1 + z 1 e + z 1 vrif
da cui

vrif
(n)

Ki T2s

(n 1)
+ Kp e(n) + Ki T2s Kp e(n 1) + vrif


e sostituendo K1 = Ki T2s + Kp e K2 = Ki T2s Kp si ottiene una relazione seguente:

vrif
(n) = K1 e(n) + K2 e(n 1) + vrif
(n 1)

Prima di scrivere il codice si osservi che il valore assunto dalle due costanti K1 e K2 , per i valori Kp e Ki
precedentemente calcolati e per il tempo di campionamento Ts ,




50 106

K1 = 5.5
+ 2.5 = 2.5001375
2





50 106

K2 = 5.5
2.5 = 2.4998625
2

ed subito chiaro che lintegrale causa una variazione praticamente trascurabile ai due valori i quali risultano
in modulo pressoch identici. Questa affermazione tanto pi vera se ora si procede con la digitalizzazione.
Consideriamo subito di creare le macro che con opportuni shift logici realizzino i due numeri K1 e K2 . Per
raggiungere questo grado di precisione, le due macro diventano
K1(e) ((e1)+(e1))
K2(e) ((e1)+(e2)+(e3)+(e4)+(e5)+(e6)+(e7)+(e8)+(e9)+(e10)+(e11))

Lultimo shift pari a 11 perch e, ossia lerrore in ingresso alle due macro, una variabile in base 12
bit e shiftare di 12 darebbe sicuramente contributo nullo. chiaro che macro come K2 sono da evitare, sia
perch il carico computazionale diventa tale da annullare (o ridurre) i benefici derivati dallintroduzione degli

38

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

shift, sia perch ci implica che un numero (e) deve valere almeno 212 perch esso venga valutato in modo
utile dallultimo shift. Tale valore difficilmente verr raggiunto se si presuppone un corretto funzionamento del
sistema di regolazione. Discorso analogo vale per gli altri shift con numero di bit almeno pari a 9. Come se non
bastasse la macro K1 chiaramente troncata in quanto il contributo del termine Ki T2s troppo piccolo. Da queste
considerazioni lecito pensare che il sistema non avr una risposta fedele a quella ottenuta studiando il sistema
in s, in z o semplicemente in 3.3.1.1 come dimostrato dalla figura 3.13-a.
Per eliminare i problemi appena esposti riguardanti il calcolo, si potrebbe pensare di approssimare il valore di
K1 e K2 al valore 0.5 (ossia (e1)) il che comporterebbe un errore trascurabile dal punto di vista del calcolo del
coefficiente, ma ci comporterebbe lannullamento del coefficiente integrale che, anche se piccolo, fondamentale per avere precisione statica. La figura 3.13-b mostra leffetto legato a questa approssimazione. chiaro che si
potrebbe agire per tentativi per ridurre lerrore a regime aumentando il coefficiente proporzionale oppure quello
integrale, ma in entrambi i casi il sistema non avrebbe pi la risposta ottenuta dal progetto nel tempo continuo.

(a) Approssimazioni di K1 e K2

(b) Annullamento Ki

Riferimento

Sistema tempo-continuo

Risposta libera del sistema

Sistema tempo-discreto

Sistema digitale

Grafici ottenuti dalla simulazione R_L_04.mdl.


Figura 3.13: Corrente con PI digitale a variabili discrete ossia int (metodo2).

Detto questo, potrebbe sembrare che se il sistema lavorasse con grandezze a pi alta precisione (float o double)
questo problema potrebbe essere attenuato. Ci tendenzialmente vero come mostrato anche in figura 3.14,
ma va sempre verificato onde evitare di scegliere processori con potenze di calcolo (e quindi costo) eccessivi.
In figura 3.14-b riportato landamento della tensione che come si vede a gradini in quanto lelaborazione
viene comunque fatta su un segnale digitale intero proveniente dal convertitore AD. Va comunque notato che le
operazioni compiute sono di moltiplicazione e accumulazione, operazioni che normalmente vengono eseguite da
molti processori (anche a basso costo) con tempi di elaborazione non troppo elevati come per esempio i processori
dsPIC30F o gli ADuC7000.

3.3. REGOLATORE DIGITALE

39

(a) Elaborazione in double di ingressi e regolazione

(b) Particolera della tensione impostata dal regolatore.

Riferimento

Sistema tempo-continuo

Risposta libera del sistema

Sistema tempo-discreto

Sistema digitale

Grafici ottenuti dalla simulazione R_L_04.mdl.


Figura 3.14: Corrente con PI digitale a variabili in doppia precisione double (metodo2).
Il codice che permette di ottenere queste risposte riportato negli algoritmi 3 e 4. Si noti che lalgoritmo 4
pu sembrare pi corto e veloce del precedente algoritmo 3. In realt ci normalmente falso soprattutto per
micro-controllori a basso costo in quanto le operazioni sviluppate sono tutte in virgola mobile e quindi possono
richiedere molti cicli di clock.

Algorithm 3 Codice C del regolatore a variabili discrete.


/***** DEFINIZIONI E VAR GLOBALI *****/

#define I_REALE u0[1]


#define I_RIF u0[0]
#define IUP 8095 /*occorre aumentare la soglia x avere la stessa risposta*/
#define IDW -IUP
#define K2(e)((e< <1)+(e> >2)+(e> >3)+(e> >4)+(e> >5)+(e> >6)+(e> >7)+(e> >8)+(e> >9)+(e> >10)+(e> >11))
#define K1(e)((e< <1)+(e> >1))
int error, error_1=0;
int out=0;
/*************************************/
/***** PROGRAMMA *****/

int k1, k2;


error = ((I_RIF - I_REALE)*8);
if(error>=0) k1=K1(error);
else k1=-(K1((-error)));
if(error_1>=0) k2=K2(error_1);
else k2=-(K2((-error_1)));
out = +out + k1 - k2;
error_1=error;
if (out>IUP) out=IUP;
else if(out<IDW) out=IDW;
y0[0]=out;
y0[1]=round((out)*100)/4096;
/*********************/

40

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

Algorithm 4 Codice C del regolatore a variabili double.


/***** DEFINIZIONI E VAR GLOBALI *****/

#define I_REALE u0[1]


#define I_RIF u0[0]
#define IUP 8095 /* occorre aumentare la soglia */
#define IDW -IUP
#define K2(e)((e*2.4998625))
#define K1(e)((e*2.5001375))
int error, error_1=0;
double out=0;
/*************************************/
/***** PROGRAMMA *****/

error = ((I_RIF - I_REALE)*8);


out = out + K1(error) - K2(error_1);
error_1=error;
if (out>IUP) out=IUP;
else if(out<IDW) out=IDW;
y0[0]=error;
y0[1]=(out*100)/4096;
/*********************/

3.3.1.3

Metodo 3: Rielaborazione del PI ottenuto dalla configurazione anti wind-up

Si consideri la figura 2.2. Il sistema cos sviluppato serve semplicemente per evitare lanti wind-up negli schemi
tempo-continui. Nonostante ci possibile definire il regolatore in z e successivamente il regolatore digitale.
Si consideri quindi il blocco della fase integrale (che dora in poi verr indicato con RI )
RI (s) =

1
Ki
1 + sK
p

riportato nel dominio z applicando il metodo di Tustin


RI (z) =

1
z + 12
= (1 b) 2
zb

1
1+

2 z1 Kp
Ts z+1 Ki

dove
b=1

Ki Ts
1
2 Ki Ts +

Kp

Introducendo i parametri
1
g = (1 b)
2


e

h=


1
1 (1 b) (1 b)
2

si ottiene
RI (z) = g +

h
zb

Il regolatore quindi pu essere rappresentato come in figura 3.15.

3.3. REGOLATORE DIGITALE

41

Figura 3.15: Ridefinizione del PI con anti wind-up analogico discretizzato con bilineare di Tustin.

Proseguendo si osserva che il blocco g pu essere eliminato ponendo un blocco equivalente prima della
1
prima del nodo sommatore
saturazione come mostrato in figura 3.16-a. Successivamente si sposta il blocco 1g
(figura 3.16-b). Considerando quindi che 1 b =

h
1g

e introducendo = 12 Ts Ki + Kp si ottiene lo schema in

figura 3.16-c ossia il regolatore in z.

(a) Sostituzione di g con la relativa funzione danello

(b) Spostamento del blocco 1/(1-g)

(c) Schema finale del PI discretizzato

Figura 3.16: Riborazioni dello schema 3.15.

Dallo schema riportato in figura 3.16-c possibile ottenere il regolatore digitale da implementare poi in
SIMULINK . Osservando il blocco in retroazione allanello si pu scrivere
xr (z) =

1b
u(z)
zb

da cui

xr (z) bz 1 = (1 b)z 1 u(z)

42

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

Ne consegue quindi la formulazione discreta


xr (n) = bxr (n 1) + (1 b)u(n 1)

(3.7)

Chiaramente luscita definita come


u(n) = xr (n) + e(n)

(3.8)

la quale poi dovr essere limitata (saturata).


In figura 3.17 sono riportati i due sottosistemi S IMULINK (file R_L_05.mdl) che realizzano il regolatore
tempo-continuo e tempo-discreto in un modello simile a quello della figura 3.5.

(a) PI anti wind-up tempo-continuo

(b) PI anti wind-up tempo-discreto.

Figura 3.17: Schemi dei sottosistemi tempo-continuo e tempo-discreto.

Avendo gi analizzato il comportamento dei regolatori senza anti wind-up, verr ora abilitata la soglia che
far in modo che la tensione in uscita non superi, per esempio, 80V. In figura 3.18 sono riportati gli andamenti di
corrente e tensione nel caso in cui la soglia sia attivata o disattivata. Come si nota la tensione tende a ridurre le
prestazioni dinamiche, anche se la precisione statica non alterata.

(a) Tensione

(b) Corrente.

Grandezza non limitata

Grandezza limitata

Figura 3.18: PI con e senza anti wind-up.

Basandosi sulle equazioni 3.7 e 3.8 e sostituendo i valori dei coefficienti del regolatore si ottiene
b = 0.99989

1 b = 1.0999 104

= 2.5001375

3.3. REGOLATORE DIGITALE

43

Approssimando i coefficienti come segue


b=1

1b=0

= 2.5

sembra che non si commetta un grande errore. Ne deriva il codice riportato nellalgoritmo 5.
Algorithm 5 PI anti wind-up: Codice C S IMULINK.
/*** MACRO E VARIABILI GLOBALI ***/
#define I_REALE u0[1]
#define I_RIF u0[0]
#define IUP 3277 /* 80/100*4096 */
#define IDW 0
#define B 1 /* 0.99999*/
#define B_1 0 /* 1-B=0.00001 */
#define GAMMA(e)((e< <1)+(e> >2)) /* 2.5001 */
int error, error_1=0;
int xr=0, out=0;
/************************************/
/*** PROGRAMMA ***/
error=((I_RIF)-(I_REALE))< <3;
xr=B*xr+B_1*out;
if(xr>IUP) xr=IUP;
else if(xr<IDW) xr=IDW;
out=xr+(GAMMA(error));
if(out>IUP) out=IUP;
else if(out<IDW) out=IDW;
y0[0]=out;
y0[1]=round(out*100)/4096;
/*************************************/

Ne derivano quindi i risultati in figura 3.19. Come si nota vi un errore statico a regime, il che era prevedibile
perch osservando il codice si nota che il termine integrale tenuto in conto dal parametro 1 b il quale in
questo caso nullo. Lunico modo per avere una risposta uguale a quella in fase di progetto utilizzare variabili
ad alta precisione come float, double o comunque intere ad almeno 32 bit come long int4 .

(a) Corrente

(b) Tensione

Figura 3.19: Risposta PI digitale relativa allalgoritmo 5.


4 Si ricorda che per M ATLAB le variabili definite int hanno la stessa dimensione dei long int in quanto il compilatore quello di
default del sistema ossia il gcc (per Linux) il quale assegna la parola a 32 bit. Nei PIC, dsPIC e altri microcontrollori da 8 a 16 bit, int
equivale a 16 bit, mentre long int a 32.

44

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

Ridefinendo le variabili in base 24 bit per poi riportarle a 12 bit nel calcolo delluscita, si ottiene il codice
riportato nellalgoritmo 6. Da questo codice si ottengono i risultati riportati in figura 3.20. Si osservi subito
una cosa molto importante: dovendo lavorare con grandezze a 24 bit, lunico parametro da dover far variare
il termine (ottenuto con la macro GAMMA) il quale verr moltiplicato per 4096; questo fa in modo che luscita
out24 sia a 24 bit. Per quanto riguarda il valore delle macro B e B1, non devono essere moltiplicati per 4096
perch xr dipende da out24 che gi in base 24 bit; in altre parole xr eredita la base di out24. Infine out
ottenuto dividendo per 4096 il valore di out24 (effettuato tramite shift di 12 bit).
Algorithm 6 PI anti wind-up con variabili a 32bit.
/*** MACRO E VARIABILI GLOBALI ***/
#define B(e)((e)-(e> >13)) /* 0.99989*/
#define B1(e)((e> >14)+(e> >15)+(e> >16)) /* (1-b)*/
#define GAMMA(e)((e< <13)+(e< <11)+(e> >1)+(e> >4)) /* 2.5001*4096 */
#define RDI 12
int error, error_1=0;
long int xr=0, out24=0, out=0;
/************************************/
/*** PROGRAMMA ***/
error=((I_RIF)-(I_REALE))< <3;
if(xr>=0) xr=B(xr);
else xr=-(B((-xr)));
if(out>=0) xr+=B1(out24);
else xr+=-(B1((-out24)));
out24=xr+(GAMMA(error)); /* shift a SX, quindi non servono controlli */
if(out24>IUP) out24=IUP; /* Calcolo di out24 */
else if(out24<IDW) out24=IDW;
out=out24> >RDI;
y0[0]=out;
y0[1]=round(out*100)/4096;

(a) Corrente

(b) Tensione

Figura 3.20: Risposta PI digitale relativa allalgoritmo .6.

3.3.1.4

Osservazioni e Confronti

Premesso che la soluzione ottima non esiste e che ogni regolatore andrebbe analizzato per ogni specifica applicazione, comunque possibile trarre delle conclusioni. Il primo metodo (3.3.1.1) realizza del codice tendenzialmente molto voluminoso in quanto se vengono previsti degli shift logici (soprattutto se negativi) occorre
effettuare un controllo sulla variabile in ingresso ad ogni macro. La macro di integrazione, poi, deve essere gestita
definendo una variabile di appoggio che occorre passargli per evitare che prima di ogni shif della macro venga

3.3. REGOLATORE DIGITALE

45

calcolata continuamente la somma dellerrore al passo attuale e al passo precedente. Infine, per evitare il sovraccarico dellintegrale, occorre limitare il valore delluscita e dellintegrale stesso5 . Questo sistema ha per dei
grandi vantaggi: permette infatti di modificare semplicemente i parametri del regolatore e le grandezze in esame
possono essere gestite a 16bit (a parte lintegrale che spesso va gestito con variabili a 32, anche se le operazioni
svolte su di esso sono semplici somme o shift, ossia operazioni leggere in termini computazionali) generando
quindi del codice tendenzialmente molto veloce.
Il secondo metodo (3.3.1.2) presenta fondamentalmente gli stessi inconvenienti del primo, con la differenza
che tutte le grandezze vanno gestite (se necessario) con variabili maggiori di 16bit. Inoltre la modifica di un
coefficiente interviene su entrambi i coefficienti K1 e K2 rendendo pi complessa laffinazione dei parametri sul
campo.
Il terzo metodo (3.3.1.3) forse il pi usato anche se, a detta di chi scrive, non il migliore. innegabile che
progettare il regolatore tempo-continuo anti wind-up una soluzione brillante e, dalla teoria sia dei controlli che
dei filtri digitali, si ereditato il fatto che se possibile si progetti il regolatore digitale partendo da quello tempo
continuo. Ma ci obbliga a ricalcolare tutto per arrivare a un risultato non differente dal caso 3.3.1.2. Inoltre
i coefficienti sono 3 appesantendo lesecuzione del codice, soprattutto se venissero realizzati con degli shift.
Inoltre i valori calcolati devono necessariamente avere grande precisione anche a livello digitale per avere un
andamento il pi fedele possibile al progetto. Daltro canto questo sistema ha il grande vantaggio di effettuare una
sola saturazione sulla variabile di uscita; infatti limitando questultima si ottiene automaticamente la saturazione
dellintegrale (ossia lanti wind-up) risparmiando una comparazione.

3.3.2

Simulazione del Duty-Cycle

Le simulazioni cos progettate e implementate fino ad ora non tengono conto precisamente del duty-cycle. Infatti
luscita del sistema anche se deriva da valori digitali, ossia ha un andamento a gradini discreti, non simula appieno il fatto che il duty-cycle una grandezza digitale con un preciso valore indipendente dalla base scelta per i
conti, funzione del clock del sistema e della frequenza di PWM che si vuole generare in uscita. Si consideri a tal
proposito un ponte ad H i cui gate vengono controllati con driver i quali ricevono un solo segnale in ingresso dal
micro-controllore (PWM), ma pilotando entrambe le valvole di un ramo (come si vedr nella sezione 4.1) semplicemente negando il segnale destinato al gate della valvola bassa rispetto a quello della valvola alta. La frequenza
di PWM viene comandata con la variabile PDCx con x pari a 1 o 2 in funzione del ramo da controllare. Non ci
si vuole addentrare ora nelle problematiche relative allimplementazione su micro processore, quindi si assuma
che una volta eseguiti i debiti calcoli indicati sul datasheet del processore, si ottenga che la variabile PDCx possa
assumere per esempio valori compresi tra 0 e 736: essendo un ponte ad H si ha che quando PDC1=PDC2=368 la
tensione media sul carico pari a 0. A questo punto occorre prevedere che il sistema reale abbia un massimo valore di tensione di DCbus, per esempio 150V. Ci vorr dire che la tensione sul carico varier in modo quantizzato
con una risoluzione legata a PDCx pari a 150V/368=0,476V/digit. Detto questo, prendendo in considerazione uno
dei metodi analizzati (per esempio il Metodo 1), nel programma di simulazione quindi opportuno apportare
una modifica tale per cui venga calcolata la tensione vera (ossia si moltiplica luscita per 100/4096) e riportata al
valore digitale di duty-cycle moltiplicando la tensione vera per 368/150, si divide la tensione vera per il massimo
valore di tensione ammissibile in uscita (ottenendo cos il duty-cycle in per-unit) e quindi moltiplicando per il
massimo valore digitale del duty-cycle accettato dal micro-controllore. Si ottiene quindi la seguente costante:
dc =
5 In

100 368
= 0, 0599
4096 150

alcuni casi occorre anche limitare il proporzionale se molto alto.

46

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

il che si traduce nella macro GET_DC indicata nel codice riportato di seguito:

#define I_REALE u0[0]


#define I_RIF
u0[1]
#define VMAX
150
#define VMAXD
6144
#define DCMAX
368
/*MACRO*/
#define KP(e)((e< <1)+(e> >1))
#define KI(e)((e> >1)+(e> >4))
#define KIS
12
#define GET_DC(v)((v> >5)+(v> >6)+(v> >7)+(v> >8)+(v> >10))
short int error, error_1=0, proporzionale;
int integrale=0;
/********************************/
short int error_i, out, dc;
error = ((I_REALE - I_RIF)< <3);
proporzionale = KP(error);
error_i=error+error_1;
if(error_i>=0)
integrale += KI(error_i);
else
integrale -= KI((-error_i));
error_1=error;
out=proporzionale+(integrale> >KIS);
if(out>VMAXD) out=VMAXD;
else if(out<-VMAXD) out=-VMAXD;
if(out>=0) y0[0]=(GET_DC(out));
else y0[0]=-(GET_DC((-out)));
y0[1]=y0[0]*VMAX/DCMAX; /* Grandezza reale */
/**** Nel codice del micro ci sar scritto circa quanto segue ****
PDC1=DCMAX+GET_DC(out);
*
PDC2=DCMAX-GET_DC(out);
*
******************************************************************/

In questo caso il sistema deve necessariamente prevedere una saturazione delluscita6 perch non possibile dare
un valore negativo o troppo elevato della grandezza PDCx. Il valore massimo digitale delluscita chiaramente il
valore arrotondato allintero minore di 150V/100*4096 ossia 6144. Questa volta luscita reale y0[1] ottenuta
moltiplicando per linverso della nuova scala cio per 150/368. Per quanto riguarda il commento finale, per il
momento non si entrer nel merito in quanto verr ripreso pi approfonditamente nel capitolo 4 in fase di sviluppo
del codice C per micro controllore.
I risultati ottenuti con il codice di cui sopra sono pressoch identici a quelli ottenuti nelle simulazioni precedenti. Si nota comunque un degrado dellinformazione (tensione) in uscita come mostra il confronto tra le
figure 3.21-a e 3.21-b. Ci si traduce nellavere delle oscillazioni leggermente pi marcate (ma sempre trascurabili come entit) nellintorno del valore di corrente di regime a causa del fatto che la minima variazione della
tensione in uscita aumentata (figura 3.22).

6 Le

saturazioni fino ad ora sono state trascurate per motivi puramente didattici. Di norma dovrebbero sempre essere previste.

3.3. REGOLATORE DIGITALE

(a) Tensione i uscita senza lintroduzione del duty-cycle

47

(b) Tensione in uscita senza introducendo il duty-cycle

Figura 3.21: Confronto tra tensioni in uscita dal regolatore.

(a) Tensione a regime senza considerare il duty-cycle.

(b) Tensione a regime considerando il duty-cycle.

Figura 3.22: Confronto tra tensioni in uscita dal regolatore a regime.

3.3.3

Regolatore Digitale con metodo di integrazione dei resti

Il metodo di gestione dellintegrale utilizzato nella sezione 3.3 si basa sullutilizzo di variabili a 32 bit e di macro
che scompongono i coefficienti reali in potenze di due. Nel capitolo 1, per, stato menzionato un secondo
metodo di gestione dellintegrale che si basa sulla gestione dei resti (a pagina 12). Per completezza ora si vuole
risolvere il medesimo problema con un metodo che tenga conto di un diverso sistema di integrazione basato
appunto sulla gestione dei resti per vedere le differenze anche dal punto di vista computazionale. Lalgoritmo che
verr presentato quello relativo al Metodo 1 ( 3.3.1.1). In questo caso per si considera il coefficiente integrale
pari a KI T2s = 1, 375 104 senza maggiorarlo di 4096. Rifacendosi allimplementazione vista nel capitolo 1
riguardo la gestione dei resti, occorre definire due macro di integrazione come INTEGRALE_H e INTEGRALE_L.
In questo caso il primo chiaramente nullo, in quanto KI T2s minore di 1, e il secondo deve tenere conto dei
decimali. Detto ci, per fare incrementare di una unit la variabile intH occorrerebbe che la variabile intL
1
raggiunga il valore 2 (KI Ts )
= 7272, 7: tutto ci rende per tanto inutile anche la definizione della macro

48

CAPITOLO 3. MODELLISTICA DEL REGOLATORE PI

INTEGRALE_L a causa del fatto che occorre valutare tutta la somma error+error_1 ossia senza effettuare

mascheramenti e/o shift. Il codice proposto il seguente:


#define I_REALE u0[0]
#define I_RIF
u0[1]
#define INT_UNIT 7273 /* minimo valore corrispondente al superamento dellunit*/
#define KP(e)((e< <1)+(e> >1))
short int error, error_1=0, proporzionale;
short int intH=0, intL=0; /* short int in Simulink sono 16 bit */
/---------------------------/
short int out, dc;
error = ((I_REALE - I_RIF)< <3);
proporzionale = KP(error);
intL += error+error_1;
if(intL>=INT_UNIT)
{
intH++;
intL-=INT_UNIT;
} else if(intL<=-INT_UNIT)
{
intH--;
intL+=INT_UNIT;
}
error_1=error;
y0[0]=proporzionale+(intH);
y0[1]=round(y0[0]*100)/4096;

Analizzando il codice si vede che le variabili sono tutte a 16 bit. intL non altro che lintegrale dellerrore attuale
pi il precedente; quando intL supera il valore di +7273, la variabile intH deve incrementarsi di una unit,
mentre se intL minore di -7273, allora intH si decrementer. Nel momento in cui si calcoler luscita y0[0],
la variabile intH non viene pi shiftata perch rappresenta gi il valore corretto nella base scelta. I risultati sono
riportati in figura 48; la risposta perfetta, senza sovra-elongazioni e con errore a regime trascurabile (figura
48-b).
Il codice cos scritto sembra pi semplice e veloce di quelli scritti in precedenza e ci tendenzialmente
vero, ma solo in questo caso. In generale infatti si potrebbero avere pi operazioni per ottenere la variabile intH
(per esempio nel caso in cui il coefficiente di integrazione sia maggiore di 1) il che comporta un aumento anche
notevole del carico computazionale. In altre parole ci dimostra che non esiste una soluzione migliore o peggiore,
ma tutte le strategie proposte andrebbero studiate e valutate in ogni specifico caso.

(a) Risposta al gradino

(b) Dettaglio della risposta al gradino

Figura 3.23: Integrazione con il metodo dei resti.

Capitolo 4

Implementazione di un regolatore PI
Lobiettivo sviluppare un regolatore PI su micro-controllore affrontando le varie problematiche relative alle
scelte hardware e software.

4.1

Regolatore PI su processori dsPIC30F

Il processore che verr utilizzato il dsPIC30F4012. Il codice che verr scritto, comunque, potr essere tranquillamente usato su tutti gli altri dsPIC, salvo il fatto che devono esserci le stesse periferiche.

Hardware del sistema di controllo


Per prima cosa occorre conoscere il sistema che si vuole controllare e realizzarne il modello. Supponiamo per
semplicit che il modello sia come quello trattato al capitolo 3, ossia un carico R-L e che si voglia tenere sotto
controllo la corrente in detto induttore. Lazionamento che ci permette di fare ci pu essere per esempio un
ponte ad H o pi semplicemente un chopper. In questo esempio sceglieremo un ponte ad H in quanto richiede
qualche accorgimento in pi rispetto al chopper. Inoltre il ponte H permetter di valutare la risposta in frequenza
e di seguire riferimenti sinusoidali (o comunque riferimenti che possono essere anche negativi). Ad ogni modo
tutta la trattazione pu essere portata semplicemente anche su un chopper.
Le potenze in gioco sullazionamento sono normalmente molto pi elevate rispetto a quelle dellelettronica
di controllo la quale si dovr interfacciare con le valvole1 del ponte H (o del chopper) con opportuni sistemi detti
driver i quali pur ricevendo un segnale normalmente in logica TTL a 0-5V riescono a generare un impulso di
correte sul gate delle valvole tale da attivarle in un tempo ragionevolmente basso e portarle in conduzione. La
tensione dei driver spesso diversa sia da quella dellelettronica che da quella del circuito di potenza (nel caso
seguente 15V). Questa tensione legata alla caratteristica di gate della valvola da controllare.
Infine vi il micro controllore e i sensori i quali normalmente sono alla stessa tensione pari a 5V.
Lhardware scelto quindi il seguente:
MDA 990 Ponte raddrizzatore a diodi (M OTOROLA). Dovr essere alimentato da un variac monofase. Si vuole
raggiungere la tensione media a vuoto di 100V sul DC-bus.
1 Per valvole si intendono dispositivi generici a semiconduttore che possono essere controllati come interruttori. In questo caso si
assumono come valvole gli IGBT ossia dispositivi che permettono una rapida interruzione di valori anche molto elevati di corrente come le
SKM100GB di S EMIKRON.

49

50

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

SKM100GB IGBT S EMIKRON da 1200V 100A alla frequenza di commutazione di 10kHz ad una temperatura
di giunzione pari a 25 C. Per come stato pensato il circuito (anche in relazione al tipo di driver)
occorre considerare un tempo morto tra la commutazione delle due valvole di uno stesso ramo non
inferiore a 2,5s 2 . In figura 4.1 riportato lo schema di un ponte H.

Figura 4.1: Ponte H.

IR21844

Driver International Rectifier che permette di generare impulsi di corrente in attivazione dellordine
di 1,4A. Inoltre possibile agire sul tempo morto da dare alle valvole senza bisogno di agire via
software andando ad agire sulla resistenza connessa tra il pin DT e Vss. Lo schema in figura 4.2
mostra la tipica connessione di questo driver il quale richiede un circuito di bootstrap. Il circuito
reale presenta anche dei diodi in parallelo alla resistenza posta tra il gate della valvola e il driver in
modo da poter avere un impulso di entit maggiore in fase di spegnimento. Questo tende a ridurre
molto i tempi morti.

Figura 4.2: Tipica connessione del driver IR21844.

LTS25NP

Sensore a effetto HALL le cui caratteristiche sono state descritte nella sezione 3.3.

Le figure 4.3-a e 4.3-b riportano la scheda realizzata (completa di ponte raddrizzatore e valvole) il cui schematico
rappresentato in figura 4.4, utile per capire quali dispositivi sono collegati al microcontrollore e facilitare la
lettura del programma. Chiaramente la scheda riportata ha molti altri dispositivi i quali non verranno esaminati
in questa sede.

2 Valore

ottenuto dalle prove sulla valvola interrompendo correnti di circa 30A a 20kHz

4.1. REGOLATORE PI SU PROCESSORI DSPIC30F

(a) Ponte H

(b) Scheda di controllo

NOTA: i diodi e i pulsanti sono gestiti in logica inversa ossia 0 = ON, 1 = OFF.
Figura 4.3: Dispositivo realizzato.

51

52

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

Figura 4.4: Schematico della scheda di controllo.

4.1. REGOLATORE PI SU PROCESSORI DSPIC30F

53

Strategia di controllo
Per prima cosa si consideri il riferimento impostato direttamente allinterno del processore (quindi non da dispositivi esterni ai quali il processore sia eventualmente interfacciato) pari a un valore costante. Lobiettivo di
ottenere sul carico un valore di corrente costante pari al riferimento. Questo implica che il ripple deve essere il
pi ridotto possibile. Per ottenere questo, il ponte H verr controllato in modo che i due duty-cycle dei due rami
del ponte siano tali per cui 1 = 1 2 come indicato in figura 4.5.

Figura 4.5: Controllo PWM con portante triangolare.


Ci permette di avere sul carico una frequenza pari al doppio di quella di commutazione delle valvole.

Periferiche richieste
Le periferiche necessarie per effettuare il controllo di corrente sono:
PWM

(Pulse Width Modulation) limpulso che attiva o disattiva le valvole e permette la regolazione della
tensione media sul carico.

ADC

(Analog to Digital Converter) convertitore analogico-digitale per poter acquisire le grandezze.

PORTx

(Porte) Porte I/O digitali (o analogiche se ingressi per ADC) per usi generali.

TIMERx

(Temporizzatori) eventuali temporizzatori per gestire alcuni eventi. Non dovrebbero servire in questa
prima applicazione.

Altre periferiche come Seriale UART, CAN, Output Compare, ecc non verranno analizzate, anche se possono
essere molto utili per prelevare informazioni dal micro-processore e quindi effettuarne il monitoraggio e il debug.

4.1.1

Sviluppo del regolatore in codice C

Il codice che si andr a implementare scritto in C orientato al compilatore C30 fornito da M ICROCHIP.
Prima di procedere alla scrittura del codice occorre inizializzare le periferiche precedentemente elencate.
Tutte le informazioni sulla famiglia dsPIC30F sono ottenibili dal manual family [4]. Si osservi infatti che il
datasheet del singolo processore approssimativo e documenta esclusivamente il comportamento delle varie

54

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

periferiche. Ci che invece serve in questo momento conoscere tutti i flags e registri che occorre settare per
impostare il corretto funzionamento delle periferiche integrate3 .
Il programma verr strutturato nei seguenti file:
global.h

definisce le principali variabili e definizioni di costanti comuni a tutti i files.

init.h

file di intestazione delle funzioni di inizializzazione. Contiene le dichiarazioni delle funzioni di


InitPORT(), InitPWM(), InitADC() ed eventuali macro.

init.c

file C di implementazione delle funzioni di inizializzazione.

pi.h

file di intestazione contenente le dichiarazioni e macro necessarie per effettuare la routine di regolazione.

main.c

file C principale. Contiene la funzione main e le funzioni di interrupt.

Temporizzazioni e dead-line
Una fase molto importante decidere le temporizzazioni e scadenze temporali. Ci fondamentale perch per
garantire il real-time occorre essere certi che le operazioni vengano eseguite correttamente e nei tempi stabiliti.
Ora occorre scegliere la frequenza di commutazione delle valvole. Da datasheet la frequenza nominale 10kHz,
ma possono funzionare anche a frequenze molto pi alte a patto che la corrente da interrompere sia inferiore
alla nominale. Si sceglie una frequenza di 20kHz. Per essere precisi occorrerebbe valutare anche la frequenza
ammissibile del driver, la quale normalmente molto alta (nellordine dei 100kHz) e non costituisce un problema.
A questo punto occorrerebbe valutare quanto il sistema impiega per eseguire le operazioni basilari (shift,
moltiplicazioni, somme, if..else, ecc). Si consideri in linea del tutto indicativa che un dsPIC30F con un quarzo
da 7,37228 MHz difficilmente supera i 2,4s/PLL4 per operazioni su variabili int a 16 bit. Questo permette di
stimare i tempi di calcolo.
Detto questo, dato il quarzo da 7,37228 MHz posto sulla scheda si sceglie di lavorare con un PLL di 8
che porta la frequenza di clock a 58,9MHz (figura 4.6). Frequenze pi alte fanno assorbire molta corrente al
processore5 il quale tende a scaldarsi e spesso a degradare le prestazioni.
Rimangono ora da definire le scadenze temporali. Sicuramente il sistema di controllo vero e proprio verr
asservito allADC, ossia la routine di controllo dovr essere eseguita ogni volta che lADC avr campionato un
nuovo valore. A sua volta il convertitore sar asservito al PWM il quale andr ad attivare il convertitore AD ad intervalli regolari di 50s (pari al reciproco della frequenza di commutazione delle valvole) o multipli: ci definisce
la base dei tempi di integrazione. Questa gestione dellADC e PWM con portante triangolare particolarmente
vantaggiosa perch permette di andare a campionare il valore della corrente nel punto centrale dellintervallo ON
o OFF del PWM; questo valore pari al valore medio nellintervallo della corrente. Rifacendosi alla figura 4.5
si noti che possibile fare scatenare gli eventi di ativazione dellADC e/o gli interrupt a uno o entrambi dei due
vertici della triangolare.
A questo punto occorre valutare che la routine che si vuole implementare (definita nelle simulazioni) abbia
un carico computazionale minore o al pi uguale allintervallo di tempo che avviene tra levento di fine conversione dellADC e listante di aggiornamento del duty-cycle del PWM. Per fare ci il metodo pi semplice
implementare il codice, eseguirlo senza collegare lhardware di potenza alla scheda e misurare per esempio il
3 Si

noti che ci non vero per i pic i quali hanno datasheet completi per ogni processore.
PLL un coefficiente moltiplicativo che pu assumere i valori x1, x4, x8, x16.
5 Si consideri che con PLL=1 il dsPIC assorbe a vuoto circa 1520mA contro i 110120mA con PLL=16.
4 il

4.1. REGOLATORE PI SU PROCESSORI DSPIC30F

55

cambiamento di stato di un pin con un oscilloscopio. Si noti che indicativamente il tempo di elaborazione di un
PI implementato con questo processore, a queste frequenze e con le modalit descritte, impiega dai 4,5 ai 6 s
per essere eseguito.

Configurazione delle periferiche


Per la configurazione delle periferiche, in funzione di quanto detto in precedenza e in funzione del layout della
scheda (figura 4.3-b), le porte B (PORTB) devono essere configurate come ingressi analogici per permettere allADC di effettuare il campionamento in modo corretto; le porte D (PORTD) sono invece configurate come input
(collegate ai pulsanti), mentre le porte E (PORTE) alle quali sono connessi i diodi led vanno settate come uscite,
mentre quelle relative al PWM non ha importanza in quanto se un pin ha una funzione ulteriore oltre a quella di
semplice porta I/O, il device ulteriore dominante rispetto a quello di semplice porta.
LADC va configurato in modo che venga letto solo un canale (ossia il segnale proporzionale alla corrente
dato dal sensore) e il risultato posto nel buffer 0 (ADCBUF0) e deve generare un interrupt (_ADCIE=1) alla fine
di ogni conversione; la chiamata allinterrupt richiesto dallADC (interrupt subroutine _ADInterrupt()) sar
la routine di regolazione vera e propria (PI). La temporizzazione del sample&hold+conversione , come detto,
legata al PWM.
Il PWM configurato per lavorare a 20kHz, ossia occorre definire la variabile PTPER, che identifica il periodo,
ottenibile da datasheet come segue:
1
PTPER =
2

Fosc
P LL
4

7372800
1
+1=
+ 1 = 368
fdesiderata
20000

(4.1)

Il valore cos calcolato per portante triangolare e il numero deve essere lintero troncato per difetto. Si noti che
questa variabile a 15bit, mentre il duty-cycle a 16bit (_PDCx dove x 1, 2, o 3) e il valore massimo impostabile
doppio rispetto a _PTPER. I tre moduli PWM devono essere indipendenti. Infine si noti che il PWM sul microcontrollore pu controllare sia la valvola alta che quella bassa di un ramo di inverter. La logica del segnale PWM
in uscita dai pin specifici condizionata dai flag High-side/Low-side PWM Output Polarity di configurazione di
figura 4.6.

Figura 4.6: Configuration bits del dsPIC30F4012.

56

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

Codice C
Si consiglia di leggere il codice seguente tenendo sempre a portata di mano [4], quanto meno per capire quali
sono le procedure necessarie per la configurazione e la gestione delle periferiche.
=======================
global.h
#ifndef __GLOBAL_H__
#
define __GLOBAL_H__
#include <p30f4012.h>
#define ON
1
#define OFF
0
/* Logica di controllo dei LED inversa */
#define LED_VERDE_ON
_RE5=0b0
#define LED_VERDE_OFF
_RE5=0b1
#define LED_ROSSO_ON
_RE4=0b0
#define LED_ROSSO_OFF
_RE4=0b1
#define CLOCK
7372800 //7372800 Clock esterno, come slle schede di valutazione
#define NBIT
12
#define NBIT2
13
#define NBASE
4095
#define NBASE2 8191
#define NBASE3 16383
#define NBASE24 16777000 //in realt 2^24=16777261
#define FREQ
20000
//20KHz
#define PER
0.00005 //Periodo
#define PERIODO (int)368
#define DUTYCYM (int)736 //DC massimo in unipolare singola gamba
#define DUTYCY PERIODO //DC massimo in unipolare doppia gamba
#define OFFSET_I
512
//Offset delle correnti per riportarle allo 0
#define CORRENTEP
ADCBUF0 //Primo buffer contenente il valore della corrente digitalizzato
#endif // __GLOBAL_H__

=======================
init.h
#ifndef __INIT_H__
#
define __INIT_H__
#define TRIGGER_AD_PWM
0b011
#define TRIGGER_AD_TMR3 0b010
#define TRIGGER_AD_AD
0b000
#define CHANNEL4
0b11
#define CHANNEL2
0b01
#define CHANNEL1
0b00
extern void InitTIMER(unsigned int nStep);
extern void InitPORT();
extern void InitPWM(int nleg, unsigned char interrupt_enable);
extern void InitAD(unsigned char trigger_AD, unsigned char ADCS_delay, unsigned char ingresso, unsigned
#endif // __INIT_H__

=======================
init.c
#include "init.h"
#include "global.h"
#include <p30f4012.h>

/** InitPORT **/


void InitPORT() {
TRISD=0x0000;
PORTD=0xFFFF;
TRISB=0xFFFF;

4.1. REGOLATORE PI SU PROCESSORI DSPIC30F

57

TRISE=0x0080; //setto come input solo il pulsante


PORTB=0xFFFF;
PORTE=0xFFFF; //Sulle mie schede i led e i pulsanti sono in logica inversa
ADPCFG=0x0000; //Specifica che PORTB, se configurato come input, analogico
}

/** Inizializza il PWM **


Il parametro in ingresso nleg determina quante gambe voglio abilitare in modo indipendente, mentre interrupt_enable indica se voglio abilitare linterrupt
************************/

void InitPWM(int nleg, unsigned char interrupt_enable) {


PTPER=PERIODO; //PWM Time Period register 15bit (Fquarz/4*PLL8)/(2*Freq desiderata). Attenzione _PTMO
PTCONbits.PTMOD=0b10; //Free Running Mode=00, Continuous Up/Dw=10. Attenzione: il periodo complessivo
PTCONbits.PTOPS=0b0000; //Postscaler
PTCONbits.PTCKPS=0b00; //Prescaler
PTCONbits.PTSIDL=0b0;
PTCONbits.PTEN=0b1;
//Abilitazione (e attivazione) del PWM
PWMCON1=0x0000;
//Inizialmente azzero tutto il registro per precauzione
if(nleg>0) {
PDC1=0; //duty cycle per PWM1 16bit, quindi duty=50%->PDCx=PTPER
PWMCON1bits.PMOD1=0b1; //Indipendent mode 0=off, 1=on
PWMCON1bits.PEN1H=0b1; //Abilito la gamba alta
PWMCON1bits.PEN1L=0b1; //Abilito la gamba bassa
}
if(nleg>=2) {
PDC1=DUTYCY; //se 2 perch controllo il ponte ad H
PDC2=DUTYCY; //duty cycle per PWM1 16bit, quindi duty=50%->PDCx=PTPER
PWMCON1bits.PMOD2=0b1; //Indipendent mode 0=off, 1=on
PWMCON1bits.PEN2H=0b1; //Abilito la gamba alta
PWMCON1bits.PEN2L=0b1; //Abilito la gamba bassa
}
FLTACON=0x0000;
_PWMIF=0;
_PWMIE=(interrupt_enable&0x1); //Abilito o no linterrupt
}

/** Inizializza lADC **/

void InitAD(unsigned char trigger_AD, unsigned char ADCS_delay, unsigned char ingresso, unsigned char ch
/* Le tabelle di configurazione sono da pagina 420 in poi del Manual Family. */

ADCHS=0;
ADCHSbits.CH0SA=ingresso&0x0F; //numero di ingressi da campionare AN0->CH1=>ADCBUF1, AN1->CH0=>ADCBUF
_SIMSAM=0b1; //se 1 -> simultaneous sampling
_SMPI=0b000; //0=Interrupt dopo ogni campionamento e si riparte dal buffer 0 a scrivere, 1=interrupt
switch(trigger_AD){
case TRIGGER_AD_PWM:
_SSRC=TRIGGER_AD_PWM; //gestito da PWM = 011
break;
case TRIGGER_AD_TMR3:
_SSRC=TRIGGER_AD_TMR3; //gestito dal timer
break;
default:
_SSRC=TRIGGER_AD_AD; //tutto gestito dallAD=111,
}
_ASAM=0b1; //Automatic sample
_CSCNA=0b0; //Disabilito lo scanning dei sample/hold se 0
_ALTS=0; //Alternate MUX Sampling: se 0 il multiplexer sempre impostato si A
ADCON2bits.CHPS = channel&0x03; //Scelta del canale: 00=S/H su CH0, 01=S/H su CH0 e CH1, 1x=CH0,1,2,3
//---Questi sono flag del PWM---//
SEVTCMPbits.SEVTCMP=0;
SEVTCMPbits.SEVTDIR=0b0;
_SEVOPS=0b0000; //0=Evento per lADC ogni intervallo di PWM, 1=conversione AD ogni 2 PWM, ecc
//------------------------------//
ADCON3bits.SAMC = 1; //tempo minimo di sample
ADCON3bits.ADCS = ADCS_delay&0x3F; //Setta il minimo tempo per la conversione A/D.
ADPCFGbits.PCFG0 = 0;
ADPCFGbits.PCFG1 = 0;
ADPCFGbits.PCFG2 = 0;
_ADIE=1;
//Abilito linterrupt
_ADIF=0;

58

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

_ADON=0b1; //Attivo lADON


}

=======================
pi.h
#ifndef __PI_H__
#
define __PI_H__
/********** REGOLATORE DI CORRENTE ***********/
#define CURRENT_BASE
100 //lem da 25A con una spira ->100A teorici, 80 in saturazione
#define OFFSET_CURRENT
512
#define INITIAL_CURRENTR 0 //eventuale valore iniziale dellintegrale
#define CURRENT_RIF
2048 //2048->50A
/***** PI di corrente *****/
#define INTEGRALEI(e)((e> >1)+(e> >4))
#define RID_IP
12
#define TKIUPI
NBASE24 // sarebbe pi corretto +13422000
#define TKIDWI -NBASE24 // sarebbe pi corretto -13422000
//----------------------------//
#define PROPORZIONALEI(e)((e< <1)+(e> >1))
#define TKPUPI
NBASE //KP threshold up
#define TKPDWI -NBASE //KP threshold down
#define VDUP
3276
// limito superiormente luscita a ~ 80V
#define VDDW
-3276 // limito inferiormente luscita a ~ -80V
/********** CHECK DUTY-CYCLE *************/
#define DCUP 699 //perdo il 5% della tensione che perdo x colpa dei tempi morti
#define DCDW 37
/********** MACRO DI RIPORTO DEL DC **************/
#define V_OFFSET
4095
#define GET_DC(v_digit)((v_digit> >4)+(v_digit> >6)+(v_digit> >7)+(v_digit> >8))
#endif // __PI_H__

In questo file vengono definite le principali costanti relative al regolatore PI. Meritano per una breve considerazioni le definizioni delle soglie relative al duty-cycle: si osservi infatti che il valore minimo e il valore
massimo sono rispettivamente il 5% e il 95% del valore massimo della variabile PDCx. Ci dovuto al fatto
che bene non far avvenire due commutazioni troppo ravvicinate. Infatti se per esempio il duty-cycle fosse
del 99% per pi di un ciclo si avrebbe la commutazione di una valvola (per esempio in spegnimento) e dopo
50106 /736'680 ns si avrebbe unaltra commutazione. Commutazioni troppo ravvicinate possono danneggiare
irreparabilmente il driver. Ci solo una precauzione nel caso le soglie VDUP e VDDW vengano modificate inavvertitamente in modo errato. Si noti che per quanto riguarda lintegrale, la soglia corretta da porre sarebbe quella
di 80/100 40962 =13422000.
=======================
main.c
#include <p30f4012.h>
#include "global.h"
#include "init.h"
#include "pi.h"
/***** Global *****************/
int errorI,errorI_1; //errore ed errore precedente
int riferimentoIp=CURRENT_RIF;
long int integraleIp; //24bit+1bit di segno
int correnteIp; //12bit+1bit di segno
long int vd_out; //variabile in base 12bit+1bt di segno
/**********************************
MAIN
**********************************/
int main() {

4.1. REGOLATORE PI SU PROCESSORI DSPIC30F

59

InitPORT();
//Inizializzo le porte
InitPWM(2,OFF); //Abilito due gambe del PWM, ma senza abilitare linerrupt
LED_VERDE_ON;
while(_RE8);
//Fino a che resta tutto in stop o non premo RE8 non fare nulla
Nop();
while(!_RE8);
//Se rilascio il pulsante parte il sistema
LED_VERDE_OFF;
InitAD(TRIGGER_AD_PWM,10,0,CHANNEL1); //Abilito lAD asservendo levento di conversione al PWM e camp
LED_ROSSO_ON;
while(1); //Entro nel ciclo infinito per evitare il reset del micro. Tutto il controllo verr gestito
}
/****************************
Interrupt SubRoutine
****************************/
void _ISR _ADCInterrupt() { //Sintassi della routine di interrupt dellADC
int dc, errorIi;
_RD0=1; //Flag per la misura dei tempi di esecuzione. Pu essere omesso.
/***************************************************
REGOLATORE DI CORRENTE: metodo dei trapezi
***************************************************/
correnteIp=((CORRENTEP-OFFSET_I))< <3; //riporto la corrente a 12bit
errorI=(riferimentoIp-correnteIp); //calcolo lerrore
//INTEGRALE:
errorIi=errorI_1+errorI; //errore x lintegrale=errore attuale + errore precedente
if(errorIi>=0)
integraleIp+=INTEGRALEI(errorIi);
else
integraleIp-=INTEGRALEI((-errorIi));
//PROPORZIONALE:
vd_out = PROPORZIONALEI((errorI))+(int)(integraleIp> >12);
if(vd_out>VDUP) vd_out=VDUP;
else if(vd_out<VDDW) vd_out=VDDW;
/***************************************************
USCITA riportata sul DC
***************************************************/
vd_out+=V_OFFSET; //porto il valore da 0 a 8191 (->13bit)
dc=GET_DC(vd_out);
if(dc>DCUP) dc=DCUP; //Controllo precauzionale sul DC
else if(dc<DCDW) dc=DCDW;
PDC2=dc;
PDC1=DUTYCYM-dc;
/***********************************************
TRATTAMENTO FINALE DELLE VARIABILI
***********************************************/
if(integraleIp>TKIUPI) integraleIp=TKIUPI;
else if(integraleIp<TKIDWI) integraleIp=TKIDWI;
errorI_1=errorI;
_ADIF=0;
_RD0=0;
_RD0=0; //Flag per la misura dei tempi di esecuzione. Pu essere omesso.
}

Osservando il codice si vede che a parte la fase di inizializzazione dei devices del micro processore, il resto
molto simile a quanto modellizzato in S IMULINK. La parte pi importante la routine di interrupt invocata dal
convertitore AD. Come si vede il sistema calcola lerrore di corrente a 12bit. Il riferimento pari a 2047 che
corrisponde a 50A. Successivamente viene calcolato lintegrale e il proporzionale. Si noti che il primo viene
condizionato tramite opportuni costrutti if che servono ad evitare gli errori legati agli shift negativi (sezione
1.3), mentre il proporzionale no; questo perch il primo shift del proporzionale ha sinistra e dello stesso valore
di quello destro, quindi il risultato presenta un errore sensibile solo se il dato in ingresso vale -1. In pi il
proporzionale non ha memoria e quindi non accumula errori. Inoltre il proporzionale non viene saturato perch
lerrore massimo che pu essere letto di 2048 che moltiplicato per 2,5 d 5120. Ammettendo che lintegrale
(opportunamente shiftato) sia pari a 4096, la loro somma inferiore a 215 ; in altre parole non vi loverflow
della variabile intera con segno a 16 bit. Una volta calcolata luscita, essa viene saturata a 3276 che corrisponde a

60

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

80V (per rispettare la simulazione). Successivamente il duty-cycle viene ottenuto dalla tensione in scala 0-8191
(ossia 13 bit) e nuovamente saturato. Questa soglia di saturazione viene posta solo per completezza per evitare
che il sistema dia un duty-cycle del 100% (o prossimo al 100%) il che pu danneggiare il driver. Conviene quindi
prevedere un 5% di tensione in meno del valore massimo e minimo. chiaro che tutto ci potrebbe essere tenuto
in conto nella saturazione della variabile vd_out. Per riportate la tensione espressa in scala 13 bit sul duty-cycle
espresso in scala 0-736 occorrerebbe dividere per 213 , moltiplicare per la corrente massima di riferimento (100A),
dividere per la tensione massima di DC-bus (100V) e moltiplicare per 736:
= vd_out13

100 736

= 0.0898
213 100

il che corrisponde alla macro GET_DC. Il numero in ingresso alla macro sempre positivo e quindi non ha bisogno
di controlli sulla variabile.
Lultima parte della routine di controllo serve per limitare lintegrale. La posizione pi corretta per effettuare
la saturazione subito dopo il calcolo dellintegrale. Il fatto che venga posta alla fine solo a titolo di esempio in
quanto si preferisce aggiornare il duty-cycle il pi presto possibile. In questo esempio ci non comporta nessun
beneficio perch i tempi di calcolo sono molto pi bassi del periodo del duty-cycle. Potrebbe invece avere effetti
positivi se i tempi fossero maggiori di questo periodo, o se il campionamento non fosse sincrono con gli eventi di
PWM.
======================

4.2

Controllo di tensione

In questo capitolo verr affrontato lo sviluppo di un regolatore mediante processore PIC16F684. Premesso quanto detto nei capitolo precedenti, si cercher di realizzare un regolatore PI per la simulazione di un controllo di
corrente. Per fare ci si utilizzer la demoboard P IC K IT 2 (e relativo programmatore P IC K IT 2) di M ICROCHIP.
Alla scheda verr connesso un circuito RC (R=1K, C=1F elettrolitico) il quale viene alimentato direttamente
dal PWM del micro controllore retroazionando la tensione sul condensatore la quale verr acquisita dal convertitore analogico-digitale. chiaro che se R e C sono scelti adeguatamente possibile avere un circuito RC che
presenta la stessa costante di tempo di un circuito RL. Chiaramente ci che verr tenuto sotto controllo non
la corrente, ma la tensione sul condensatore in quanto questultima presenta lo stesso andamento della corrente.
Scegliendo opportunamente R e C sarebbe possibile anche avere anche la stessa risposta (in termini di dinamica)
di un eventuale sistema R-L da simulare.
GRL (s) =

1
RL

1 + s RLL

GRC (s) =

1
1 + sRC

se

R=1
C = L/RL

In figura 4.7 riportato lo schema di connessione del circuito RC alla demo board PicKit2 il cui datasheet
[7] disponibile su [L3].
Il vantaggio principale di ci che il micro processore realizza contemporaneamente il sistema di controllo,
lattuatore e il sensore senza bisogno di collegare altri dispositivi esterni. Esaminando [7] si osserva che la scheda
non presenta un clock esterno, quindi il micro processore dovr necessariamente utilizzare il proprio oscillatore
interno (frequenza nominale 4MHz); questi tipi di oscillatori non sono precisissimi quindi le formule descritte
in [8] per il calcolo del PWM potrebbero non essere affidabili. consigliabile quindi andare a misurare con un

4.2. CONTROLLO DI TENSIONE

61

(a) Connettore dei pin disponibili (da datasheet


della demo board PicKit2)

(b) Circuito R-C e relative connessioni


alla demo board.

Figura 4.7: Schema di collegamento del circuito RC ai pin accessibili della scheda di valutazione P IC K IT 2
DEMO.
oscilloscopio la frequenza di PWM che, in questo caso, verr impostata alla massima possibile e pari a 3,9kHz.
Tale frequenza sar anche quella di campionamento.

4.2.1

Progetto e implementazione del regolatore

Il progetto del regolatore resta pressoch invariato rispetto a quanto detto nei capitoli 2 e 3. Si consideri quindi un margine di fase di 90 e una banda passante di 1500 rad/s. Ne conseguono KP =1,5 e KI =1500.
Implementando il regolatore in digitale si ha che il coefficiente di integrazione KI sar pari a:
KI = KI

TS
1
= 1500
= 0.1923
2
2 3900

mentre KP resta pari a KP . Il codice si sviluppa quindi nei seguenti files:


main.c

file principale contenete la funzione main, le macro del regolatore e le funzioni di interrupt

init.h

file contenente i prototipi delle funzioni

init.c

file di implementazione delle funzioni definite in init.h

Configurazione del processore e relative periferiche


I bit di configurazione del processore devono essere settati come segue: watchdog disabilitati, clock interno
(Internal RC clockout) e Master Clear Enabled (figura 4.8).
Per quanto riguarda le periferiche, ci che serve la configurazione delle porte I/O le quali vanno definite
come output per le porte C (PORTC) alle quali sono collegati i led della demo board, e come input analogico la
porta 1 delle porte A (RA1).
LADC dovr essere configurato in modo da leggere lingresso analogico su RA1. Si sceglie di usare solo gli
8 bit pi significativi quindi il risultato del campionamento dovr essere giustificato a sinistra ossia resettando
il bit ADFM.
Il PWM gestito tramite il timer 2 grazie al quale possibile definire il periodo di PWM e il numero di periodi
che devono trascorrere perch venga generato linterrupt. La configurazione tale per cui si vuole ottenere la
massima frequenza di PWM e un interrupt ad ogni periodo quindi postscaler e prescaler verranno azzerati (almeno
inizialmente). Il duty-cycle una grandezza a 10 bit i cui 8 bit pi significativi sono contenuti nella variabile
CCPR1L. Gli altri due bit verranno mantenuti a 0.

62

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

Figura 4.8: Configuration bits per processore pic16f684 (da MPLab).


Codice C
Si consiglia di leggere il codice seguente tenendo sempre a portata di mano [8], quanto meno per capire quali
sono le procedure necessarie per la configurazione e la gestione delle periferiche. La base scelta per i calcoli 8
bit.
E SEMPIO N 1:
=======================
init.h
#ifndef __INIT_H__
#define __INIT_H__
extern
extern
extern
extern
#endif

void InitPORT(void);
void InitTIMER2(void);
void InitPWM(void);
void InitAD(void);
//__INIT_H__

//porte
//x controllo PWM
//set pin PWM + event trigger AD
//config AD

=======================
init.c
#include "init.h"
#include "htc.h"

void InitPORT() {
ANSEL=0x03;
TRISA=0b00000011;
TRISC=0x00;
PORTC=0;
CMCON0=0xFF; //se non metti questo le ANx assumono valori assurdi!!!!
}
/****************************
PWM: Per capire come i tempi impostati nel timer 2 siano correlati al PWM e come configurare le porte, s
Si noti che per fare il ponte ad H occorre settare P1M=0b10 (vedere in [8] figura 11-6)
****************************/
void InitPWM() { //riferirsi a CCP1CON
CCP1CON=0x00; //azzero tutto per sicurezza
P1M1=0b1; P1M0=0b0; //01=Full bridge foreward. 10=Half bridge (comando 2 valvole)
CCP1M3=0b1; //1100=P1A,C,B,D attive alte
CCP1M2=0b1; //1101=P1A,C attiveH, B,D attiveB //in altre parole B e D sono negate
CCP1M1=0b0; //1110=P1A,C attiveL, B,D attiveB
CCP1M0=0b0; //1100=P1A,C,B,D attiveL
InitTIMER2();
}

4.2. CONTROLLO DI TENSIONE

63

/* TIMER2: Timer a 8 bit. */


void InitTIMER2() {
T2CON
=0x00;
//Azzero tutto per precauzione
TOUTPS3 =0b0;
TOUTPS2 =0b0; TOUTPS1=0b0; TOUTPS0=0b0; //Postscaler 0000=1:1, 1111=1:16
T2CKPS1 =0b0; T2CKPS0=0b0; //Prescaler 00=1, 01=4, 1x=16
TMR2IF =0;
//Azzero il flag di interrupt
TMR2IE =1;
//Abilito linterrupt. Verr usato come interrupt del PWM!
TMR2
=0;
//Contatore da comparare a PWM
PR2
=0xFF;
//Con PR2 definisco il periodo del PWM
TMR2ON =1;
//Attivo il TMR
}
void InitAD(void) {
ADFM=0b0; //0= giustificazione a sinistra
VCFG=0b0; //0= tensione di riferimento pari ai 5V di alimentazione
CHS2=0; CHS1=0; CHS0=1; // 000=AN0=RA0, 001=AN1
ADCS0=0; ADCS1=0; ADCS2=0; //000=Fosc/2 x la conversione, che con il clock interno a 4MHz sono circa
ADIF=0;
ADIE=1;
ADON=1; //abilito ladc
}

=======================
main.c
#include <htc.h>
#include "init.h"
//DEFINIZIONI
#define RIFERIMENTO
5
//in volt
#define RIFD
105 //riferimento digitale
#define INTEGRALE(e)((e> >3)+(e> >4)+(e> >8))
#define PROPORZIONALE(e)((e)+(e> >1))
//GLOBALS
short int error, error_1, riferimento, proporzionale; //8bit con segno
int out, integrale; //16bit
void main() {
GIE=1; //interrup globalo ON
PEIE=1; //interrupt delle periferiche ON
InitPORT();
InitAD();
InitPWM();
InitTIMER1();
GODONE=1; //inizio prima conversione
while(1); //entro nel ciclo infinito
}
// INTERRUPT SUB-ROUTINE
void interrupt isr(void) {
int errorI;
if(TMR2IF) //se scatta linterrupt a causa del timer 2 (ossia del PWM) allora...
{
RC0=RC0^0x1; //lampeggio del primo led (per debug)
GODONE=0b1; //Inizio conversione AD
TMR2IF=0b0; //azzero il flag di interrupt
}
if(ADIF)
{
RC1=0b1;
// set di un bit per la misura dei tempi di calcolo
ADIF=0b0;
error=RIFD-(ADRESH);
//calcolo dellerrore
errorI=(int)error+error_1; //cast di error per eseguire i calcoli in int
if(errorI>=0) integrale+=INTEGRALE(errorI);
else integrale-=INTEGRALE((-errorI));
if(integrale>255) integrale=255;
//saturazione positiva dellintegrale
else if(integrale<-255) integrale=-255; //saturazione negativa dellintegrale
proporzionale=PROPORZIONALE(error);
out=(int)proporzionale+integrale;
if(out>255) out=255;
//soglia superiore delluscita
else if(out<0) out=0; //soglia inferiore delluscita

64

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

CCPR1L=out;
error_1=error; //salvo lerrore attuale
RC1=0b0 // Reset del bit per la misura dei tempi di calcolo
}
}

=======================
In questo primo esempio il codice proposto realizza brutalmente il regolatore gestendo lintegrale a 16 bit
in modo da poter avere un valore dellintegrale compreso tra 255. Si infatti ipotizzato che la base sia 8 bit
(ossia con 2555V in ingresso) ed noto che luscita sia ancora una tensione compresa tra 0V e 5V; ci implica
che anche lintegrale debba avere una soglia pari al valore massimo raggiungibile dalluscita o, per meglio dire,
raggiungibile dalla variabile out. Tale considerazione andrebbe fatta anche per il proporzionale il quale, per,
viene gestito a 8bit con segno (short int). evidente che ci potrebbe dare problemi legati al bit di segno
che il compilatore assegna allultimo bit; nonostante questo ragionevole pensare che non vi siano particolari
problemi di computazione in quanto valori negativi inferiori a -127 (ossia 27 -1) non dovrebbero mai verificarsi,
soprattutto a regime. Questa scelta pu sembrare uninutile complicazione in quanto se si applicasse la stessa
considerazione fatta per lintegrale a tutte le variabili questo problema, effettivo o presunto che sia, cesserebbe
di esistere. per necessario tenere presente che la potenza computazionale di questi processori non rilevante
e, unitamente al fatto che si sta lavorando con loscillatore interno da 4MHz, si ha che il codice deve essere il
pi performante possibile; dove possibile quindi meglio usare variabili con dimensione di memoria pari alla
parola del processore (8 bit in questo caso).
Detto ci, esaminando il codice del regolatore dovrebbe essere tutto chiaro fino al calcolo delluscita (out). A
questo punto viene settato il duty-cycle pari alluscita (CCPR1L=out) e ci forse richiede una breve spiegazione:
da [8] cap11 si evince che il duty-cycle una variabile a 10bit divisa in una variabile da 8 bit pi significativi
(CCPR1L) e 2bit meno significativi (DC1B<1:0> nel registro CCP1CON). Detto ci, noto che il valore del
duty-cycle dato dal valore di OUT moltiplicato per il reciproco del coefficiente di conversione (pari a 256/5V)
diviso il valore massimo della tensione di uscita (5V in questo caso), per il valore massimo digitale del duty-cycle
(210 ):
digit = out

5 1024

= out 22 = out  2
256
5

ma essendo OUT un valore compreso nei primi 8 bit, ne deriva che OUT il valore dei primi 8 bit pi significativi
del duty-cycle. Gli ultimi due bit sono sicuramente nulli, quindi non necessario settarli.
Il codice cos sviluppato formalmente corretto, ma esaminando luscita con un oscilloscopio si nota che vi
sono dei problemi legati al controllo. Fugati i dubbi legati ai problemi di calcolo, si suppone che il regolatore
presenti dei problemi legati ai tempi di esecuzione. Per valutare ci occorre misurare i tempi osservando il
cambiamento di stato dei bit RC0, RC1, RC2 e RC3 (i quali sono connessi ai diodi led sulla demo board).
Disabilitando il regolatore, tramite RC0 si valutano gli istanti in cui avviene linterrupt a fronte dellevento di
PWM come si pu osservare dalla figura 4.9. Attivando il regolatore possibile valutare gli istanti in cui la
routine di regolazione comincia e termina e, per differenza, ottenere i tempi di esecuzione della stessa. Se
tutto funzionasse correttamente, ci si dovrebbe aspettare che listante di inizio della routine e quello finale siano
compresi in un singolo periodo di PWM, ma dalla figura 4.10 si osserva che cos non . Infatti il tempo di
esecuzione della routine di regolazione pi di 100s e quindi maggiore del periodo di PWM. Analizzando il
grafico 4.10-b si osserva che i tempi di esecuzione non sono sincroni con la triangolare (tensione sul condensatore)
e pertanto non saranno sincroni con il PWM, ma ci causa il sovrapporsi degli eventi di interrupt; per esempio
frequente che levento di interrupt di PWM scatti durante la regolazione andando cos a sfasare anche gli altri
eventi (figura 4.10-a); lo sfasamento legato allevento di PWM crea un ritardo nellattivazione dellADC e ci si

4.2. CONTROLLO DI TENSIONE

65

La frequenza di PWM 3,9kHz (rosso)


e ogni evento di PWM (blu) avviene
con la stessa frequenza ed rappresentato da ogni singolo fronte di salita e
discesa.

Figura 4.9: Interrupt di PWM sovrapposto al segnale di PWM con al 50%.

(a) Sfasamento degli eventi di interrupt (regolatore disabilitato).

(b) Andamento della tensione sul condensatore e misura dei tempi


di esecuzione (regolatore abilitato).

Figura 4.10: Sfasamento degli eventi di interrupt.

ripercuote sui tempi di integrazione. Una fotografia della tensione in una finestra temporale pi ampia dimostra
landamento irregolare della tensione stessa la quale non ha un valore medio costante6 (figura 4.11).

6 Il

valore medio inteso come valore calcolato in ogni singolo intervallo di PWM.

66

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

Il fatto che lattivazione della conversione sia effettuata in ritardo, in


linea teorica comporta che il valore
campionato sia un qualsiasi valore
compreso allinterno del ripple di un
periodo di PWM. Ci avviene con una
certa frequenza generando unonda
che nel tempo presenta una evidente
sub-armonica

Figura 4.11: Andamento reale della tensione sul condensatore.


E SEMPIO N 2:
Per ovviare a quanto detto le soluzioni sono fondamentalmente tre. La prima provare a riscrivere il codice
in assembler, cosa che non verr affrontata in quanto oltre che complesso pu anche risultare inutile a causa del
fatto che se il compilatore C riesce ad ottimizzare il programma; molto probabile che la scrittura del codice
in assembler non porti i vantaggi sperati. La seconda soluzione prevede di allungare il periodo di PWM ma la
cosa non conveniente perch si rischia di aumentare troppo il ripple. La terza consiste invece nel far avvenire
levento di interrupt ogni due periodi di PWM sfruttando il post-scaler. Ci comporta che il PWM ha ancora
la stessa frequenza (e quindi ripple pi basso possibile), ma la base dei tempi di integrazione raddoppiata. Il
codice seguente rappresenta la sola funzione di inizializzazione del PWM e il main file in quanto sono le uniche
due cose che variano rispetto al caso precedente.
=======================
init.c
...
void InitTIMER2() {
T2CON
=0x00;
//Azzero tutto per precauzione
TOUTPS3 =0b0; TOUTPS2=0b0; TOUTPS1=0b0; TOUTPS0=0b1; //Postscaler 0000=1:1, 1111=1:16
T2CKPS1 =0b0; T2CKPS0=0b0; //Prescaler 00=1, 01=4, 1x=16
TMR2IF =0;
//Azzero il flag di interrupt
TMR2IE =1;
//Abilito linterrupt. Verr usato come interrupt del PWM!
TMR2
=0;
//Contatore da comparare a PWM
PR2
=0xFF;
//Con PR2 definisco il periodo del PWM
TMR2ON =1;
//Attivo il TMR
}
...

=======================
main.c
#include <htc.h>
#include "init.h"
//DEFINIZIONI
#define INTEGRALE(e)((e> >2)+(e> >3)+(e> >7))

4.2. CONTROLLO DI TENSIONE

67

#define PROPORZIONALE(e)((e)+(e> >1))


//GLOBALS
short int error, error_1, proporzionale, riferimento; //8bit
int out, integrale; //16bit
void main() {
GIE=1; //interrup globalo ON
PEIE=1; //interrupt delle periferiche ON
InitPORT();
InitAD();
InitPWM();
InitTIMER1();
GODONE=1;
while(1); //entro nel ciclo infinito
}
// INTERRUPT SUB-ROUTINE
void interrupt isr(void) {
int errorI;
if(TMR2IF) { //se scatta linterrupt a causa del timer 2 (ossia del PWM) allora...
RC0=RC0^0x1;
GODONE=1;
TMR2IF=0b0; //azzero il flag di interrupt
}
if(ADIF) {
RC1=0b1;
ADIF=0b0;
error=RIFD-(ADRESH);
errorI=(int)error+error_1;
if(errorI>=0) integrale+=INTEGRALE(errorI);
else integrale-=INTEGRALE((-errorI));
if(integrale>255) integrale=255;
else if(integrale<-255) integrale=-255;
proporzionale=PROPORZIONALE(error);
out=(int)proporzionale+integrale;
if(out>255) out=255;
else if(out<0) out=0;
CCPR1L=out;
error_1=error;
RC1=0b0;
}
if(TMR1IF) {
RC3=RC3^0b1;
TMR1ON=0b0;
TMR1IF=0b0;
}
}

=======================
Il fatto che ora i tempi di integrazione siano doppi (grazie a TOUTPS0=0b1) implica che il coefficiente di
integrazione sia doppio. Ne risulta che la macro INTEGRALE sia definita come:
#define INTEGRALE(e)((e> >2)+(e> >3)+(e> >7))

In figura 4.12 sono riportati gli istanti in cui avviene levento di interrupt del PWM e i tempi di inizio ed
esecuzione correlati alla routine di regolazione. La frequenza con cui si verificano gli interrupt di PWM di circa
1938 kHz (pari a 516s) e si ha quindi tutto il tempo per eseguire la routine di regolazione.
E SEMPIO N 3:
Il sistema fino ad ora proposto permette di effettuare la regolazione in modo corretto. Per il valore di tensione
tenuto sotto controllo non il valore medio, bens il valore di tensione nel punto pi basso della triangolare7 o
comunque in un intorno di questo punto. Scopo di questo terzo esempio quello di mostrare come risolvere
7 Si ricorda infatti che in questo tipo di micro-processore il PWM viene generato da unonda a dente di sega e non da una triangolare (come
invece possono fare per esempio i dsPIC), quindi se linterrupt avviene in un vertice della portante, questo istante non corrisponde a met del
tempo TON (o TOF F ).

68

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

(a) Periodo di PWM (rosso) e interrupt relativo (blu, uno per ogni (b) Tensione sul condensatore (rosso), tempo di esecuzione routine
fronte)
PI (blu), interrupt dellADC

Figura 4.12: Regolazione in due periodi di PWM.


questo problema. Prima di mostrare il codice per bene individuare i tempi esatti in cui avvengono i vari
interrupt: infatti osservando la figura 4.13 (o anche la figura 4.9) possibile vedere come tra londa di PWM e
la rilevazione dellinterrupt di PWM vi sia un ritardo pari a circa 32s8 di cui necessariamente si dovr tenere
conto.

Figura 4.13: Ritardo tra linizio del PWM e leffettiva rilevazione dellinterrupt.
Per risolvere il problema quindi intuitivo pensare di sfruttare un timer (o contatore) il quale dovr attendere
il tempo necessario per fare in modo che la conversione AD parta nellistante corrispondente al punto medio
dellintervallo TON del PWM. I timer a disposizione sono il timer TMR0 e TMR1: il primo non si pu utilizzare
in quanto non possibile poterlo attivare via software, quindi la scelta ricade inevitabilmente su TMR1. Il codice
che mostra una possibile soluzione del problema il seguente:
=======================
8 Tale ritardo probabilmente imputabile ad alcuni fattori tra cui la chiamata di funzione di interrupt che deve salvare il contesto del
programma e alla comparazione if(TMR2IF) per identificare levento di PWM.

4.2. CONTROLLO DI TENSIONE

69

init.h
#ifndef __INIT_H__
#define __INIT_H__
extern
extern
extern
extern
extern
#endif

void InitPORT(void);
void InitTIMER1(void);
void InitTIMER2(void);
void InitPWM(void);
void InitAD(void);
//__INIT_H__

//porte
//x controllo PWM
//set pin PWM + event trigger AD
//config AD

=======================
init.c
#include "init.h"
#include "htc.h"
void InitPORT() {
ANSEL=0x03;
TRISA=0b00000011;
TRISC=0x00;
PORTC=0;
CMCON0=0xFF; //se non metti questo le ANx assumono valori assurdi!!!!
}
void InitPWM() { //riferirsi a CCP1CON
CCP1CON=0x00; //azzero tutto per sicurezza
P1M1=0b1; P1M0=0b0; //01=Full bridge foreward. 10=Half bridge (comando 2 valvole)
CCP1M3=0b1; //1100=P1A,C,B,D attive alte
CCP1M2=0b1; //1101=P1A,C attiveH, B,D attiveB //in altre parole B e D sono negate
CCP1M1=0b0; //1110=P1A,C attiveL, B,D attiveB
CCP1M0=0b0; //1100=P1A,C,B,D attiveL
InitTIMER2();
}
/* TIMER2: Timer a 8 bit. */
void InitTIMER2() {
T2CON
=0x00;
//Azzero tutto per precauzione
TOUTPS3 =0b0;
TOUTPS2 =0b0; TOUTPS1=0b0; TOUTPS0=0b0; //Postscaler 0000=1:1, 1111=1:16
T2CKPS1 =0b0; T2CKPS0=0b0; //Prescaler 00=1, 01=4, 1x=16
TMR2IF =0;
//Azzero il flag di interrupt
TMR2IE =1;
//Abilito linterrupt. Verr usato come interrupt del PWM!
TMR2
=0;
//Contatore da comparare a PWM
PR2
=0xFF;
//Con PR2 definisco il periodo del PWM
TMR2ON =1;
//Attivo il TMR
}
void InitAD(void) {
ADFM=0b0; //0= giustificazione a sinistra
VCFG=0b0; //0= tensione di riferimento pari ai 5V di alimentazione
CHS2=0; CHS1=0; CHS0=1; // 000=AN0=RA0, 001=AN1
ADCS0=0; ADCS1=0; ADCS2=0; //000=Fosc/2 x la conversione, che con il clock interno a 4MHz sono circa
ADIF=0;
ADIE=1;
ADON=1; //abilito ladc
}
void InitTIMER1() {
TMR1L=0xFF; TMR1H=0xFF;
T1CON=0;
TMR1ON=0b0;
TMR1IF=0;
TMR1IE=1;
}

=======================
main.c
#include <htc.h>

70

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

#include "init.h"
#define RIFD
(short)80 //riferimento digitale
#define INTEGRALE(e)((e> >3)+(e> >4)+(e> >8))
#define PROPORZIONALE(e)((e)+(e> >1))
//GLOBALS
short int error, error_1, proporzionale, riferimento; //8bit
int out, integrale; //16bit
//DELCARATION
void main() {
GIE=1; //interrup globalo ON
PEIE=1; //interrupt delle periferiche ON
InitPORT();
InitAD();
InitPWM();
InitTIMER1();
GODONE=1;
while(1); //entro nel ciclo infinito
}
// INTERRUPT SUB-ROUTINE
void interrupt isr(void) {
int errorI;
if(TMR2IF) {//se scatta linterrupt a causa del timer 2 (ossia del PWM) allora...
TMR1ON=0b1; //attivo il timer1
RC0=RC0^0x1;
TMR2IF=0b0; //azzero il flag di interrupt
}
if(ADIF) {
RC1=0b1;
//flag di misura del tempo
ADIF=0b0;
error=RIFD-(ADRESH);
errorI=(int)error+error_1;
if(errorI>=0) integrale+=INTEGRALE(errorI);
else integrale-=INTEGRALE((-errorI));
if(integrale>255) integrale=255;
else if(integrale<-255) integrale=-255;
proporzionale=PROPORZIONALE(error);
out=(int)proporzionale+integrale;
if(out>255) out=255;
else if(out<0) out=0;
CCPR1L=out;
error_1=error;
TMR1H=0xFF; //setto a 255 la parte alta del TMR1
TMR1L=0xFF-(CCPR1L> >1)+36; //sottraggo a 255 il tempo necessario
RC1=0b0; //flag di misura del tempo
}
if(TMR1IF) {
RC3=RC3^0b1; //flag per individuare levento
GODONE=1;
//attivo il campionamento
TMR1ON=0b0; //spengo il timer1
TMR1IF=0b0;
}
}

=======================
Il codice sostanzialmente non diverso per quanto riguarda linizializzazione e la regolazione se non per il fatto che stata aggiunta la funzione InitTMR1. Nella funzione di interrupt si pu osservare che levento di PWM fa
attivare TMR1 e non pi la conversione. Occorre ora ricordarsi che nei PIC il timer comincia a contare da un valore (nel caso di TMR1 comincia dal valore TMR1H28 +TMR1L) per arrivare la massimo (in questo caso 0xFFFF,
ossia 65535 in quanto timer a 16 bit), azzerarsi e generare linterrupt. Ci implica che se si vuole far contare al
timer un numero x di impulsi, il valore TMR1H28 +TMR1L deve essere pari a TMR1H28 +TMR1L=0xFFFFx. La parte di codice che esegue questi passaggi chiaramente TMR1L=0xFF-(CCPR1L> >1)+36; dove
(CCPR1L> >1)+36=x. CCPR1L il duty-cycle ossia il numero di tic che occorre aspettare per attendere un

tempo pari a TON . per questo viene diviso per 2 (mediante shift). A questo viene poi sommato 36. Questo nu-

4.2. CONTROLLO DI TENSIONE

71

mero deriva da quanto detto in precedenza in quanto per avere 32s su un timer senza pre/post-scalatori occorre
un numero di tic pari a:

1
fosc
4
N = 32
32s = N
=N
4
4 106 s
Il fatto che sia stato posto 36 legato al fatto che, una volta programmato il processore, effettuando alcune
misure il risultato sembrato pi preciso; in altre parole si affinato sul campo il dispositivo. I risultati di
questo programma sono visibili in figura 4.14.

Si osserva che il PWM in regolazione (rosso)


viene intersecato nel punto medio dallonda che
rappresenta listante di inizio conversione AD
(blu). Chiaramente anche la tensione sul condensatore intersecata nel punto medio.

Figura 4.14: Sincronizzazione dellistante di campionamento con il punto medio di TON .

72

CAPITOLO 4. IMPLEMENTAZIONE DI UN REGOLATORE PI

Capitolo 5

Regolatore PID
In questo capitolo verr affrontato lo studio di un regolatore PID. Tutta la trattazione realizzata basandosi sul
lavoro fatto per stabilizzare il levitatore elettromagnetico studiato in [5] e [6].

5.1

Regolatore tempo-continuo

Luscita di un regolatore PI nel dominio del tempo funzione dellerrore in ingresso ed la seguente:
Z
uP I (t) = KP e(t) + KI

d
e(x)dx + KD e(t) = KP
dt

1
e(t) +
Ti


d
e(x)dx + Td e(t)
dt

(5.1)

e, applicando la trasformata di Laplace, si ottiene



UP I =


s2 KD + sKP + KI
KI
KP +
+ sKD E(s) =
E(s) = P I(s) E(s) = R(s) E(s)
s
s

(5.2)

Realizzare un regolatore PID quindi fisicamente impossibile in quanto il grado del numeratore maggiore
del denominatore. Ci in teoria non un problema se si pensa ai regolatori digitali; infatti con un micro controllore
possibile effettuare i calcoli necessari affinch la routine di regolazione possa essere compiuta. Nonostante ci
preferibile studiare un regolatore che sia fisicamente realizzabile introducendo un polo in alta frequenza sul
termine derivativo. Secondo quanto spiegato in [2] una formulazione interessante esprimere la parte derivativa
come segue:
UD (s) =

sKD
1 + s TNd

(5.3)

dove, secondo [2], N un numero tipicamente compreso tra 3 e 30, mentre Td chiaramente pari a KD /KI .
Nonostante ci il progetto del regolatore PID si sviluppa basandosi sullequazione 5.2 in quanto pi semplice
da trattare. Per il progetto si possono seguire vari metodi; di seguito ne vengono esposti alcuni indicandone pregi
e difetti.
Metodo di Zigler e Nichols
La via tradizionale usare il metodo Zigler e Nichols in anello chiuso che si basa sullosservazione della risposta
al sistema ponendo KD e KI pari a 0 e facendo variare KP partendo da valori molto piccoli non a raggiungere
unoscillazione permanente della risposta. Da questo si determina il periodo di oscillazione e successivamente
73

74

CAPITOLO 5. REGOLATORE PID

i valori di KD e KI mediante apposite tabelle. Chiaramente questo sistema non permette una determinazione
analitica della soluzione. Per maggiori informazioni si rimanda a [9].
Metodo analitico
Il metodo analitico tendenzialmente simile a quello esposto per il regolatore PI (sezione 2.1.2). Anche in questo
caso infatti possibile fissare margine di fase e banda passante, ma occorre aggiungere anche una terza equazione
a causa della nuova incognita KD . Per fissare la terza equazione si ricorre al margine di guadagno. Il margine
di guadagno di per s non d solo uninformazione sullasintotica stabilit, ma qualifica anche la robustezza
della stessa; in altri termini indica la sicurezza con la quale possiamo tollerare incertezze sul modello senza
compromettere lasintotica stabilit ([10]). Per ottenere il margine di guadagno occorre calcolare la pulsazione
p ovvero quel valore di frequenza per la quale la fase della funzione danello L(s)1 risulta pari a 180 ; ottenuto
questo valore occorre porre il modulo di L(s) maggiore di 1:
km =

1
>1
|L(jp )|

con

L(jp ) = 180

Ci comporta la nascita di una ulteriore incognita (p appunto) che si aggiunge alle altre due equazioni sul margine di fase e banda passante: il sistema risulta costituito da quattro equazioni in quattro incognite, ma nonostante
ci non risolvibile in forma chiusa a causa del fatto che lequazione per determinare p trascendente. Il
sistema di equazioni comunque il seguente:

cos()

KP = |R(jt )| cos() = |G(j

t )|

K + K 2 = |R(j )| sin() = sin()


I
D t
t
|G(jt )| t
1
|KP + jP KD jP KI | =

km |G(jp )|

(KP + jP KD jP KI ) = 180 G(jp )

(5.4)

Questo sistema permetterebbe di decidere il tipo di risposta desiderata e calcolare esattamente i vari coefficienti.
Metodo del piazzamento poli
Il metodo del piazzamento poli permette di scegliere i poli e determinare degli opportuni coefficienti per fare in
modo che tali poli siano quelli del sistema. Per fare ci si ricorre alla funzione place di M ATLAB come indicato
nellalgoritmo 7. Per poter applicare il metodo seguente occorre ottenere le matrici di stato che descrivono il
sistema in esame G(s). Le matrici che occorrono sono quella di stato A e quella degli ingressi B. La funzione
M ATLAB place che permette di ottenere un vettore K dato un fissato vettore P di autovalori che moltiplicata per
il vettore B degli ingressi e sottratto ad A permette di ottenere la nuova matrice di stato:
An = A B K
A questo punto possibile ottenere la nuova funzione di trasferimento. Data questa funzione poi possibile per
analogia confrontarne il denominatore con quello della funzione L(s) espressa nelle incognite KP , KI , KD .
Tutto ci valido nellipotesi che il sistema sia SiSo o MiSo e lo stato sia accessibile ovvero che tutte le
grandezze del sistema siano rilevabili2 .
1 Si

ricorda che con L(s) si intende L(s) = RP ID (s) G(s)


pratica spesso le grandezze non accessibili vengono stimate aggirando quindi il problema e permettendo sempre, almeno in linea
di massima, di utilizzare questa tecnica.
2 Nella

5.1. REGOLATORE TEMPO-CONTINUO

75

Algorithm 7 Utilizzo funzione place di M ATLAB.


sys = tf(num, den); %definizione dela funzione di trasferimento G(s)
[A, B, C, D] = tf2ss(num, den); %generazione delle matrici di stato
P =[ p1 p2 ... pn]; %definizione del vettore dei poli di lunghezza pari alla dimensione di A
K = place(A, B, P); %definizione del vettore K
An = A-B*K; %definizione del nuovo sistema da considerarsi in anello chiuso
[num_n, den_n] = ss2tf(An, B, C, D); %calcolo i nuovi denominatori
sys_n = tf(num_n, den_n); %calcolo nuovo sistema (in anello chiuso)

Si noti che le incognite sono tre, quindi il sistema in esame deve essere almeno del terzo ordine. Se fosse di ordine inferiore, la funzione sys nellalgoritmo 7 dovrebbe essere portata al terzo ordine moltiplicando
numeratore e denominatore per s come nellesempio seguente:
sys=tf(20,[1 10 0]);
sys=tf([20 0], [1 10 0 0]);

% NO
% SI

I due sistemi hanno esattamente la stessa risposta, ma la matrice A risulter di dimensione 3x3 e non 2x2. Si
ricorda che per ottenere le matrici A, B, C e D del sistema dati numeratore e denominatore della funzione di
trasferimento, in M ATLAB si utilizza la funzione tf2ss3 :
[A,B,C,D]=tf2ss([20],[1 10]);
[A,B,C,D]=tf2ss([20 0 0],[1 10 0 0]);

% A matrice 1x1
% A matrice 3x3

Questo metodo permette di determinare un nuovo sistema da considerarsi in anello chiuso (sys_n nellalgoritmo
7 che verr indicata in seguito con F 0 (s)) il quale sar stabile e caratterizzato da una certa risposta dinamica.
A questo punto se si calcolasse la funzione di trasferimento in anello chiuso F (s) che comprende il regolatore
R(s) e la funzione G(s) (sys nellalgoritmo 7), si otterrebbe una funzione che come al solito non altro che
un rapporto tra due polinomi i cui denominatori sono dello stesso grado. Quindi per analogia si otterranno i
coefficienti KP , KI , KD del regolatore PID. Questo metodo ha il difetto che la risposta del sistema in anello
chiuso calcolato (F (s) = R(s)G(s)) sar s stabile, ma diversa dalla funzione sys_n perch il numeratore delle
due funzioni non viene valutato per ottenere i coefficienti del regolatore, ma solo il denominatore considerato
(per capire meglio quanto appena detto si consideri lesempio posto alla fine di questa sezione). Inoltre i poli
fissati non danno informazioni riguardo al margine di fase e quindi normalmente il sistema calcolato sottoposto
ad un gradino presenta sovra-elongazioni pi o meno sensibili. Inoltre occorre tenere presente che fissando poli
troppo elevati (in modulo), ossia velocizzando la risposta del sistema, si tende ad avere una elevata reazione da
parte del regolatore.
Vi sono per anche grandi pregi come la possibilit di fissare la dinamica a piacimento4 e quindi di stabilizzare
i sistemi instabili.
E SEMPIO : si supponga un sistema del primo ordine da controllare e un regolatore PID da cui derivano le relative
funzioni di anello e in anello chiuso:
G(s) =

s+a

R(s) =

F (s) =
3 Una

KD s2 +KP s+KI
s

L(s) = G(s)R(s) =

KD s2 + KP s + KI
s (s + a)


KD s2 + KP s + KI
L(s)
= 2
1 + L(s)
s (K D + 1) + s (KP + a) + KI

lista dei comandi principali per lo situdio dei sistemi si pu trovare in [11]
vero entro i limiti della moderazione del controllo e della risposta libera del sistema se esso instabile. Infatti se un sistema
instabile i poli che stabilizzano il sistema devono possibilmente essere scelti in modulo maggiori del modulo maggiore dei poli del sistema
da stabilizzare.
4 Ci

76

CAPITOLO 5. REGOLATORE PID

e si supponga inoltre che il guadagno e la costante di tempo a siano pari allesempio precedente, ossia
rispettivamente pari a 20 e 10. Ora si vogliono fissare i poli. Premesso che la funzione place non piazza
poli coincidenti, si supponga di fissare il seguente vettore di poli: poli=-[30 100] tale per cui la funzione M ATLAB min(abs(poli)) restituisca un valore maggiore di 10. A questo punto occorre determinare
le matrici di stato del sistema. Basandosi su quanto riportato nellalgoritmo 7, si eseguono i seguenti comandi:
sys = tf([ 20 0 ], [ 1 10 0 ]); %aggiungo uno 0 per avere un sistema 2x2
[A, B, C, D] = tf2ss(num, den); %generazione delle matrici di stato (A 2x2)
P =[ -30 -100 ]; %definizione del vettore dei poli P 1x2
K = place(A, B, P); %ne risulta K=[ 120 3 ]
An = A-B*K; %definizione del nuovo sistema da considerarsi in anello chiuso
[num_n, den_n] = ss2tf(An, B, C, D); %calcolo i nuovi denominatori
sys_n = tf(num_n, den_n); % questa F(s)

A questo punto il numeratore vale den_n=[1 130 3000] e la funzione danello F 0 (s) =

20s
s2 +130s+3000

la

quale evidentemente asintotica a 0 a causa dells a numeratore. Quello che per interessa il denominatore il quale per analogia con il denominatore di F(s) si ha:

1 = KD + 1
KD = 20 = 0.05
130 = KP + a
KP = (130 10)/20 = 6

3000 = KI
KI = 3000/20 = 150
Quindi F (s) 6= F 0 (s) come anche L(s) 6= L0 (s). Da ci si possono trarre alcune osservazioni. La
funzione F (s) ha numeratore e denominatore uguali in grado. Ci implica che sicuramente il sistema
presenter errore non nullo a regime. Di questo per non si terr conto in questo esempio che mira solo
a far vedere come ottenere i coefficienti5 . Si osservi inoltre che se il sistema fosse instabile (per esempio
a=-10) questa procedura avrebbe stabilizzato il sistema, ma non per ogni valore di KP . Infatti chiaro
che tutti i coefficienti del regolatore debbano essere maggiori di 0 (o al limite uguali). Quindi si deve
necessariamente avere che il coefficiente di s (in questo caso pari a 130) sia maggiore di a. Infine si
noti che la determinazione dei coefficienti (soprattutto di KD ) non tiene conto delleventuale polo in alta
frequenza. Normalmente questo polo bene prevederlo, ma non in fase di progetto in quanto tende a
complicare anche notevolmente le formule.

5.2

Regolatore Discreto

Anche in questo caso possibile procedere in pi modi per la discretizzazione del regolatore.
Metodo 1: separazione della parte P, I e D
La discretizzazione del regolatore viene fatta seguendo le stesse indicazioni date nella sezione 2.2.2 ossia applicando la trasformazione di Tustin. Sullanalisi vera e propria del sistema si entrer nel dettaglio pi avanti;
tuttavia bene riallacciarsi ad una nota fatta in precedenza riguardante il posizionamento di un polo in alta
frequenza (equazione 5.3). Provando ad applicare Tustin alla componente derivativa del regolatore si ottiene:
RD (z) = KD

2
TS

z1
z+1


uD (z) =


2KD
1 z 1 e(z) z 1 uD (z)
Ts

(5.5)

5 Possibili soluzioni per migliorare la risposta potrebbero essere laggiunta di un integratore o di un eventuale regolatore in cascata a quello
appena determinato.

5.2. REGOLATORE DISCRETO

77

Osservando questa relazione subito chiaro che il termine costante

2KD
Ts

tanto pi grande quanto pi piccolo

lintervallo di campionamento. Molto spesso nella pratica il valore assunto da questo parametro tale per cui
il micro non riesce a gestirlo con le normali variabili. Inoltre, se sommato alla parte proporzionale e integrale,
questo termine ordini di grandezza pi elevato e vanifica leffetto degli altri parametri.
Studiando invece la funzione con il polo in alta frequenza (equazione 5.3) si ottiene:
RD (z) = KD

2
Ts

z1
z+1


2
Ts

1


z1
z+1

Td
N

= KD
+1

z1
2
2 z1

 
 = KD
Td 2
Td 2
Ts
Ts za + b
z
+1 + 1
N Ts
N Ts
|
{z
} |
{z
}
a

(5.6)
da cui si ottiene la relazione
uD (z) =


b
2KD
1 z 1 e(z) z 1 uD (z 1 )
aTs
a

Ora il termine moltiplicativo della differenza

2KD
aTs

(5.7)

risulta molto pi contenuto in quanto a e Ts1 hanno circa

lo stesso ordine di grandezza. Ci rende il sistema pi semplice da trattare dal punto di vista numerico anche per
un micro processore. Tutto ci sar pi chiaro in fase di scrittura del codice, ma fin dora possibile sostituire
alcuni plausibili valori per vedere le differenze numeriche dei coefficienti. Per esempio supponendo coefficienti
KP = 2, KI = 500, KD = 1 e un tempo di integrazione pari a Ts = 50s si avrebbe nel primo caso
KD
2KD
Ts = 40000, mentre nel secondo caso, se per esempio N = 10, Td = KP = 0, 5, a = 2001, b = 1999 e
2KD
aTs

= 19, 99; le grandezze sono decisamente pi consone al micro processore.

Metodo 2: discretizzazione della funzione Z totale


In questo caso si considera la funzione equivalente che esprime il regolatore PID. Partendo dalla funzione tipica
(ossia P+I+D) si ha, trasformando con Tustin, la seguente relazione:

RP ID (z)

2 z1
Ts z + 1
+ KD
=
2 z1
Ts z + 1
KP (z 2 1) + T2s KI (z + 1)2 + T2s KD (z 1)2

= KP + KI
=

z2
=

=

(5.8)
=


z2 1


KP + T2s KI + T2s KD + z Ts KI +

4
Ts KD

z2 1

+ z 1 Ts KI +

4
Ts KD

KP +

Ts
2 KI

2
Ts KD

Ts
2 KI

+ z 2

2
Ts KD

Ts
2 KI

2
Ts KD

1 z 2

ma anche in questo caso evidente che se i tre coefficienti non sono di ordine di grandezza paragonabile, i
termini di questa relazione sono difficilmente gestibili in quanto tutti i coefficienti moltiplicativi della variabile
z, presentano il coefficiente KD diviso per Ts . Ricalcando lesempio precedente in cui KP = 2, KI = 500,
 KP  Ts KI e quindi il termine proporzionale e ancora di pi quello integrale per
KD = 1 chiaro che KTD
s
essere valutati richiederebbero precisioni molto elevate.
Viste le considerazioni fatte per il metodo 1, anche in questo caso si terr in considerazione il polo in alta

78

CAPITOLO 5. REGOLATORE PID

frequenza. La funzione tempo-continua diventa quindi la seguente:


R(s)

s2 KD +
KP s + KI
sKD
+ Td
=
s
sN +1

Td
N KP

+ s KP +

Td
N KI

+ KI

s2 TNd + s

s2 a + sb + c
(5.9)
s2 TNd + s

Procedendo con la trasformazione di Tustin si ottiene:

RP ID (z)

4
Ts2

4
Ts2

z1
z+1

2

z1
z+1

a+
2

Td
N

2
Ts

z1
z+1

2
Ts

b+c
 =

z1
z+1

4
Ts2

2
2
Ts z 1 b + c (z
2
1) TNd + T2s (z 2 1)

(z 1) a +
4
Ts2

(z

 




z 2 a T42 + b T2s + c + z 2c a T82 + a T42 b T2s + c
s
s




s 
4Td
8Td
4Td
2
2
z N T 2 + Ts z N T 2 + N T 2 T2s
s

1)

(5.10)

Anche in questo caso a, b e c (legate ai coefficienti del regolatore) sono confrontabili, quindi tutti i termini che
presentano Ts2 a numeratore sono termini preponderanti.

5.3

Regolatore PID di corrente

Il regolatore PID che verr presentato, mira a risolvere un problema nato nel sistema di controllo di un levitatore
magnetico EMS con doppia bobina studiato in [5] e [6]. Senza entrare troppo nel dettaglio della macchina in
esame, basti sapere che il levitatore costituito da due espansioni esapolari e su ogni polo montata una bobina
di polarizzazione e una di regolazione. Tutte le bobine dei sei poli sono connesse in serie. Inoltre per quanto
riguarda la polarizzazione gli avvolgimenti di entrambe le espansioni esapolari sono a loro volta connesse in serie.
Ovviamente ci non stato fatto per la regolazione in quanto essa deve funzionare in modo indipendente per il
controllo di ciascun traferro. La bobina di polarizzazione ha il compito di sostenere il flusso magnetico al traferro
e il regolatore ha il compito di mantenere costante la corrente in questa bobina. In figura5.1 rappresentato
un singolo polo e le equazioni relative ai due avvolgimenti. Senza scomodare tutti i modelli studiati in [6], si
consideri un singolo avvolgimento come un induttore accoppiato ad un altro in una configurazione tale per cui il
flusso che si concatena con le spire dellavvolgimento possa variare a fronte fondamentalmente di due fenomeni:
il primo la variazione di traferro che provoca una variazione di tipo mozionale (infatti linduttanza funzione
del traferro ), mentre il secondo legato alla regolazione la quale per stabilizzare il sistema deve generare una
corrente che s mediamente costante, ma istantaneamente ha variazioni difficilmente prevedibili.
Dei due problemi elencati, il primo trascurabile perch se il sistema funziona correttamente, il traferro
tendenzialmente costante o comunque i movimenti sono molto piccoli e non troppo rapidi6 e quindi i termini mozionali non sono significativi. Il secondo termine invece complesso da gestire e causa grandi interferenze anche
a frequenze maggiori di 1 kHz. Utilizzando un PI questi disturbi sono particolarmente visibili e laccoppiamento
tale che tende ad instabilizzare il sistema se il controllo non fatto adeguatamente.
Per questo motivo si scelto di utilizzare un PID. Un PID ha tendenzialmente lo svantaggio di amplificare
i disturbi sul riferimento. Tali disturbi derivano normalmente dallaccoppiamento dei conduttori che collegano
sensore e micro-processore. Nonostante ci si presuppone che il sistema sia schermato e filtrato adeguatamente.
Detto questo, prima di valutare i reali vantaggi di un PID in questo sistema bene definire il modello (semplificato) del sistema che si vuole controllare. Banalmente il sistema viene analizzato come un semplice circuito
6 Oscillazioni

stimate intorno alla decina di Hz.

5.3. REGOLATORE PID DI CORRENTE

79

A fronte di ragionavoli ipotesi sulla linearit


del circuito magnetico, un possibile modo di
descrivere il sistema il seguente:

z
}|
{

d
vp = Rp ip + dt
(Lp ()ip + Lm ()ir )
d
(Lr ()ir + Lm ()ip )
vr = Rr ir + dt

|
{z
}

(a) Polo centrale di una espansione esapolare

Figura 5.1: Singolo polo EMS con bobine di regolazione e polarizazione.


R-L7 al quale per sommato un disturbo sotto forma di forza elettromotrice (e(t)) variabile con legge ignota
nel tempo:
d
(5.11)
vp = Rp ip + Lp ip + e(t)
dt
schematizzabile come in figura 5.2.

G(s) =

1
Rp + sLp

Rp = 0.42
Lp = 0.0983H
Figura 5.2: Schema a blocchi relativo al controllo del sistema descritto dallequazione 5.11.
Per studiare leffetto del regolatore sul sistema visto dallingresso e(t), ossia dal disturbo, sufficiente studiare
la funzione di trasferimento seguente:
I(s)
G(s)
=
e(s)
1 + G(s)R(s)

(5.12)

Ora si considerino i regolatori PI e PID classici (ossia senza poli in alta frequenza). La funzione di trasferimento
del disturbo in funzione dei due tipi di regolatori fondamentalmente la stessa:
s
s2 LP +s(R+KP )+KI
s
s2 (Lp +KD )+s(R+KP )+KI

per regolatore PI
per regolatore PID

In entrambi i casi si nota una s a numeratore. Ci implica che il sistema tende a derivare il disturbo. Se il
disturbo fosse a gradino ci benefico perch annullerebbe il valore del disturbo a regime, ma se presentasse
7 Con L si intende lauto induttanza di polarizazione equivalente dei dodici poli vista ai morsetti di ingresso e uscita dellindutore in esame
calcolata al traferro di 4mm.

80

CAPITOLO 5. REGOLATORE PID

delle armoniche, queste verrebbero amplificate (in quanto derivate) anche se la retroazione tende ad attenuare
questo fenomeno. Fermo restando quanto detto si osservino allora i termini a denominatore: si nota che a pari
KP e KI , laggiunta del derivativo aumenta linerzia (in termini elettrici) del sistema. Ci implica che a fronte
di un gradino, il disturbo si annuller presentando oscillazioni di durata leggermente superiore, ma pi contenute
in termini di ampiezza.

5.3.1

Progetto del regolatore

La determinazione di parametri come gi accennato in precedenza non semplice se effettuata in anello chiuso.
Quindi in questo caso il metodo di progetto stato un po pi spartano. Per prima cosa non si tenuto conto del
termine in alta frequenza in quanto esso dipende dai termini KP e KD , quindi verr determinato di conseguenza
una volta trovati gli altri coefficienti. Detto ci si proceduto fissando i coefficienti KP e KI (noti gi dalla
pratica per le prove fatte con il regolatore PI) e successivamente si cercato di scegliere un KD al massimo pari a
1 che permettesse di ottenere una risposta con una banda passante maggiore o uguale a 1000 rad/s. I coefficienti
trovati sono KP =10, KI =1000, KD =1. Successivamente stato scelto il coefficiente N necessario per il polo in
alta frequenza (equazione 5.3) anche in relazione a come verr scritto il codice. Si noti fin dora che maggiore
N , migliore il comportamento in quanto il regolatore si comporta da come un PID puro in una gamma di
frequenze maggiore, ma di contro i numeri da gestire, soprattutto a livello digitale, sono molto pi elevati. In
simulazione un giusto compromesso sembrato i coefficiente N =10.
Il regolatore cos realizzato caratterizzato da un banda passante pari a t =1110 rad/s e un margine di fase
m =94 . Per valutare meglio il comportamento del regolatore PID cos ottenuto, si consideri un regolatore PI
ottenuto in forma chiusa con la stessa banda passante e margine di fase m =908 . Da ci si otterrebbero i valori
KIpi =466,2 e KP pi =109,16. Il diagramma di Bode di L(s) = RP ID (s)G(s) e LP I (s) = RP I (s)G(s) ossia
le funzioni di anello date rispettivamente dal regolatore PID e PI sono riportate in fgura 5.3; in questa figura
riportato anche landamento della funzione danello ottenuta dal regolatore PI ottenuto dagli stessi coefficienti
integrale e proporzionale del regolatore PID. Si osserva che tutti gli andamenti sono stabili in anello chiuso ed
in particolare PIpi e PID coincidono in alta frequenza. Osservando poi la risposta in frequenza della funzione di
trasferimento tra uscita e disturbo relativa alla funzione danello L(s) ottenuta con regolatore PI e PID (figura
5.4) si osserva che per disturbi di qualche decina di Hz il sistema con PID attenua un po meglio, ma per le altre
frequenze il regolatore PI sembra nel complesso migliore.
Da questa analisi pu sembrare che non vi sia motivo di utilizzare un PID per il controllo, ma che convenga
concentrarsi su un regolatore PI. In realt cos non perch i problemi reali si hanno quando si va a creare il
regolatore digitale (cio quando lo si sintetizza in C) nel quale il termine KP di valore superiore a 100 e KI di
circa 450 causano alcuni problemi di calcolo. Il termine proporzionale molto alto e quindi tende a dare in uscita,
a fronte per esempio di piccoli errori in ingresso, grandi variazioni di duty-cycle, mentre lintegrale tale per cui il
termine KI = KI T2s piccolissimo; talmente piccolo che in alcune versioni del programma era stato addirittura
eliminato trasformando di fatto il regolatore in un semplice proporzionale9 : introdurre tale termine, anche se
piccolissimo, comportava normalmente linstabilit del sistema sia in simulazione sia sul campo. Adottare invece
la soluzione PID permette di avere termini nel complesso pi gestibili. In realt anche il PID presenta questi
problemi se non venisse implementato senza polo in alta frequenza. A tal proposito si tenga sempre presente che
se il fattore N aumentasse, il coefficiente derivativo digitale aumenterebbe anchesso in modo proporzionale.
osservi che se fosse m = 94 , determinando KI e KP in forma chiusa si otterrebbe un KI negativo e quindi il sistema sarebbe
instabile. Porre m = 90 migliora comunque la risposta almeno in termini di fase.
9 Tra le varie versioni fatte ve nera una in cui il regolatore era un semplice P in cascata ad un filtro passa-basso (ovviamente digitale) che
tagliava frequenze molto alte. Questo risolse molti problemi, ma presentava comunque oscillazioni di ampiezza rilevante sulla corrente di
uscita.
8 Si

5.3. REGOLATORE PID DI CORRENTE

81

blu - PI ottenuto dai coefficienti PID, verde - PI con la stessa t di PID, rosso - PID
Figura 5.3: Diagramma di Bode delle funzioni danello ottenute con regolatori PI e PID.

Figura 5.4: Risposta in frequenza della funzione di trasferimento tra uscita I(s) e disturbo e(s).

5.3.2

Simulazione del regolatore digitale

La simulazione deve ovviamente rispettare il pi possibile la configurazione del caso reale. Si noti a tal proposito
che il sistema di controllo PID stato sviluppato per essere particolarmente reattivo: mentre tutto il sistema
controllato con PWM a 20kHz, il PWM del regolatore di polarizzazione viene gestito a 40kHz. Il periodo di
PWM anche il tempo di integrazione che in questo caso sar quindi pari a Ts =25s.
La simulazione verr condotta come al solito confrontando la soluzione tempo-continua (s), tempo-discreta
(z) e digitale (C S IMULINK) usando il modello in figura 5.5. Il disturbo verr posto allinterno del regolatore come

82

CAPITOLO 5. REGOLATORE PID

indicato. Il metodo di implementazione segue il primo metodo di discretizzazione (sezione 5.2) del regolatore,
ossia i termini P, I e D sono valutati separatamente.

Figura 5.5: Modello per la simulazione PID.

Implementazione classica del regolatore


Limplementazione classica prevede di scrivere il regolatore basandosi sulla funzione z. Si osservi fin dora che
tutti e tre i regolatori non presentano soglie sulluscita. Ci legato fondamentalmente al fatto che porre un anti
wind-up poteva complicare almeno inizialmente le cose, senza una reale utilit in quanto le saturazioni sar s
bene tenerle in considerazione, ma in fase di implementazione su micro-processore. Scopo di queste simulazioni
riuscire a sintetizzare il regolatore in modo corretto e vedere quali sono le problematiche (soprattutto di calcolo).
Il codice il seguente:
/* DEFINIZIONI */
#define I_REALE u0[1]
#define I_RIF
u0[0]
#define OUP
7373 /*=90V*/
#define ODW
-OUP
#define IUP
1887400 /* =OUP*2^8 */
#define IDW
-IUP
#define DUP
OUP /* Soglia del derivativo */
#define DDW
-DUP
/*MACRO*/
#define KP(e)((e*10))
#define KI(e)((e*3)+(e> >3)+(e> >4))
#define KIS
8
#define KD(e)((e*799))
#define B_A(ba)((ba)-(ba> >7)+(ba> >8)+(ba> >10)+(ba> >11))
#define KDS
3
short int error, error_1=0, proporzionale;
long int integrale=0, derivata=0;

5.3. REGOLATORE PID DI CORRENTE

83

/* --- FUNZIONE DI REGOLAZIONE --- */


short int error_i, error_d, dc;
double out; /* a 32bit perch 4096*10+7373+7373 > 2^15 */
error = ((I_RIF-I_REALE)*8);
error_i = error+error_1;
error_d = error-error_1;
error_1 = error;
/* PROPORZIONALE */
proporzionale = KP(error);
/* INTEGRALE */
if(error_i>=0) integrale+=KI(error_i);
else integrale-=KI((-error_i));
/* DERIVATIVO */
if (derivata>=0) derivata=B_A(derivata); /*Per prima cosa peso subito la derivata... */
else derivata=-(B_A((-derivata)));
derivata += KD(error_d);
/*...poi aggiungo il nuovo termine */
/* OUT */
out=(derivata> >KDS)+proporzionale+(integrale> >KIS); /* sarebbe meglio fare il cast a long */
y0[0]=out;
y0[1]=(y0[0]*50)/4096;
y0[2]=error;
y0[3]=proporzionale;
y0[4]=integrale> >KIS;
y0[5]=derivata> >KDS;

Leggendo il codice si possono trovare alcune definizioni riguardo le soglie che per non vengono utilizzate.
Come noto la macro KP non altera il coefficiente a differenza di KI e KD. Essendo KI=KI T2s =0,0125 si preferito
moltiplicarlo per 256 (28 ) portandolo KI=3,2 per aumentarne la precisione; esattamente quanto fatto per il
regolatore di corrente PI (paragrafo 3.3.1) anche se in quel caso il termine KI stato maggiorato di 212 . Per
quanto riguarda il termine KD esso pari a KD=KD T2s a '99,875; potrebbe sembrare insensato maggiorare questo
valore, ma cos stato fatto. Precisamente stato maggiorato di 23 . Questo perch il termine derivativo
accompagnato dal termine B_A il quale negativo e in valore assoluto pari a 0,9975. Da questo termine
richiesta la massima precisione possibile! pi si riesce a renderlo in maniera precisa, pi fedele sar la risposta.
Si osserva che questo valore va a riscalare (pesare) il valore al passo precedente della derivata, quindi il risultato
di tale operazione un numero nella stessa base della derivata e per questo non pu essere riscalato. Detto ci
4
chiaro che conviene riscalare il termine derivativo che in questo caso pari a KD=KD T2s a '99,87523 =799; ora la
derivata un valore in base 11 bit. Tornando un momento sul termine B_A si detto che il suo valore negativo.
Leggendo il codice, per si nota come questo termine venga gestito come termine positivo. Questo perch se si
valuta lespressione 5.7 si osserva che il termine viene sottratto per ottenere il risultato voluto e quindi come
gestire un fattore positivo.
I riscalamenti introdotti su proporzionale e integrale fanno s che le variabili derivata e integrale debbano essere a 32 bit. chiaro che quando luscita verr calcolata (out), le grandezze dovranno essere riportate
in base 12 bit mediante appositi shift.
Per quanto riguarda le varie grandezze portate in uscita (y0[0], y0[1], ecc) servono solo per attivit di
debug.
In figura 5.6 sono riportati gli andamenti di corrente circolante nel sistema e tensione in uscita dal regolatore
a fronte di un ingresso a gradino con disturbo di tensione pari ad una sinusoide di ampiezza 30V e frequenza
1000rad/s. Mentre in uscita gli effetti del disturbo sono trascurabili, sulla tensione si vede che vi una armonica
che mira ad eliminare gli effetti del disturbo e. Si nota inoltre che allinizio vi un impulso di tensione che
raggiunge circa i 2700V. chiaro che nel caso reale occorrer prevedere una saturazione.
Come si vedr in seguito un valore elevato di N unito al fatto che vengano fatte determinate scelte su come
calcolare la derivata, potrebbe provocare alcuni problemi a livello computazionale risolvibili per esempio dimi-

84

CAPITOLO 5. REGOLATORE PID

Figura 5.6: Riferimento a gradino con disturbo sinusoidale a 1000rad/s di ampiezza 30 V.


nuendo N . Se si volesse ridurre il coefficiente N per esempio a 5 ne conseguirebbe la seguente variazione nel
codice:
#define KD(e)(((e*799)+(e> >1)))
#define B_A(ba)((ba)-(ba> >7)+(ba> >8)+(ba> >9)+(ba> >11))
#define KDS
4

Queste macro sono legate al fatto che KD=49,9688 e viene maggiorato di 24 , mentre ab =-0,9988. Dal punto di
vista delle simulazioni non vi sono cambiamenti sensibili.
Implementazione del regolatore con derivata a 20Ts
In altri casi affrontati sul levitatore si visto che spesso il sensore introduce degli errori spesso causati da interferenze ed accoppiamenti. Ci non causa tendenzialmente problemi in un controllo PI, ma pu causarne per
la parte derivativa. Supponendo ora che il derivativo sia molto elevato facile prevedere che si possano avere
grandi escursioni del duty-cycle a fronte di errori molto piccoli. Di contro esiste anche il problema opposto. Se
il derivativo molto piccolo e il sistema presenta inerzie molto alte probabile che tra un quanto di tempo (Ts ) e
laltro vi siano variazioni talmente piccole che non possano essere valutate. In entrambi i casi, quindi, si rischierebbe esclusivamente di derivare il rumore il quale tipicamente ad alta frequenza e quindi pu dare contributi
significativi.
Tra le varie soluzioni provate per ovviare al problema, quella che ha dato i migliori risultati di considerare
la derivata in una scala temporale diversa, ossia allerrore attuale deve essere sottratto non al valore precedente,
ma al valore di n volte precedenti, per esempio 20; con un intervallo di 20 campioni la finestra temporale su cui
viene effettuata la derivata pari a Tsn =2025s=500s. Quindi ricalcolando lequazione 5.6 con Tsn al posto
di Ts si ottengono i seguenti coefficienti:
KD=49,3827

b
a =-0,9753

a=81

b=-79

Attenzione per che questi valori sono stati ottenuti con N =5. Si notato che aumentando N si hanno problemi
di integrazione che provocano oscillazioni non accettabili. Ci dovuto al termine B_A: annullandolo, infatti, il
sistema torna ad avere una risposta corretta nel senso che arriva a regime e lerrore statico nullo, ma
landamento della risposta ben diverso da quello del regolatore z. Probabilmente questo dovuto al fatto che
tutti i termini che costituiscono le grandezze derivative (ossia KD e B_A) richiedono di rappresentare i coefficienti
calcolati nel modo pi preciso possibile; anche piccole variazioni possono dare risultati completamente errati.

5.3. REGOLATORE PID DI CORRENTE

85

Il codice proposto di seguito realizza quanto detto:

/* DEFINIZIONI */
#define I_REALE u0[1]
#define I_RIF
u0[0]
#define OUP
7373 /*=90V*/
#define ODW
-OUP
#define IUP
1887400 /* =OUP*2^8 */
#define IDW
-IUP #define EDTHUP 147 /* 7373/KD = Soglia errore derivativo */
#define EDTHDW -EDTHUP
#define DUP
OUP /* Soglia del derivativo */
#define DDW
-DUP
/*MACRO*/
#define KP(e)((e*10))
#define KI(e)((e*3)+(e> >3)+(e> >4))
#define KIS
8
#define KD(e)(((e*790)+(e> >3)))
#define B_A(ba)((ba)-(ba> >5)+(ba> >8)+(ba> >9)+(ba> >11))
#define KDS
4
#define ND
20 /*Campioni x la derivazione */
short int error[ND], error_1=0, proporzionale;
long int integrale=0, derivata=0;
/* --- FUNZIONE DI REGOLAZIONE ---*/
short int error_i, error_d, dc, i;
double out; /* a 32bit perch 4096*10+7373+7373 > 2^15 */
for(i=ND-1; i>0; i--)
error[i]=error[i-1]; /* sposto tutti i termini precedenti */
error[0] = ((I_RIF-I_REALE)*8);
error_i=error[0]+error[1];
/* errore integrale */
error_d=error[0]-error[ND-1]; /* errore derivativo */
/* PROPORZIONALE */
proporzionale = KP(error[0]);
/* INTEGRALE */
if(error_i>=0) integrale+=KI(error_i);
else integrale-=KI((-error_i));
/* DERIVATIVO */
if (derivata>=0) derivata=B_A(derivata); /*Per prima cosa peso subito la derivata... */
else derivata=-(B_A((-derivata)));
derivata += KD(error_d);
/*...poi aggiungo il nuovo termine */
/* OUT */
out=(derivata> >KDS)+proporzionale+(integrale> >KIS);
y0[0]=out;
y0[1]=(y0[0]*50)/4096;
y0[2]=error[0];
y0[3]=proporzionale;
y0[4]=integrale> >KIS;
y0[5]=derivata> >KDS;

Il codice sostanzialmente uguale al precedente tranne per il fatto che error_d viene calcolato con il valore
attuale e il valore di 20 passi prima. chiaro che per fare ci occorre memorizzare tutti i termini fino al ventesimo
e tramite il ciclo for i termini vengono spostati indietro di una posizione aggiornando cos ad ogni ciclo (ossia
ogni Ts ) la finestra temporale per eseguire la derivata.
Per quanto riguarda i risultati essi sono soddisfacenti, ma possibile comunque identificare dei problemi allinizio del gradino e sul fatto che la risposta non fedele a quella della soluzione con il regolatore in z-trasformata,
in quanto questultimo sviluppato considerando un intervallo di tempo pari a Ts , mentre il regolatore digitale effettua la derivata a 20Ts . In figura 5.7-a riportato il comportamento del sistema con ingresso a gradino,
ma senza disturbo, mentre in 5.7-b stato aggiunto un disturbo sinusoidale di 30V a 100rad/s. Chiaramente
landamento tra regolatore z (rimasto invariato) e regolatore C sono diversi.

86

CAPITOLO 5. REGOLATORE PID

(a) Nessun disturbo

(b) Disturbo sinusoidale: 30V - 100rad/s

Figura 5.7: Risposta con regolatore ottenuto con N=5 e derivata su 20 campioni.

5.3.3

Implementazione su micro-processore dsPIC30F

Anche questa volta il codice implementato scritto in C orientato al compilatore C30 di M ICROCHIP. I files di
progetto sono i seguenti:
global.h

definisce le principali variabili e definizioni di costanti comuni a tutti i files.

init.h

file di intestazione delle funzioni di inizializzazione. Contiene le dichiarazioni delle funzioni di


InitPORT(), InitPWM(), InitADC() ed eventuali macro.

init.c

file C di implementazione delle funzioni di inizializzazione.

pid.h

file di intestazione contenente le dichiarazioni e macro necessarie per effettuare la routine di regolazione.

main_Polarizzazione.c file C principale. Contiene la funzione main e le funzioni di interrupt.


Per quanto riguarda la configurazione delle periferiche e la determinazione delle scadenze temporali, si osservi
che non cambiato nulla dal sistema descritto al capitolo 4. Anche la formula per il calcolo del periodo di PWM
(4.1) non cambiata anche se in questo caso il PLL rispetto al caso precedente (figura 4.6) adesso il PLL pari a
x16. Per si detto che la frequenza di commutazione stata portata a 40 kHz quindi lequazione 4.1 risulta:
PTPER =

16
7372800

+ 1 = 368
24
40000

Codice C
Si consiglia di leggere il codice seguente tenendo sempre a portata di mano [4], quanto meno per capire quali sono
le procedure necessarie per la configurazione e la gestione delle periferiche. Si noti che il codice seguente nasce
dalla raffinazione di altre versioni del codice, quindi potrebbero esserci definizioni e variabili che non vengono
usate nel codice vero e proprio. Infine si osservi che il codice relativo alla derivata calcolata con polo in alta
frequenza con N =5 e una maggiorazione del coefficiente derivativo di 24 per contenere le variazioni sul piccolo
errore, come detto in precedenza.

5.3. REGOLATORE PID DI CORRENTE

=======================
global.h
#ifndef __GLOBAL_H__
#define __GLOBAL_H__
#include <p30f4012.h>
#define ON
1
#define OFF
0
/* Logica di controllo dei LED inversa */
#define LED_VERDE_ON
_RE5=0b0
#define LED_VERDE_OFF
_RE5=0b1
#define LED_ROSSO_ON
_RE4=0b0
#define LED_ROSSO_OFF
_RE4=0b1
#define CLOCK
7372800
//Clock esterno, come sulle schede di valutazione
#define NBIT
12
#define NBIT2
13
#define NBASE
4095
#define NBASE2 8191 #define
NBASE3 16383 #define
NBASE24 16777000
//in realt 2^24=16777261
#define FREQ
40000 //40KHz
#define PER
0.000025 //Periodo
#define DUTYCYM (int)736 //DC massimo in unipolare singola gamba
#define DUTYCY PERIODO //DC massimo in unipolare doppia gamba
#define DUTYCYUP 332
//Saturazione UP di duty-cycle
#define DUTYCYDW -332
//Saturazione DW di duty-cycle
#define OFFSET_I 518
//Offset delle correnti per riportarle allo 0
#define CORRENTEP ADCBUF0 //an0!
#endif //end of __GLOBAL_H__

=======================
init.h
#ifndef __INIT_H__
#define __INIT_H__
#define TRIGGER_AD_PWM
0b011
#define TRIGGER_AD_TMR3 0b010
#define TRIGGER_AD_AD
0b000
#define CHANNEL4
0b11
#define CHANNEL2
0b01
#define CHANNEL1
0b00
extern void InitTIMER(unsigned int nStep); //Non serve in questo programma
extern void InitPORT();
extern void InitPWM(int nleg, unsigned char interrupt_enable);
extern void InitAD(unsigned char, unsigned char, unsigned char, unsigned char);
#endif //__INIT_H__

=======================
init.c
#include <p30f4012.h>
#include "Init.h"
#include "Global.h"
/** Inizializzazione delle PORTE (I/O, digitali/analogiche **/
void InitPORT() {
TRISD=0x0000;
PORTD=0xFFFF;
TRISB=0xFFFF;
TRISE=0x0080;
PORTB=0xFFFF;
PORTE=0xFFFF; //Sulle mie schede i led e i pulsanti sono in logica inversa
ADPCFG=0x0000;

87

88

CAPITOLO 5. REGOLATORE PID

}
/** Inizializza il PWM *******************************************************************
Il parametro in ingresso nleg determina quante gambe voglio abilitare in modo indipendente
******************************************************************************************/
void InitPWM(int nleg, unsigned char interrupt_enable) {
PTPER=PERIODO; //Attenzione a _PTMOD!!! che influenza PTPER se >= 0b10
PTCONbits.PTMOD=0b10; //Free Running Mode=0b00, Continuous Up/Dw=0b10
PTCONbits.PTOPS=0b0000; //Postscaler
PTCONbits.PTCKPS=0b00; //Prescaler
PTCONbits.PTSIDL=0b0;
PTCONbits.PTEN=0b1;
PWMCON1=0x0000;
if(nleg>0) {
PDC1=0; //duty cycle per PWM1 16bit, quindi duty=50%->PDCx=PTPER
PWMCON1bits.PMOD1=0b1; //Indipendent mode 0=off, 1=on
PWMCON1bits.PEN1H=0b1; //Abilito la gamba alta
PWMCON1bits.PEN1L=0b1; //Abilito la gamba bassa
}
if(nleg>=2) {
PDC1=DUTYCY; //se 2 perch controllo il ponte ad H
PDC2=DUTYCY; //duty cycle per PWM1 16bit, quindi duty=50%->PDCx=PTPER
PWMCON1bits.PMOD2=0b1; //Indipendent mode 0=off, 1=on
PWMCON1bits.PEN2H=0b1; //Abilito la gamba alta
PWMCON1bits.PEN2L=0b1; //Abilito la gamba bassa
}
if(nleg>=3) {
PDC3=0; //duty cycle per PWM1 16bit, quindi duty=50%->PDCx=PTPER
PWMCON1bits.PMOD3=0b1; //Indipendent mode 0=off, 1=on
PWMCON1bits.PEN3H=0b1; //Abilito la gamba alta
PWMCON1bits.PEN3L=0b1; //Abilito la gamba bassa
}
FLTACON=0x0000;
_PWMIF=0;
_PWMIE=(interrupt_enable&0x1);
}
void InitAD( unsigned char trigger_AD, unsigned char ADCS_delay,
unsigned char ingresso,
unsigned char channel ) {
/* Le tabelle di configurazione sono da pagina 420 in poi del Manual Family [4]. */
ADCHS=0;
ADCHSbits.CH0SA=ingresso&0x0F; //ingressi AN0->CH1=>ADCBUF1, AN1->CH0=>ADCBUF0
_SIMSAM=0b1; //se 1 -> simultaneous sampling
_SMPI=0b000; //Interrupt dopo ogni campionamento se 0
switch(trigger_AD)
{
case TRIGGER_AD_PWM:
_SSRC=TRIGGER_AD_PWM; //011=PWM trigger event
break;
case TRIGGER_AD_TMR3:
_SSRC=TRIGGER_AD_TMR3; //Timer3 trigger event
break;
default:
_SSRC=TRIGGER_AD_AD;
//ogni fine conversione lAD si autoriattiva
}
_ASAM=0b1; //Automatic sample
_CSCNA=0b0; //Disabilito lo scanning dei sample/hold se 0
_ALTS=0; //Alternate MUX Sampling disabilitato
ADCON2bits.CHPS = channel&0x03; //00=S/H su CH0, 01=S/H su CH0 e CH1, 1x tutti
//---Questi sono flag per PWM---//
SEVTCMPbits.SEVTCMP=0;
SEVTCMPbits.SEVTDIR=0b0;
_SEVOPS=0b0000; //se 1,ogni 2 PWM scatta lint AD
//------------------------------//
ADCON3bits.SAMC = 1; //tempo minimo di sample
ADCON3bits.ADCS = ADCS_delay&0x3F; //Setta il minimo tempo per la conversione A/D.
ADPCFGbits.PCFG0 = 0;
ADPCFGbits.PCFG1 = 0;
ADPCFGbits.PCFG2 = 0;
_ADIE=1; _ADIF=0;

5.3. REGOLATORE PID DI CORRENTE

89

_ADON=0b1; //Attivo lADON


}

=======================
pid.h
#define CURRENT_BASE
50 //lem da 25A con una 2 spire ->50A teorici, 40 saturati
#define OFFSET_CURRENT 512
#define INITIAL_CURRENT 0 //eventuale valore iniziale della corrente
#define CURRENT_RIF
2047 //2047=25A
/***** PID di corrente *********/
#define PROPORZIONALEI(e)((e*10))
#define INTEGRALEI(e)((e*3)+(e> >3)+(e> >4))
#define KIS
8 //shift per lintegrale
#define KD(e)(((e*800)-(e> >1))) //con 400 o 500 forse meglio
#define B_A(ba)((ba)-(ba> >7)+(ba> >8)+(ba> >9)+(ba> >11))
#define KDS
4 //shift per la derivata
//---------SOGLIE------------//
#define OUP
7373 /*=90V -> 90/50*4096*/
#define ODW
-OUP
#define IUP
1887400 /* =OUP*2^8 */
#define IDW
-IUP
#define DUP
OUP /* Soglia del derivativo */
#define DDW
-DUP
/********** CHECK DUTY-CYCLE *************/
#define DCUP 699 //perdo il 5% della tensione x sicurezza #define DCDW 37
/********** MACRO DI RIPORTO DEL DC **************/
#define V_OFFSET
4097
#define GET_DC(v_digit)((v_digit> >4)+(v_digit> >6)+(v_digit> >7)+(v_digit> >8))

Rispetto alle simulazioni sono state aggiunte le soglie per variabili di uscita, integrale e derivata, oltre alla acro
GET_DC per il calcolo del valore digitale del duty-cycle.

=======================
main_Polarizzazione.c
#include <p30f4012.h>
#include "Global.h"
#include "Init.h"
#include "pid.h"
/***** Global *****************/
int errorI, errorI_1=0, proporzionale, correnteIp, riferimentoIp=CURRENT_RIF, vd_out;
long int integrale=INITIAL_CURRENT, derivata=0;
/******************************/
/********* MAIN *******************/
int main() {
InitPORT();
InitPWM(2,OFF);
LED_VERDE_ON;
while(_RE8); //fino a che resta tutto in stop o nn premo RE8 nn fare nulla
Nop();
while(!_RE8);
LED_VERDE_OFF;
InitAD(TRIGGER_AD_PWM,10,0,CHANNEL1);
LED_ROSSO_ON;
while(1);
}
/**********************************/
/****************************
Interrupt SubRoutine
****************************/
void _ISR _ADCInterrupt() {

90

CAPITOLO 5. REGOLATORE PID

int dc, dcaux, errorIi, errorId;


_RD0=1; //Flag per la misura dei tempi di esecuzione
/***************************************************
REGOLATORE DI CORRENTE: metodo dei trapezi
***************************************************/
correnteIp=((CORRENTEP-OFFSET_I))< <3; //riporto la corrente a 12bit
errorI=(riferimentoIp-correnteIp); //calcolo lerrore
//INTEGRALE
errorIi=errorI_1+errorI;
errorId=errorI-errorI_1;
if(errorIi>=0)
integrale+=INTEGRALEI(errorIi);
else
integrale-=INTEGRALEI((-errorIi));
//PROPORZIONALE
proporzionale=PROPORZIONALEI(((long int)errorI));
//DERIVATA
if(derivata>=0) derivata=B_A(derivata);
else derivata=-(B_A((-derivata)));
derivata+=KD(errorId);
//CALCOLO DELLUSCITA
vd_out=(derivata> >KDS)+proporzionale+(integrale> >KIS);
if(vd_out>OUP) vd_out=OUP;
else if(vd_out<ODW) vd_out=ODW;
/***************************************************
USCITA riportata sul DC
***************************************************/
vd_out+=V_OFFSET; //porto il valore da 0 a 8191 (->13bit)
dc=GET_DC(vd_out);
if(dc>DCUP) dc=DCUP;
else if(dc<DCDW) dc=DCDW;
PDC2=dc;
PDC1=DUTYCYM-dc;
/************************************
TRATTAMENTO FINALE DELLE VARIABILI
************************************/
if(integrale>IUP) integrale=IUP;
else if(integrale<IDW) integrale=IDW;
errorI_1=errorI;
if(derivata>DUP) derivata=DUP;
elae if(derivata<DDW) derivata=DDW;
errorI_1=errorI;
_ADIF=0;
_RD0=0;
}

Il codice del regolatore non molto diverso da quello delle simulazioni. In pi a prima si osserva che tramite la
macro GET_DC viene calcolato il termine del duty-cycle (dc) riscalando la grandezza vd_out opportunamente
saturata tra 0 e 736. Una volta ottenuto il duty-cycle questo viene precauzionalmente limitato tra DCDW e DCUP
in modo da avere un duty-cycle compreso tra 5% e 95% del dutty-cycle per ogni singola gamba10 . Successivamente il valore dc viene assegnato ad una gamba (PDC2=dc) mentre il suo complemento vine assegnato allaltra
(PDC1=DUTYCYM-dc). Infine, oltre alla saturazione delluscita, si procede anche alla saturazione dellintegrale e
derivata. Infatti la derivata presenta un termine (B_A) integrativo ossia si pu dire che anche la derivata una
variabile con memoria in quanto dipende dagli stati precedenti.
=======================
Per quanto riguarda lo sviluppo del codice con derivata ogni 20Ts verranno riportate le modifiche rispetto al
codice precedente:
=======================
10 Ci

aiuta a evitare che le valvole e/o i driver si danneggino.

5.3. REGOLATORE PID DI CORRENTE

pid.h
...
/***** PID di corrente *********/
#define PROPORZIONALEI(e)((e*10))
#define INTEGRALEI(e)((e*3)+(e> >3)+(e> >4))
#define KIS
8
#define KD(e)(((e*790)+(e> >3))) //con 500 forse meglio
#define B_A(ba)((ba)-(ba> >5)+(ba> >8)+(ba> >9)+(ba> >11))
#define KDS
4
#define STEPN 20 //STEP per il calcolo della derivata
...

=======================
main_Polarizzazione.c
/***** Global *****************/
int errorI[STEPN], proporzionale, correnteIp, riferimentoIp=CURRENT_RIF, vd_out;
long int integrale=INITIAL_CURRENT, derivata=0;
/***********************************************************/
...
/****************************
Interrupt SubRoutine
****************************/
void _ISR _ADCInterrupt() {
int dc, dcaux, errorIi, errorId, i;
_RD0=1; //Flag per la misura dei tempi di esecuzione
/***************************************************
REGOLATORE DI CORRENTE: metodo dei trapezi
***************************************************/
correnteIp=((CORRENTEP-OFFSET_I))< <3; //riporto la corrente a 12bit
for(i=STEPN-1; i>0; i--) errorI[i]=errorI[i-1];
errorI[0]=(riferimentoIp-correnteIp); //calcolo lerrore
errorIi=errorI[0]+errorI[1];
errorId=errorI[0]-errorI[STEPN];
//INTEGRALE
if(errorIi>=0) integrale+=INTEGRALEI(errorIi);
else integrale-=INTEGRALEI((-errorIi));
//PROPORZIONALE
proporzionale=PROPORZIONALEI((errorI[0]));
//DERIVATA
if(derivata>=0) derivata=B_A(derivata);
else derivata=-(B_A((-derivata)));
derivata+=KD(errorId);
// CALCOLO DELLUSCITA
vd_out=(derivata> >KDS)+proporzionale+(integrale> >KIS);
if(vd_out>OUP) vd_out=OUP;
else if(vd_out<ODW) vd_out=ODW;
...

=======================

91

92

CAPITOLO 5. REGOLATORE PID

Appendice A

Breviario sulla sintassi C


In questa appendice vengono riportate le nozioni base necessarie per la scrittura di un programma in C. Per
informazioni pi complete e dettagliate si rimanda comunque alla lettura di un buon libro sui fondamenti del C o
alle numerosissime guide su internet come per esempio [L6].

A.1

Tipi di dati

Le informazioni che verranno date di seguito si possono trovare anche nel manuale del compilatore. Nel caso
di dsPIC si fa riferimento al manuale del compilatore C30 [3]. Le informazioni sotto riportate sono di carattere
generale, quindi si consiglia sempre di verificarle con quanto scritto nel manuale del compilatore che si ha in
dotazione.

Scalari
char

8bit con segno. Usato per i caratteri.

unsigned char 8bit senza segno.


short int 8bit interi con segno. Usato per i numeri. Se il processore a 32bit, tipicamente short int a

16bit.
unsigned short int 8bit senza segno. Valgono le considerazioni fatte per short int.
int

16bit con segno. Tipicamente la parola del processore se il processore computa a 16 bit o pi. In
altre parole se il processore a 8bit, int vale sempre 16, mentre se il processore a 32 bit, int a
32bit. Se non precisato, in questa sede si assume int pari a 16bit.

unsigned int 16bit con segno. Valgono le considerazioni fatte per int.
long int 32bit con segno. Tipicamente se il processore a 32bit e int a 32bit, long int resta comunque

a 32 bit.
unsigned long int 32bit senza segno. Valgono le considerazioni fatte per int.
long long int 64bit con segno; con unsigned diventa senza segno.

93

94

APPENDICE A. BREVIARIO SULLA SINTASSI C

float

32bit in virgola mobile, tipicamente a 64 per sistemi a 32bit. Nel caso del C30 il valore va da 2126
a 2128 .

double

32bit a virgola mobile tipicamente a 64 per sistemi a 32bit. valgono le stesse considerazioni di
float.

long double 64bit in virgola mobile, tipicamente 128 per sistemi a 32bit. il valore va da 21022 a 21024 .

Spesso double e long double hanno la stessa lunghezza. Ci dipende tipicamente dal compilatore
o dai parametri si compilazione.
Per assegnare (o definire) un numero si pu ricorrere alle forme seguenti:
c=A

assegna un carattere

x=123

assegna un numero espresso in decimale

y=0x3F0

assegna un numero espresso in esadecimale. In questo caso il valore a 16bit.

z=0b101

assegna un numero espresso in binario.

o=011

assegna un numero ottale.

l=123L

assegna un numero di tipo long. Chiaramente se l non long il compilatore provveder alla
castizzazione.

f=2.344

assegna un numero in virgola mobile (float o double). Si pu anche porre una f alla fine per
forzare il tipo float, ma il numero deve avere anche il . (per esempio 0.1f)

Array
Gli array sono strutture di dati omogenei contigui. Sono definiti come segue:
char string[100]; //definizione stringa di lunghezza 100 byte
int vector[10]; //definizione vettore di 10 numeri interi a 16 bit.
string[10]=X;
//assegnazione del carattere X allundicesimo carattere

lincremento dellindice in string permette di accedere ai vari byte della stringa (ossia ci si sposta di 8bit per
volta), mentre in vector permette di accedere ai vari numeri del vettore (ossia ci si sposta di 16bit per volta).
Per accedere ai vari valori sufficiente scrivere il nome della variabile seguito da un numero che, per esempio
nel caso della variabile string, va da 0 a 99. I valori negativi non sono accettati, mentre quelli superiori a 99
causano i cos detti buffer overflow; ci in un microprocessore si traduce nella sovrascrittura di altre variabili e/o
indirizzi di ritorno delle funzioni1
Un array pu anche essere definito come un puntatore (pag. 96), ma il metodo per accedervi il medesimo.
anche possibile definire array di strutture.
1 Normalmente in processori come i pic ci si traduce in un reset. Si osservi che in alcuni micro della serie 18 possibile, configurando
opportunamente i configuration bits, impedire il reset a fronte di un buffer/stack-overflow.

A.1. TIPI DI DATI

95

Strutture e unioni
Le strutture sono aree dati formattate (strutturate) in un particolare modo. Tipicamente racchiudono pi dati
spesso di tipo diverso. Si indicano come segue
struct NOME_STRUTTURA {
tipo NOME_VARIABILE1, NOME_VARIABILE2;
tipo NOME_VARIABILE3;
} ;

dove il NOME_STRUTTURA pu anche essere posto alla fine, ossia dopo la parentesi graffa chiusa. Normalmente la
definizione della struttura preceduta dalla keyword typdef che permette di definire un nuovo tipo di variabile:
typedef struct {
tipo NOME_VARIABILE1, NOME_VARIABILE2;
tipo NOME_VARIABILE3;
} NOME_STRUTTURA ;

Per richiamare la struttura e per accedere ai vari campi si scrive semplicemente:


typedef struct { //definizione della struttura
int x; char c; //campi
} t_struct; //t_ indica che un tipo; una pura convenzione.
struct t_struct x,y; //definizione delle variabili
x.x=10; //assegno il numero 10;
x.c=x; //assegno il carattere x
y=x; //copio x in y. Non tutti i compilatori lo accettano.

Spesso per necessario poter accedere singolarmente ai singoli bit che compongono una struttura. Una struttura
come la seguente permette di fare ci:
typedef struct {
unsigned LSB
unsigned BIT2
unsigned
unsigned NIBBLE
short int BYTE

:1;
:1;
:2;
:4;
:8;

//bit meno significativo


//2 bit
//2 bit non indirizzabili
//4 bit = 1 Nibble
//byte con segno; :8 in questo caso non obbligatorio,
//come non obbligatorio cambiare variabile in short int

} t_ComplexStruct;

Cos facendo possibile definire una variabile (in questo caso di 16bit) divisi in vari campi che minimo devono
essere di 1 bit. Ci risulta molto comodo nei micro controllori.
Dal punto di vista della memoria, una struttura occupa tanti byte quanti quelli delle singole variabili definite
allinterno; per esempio t_struct definita in precedenza occupa 3 byte. Spesso per utile avere una certa area
di memoria alla quale si vuole accedere contemporaneamente con due o pi formattazioni diverse. Per fare ci si
ricorre alle union come segue:
typedef union {
long int l;
//32 bit
unsigned int i; //supposto int 16 bit
char c[2];
} t_union;

La union appena definita permette di accedere alla stessa area di memoria agendo sullo scalare i o sullarray c.
Per esempio:

96

APPENDICE A. BREVIARIO SULLA SINTASSI C

t_union x;

x.l=0x10009; //x.i=0x0009, c[0]=0x09, c[1]=0x00


x.i=0xF50;
x.c[1]++;

//setto la variabile i: c[0] vale 0x50, c[1]=0x0F, l=0x10F50


//ora si ha i=0x1050 e l=0x11050

questo implica che sizeof(t_union)6=sizeof(long int)+sizeof(int)+2*sizeof(char). In altre parole tutte le variabili contenute in una union partono dal medesimo indirizzo di memoria. Per capire meglio
lorganizzazione della memoria si osservi la tabella seguente che mostra come allocato il valore 0x11050:

La variabile di dimensioni maggiori setta la dimensione della union e viene posizionata, in questo esempio, alla
posizione di memoria 0x2000; a questa posizione corrisponde anche il primo byte (ossia quello meno
significativo) della union. Tutte le altre variabili vengono collocate a questo indirizzo di memoria: condividendo
lo stesso indirizzo di memoria tutti sottocampi della variabile x condividono i singoli byte. Attenzione per che
lesempio proposto solo qualitativo per capire come funziona una union. Infatti lorganizzazione dei dati
dipende dal processore. Lesempio quindi calza per i processori dsPIC30F i quali rappresentano i dati nel
formato little endian (vedi [3] 5.3) ossia il byte pi significativo risiede allindirizzo di memoria pi alto,
viceversa il formato big endian usato per esempio nei processori P OWER PC di F REESCALE (IBM).
Se ora si volesse fare in modo che la variabile c[2] punti al secondo e terzo byte della union, possibile unire
quanto finora detto e ottenere una struttura di questo tipo:
typedef union {
long int l;
//32 bit
unsigned int i; //supposto int 16 bit
struct {
unsigned
:8;
char c[2];

};
} t_union;

Puntatori
Si indicano con * prima del nome della variabile:
void*

puntatore generico.

char*

puntatore a carattere o ad array di caratteri (ossia stringhe).

int*

puntatore a numero intero o ad array di numeri interi.

I puntatori sono tutti di dimensione pari alla parola del processore. Ci significa che in termini di memoria non
vi differenza tra char*, int*, ecc.
Lo stralcio di codice seguente mostra come si indica alla variabile di puntare ad una determinata cella di
memoria:

A.1. TIPI DI DATI

97

int x,*y; //x un numero, y un puntatore

...
y=&x;

il carattere & seguito dal nome di una variabile, ne restituisce il puntatore. Per modificare il valore contenuto
allindirizzo di memoria contenuto in y (ossia per modificare il valore di x) si procede come segue:
*y=3; //equivale a scrivere x=3

ossia il carattere * seguito dalla variabile permette di accedere alla locazione di memoria puntata dal puntatore.
In altre parole il valore (3 in questo caso) viene scritto nella variabile x.
Nota: si osservi che la definizione multipla di puntatori NON si scrive come segue:
int* x,y,z;

ci infatti definisce che solo x in puntatore a variabili di tipo int, mentre y e z sono interi normali. La
scrittura corratta pu essere fatta in almeno due modi; il primo, pi semplice, il seguente:
int *x, *y, *z;

il secondo invece prevede la definizione di un tipo di dato int*:


typedef intp int*;
intp x,y,z;

Come accennato a pag. 94, un puntatore pu definire un array; per esempio:


int i,x[3],*y;
for(i=0; i<3; i++) x[i]=i; //riempio larray.
y=x; //indico che y deve puntare allarray x. Si noti che x senza quadre un puntatore.
y[2]=100; //accedo a x tramite y, ma con la stessa sintassi. ora anche x[2] 100.

quindi ora y[i] pari a x[i]. Si noti per che se le variabili fossero definite come int, ma il puntatore come
char, possibile accedere a qualsiasi byte dellarray x:
int i,x[3];
char *y;
x[0]=0x0001; x[1]=0x0203; x[2]=0x0405; //riempio larray.
y=(char*)x; //indico che y deve puntare allarray x, ma va castizzato!!

In questo caso y[3] sar uguale a 0x02, y[4] sar uguale a 0x03, ecc. Discorso analogo per le strutture.
Riprendendo per esempio la struttura t_struct si osserva che se viene definito il puntatore, laccesso ai campi
della struttura non avviene pi con il punto, ma con la freccia -> come segue:
t_struct *y;
...
y->x=10;

Keyword const e volatile


Le keyword const e volatile servono per qualificare il tipo di dichiarazione di variabile. Vengono poste in
una dichiarazione prima del tipo come segue:
const int x;
volatile char y;
const volatile struct s;

98

APPENDICE A. BREVIARIO SULLA SINTASSI C

Queste keyword possono essere poste davanti a qualsiasi tipo di variabile (scalari, array, union, struct, enum, ecc).
const specifica che la variabile creata possiede un valore che non pi modificabile allinterno del program-

ma. In realt ci dipende dal compilatore. Si consideri infatti il seguente programma di esempio:
#include <stdio.h>
int main() {
const int x=123; //definizione e inizializzazione della costante
const int *px;
//puntatore costante
int *p=&x;
//puntatore normale
px=(int*)&x;
//questo permesso ma da un warning
x=0;
//errore di compilazione in gcc!
*px=10; //errore di compilazione in gcc!
//permesso
*p=20;
printf("%i\n",x);
}

Questo programma non orientato al micro controllore ed da intendersi puramente come un esempio; Per essere
compilato richiede un compilatore apposito2 . Compilando ed eseguendo il programma, il compilatore restituisce
chiaramente due errori relativi al fatto che si sta cercando di assegnare grandezze costanti; viene anche generato un warning a causa del fatto che *px non viene inizializzato in fase di dichiarazione, ma successivamente.
Loutput del compilatore gcc il seguente:
cc
file.c
-o file
file.c: In function main:
file.c:6: warning: initialization discards qualifiers from pointer target type
file.c:9: error: assignment of read-only variable x
file.c:10: error: assignment of read-only location
make: *** [c] Error 1

Ora se si suppone di commentare le righe che danno il warning e gli errori, il programma viene compilato.
Non solo: il programma funziona anche andando addiritura a modificare il valore della variabile const tramite il
puntatore *p. Questo comportamento legato sia al compilatore sia al fatto che si sta compilando il programma
per un sistema operativo. Si osservi che una assegnazione di questo tipo (ossia forzare la scrittura di una const)
in un microprocessore come il dsPIC30F causa il reset del processore: infatti lassegnazione di variabili const
(per esempio x=0) in C30 non d errori di compilazione ma le istruzioni generate sono illegali.
Nota: si osservi che definire const int *px vuol dire definire un puntatore normale che per punta ad un
valore immodificabile ed questa la ragione per cui nellesempio viene restituito un warning e non un errore. Se si volesse definire un puntatore costante, ossia che contenga un indirizzo di memoria ben preciso,
occorre definire il puntatore in questo modo:
int *const px = &variabile_int;

linizializzazione deve essere fatta subito con il puntatore a una qualsiasi variabile di tipo analogo (int in
questo caso). Si osservi cha px punter sempre e solo allindirizzo di memoria della variabile variabile_int.
volatile invece tipicamente usate nei sistemi real-time e/o embedded. Si supponga di definire una variabile

che non altro che un alias per identificare la mappatura di un registro del processore per il controllo di un
particolare dispositivo. Un modo per farlo il seguente:
static volatile unsigned char TMR0 @ 0x01;
2 In

questo caso il gcc di Linux, ma va bene qualsiasi altro compilatore.

A.2. DICHIARAZIONI

99

in particolare queta riga indica dove si trova il registro di accumulazione del registro Timer03 del processore
PIC16F684. Tale registro contiene il valore del timer. Si supponga ora come esempio di fare un loop al fine di
bloccare il programma (ossia la funzione main) fino a che il valore del timer non sia tornato a 0 in questo modo:
int main() {
...
while(TMR0!=0); //blocco qui lesecuzione se TMR0 diverso da 0
...
}

Questo (pseudo) codice corretto proprio perch TMR0 stato definito come volatile. Se non fosse stato definito
in questo modo, il compilatore in fase di ottimizzazione potrebbe vedere TMR0 come una variabile qualunque
e quindi la tendenza sarebbe quella di trattare la variabile andandola a caricare in un registro controllando poi
nel ciclo while il valore di tale registro. Ci corretto dal punto di vista del compilatore perch velocizza le
operazioni, ma non ci che si voleva realizzare!
Nota: Quanto detto, per, non vale solo per le variabili che hanno indirizzi di memoria assoluti e ben precisi
(come TMR0 appunto), anche per variabili gestite in interrupt e controllate in polling4 , come nellesempio
seguente:
volatile char contatore; //variabile glogale
int main() { //main function
...
while(contatore<N);
...
}
void isr interrupt() { //interrupt function
...
contatore++;
...
}

A.2

Dichiarazioni

Dichiarazione di funzione
Le dichiarazioni di funzione possono essere fatte fondamentalmente in due modi. Il primo prevede di creare un
file .h dove vengono definiti tutti i prototipi i quali vengono implementati in un file .c (normalmente chiamato con
la stessa base del file .h) il quale include il file .h con le definizioni dei tipi. Il vantaggio principale di ci che
ogni funzione implementata ha uno scope globale. In altre parole se si definiscono delle funzioni come segue:
extern void function1(void);
extern void function2(void);
extern void function3(void);

quando le si andr ad implementare, la prima funzione potr chiamare al suo interno tutte le altre definite successivamente. Non solo: la visibilit di queste funzioni sar globale per tutti i file che includeranno il file .h che
le definisce (ossia da dopo la macro #include). chiaro che se allinterno del file .c che implementa le tre
funzioni viene definita una quarta funzione, questa avr visibilit solo allinterno del file .c, come nellesempio
che segue:
3 Codice
4 Ci

prelevato dal file pic16f684.h reperibile dal compilatore C PicLite di HT su [L4].


vero in particolar modo nei sistemi a micro controllore.

100

APPENDICE A. BREVIARIO SULLA SINTASSI C

//Inclusione di funzioni.h dove sono definite le tre funzioni function1, 2 e 3


#include funzioni.h // perch il file nella directory corrente
//dichiarazione della quarta funzione visibile sono allinterno del file .c!
void function4(void);
//Implementazione delle prime 3 funzioni
void function1() {
//TODO
}
void function2() {
//TODO
}
void function3() {
//TODO
}
void function4() {
//TODO
}

La funzione function4 definita allinizio viene vista da tutte le altre tre funzioni e a sua volta pu chiamare
tutte le funzioni definite in funzioni.h in quanto definita dopo linclusione di tale file. Si noti che se fosse
stata definita per esempio dopo limplementazione della funzione 1, questultima non avrebbe potuto chiamare la
funzione 4.
Il secondo modo per definire e implementare le funzioni direttamente allinterno del file sorgente .c. La
norma quella di definire prima tutte le funzioni e di implementarle poi in fondo al file, tipicamente dopo
la funzione main. Ci perch valgono ancora tutte le considerazioni relative alla visibilit fatte per il caso
precedente.
Unultima nota riguardo la definizione delle funzioni che non necessario definire subito i nomi delle
grandezze necessarie, ma si pu procedere definendo la funzione come segue:
void functionX(int, unsigned, char);

Implementazione delle funzioni


Limplementazione delle funzioni pu essere fatta subito dopo la definizione della funzione, oppure in un altro
punto del programma (come precedentemente accennato) la quale anche la scelta consigliata. Come detto i
parametri della funzione possono anche non essere indicati preventivamente, ma quando la funzione viene implementata allora verranno definiti i nomi delle grandezze (int, unsigned e char rifacendosi al caso precedente).
Se invece le funzioni viene definita subito con i relativi nomi dei parametri, nel momento in cui si effettuer
limplementazione dovranno essere reindicati con lo stesso nome:
void functionX(int a, unsigned b, char c) {
//TODO
}

Si nota che la keyword extern non viene ridefinita.


Un altro modo per definire e implementare le funzioni il seguente:
int functionC(x)
int x;
{
//TODO
}

A.2. DICHIARAZIONI

101

Questo tipo di definizione normalmente prevede una implementazione in inline ossia viene definito subito il
codice che realizza la funzione senza definire precedentemente la funzione; questo perch se venisse definita
precedentemente il compilatore potrebbe restituire un warning dicendo che la funzione ha un parametro senza
tipo. Si noti comunque che questo tipo di sintassi valido solo in C e non in C++. comunque una definizione
obsoleta.
Nota: Le funzioni possono essere definite e/o implementate con la keyword static. Per la programmazione su
micro controllore questo pu non essere rilevante, ma per sistemi pi complessi o di alto livello (come
sistemi operativi real-time) pu prevenire la ridefinizione di funzioni che possono creare ambiguit o che
non devono essere ridefinite in nessun file (per esempio nel kernel Linux le primitive di I/O che devono
essere esportate).

Variabili, costanti e parametri


I parametri in una funzione possono essere:
Nulli

indicati con void, ma i pi di compilatori accettano anche le parentesi vuote. Per esempio:
int func1(void);
int func2();

Valori

indicati con il tipo di variabile definibile dallutente come int, char, ecc. Per esempio:
int func3(int x, char c);

I valori passati possono essere ridefiniti internamente, ma ci non causer nulla alle variabili passate
dallesterno alla funzione una volta che questa viene chiusa perch il valore di queste grandezze
che viene copiato nello stack e non il loro putatore.
Puntatori

Per esempio con:


int func4(int *x, struct ST *c);

in questo caso se allinterno della funzione (ossia in fase di implementazione) x viene assegnata come
x=(int*)c ora punter a un diverso indirizzo di memoria, ma la variabile passata dallesterno non
subir modifiche; se per si assegna *x=10 allora la variabile esterna passata alla funzione assumer
il valore 10.
Costanti

Indicano che il valore non pu essere modificato. Servono tipicamente per passare stringhe definite
dallutente. Per esempio:
void func5(const char *str); tipicamente verr chiamata come func5(Stringa generica
);
esempi tipici sono le funzioni standard del C relativa allutilizzo delle stringhe definite in string.h,

come strcmp, strncmp, ecc.


Le variabili definite allinterno delle funzioni hanno visibilit locale alla funzione e vengono allocate nello stack,
quindi se non vengono inizializzate internamente alla funzione, tali variabili assumono un valore che dipende
dalla storia dello stack; eccezione fatta nel caso in cui le variabili siano definite come static, nel qual caso non
solo verranno inizializzate una sola volta, ma alluscita della funzione il loro valore non verr perso. Si noti che
se una variabile locale ha lo stesso nome di una globale, la variabile utilizzata nella funzione sar quella locale.
Chiaramente il valore delle variabili globali (o comunque con visibilit superiore) non viene alterato.

102

APPENDICE A. BREVIARIO SULLA SINTASSI C

Dichiarazioni di MACRO
Alcuni esempi di come si definisce una macro sono i seguenti:
#define
#define
#define
#define

MACRO1
((int)c+1)
MACRO2(x,y)((x+1)%y)
MACRO3(var,field)((var)->(field))
MACRO4(i)(MACRO##i)

La prima la definizione di una costante, la seconda una macro a tutti gli effetti in quanto esegue alcuni conti
dati due parametri in ingresso. La terza prevede che il parametro var sia un puntatore a una struttura e field dia
uno dei suoi campi. Infine la quarta macro in funzione del numero i chiama una delle altre macro. Per esempio
se si volesse chiamare la prima macro sufficiente scrivere MACRO4(1). Si noti che se i contenuto allinterno
di una parola, la macro 4 va definita come MACRO4(i)(STRH##i##STRL) dove STRH e STRL sono le stringhe
alta e bassa che compongono la macro.
Una macro pu anche essere definita su pi righe (come qualsiasi altro comando) ricorrendo al carattere \
come nellesempio seguente:
#define DEFINE_PRINT_ERROR \
printf(Error %i at %X\n, \
num_error, index_error)
#define MACRO_PRINT_ERROR(n,i)( \
printf(Error %i at %X\n, \
n, i) )

Appendice B

Validit del regolatore PI


Un regolatore PI come quello studiato nei capitoli 3 e 4, non sempre la soluzione migliore. Lesempio che verr
ora proposto mostra che il regolatore non pu essere progettato, in linea teorica, con qualsiasi banda passante; la
soluzione sar quella di cambiare tipo di regolatore.
Si consideri quindi il circuito in figura B.1 e la relativa funzione di trasferimento tra Vin e Vout :

1
Vout
LC
= 2
1
Vin
s + s CR
+

1
LC

Figura B.1: Circuito R-L-C.


Supponendo i valori R=100, L=10mH, C=470F ne consegue che i poli del sistema siano complessi
coniugati e pari a -10,64461,14i. Le risposte in frequenza relative sono rappresentate in figura B.2.
Supponendo ora di effettuare il calcolo relativo a un PI per il controllo del sistema secondo quanto detto nel
capitolo 4 (equazioni 2.3) impostando per esempio 1000 rad/s come banda passante e 90 come margine di fase,
i coefficienti del regolatore saranno Kp=0,1 e Ki=-3700. Questo risultato notevole ed dovuto al fatto che la
frequenza di taglio impostata per il calcolo dei regolatori superiore alla pulsazione di risonanza, come si nota
anche dai grafici in figura B.3. Inoltre dal diagramma di Bode si nota che la funzione L(s) = R(s) G(s) taglia
lasse a 0dB con pendenza -60dB/decade.
Si potrebbe quindi pensare di ridurre la banda passante ad un valore inferiore alla pulsazione di risonanza, per
esempio wt = 100. Le cose per non migliorano perch il sistema presenta un margine di fase negativo (figura
B.4). Ci nonostante, per, le cose non migliorano perch, anche se ora Kp=0,01 e Ki=95,3, il margine di fase
negativo.
Si noti che in alcuni casi il sistema si stabilizza se la banda passante viene drasticamente ridotta rispetto alla
pulsazione di risonanza. Nonostante ci si vede come si perdano tutti i vantaggi derivati dal calcolo in forma
103

104

APPENDICE B. VALIDIT DEL REGOLATORE PI

(a) Diagramma di Bode

(b) Diagramma di Nyquist

Figura B.2: Risposta in frequenza del circuito RLC.

(a) Diagramma di bode L(s)

(b) Diagramma di Nyquist L(s)

Figura B.3: Risposta in frequenza della funzione danello L(s) calcolata con pulsazione di taglio a 1000 rad/s.
chiusa dei parametri. Il sistema infatti anche se venisse stabilizzato avrebbe risposte lentissime. Il regolatore
PI in questo caso non lideale. In questi casi preferibile definire un regolatore generico che vada (al limite)
a cancellare i poli complessi coniugati e introduca un polo a pi alta frequenza in modo da avere una risposta
complessiva migliore. La soluzione da adottare una funzione generica del tipo seguente:
QN
n
(s + an )
R(s) = k QMn=1
m
m=1 (s + bm )

(B.1)

In particolare noto dalla teoria che un sistema di regolazione deve avere un integrale per annullare lerrore a
regime; quindi si pu esprimere R(s) = R1 (s)R2 (s) dove R2 = 1s ossia un integratore. Detto ci chiaro che
R1 (s) verr modellizzato basandosi sulla funzione risultante RG(s) = R2 (s) G(s) la quale risulta ovviamente
con una pendenza maggiore di 20dB/dec; ci implica che occorrer porre almeno due zeri. Perch la funzione
sia fisicamente realizzabile1 occorre per prevedere anche due poli: avendo R2 (s) un polo nellorigine, occorre
1 Anche se non necessario che la funzione sia fisicamente realizzabile per implementarla su un micro, se la funzione di questo tipo i
termini del regolatore sono tipicamente pi facilmente gestibili da un micro-processore.

105

(a) Diagramma di bode di L(s)

(b) Diagramma di Nyquist di L(s)

Figura B.4: Risposta in frequenza della funzione danello L(s) calcolata con pulsazione di taglio a 100 rad/s.

aggiungere almeno un polo in alta frequenza. La funzione avr una forma simile alla seguente:
R(s) = R1 (s) R2 (s) = k

(s + a1 )(s + a2 ) 1

(s + b)
s

(B.2)

dove a1 e a2 sono tali per cui si cercher di ridurre (al limite annullare) leffetto della risonanza. Lo studio di
sistemi come questo pu essere fatto per via grafica ponendo il denominatore della funzione pari a quello della
funzione G(s) in modo da cancellare i poli complessi coniugati, ossia la risonanza. Infine si inserisce un polo in
alta frequenza per quanto detto poco prima e un coefficiente k che aggiusti la risposta in termini di guadagno e
banda passante. La funzione proposta la seguente:
R(s) = k

s2 + 21.766s + 2.1277 105


s2 + c1 s + c2
=
0.005
ds2 + s
s(2.5 104 s + 1)

(B.3)

I diagrammi relativi alla funzione L(s) = R(s) G(s) sono riportati in figura B.5. chiaro che un andamento

(a) Diagramma di Bode

(b) Diagramma di Nyquist

Figura B.5: Diagrammi di Bode e Nyquist relativi alla funzione danello L(s) con eliminazione della risonanza.

106

APPENDICE B. VALIDIT DEL REGOLATORE PI

come quello ottenuto legato al fatto che la risonanza stata cancellata in modo perfetto. Ci dipendente
dal fatto che si assume il sistema modellizzato in modo perfetto. Nella pratica, per, difficile che il modello
rispecchi in modo perfetto la realt; ci implica che il modello del regolatore pu introdurre un altro punto di
risonanza il quale tende ad incrementare una certa gamma di frequenze. Si supponga per esempio che i poli
per compensare la risonanza siano pari a -10,64400,14i, ossia larmonica alla quale avviene la risonanza pi
bassa. Si ottengono i grafici in figura B.6.

(a) Diagramma di Bode

(b) Diagramma di Nyquist

Figura B.6: Diagrammi di Bode e Nyquist relativi alla funzione danello L(s) con zeri risonanti a sinistra.

Si noti che il fatto di aver posto gli zeri a sinistra della risonanza necessario, come mostrato in figura B.7.
Infatti ponendo gli zeri in modo tale che la risonanza si sposti a destra della risonanza introdotta dalla funzione
G(s), il sistema instabile. A sostenere ci, in figura B.8 sono riportate le due risposte al gradino nei due casi
appena studiati.

(a) Diagramma di Bode

(b) Diagramma di Nyquist

Figura B.7: Diagrammi di Bode e Nyquist relativi alla funzione danello L(s) con zeri risonanti a sinistra.

B.1. DISCRETIZZAZIONE DEL REGOLATORE

(a) Step con zeri risunanti a sinistra

107

(b) Step con zeri risonanti a destra

Figura B.8: Risposta al gradino unitario relativa ai casi in figura B.6 e B.7.

B.1

Discretizzazione del regolatore

Il regolatore in z trasformata sufficiente applicare alla funzione B.3 la trasformazione ti Tustin (equazione 2.15)
da cui si ottiene:



4 + 2c1 Ts c2 Ts2 z 2 + 2c2 Ts2 8 z + 4 + 2c2 Ts 2c1 Ts2
(B.4)
R(z) = k
(4d + 2Ts ) z 2 8dz + (4d 2Ts )
da cui ne deriva lespressione delluscita del regolatore nelle sequenze:

y (n)

2c2 Ts 8
4 c1 Ts 2c1 Ts2
4 + 2c1 T s + c2 Ts
+ e (n 1)
+ e (n 2)
= k e (n)
4d + 2Ts
4d + 2Ts
4d + 2Ts
2Ts 4d
8d
+ y (n 2)
+y (n 1)
4d + 2Ts
2Ts + 4d



+
(B.5)

Per la scrittura del codice ci si appoggia alla scrittura allequazione B.5 espressa come segue:
y (n) = e (n)E0 + e (n 1)E1 + e (n 2)E2 + y (n 1)Y 1 + y (n 2)Y 2

(B.6)

le cui costanti, per analogia con B.5, sono facilmente individuabili; ogni costante verr espressa con la rispettiva
macro.
Sostituendo ora i valori dei parametri del sistema possiamo tracciare il diagramma di Bode di R(s) e R(z). Il
tempo di campionamento scelto Ts = 50 106 s da cui si ottiene la seguente funzione di trasferimento in z:
R(z) =

0.02001z 2 0.03999z 0.01999


0.0011z 2 0.002z + 0.0009

I diagrammi di Bode sono riportati in figura B.9. Come si nota, il sistema presenta una distorsione in bassa
frequenza. Anche se sembra che la fase sia migliore perch resta a 90 per una gamma di frequenze pi ampia,
in realt ponendo R(z) in cascata a G(s) il sistema complessivo risulta instabile. Ci risulta dalle simulazioni,
ma facilmente intuibile dal semplice diagramma di Bode. Come detto, infatti, se i due poli complessi coniugati
dovuti agli zeri hanno una pulsazione maggiore della pulsazione di risonanza individuata in G(s), il sistema
si instabilizza. Ricordando che R(s) stata progettata per eliminare perfettamente i poli di G(s), chiaro

108

APPENDICE B. VALIDIT DEL REGOLATORE PI

Figura B.9: Diagramma di Bode della funzione R(s) e R(z).

che il picco risonante (di R(z)) spostato verso destra, il sistema instabile. La funzione in z deve quindi
essere ricalcolata tramite lintroduzione della distorsione del tempo di campionamento; ci spiegato in modo
esaustivo in [3] e consiste semplicemente nel calcolare un nuovo valore di Ts con il quale calcolare i coefficienti
in z. Esaminando il grafico in figura B.9 si intuisce che per fare in modo che le due guglie si sovrappongano
occorrerebbe ridurre Ts in modo che il grafico venga compresso. Attenzione per al fatto che la funzione R(z)
dovr essere plottata con Ts pari a 50106 s ossia il vecchio intervallo di campionamento. Per chiarire questo
aspetto di seguito viene riportato del codice M ATLAB per valutare la distorsione:

Tsd=fattore_distorsione*Ts;
%c1,c2 : coefficienti del denominatore G(s); d=1/4000 : polo in alta frequenza in R(s)
%coefficienti del numeratore
Zn2=k*(4+2*c1*Tsd+c2*Tsd^2); Zn1=k*2*(c2*Tsd^2-4); Zn0=k*(4-2*c1*Tsd+c2*Tsd^2);
%coefficienti del denominatore
Zd2=4*d+2*Tsd; Zd1=-8*d; Zd0=4*d-2*Tsd;
z=tf(z,Ts); % z rimande calcolata con passo Ts!
Rz=(Zn2*z^2+Zn1*z+Zn0)/(Zd2*z^2+Zd1*z+Zd0);
%se presente R definita nel dominio s plottare con:
bode(R, Rz);

Il valore della variabile fattore_distorsione stato individuato per tentativi e posto pari a 0,86. Con questo
valore si ottiene il diagramma di Bode e la risposta al gradino relativi rispettivamente al sistema tempo-continuo
e discreto (figura B.10-a e B.10-b). I coefficienti della funzione diventano:
R(z) =

0.02001z 2 0.04z 0.01999


0.001074z 2 0.002z + 0.000926

B.2. MODELLISTICA

109

(a) Bode

(b) Step

Figura B.10: Diagrammi con R(z) calcolata in distorsione.

B.2

Modellistica

I risultati riportati in figura B.12 sono riportati i risultati del modello S IMULINK sviluppato in figura B.11.

Figura B.11: Modello in s e z del sistema in esame.


La modellistica dei sistemi studiati abbastanza semplice e non altro che limplementazione delle funzioni
indicate precedentemente in s e z. Pi complesso invece il regolatore C il quale verr implementato basandosi
sullequazione B.6. Le costanti dellequazione B.6 sono:
E0=18.6313
Y1=1.8623

E1=-37.2426
Y2=-0.8623

E2=18.6167

Sviluppare il codice C con variabili double quindi abbastanza semplice: Uno stralcio di tale codice, i cui risultati
sono mostrati in figura B.13, il seguente:
/* 0: errore attuale; 1: errore precedente; 2: errore di 2 passi precedenti */
double error[3];
/* 0: uscita attuale; 1: uscita precedente; 2: uscita di 2 passi precedenti */
double out[3];
out[0]=error[0]*18.4264-error[1]*36.8288+error[2]*18.4096+out[1]*1.8416-out[2]*0.8416;

110

APPENDICE B. VALIDIT DEL REGOLATORE PI

(a) Dettaglio della risposta a gradino

(b) Tensione dovuta allingresso a gradino

Si noti che il regolatore C non implementato in questi grafici. Per i colori riferirsi alla figura B.11.

Figura B.12: Confronto dell risposta dei regolatori tempo-continuo e tempo-discreto.

(a) Risposta al gradino

(b) Tensione in uscita dal regolatore

Figura B.13: Risposta del regolatore C realizzato con variabili double.


Come si vede landamento della risposta del regolatore z si sovrappone perfettamente a quella del regolatore C.
Ora per occorre adattare il codice a un micro controllore, quindi necessario passare in digitale anche per quanto
riguarda le grandezze. Si assume a titolo di esempio un trasduttore con portata 10V che riporti il risultato a
10 bit ossia compreso nellintervallo 01023 acquisito dal micro processore. Lequazione per la trasduzione si
assume pari a:
Vdigit =

Vreale
512 + 512
10V

Il riferimento applicato avr un valore di picco pari a 1V. Di seguito viene riportato il codice C S IMULINK
necessario per eseguire la regolazione con variabili intere:
#define RIFERIMENTO u0[0]
#define VALOREREALE u0[1]
#define E0(e)((e*75475)+(e> >1)+(e> >3)+(e> >4)+(e> >6)+(e> >9)+(e> >10))
#define E1(e)((e*150850)+(e> >1)+(e> >3)+(e> >4)+(e> >5)+(e> >8)+(e> >10))
#define E2(e)((e*75405)+(e> >1)+(e> >3)+(e> >4)+(e> >8)+(e> >10)
#define Y(y)((y> >1)+(y> >2)+(y> >4)+(y> >6)+(y> >7)+(y> >8)+(y> >10))
int out[3]; /* 32bit. Array per tenere conto di allo stato attuale, precedente e di 2 volte prima */
short int error[3]; /* 16bit. array analogo a out, ma per gestire lerrore */

B.2. MODELLISTICA

111

/-----------------------------/
int intE0, intE1, intE2; /*Variabili a 32bit*/
int intY, outD; /*Variabili e 32bit */
/* Riposizionamento elementi array */
error[2]=error[1];
error[1]=error[0];
error[0]=(RIFERIMENTO-VALOREREALE)< <3;
/* Analogamente per luscita */
out[2]=out[1];
out[1]=out[0];
/* Calcolo dei vari componenti delluscita */
if(error[0]>=0) intE0=E0(error[0]);
else intE0=-(E0((-error[0])));
if(error[1]>=0) intE1=E1(error[1]);
else intE1=-(E1((-error[1])));
if(error[2]>=0) intE2=E2(error[2]);
else intE2=-(E2((-error[2])));
outD=out[1]-out[2];
if((outD)>=0) intY=(Y(outD));
else intY=-(Y((-outD)));
/* Calcolo luscita */
out[0]=intE0-intE1+intE2+out[1]+intY;
/* Gestione delluscita del blocco S-Function Builder */
y0[0]=out[0]> >12; /* visualizzo y0[0] in base 2^12 */
y0[1]=((double)out[0]*10)/(4096*4096); /* converto tutto in grandezze fisiche reali */

Il codice appena riportato il risultato di alcuni passaggi che mirano a portare il codice formalizzato in grandezze
double a grandezze di tipo intero (int). Per prima cosa il sistema in base 4096 (12 bit) troppo impreciso e
si passati subito a lavorare in base 16777216 (24 bit). Il cambiamento di base, per, non riguarda il calcolo
dellerrore (il quale riportato in base 4096), ma il calcolo dei coefficienti E0, E1 ed E2 i quali rispetto al valore
vero vengono moltiplicati per 4096 aumentando notevolmente la precisione.
Esaminando quindi il codice si individuano le prime definizioni delle macro relative ai parametri appena
descritti i quali vanno a moltiplicare gli errori e, subito dopo, si nota la macro Y. Questa macro sostituisce le
macro che realizzano i valori Y1 e Y2 in quanto si notato che Y1-1-Y2'1.1102106 , quindi trascurabile. Ci
permette di porre Y1=Y2+1 da cui:
out[1]*Y1-out[2]*Y2=out[1]+(out[1]-out[2])Y

dove Y=Y2. Questo costrutto permette di ridurre il carico computazionale, come si vedr nel corso del programma, in quanto si eseguono sia una comparazione (if) che una macro in meno. A questo punto occorre notare una
cosa molto importante: a differenza di quanto detto per i coefficienti E, i coefficienti Y1, Y2 e di conseguenza Y
non sono maggiorati di 4096, ma restano al valore calcolato inizialmente; ci dovuto al fatto che questi coefficienti pesano i valori precedenti della variabile out[0] la quale deriva dallelaborazione dellerrore per un
coefficiente E in base 4096 che porta inevitabilmente la variabile out[0] in base 16777216. Quindi out[i]*Y
anchesso un numero in base 1677216.
Proseguendo nellanalisi si trovano le dichiarazioni dei due array (out e error) di 3 elementi che tengono
conto del valore corrente (0), del valore precedente (1) e del valore di due passi precedenti (2).
Passando allinterno del programma vero e proprio si vede che larray dellerrore viene aggiornato spostando
indietro di una posizione i vecchi valori e, infine, viene calcolato il nuovo valore dellerrore (error[0]) portato,
mediante uno shift di tre bit, in base 4096. Analogamente viene fatto per i vari elementi dellarray out. Successivamente vengono calcolati i vari componenti delluscita. Tenendo presente che le varie macro hanno shift verso
destra, occorre fare un controllo sul segno della grandezza come gi visto nei capitoli precedenti. Successivamente si effettua il calcolo delluscita out[0]. Le uscite y0 invece sono relative al blocco S-Function di S IMULINK.
Si noti che luscita y0[1] il valore reale della tensione applicata.

112

APPENDICE B. VALIDIT DEL REGOLATORE PI

I risultati relativi al riferimento a gradino sono riportati in figura B.14. Come si nota la dinamica e la velocit
di risposta sono pressoch identiche a quelle della funzione con regolatore z. Anche dal punto di vista dinamico
linseguimento del riferimento avviene perfettamente; landamento mostrato in figura B.15 mostra come reagisce
il sistema a fronte di un riferimento sinusoidale da con pulsazione di 1000rad/s. Si noti che il riferimento seguito
molto meglio se variabile rispetto al gradino. Infatti se si ingrandisse la figura B.14 nel tratto finale, si vedrebbe
un leggero scostamento (ingegneristicamente accettabile) tra luscita dovuta al regolatore C e quella dovuta al
regolatore z con riferimento a gradino rispetto al riferimento sinusoidale. Nonostante ci, questo il migliore
risultato ottenuto.

(a) Step

(b) Tensione applicata

Figura B.14: Riferimento a gradino del regolatore C.

(a) Sinusoide 1000 rad/s

(b) Tensione applicata

Figura B.15: Riferimento sinusoidale del regolatore C.


Come detto poco prima, la tensione in uscita dal blocco S-Function Builder un valore reale. Ci vero anche
nella realt, ma occorre tenere presente che la variabile che tiene conto del duty-cycle nel micro controllore (per
esempio PDCx nei processori dsPIC30F) una variabile discreta, quindi la tensione applicata al carico sar una
frazione ben precisa della massima tensione applicabile (ossia della tensione di DC bus). A titolo di esempio si
supponga di avere un ponte H con una tensione di DC bus pari a 50V e che il valore massimo del duty-cycle sia
per esempio 736; essendo un ponte ad H se la variabile duty-cycle pari a 368 la tensione sul carico nulla.

B.2. MODELLISTICA

113

Questo vuol dire che la risoluzione della tensione sul carico pari a 250V/736, ossia 0,1359V. Una possibile
soluzione per tenere conto di ci prevede una modifica al codice precedentemente riportato come segue:
/*dc=368+y0[1]*368/50; dc una variabile unsigned int a 16bit sul micro
va realizzato con una macro (GET_DC())per evitare la divisione */
#define GET_DC(o)((o> >18)+(o> >21)+(o> >24))
short int dc;

...
/* Gestisco luscita del blocco S-Function Builder */
if(out[0]>=0) dc=GET_DC(out[0]);
else dc=-(GET_DC((-out[0])));
if(dc>368) dc=368;
else if(dc<-368) dc=-368;
y0[0]=dc+368; /* Reale valore del duty-cycle PDC1 */
y0[1]=((double)dc*50)/736; /*valore reale della tensione*/

Chiaramente lintroduzione del duty-cycle degrada la risposta come mostrato in figura B.16. Come prevedibile, la risposta al gradino peggiora leggermente come anche quella sinusoidale, anche se questultima meno
vistosamente. I risultati ottenuti sono quindi pi che soddisfacenti.

(a) Riferimento a gradino

(b) Riferimento sinusoidale

Figura B.16: Risposta con introduzione del duty-cycle.

114

APPENDICE B. VALIDIT DEL REGOLATORE PI

Riferimenti
Bibliografia
[1]

DALLA TEORIA AL CODICE MACCHINA: SCRITTURA DEL CODICE PER UN PI DIGITALE


- M. Matuonto, F. L. Mapelli

[2]

Elementi di CONTROLLO DIGITALE - Guido Guardabassi

[3]

Manuale del compilatore C30 (su [L3] application note 51284D)

[4]

Manual Family dsPIC30F (su [L3] application note 70046D)

[5]

ANALISI TEORICA E SPERIMENTALE DEGLI APPARATI DI ECCITAZIONE E LEVITAZIONE NEI SISTEMI MAGLEV EMS - Tesi di dottorato di Giovanni Maria Foglia - dip. Ing. Elettrica
- Politecnico di Milano - anno 2001

[6]

PROGETTO E REALIZZAZIONE SPERIMENTALE DEL SISTEMA DI REGOLAZIONE DI UN


LEVITATORE EMS TRADIZIONALE E A MAGNETI PERMANENTI - Tesi di laurea di Calzoni
Pietro - anno 2006

[7]

Datasheet della demo board PicKit2 (su [L3] datasheet DS-51556A)

[8]

Datasheet del processore PIC16F684 (su [L3] datasheet 41202D)

[9]

Paolo Bolzen, Riccardo Scattolini, Nicola Schiavoni, Fondamenti di controlli automatici, McGraw
Hill 1998

[10]

Fondamenti di automatica I - Paolo Rocco, Politecnico di Milano

[11]

Comandi M ATLAB di uso comune - Giudicatti Italo

Link
[L1]

http://www.iac.cnr.it/~amadori/M4

[L2]

http://www.ettorepanella.com/public/corsi/Trasformata%20Z.pdf#search=%22Z%20trasformata%22

[L3]

http://www.microchip.com

[L4]

http://www.ht-soft.com

[L5]

http://www.freescale.com

[L6]

http://publications.gbdirect.co.uk/c_book/

www.lyx.org LYX programma con cui stata scritta questa dispensa (front-end per LATEX)
115