Sei sulla pagina 1di 13

Metodi e algoritmi in Matlab per lo studio di sistemi

dinamici
Simone Onorati

Università di Pisa
Corso di Cibernetica Fisiologica
a. a. 2016-17

1 Le tre facce dell’impiego di Matlab nei modelli


I problemi di ordine generale, relativi a un modello numerico, che potrebbero voler essere
risolti con Matlab c
sono tre. In ciascuno, un fattore tra ingresso, uscita e parametri del
sistema sono incogniti (Figura 1).
• Predizione (o simulazione): conosciamo l’ingresso (scalare o vettoriale) al sistema
e la struttura di questo (inclusi i parametri), e vogliamo trovarne l’uscita (scalare o
vettoriale) con quell’ingresso. Questa è l’applicazione più classica e frequente – posto
che la soluzione analitica del sistema di equazioni descrivente il modello è quasi sempre
irrealizzabile.

• Diagnosi (o deconvoluzione): al contrario di prima, conosciamo i parametri del


sistema e l’uscita, e vogliamo determinare l’ingresso che ha determinato quell’uscita.

• Identificazione: conosciamo ingressi ed uscite, e non conosciamo la struttura (in


termini di equazioni o FdT o soltanto parametri da tarare) del sistema, e vogliamo
determinarli per tentativi. Noi considereremo solo l’identificazione parametrica, in cui
la morfologia delle EDO del sistema è nota.

2 Simulazione
In generale, per performare una simulazione in un software occorre conoscere:
• la morfologia delle EDO o dello schema a blocchi del modello;

• il valore numerico di tutti i parametri (che devono essere stati identificati o stimati);

• i valori di tutte le C. I. (che devono essere fissate in modo opportuno).


Volendo proporre una simulazione in un articolo scientifico, bisogna fornire tutte queste
informazioni, e giustificarne la scelta.
La simulazione in Matlab può essere impostata con due modalità: tramite codice puro,
ed entro l’ambiente grafico Simulink.

1
Figura 1: I tre problemi generali riguardanti un modello risolvibili con Matlab.

Simulazione con puro codice Matlab


Questa è la scelta meno intuitiva ma anche meno onerosa per il calcolatore. Invece di
porre tutte le istruzioni in un unico script, si consiglia di organizzare il codice nel seguente
modo, più chiaro e «pulito» (Figura 2). Si crea uno script principale (es. main.m) che esegua
in ordine:
• pulizia del workspace (eliminazione di tutte le variabili della sessione precedente), della
console e chiusura di tutte le figure della sessione precedente;
• dichiarazione e caricamento dei parametri e delle C. I. (variabili global), chiamando
uno script apposito;
• lancio del risolutore (function Matlab come ode45), dandogli in «pasto» la function
handle rappresentante il problema numerico;
• generazione dei grafici, con un secondo script apposito.
Quindi, come mostra la figura 2, lo script principale ne chiama due secondari (model_para-
meters.m e grafici.m), semplicemente trovando un’istruzione composta dal loro nome. Il
risolutore del problema (function con prefisso ode) è invece una vera e propria funzione – ne
parleremo poi.
Prendiamo come esempio esplicativo la simulazione del modello di Wodartz e Nowak, il
più basilare che descrive l’HIV:

ẋ = λ − dx − βxv


ẏ = βxv − ay

v̇ = ky − uv

dove x è la concentrazione dei linfociti CD4+ sani, y quella dei CD4+ infetti e v quella del
virus HIV libero; λ il tasso di proliferazione cellulare naturale, d quello di mortalità naturale,
β il tasso di infezione virale, a la mortalità delle cellule infette, k la proliferazione virale e u
il tasso di inattivazione naturale del virus.
Il codice del main.m sarà del tipo:

2
Figura 2: Struttura degli script Matlab suggerita per la simulazione.

clear
close all
clc

model_parameters;
N = 30*36;

[time_E, XX] = ode45(’fun’,0:N, X0);

grafici

Dopo aver dato le istruzioni preliminari di pulizia, si chiama lo script model_parameters.m,


che definisce i parametri del modello (qui tutti già noti, in caso contrario si ricorrerebbe alla
stima parametrica, v. sotto) e le condizioni iniziali (CI):

global lambda d beta a k u X0;

lambda = 7;
d = 0.007;
beta = 4.2163e-7;
a = 0.0999;
k = 90.67;
u = 0.2;

X0 = [1000 0 10^4]; % Condizioni iniziali

Conviene inizializzare in uno script a parte i parametri, per trovare facilmente (specie nel
caso di main lunghi) il luogo dove modificare eventualmente i valori. Notare che i parametri
sono definiti come global.

3
Di solito si evita di dichiarare variabili globali (cioé visibili a tutte le function e script
nella cartella di lavoro in cui sono dichiarate come global, ed accessibili tramite il loro nome)1
per non rischiare di impiegare altrove variabili locali con lo stesso nome, il che darebbe errore
o malfunzionamento. Nel caso della simulazione di modelli, però, ciò si rivela utile poiché
in questo modo la function handle da risolvere (v. sotto) può leggere i parametri da usare
dall’esterno, senza bisogno che le vengano passati cone argomenti in ingresso.
A questo proposito, è opportuno ricordare la distinzione tra due categorie di file .m, che
si comportano in modo molto diverso rispetto alle variabili:

• Gli script (o procedure), file .m che iniziano con un’istruzione, e sono visibili sem-
plicemente come un blocco di codice che Matlab legge interamente prima di passare
all’istruzione successiva nello script chiamante. Le variabili finora presenti nel workspa-
ce sono accessibili dallo script chiamato, e quelle create durante l’esecuzione di questo
restano nel workspace al suo termine.

• Le funzioni, particolari file .m che iniziano con la riga function Y = NOME_FUNZ(X).


Quando vengono chiamate (Y = NOME_FUNZ(X)), come per gli script si esegue in se-
quenza il codice della function, ma a differenza di quelli Matlab suppone che all’utente
interessino solo le variabili di uscita dalla function, ottenute a partire da quelle in
ingresso, passate alla funzione. Per questo (e per proteggere le variabili del workspace
principale dalla sovrascrittura, da parte di variabili con stesso nome usate entro func-
tion), le variabili finora presenti nel workspace, eccetto quelle passate e le global, non
sono visibili alla function, e le variabili create durante l’esecuzione di questa vengono
distrutte al suo termine, eccetto quelle di uscita, passate allo script chiamante. In altre
parole, ogni function ha il «suo» workspace, separato da quello degli script.2

Pertanto, c’è bisogno di dichiarare i parametri del modello come global solo perché siano
accessibili nella fun.m (usata poi nel risolutore come function handle). Invece, nello script
grafici.m sono disponibili gli output di ode45 in quanto variabili create entro lo script main.m.
Anche il vettore delle CI, creato entro model_parameters, è disponibile nel main, e quindi
non occorre dichiararlo come global.
In alternativa, se i dati numerici (parametri, CI) sono numerosi, si può renderli disponibili
come file di variabile (.mat) e caricarlo nell’ambiente.
Si definisce poi il tempo di simulazione come numero di campioni (istanti discreti), N (le
simulazioni in Matlab sono sempre discrete, anche se il modello è a tempo continuo!). Per
come sono definiti i parametri, il tempo discreto è in giorni. Nel nostro caso, simuliamo 3
anni di HIV, quindi N = 30 · 36 giorni (3g/mese · 36mesi). Quindi si chiamano la function
risolutrice (ode45, sulla cui sintassi v. sotto) e lo script per generare i grafici.

La function risolutrice
La function che risolve numericamente il problema è propria di Matlab, ed implementa un
metodo numerico per risolvere una singola o un sistema di EDO del primo ordine (un’ EDO
di ordine superiore va sempre riscritta come sistema per poter essere risolta in Matlab). La
scelta del risolutore dipende dalla tolleranza ammessa dal problema, dalla complessità delle
1 In Matlab occorre dichiarare esplicitamente solo variabili global
2 Invece, funzioni chiamate entro altre funzioni, pur avendo un proprio workspace, possono accedere in
lettura e scrittura alle variabili usate nelle function di livello superiore.

4
Tabella 1: Risolutori numerici di problemi differenziali nativi di Matlab.

equazioni e dal fatto che il problema sia stiff o meno.


Un problema è detto stiff (stiffness = rigidità, impassibilità) se è oneroso da risolvere
con metodi numerici tradizionali (espliciti), poiché la soluzione esatta presenta componenti
a dinamiche con velocità molto diversa. Questo a sua volta è correlato alla presenza di
parametri delle EDO con differenti ordini di grandezza. Si può trovare che in tal caso
risultano più rapidi alcuni metodi impliciti (perciò cambiano le function consigliabili).
Nella pratica, si comincia utilizzando un risolutore per problemi non stiff ; se ci si accorge
che la risoluzione è lentissima, significa che il problema è stiff e si passa ad un risolutore
dedicato.
La tabella 1 mostra i risolutori nativi di Matlab, il loro grado di accuratezza e le situazioni
in cui conviene impiegarli.
L’ode45 si utilizza nel 95% dei casi. L’ode23 è più rapido ma non molto accurato. L’ode15s è
il primo da utilizzare in caso di problemi stiff.
Si noti che a seconda del risolutore, i tempi di calcolo necessari per raggiungere l’accura-
tezza predefinita possono essere anche molto diversi; la differenza si amplifica quante più sono
le flops). Il tempo di calcolo è un parametro fondamentale nella pratica di ricerca: bisogna
valutare quale risolutore scegliere anche in funzione del tempo massimo che si accetta per il
calcolo.
La sintassi più semplice di una odeXXX è la seguente:

[t,y] = ode45(odefun,tspan,y0)

Dove:
• t è il vettore con gli istanti temporali a cui è calcolata la soluzione numerica, che
dipendono dalla scelta di tspan.
• y contiene i campioni della soluzione. Nel caso più generale, y è una matrice le cui
colonne sono le soluzioni numeriche per ogni componente della funzione vettoriale
presente nella odefun, e le cui righe corrispondono agli istanti temporali (o, in generale,
ascisse) presenti in t.

5
• odefun è la function handle, ossia l’EDO o il sistema di EDO da risolvere, specificato
in uno dei due modi descritti più sotto.

• tspan è l’intervallo temporale (o, in generale, dell’ascissa) di integrazione. Se sono


specificati solo l’istante iniziale e finale, [t0 tf], la soluzione y è restituita ad ogni
istante tra i due che sia multiplo del passo di integrazione h. Se invece, come nel nostro
caso (0:N), è specificato un vettore di 3 o più istanti, la soluzione sarà fornita in output
a quegli istanti (quindi t = tspan), sebbene sia calcolata internamente ad ogni passo
di integrazione h (in genere molto più piccolo). 3

• y0 sono le condizioni iniziali (il vettore deve avere la stessa dimensione dell’uscita
definita nella odefun).

È possibile specificare una tolleranza ed un passo di integrazione arbitrari nel metodo


numerico, e molte altre opzioni – si veda doc ode45 per come farlo.
La function handle deve avere come variabile dipendente (scalare o vettoriale) la deri-
vata della funzione incognita, e come variabili indipendenti, in ordine, un’ascissa (tempo
o spazio) e la funzione – infatti rappresenta l’equazione differenziale y 0 = f (t, y). Può
essere specificata direttamente in linea (con @(t,y) ESPRESSIONE(t,y)), o essere della
forma ’NOME_FUNZIONE’, essendo in questo caso la funzione definita in un file NO-
ME_FUNZIONE.m, sempre con y 0 variabile indipendente e y, t variabili indipendenti. Que-
sto uso è più chiaro in caso di espressioni lunghe, vettori di EDO o equazioni coinvolgenti
parametri da tarare.
Nel nostro esempio, conviene scrivere la descrizione I/O del modello in una function
fun.m, utilizzata come primo argomento (tra apici) di ode45 nel main:

function Xdot = fun(t,X)


% Xdot sta per <<X punto>>, cioè derivata temporale di x

global lambda d beta a k u

x = X(1); % Si rinominano le componenti della var. indip. per chiarezza


y = X(2);
v = X(3);

Xdot = zeros(3,1); % Inizializzazione della var. di uscita (vettoriale)

%% Equazioni differenziali scalari

Xdot(1) = lambda - d*x - beta*x*v;


Xdot(2) = beta*x*v - a*y;
Xdot(3) = k*y - u*v;

Attenzione È obbligatorio specificare come ingresso alla fun sia la variabile dipendente
X (scalare o vettoriale) sia il tempo, anche nel caso in cui l’EDO o il sistema non siano
esplicitamente dipendenti dal tempo.
3 Viene eseguita un’interpolazione della soluzione «interna» se gli istanti scelti non sono multipli di h (?)

6
Notare che la function dichiara i parametri come global per poterne leggere i valori dal
workspace degli script.
È importante preallocare le variabili vettoriali o matriciali come oggetti di zeri: questo
incrementa molto la velocità di calcolo, poiché non obbliga Matlab a far posto continuamente
in memoria per adattare progressivamente la dimensione dell’oggetto, ma essa è nota (e la
memoria predisposta) sin dall’inizio.

Simulazione con Simulink


Simulink c
è un ambiente grafico per la simulazione dipendente da Matlab. Tutto ciò che
si può fare in Simulink si più fare direttamente con un opportuno codice Matlab. Il vantaggio
di Simulink sta nella migliore rappresentazione delle informazioni; il grosso svantaggio sta
nell’enorme incremento dei tempi di calcolo rispetto all’implementazione diretta in codice
Matlab – incremento significativo, comunque, solo per problemi di una certa complessità.
Quindi conviene assolutamente non usare Simulink per problemi numericamente complessi.
La simulazione Simulink viene lanciata direttamente attraverso l’ambiente grafico, sebbene
corrisponda a comandi Matlab e quindi sia lanciabile anche entro uno script (v. filemain
fornito dal relatore).
Volendo disegnare il modello in Simulink, per modelli ad EDO è fondamentale usare
il blocco integratore, che riceve in ingresso la variabile derivata e dà in uscita quella non
derivata, per poterla poi utilizzare, determinando i vari contributi alla derivata. Come visto
nel modello della glicemia, le EDO si costruiscono graficamente, con uno «schema a blocchi»
– v. la Figura 3 per il caso del modello di Wodartz-Nowak.

Modelli a tempo discreto


Si sa che qualunque modello a tempo continuo viene internamente discretizzato per
poter essere risolto numericamente. Per modelli definiti a tempo discreto, l’ascissa e i valori
corrispondenti della funzione sono successioni, e quindi la simulazione può essere eseguita
direttamente con istruzioni iterative di base: si imposta un ciclo for in cui il contatore è il
tempo discreto, e si aggiornano i vari stati in base alle leggi alle differenze. . .
Nel caso le grandezze alla nuova iterazione non siano funzione esplicita di quelle all’iterazione
precedente, si ricorrerà alla soluzione dell’equazione tramite fzero.
Solitamente, comunque, si ragiona nel tempo continuo, e si lascia a Matlab il compito di
fornire una soluzione campionata in ogni caso, secondo necessità.

3 Identificazione parametrica
L’identificazione (o stima, o taratura) dei parametri di un modello matematico viene
effettuata con una delle seguenti modalità:

• si utilizzano i valori più adatti presenti in letteratura (tarati e collaudati in passato);

• si ottengono i valori esatti da considerazioni fisico-biologiche (ragionamenti);

• si ricavano da considerazioni matematiche, essendo noti già altri parametri;

7
Figura 3: Schema Simulink del modello di Wodartz e Nowak.

• si ottengono per data fitting, cioè si usano i valori che consentono la migliore approssi-
mazione dell’andamento simulato a un andamento misurato (a parità di CI) dal sistema
che si sta modellando.

Per quanto riguarda la terza modalità, si consideri l’esempio seguente, nel modello di
Wodartz e Nowak. Allo stato di regime senza infezione (v ≡ 0∀t), la prima EDO diventa:

ẋ = λ − dx − βxv ⇒ 0
|{z} = λ − dx∞ − 
βxv

|{z}
ẋ = 0 a regime v≡0

Da cui, conoscendo già il parametro d (tasso di mortalità cellulare naturale) e conoscen-


do da studi biologici la concentrazione media di CD4+ in un organismo sano da tempo,
quantificabile proprio in x∞ , si può stimare il parametro λ:

λ = d · x∞

Identificazione tramite data fitting


La quarta modalità è la più comune e generale – non richiede infatti alcuna ipotesi a
priori sul modello o sui parametri. Si fonda sull’idea che i «migliori» valori dei parametri non
ancora noti sono quelli che descrivono meglio l’uscita sperimentale, ossia che minimizzano
una funzione legata allo scarto complessivo tra la sequenza sperimentale disponibile e quella
simulata.

8
Si tratta quindi di risolvere un problema di ottimizzazione (minimizzazione). La funzione
di costo più comune, che si vuole minimizzare (come un costo totale) è l’indice di qualità
ISE a tempo discreto,
n
X 2
ISE = ci · x̂(i) − x(i)
i=1

dove x̂(i) sono i campioni predetti (in uscita) dal modello, x(i) quelli sperimentali e ci dei
coefficienti di peso. L’ISE, quindi, rappresenta la somma pesata degli errori quadratici del
campione predetto rispetto a quello misurato.
Se i pesi sono tutti uguali, il punto di minimo non varia con il peso comune c e l’ISE
rappresenta, per c = 1, l’errore quadratico «totale» tra le due sequenze.
La minimizzazione dell’ISE si appoggia sulle funzioni matlab fminunc e fmincon, in grado
di trovare il più vicino punto di minimo locale a una posizione iniziale x0 di una funzione
argomento, rispettivamente senza vincoli e sotto diversi tipi di vincolo. Le function risolvono
quindi problemi di minimo vincolato e non («unc» sta per unconstrained, e «con» per
constrained). Le loro sintassi più comuni sono:

[x,fval] = fminunc(fun,x0)
[x,fval] = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon)

Per entrambe, l’uscita x rappresenta il punto di minimo della funzione (scalare o vettoriale,
a seconda del dominio di quella) trovato dall’algoritmo, e fval il corrispondente valore della
funzione (argomento omissibile). Gli ingressi sono, in ordine:

• fun: la funzione ’di costo’ da minimizzare, data come function handle, con le stes-
se regole che per le odeXXX: può essere espressa direttamente con c_fun = @(x)
ESPRESSIONE(x) (dove x può essere vettoriale e quindi l’espressione una funzione delle
sue componenti), oppure può essere descritta in un file function a sè (c_fun.m), e
chiamata in argomento con ’c_fun’.

• x0: la posizione iniziale nel dominio, da cui iniziare la ricerca del punto di minimo.

• A, b: una matrice e un vettore che descrivono un vincolo di disuguaglianza lineare


sulla variabile indipendente x (Ax ≤ b). Sono due argomenti obbligatori per fmincon
(altrimenti si userebbe fminunc).

• Aeq, beq: come sopra, ma il vincolo lineare è ora di uguaglianza (Aeq x = beq ).

• lb, ub: barriere rispettivamente inferiori e superiori entro cui x (o le componenti di x)


devono mantenersi (vincoli di massimo e minimo sulla variabile indipendente). Se x
è vettoriale, lb e ub devono essere vettori il cui n-esimo argomento è il vincolo per
l’n-esima componente di x.

• nonlcon: vincoli non lineari su x. Vanno espressi come function handle con due uscite,
[c(x), ceq(x)], due funzioni rappresentanti i vincoli: c(x) ≤ 0 e ceq (x) = 0.

nota In fmincon si possono imporre uno o più tipi di vincolo a piacere. Qualora in
fmincon non si voglia imporre alcuni argomenti in posizione intermedia (ad esempio i due
vincoli ’obbligatori’ A e b), li si imposta a [] (come sarà fatto nell’esempio sottostante). nota
È fortemente consigliato aggiungere un terzo argomento di uscita, exitflag, un numero

9
intero che indica se la ricerca del minimo è andata a buon fine (+1) o meno (altro numero).
Si veda doc fmincon per i dettagli. In particolare, un exitflag di −2 indica che non è stato
trovato alcun punto di minimo locale sotto i vincoli specificati.
Le function minimizzatrici seguono un algoritmo numerico iterativo: data la scelta iniziale
x0, calcolano il valore corrispondente della fun da ottimizzare, e da questa informazione
modificano l’ingresso x in modo da avvicinarsi al punto di minimo. Il ciclo si ripete finché
non viene soddisfatto un criterio di arresto – x si trova allora molto vicino al punto di minimo
(vincolato) più prossimo a x0 , se esiste.

Quale esempio, supponiamo che i parametri λ, a e u del modello di Wodartz e Nowak non
siano noti dalla letteratura, e si voglia stimarli per data fitting a partire da dati sperimentali4 .
Nella nostra applicazione, è necessario creare un file c_fun.m, poiché l’espressione della
funzione di costo è laboriosa da ottenere: essa dipende dai campioni sperimentali e da quelli
previsti dal modello con i parametri attualmente impostati (in fase di taratura). Bisognerà
quindi eseguire la simulazione con odeXXX all’interno di c_fun.m (v. l’esempio sottostante).
Ad ogni iterazione dell’algoritmo di minimizzazione, verrà valutato il valore della c_fun con i
parametri attualmente presenti, per poi modificare la variabile indipendente (i parametri) in
modo da avvicinarsi al punto di minimo.
La funzione di costo sarà l’ISE in funzione dei tre parametri incogniti, x = (λ, a, u). I
dati sperimentali sono disponibili nel file experimental_data.mat. Si userà fmincon, volendo
specificare valori massimi e minimi per i parametri dato semplicemente il loro significato.
La function troverà quindi i 3 parametri tali che la curva in uscita dal modello si avvicina
massimamente alla sperimentale. La famiglia di curve è decisa dal tipo di EDO ma talvolta
anche dal valore degli stessi parametri.
La c_fun.m sarà così implementata:

function CF_val = c_fun(Uvec)

global data dvstd tdata lambda d beta a k u T_f X0

% I parametri incogniti sono l’ingresso della funzione di costo (Uvec)

lambda = Uvec(1);
a = Uvec(2);
u = Uvec(3);

% Calcolo degli andamenti previsti dal modello, con i parametri attuali

tempo = 0:T_f;
[~,XE] = ode45(’fun’,tempo,X0); % L’uscita ’vettore dei tempi’ non viene
% prelevata (non occorre, è uguale a ’tempo’)

%% Implementazione della funzione di costo


4 Poiché qui il fine è solo didattico, tali dati di cui si parla sono in realtà provenienti da una simulazione

(proprio con i valori usati in precedenza); considerarli come fossero dati sperimentali. La stima dei parametri
sarà buona se i valori stimati saranno uguali, a meno di una piccola tolleranza, a quelli usati per generare i
dati "sperimentali"

10
CF_val = 0; % Inizializzazione

for i = 1:length(tdata)
CF_val = CF_val + ...
(1/dvstd(i,1))*((XE(tdata(i),1) - data(i,1)))^2+ ...
(1/dvstd(i,2))*((XE(tdata(i),2) - data(i,2)))^2 + ...
(1/dvstd(i,3))*((XE(tdata(i),3) - data(i,3)))^2;
end

La function utilizza diverse variabili definite all’infuori di essa, prelevate grazie al loro
ambito globale: i parametri già noti (d, beta, k), gli andamenti sperimentali (tdata, istanti
temporali; data, matrice le cui colonne sono le sequenze sperimentali di x(t), y(t) e v(t);
dvstd, matrice con i valori di deviazione standard delle varie misure rispetto alle sequenze
medie, presenti in data), il numero dei campioni delle sequenze (T_f) e infine le scelte iniziali
di tentativo per i parametri (vettore x0).
Come si vede dalle ultime righe, la funzione di costo (calcolata con i parametri attuali ad
ogni iterazione di fmincon) è costituita dalla somma di tutti gli scarti quadratici dei campioni
simulati da quelli sperimentali, sommati sia per istanti temporali (indice i) che per variabile
(x, colonna 1, y, colonna 2, v, colonna 3), e pesati inversamente alla deviazione standard di
ciascun campione.
È molto importante scegliere razionalmente i pesi dei vari contributi nell’indice. Molto
spesso, si sceglie di dare pesi diversi invece che tutti uguali (unitari, per semplicità) per
diverse ragioni:5

• Più un dato è considerato incerto, meno lo si pesa, poiché se ne attribuisce minore


affidabilità, e si privilegia così l’aderenza delle curve simulate a quelle sperimentali
più attendibili. Una tecnica comune, allo scopo, è usare come peso f rac1σ del dato
sperimentale (σ è la sua deviazione standard campionaria), cosicché maggiore è questa,
cioè meno il dato è «affidabile», minore sarà il peso nel formare l’ISE.

• È buona norma uniformare i contributi al costo di variabili con ordini di grandezza


diversi. Infatti, variabili numericamente più grandi (di uno o più ODG) danno ragio-
nevolmente scarti quadratici maggiori rispetto a variabili più piccole; ne deriva che le
prime danno un contributo molto maggiore all’ISE, e la sua minimizzazione privilegerà
l’aderenza delle loro curve alle sperimentali, quasi trascurando quella delle variabili
numericamente piccole.
Per correggere questo fenomeno, bisognerebbe dividere i pesi per la deviazione standard
degli scarti (altra cosa rispetto alla σ di prima); per non appesantire il calcolo della
cost function ad ogni iterazione, un metodo surrogato è dividere i pesi per la deviazione
standard inter-sequenze sperimentali, come nella prima situazione.

• Se si sta minimizzando la funzione di costo di un controllore predittivo (v. lezioni di


Cibernetica Fisiologica), al posto dell’ISE si utilizzerà l’indice Lineare Quadratico, in
cui agli addendi di errore si aggiunge l’energia del controllo. Si può scegliere la priorità
5 Più un addendo dell’ISE è pesato, più la minimizzazione dell’ISE totale tende a minimizzare quell’addendo,

poiché esso approssima meglio la funzione somma.

11
nel minimizzare l’errore o l’energia di controllo differenziando i pesi dei due gruppi di
addendi di una stessa quantità.

• Sempre all’interno di un controllore predittivo, nel modulo di calcolo dell’uscita target,


si può indirizzare il controllo verso il soddisfacimento di particolari obiettivi scegliendo
opportunamente i pesi della funzione di costo.

Il nostro modello rientra nel secondo caso. Siccome nella pratica i dati del virus sono
numericamente maggiori delle concentrazioni cellulari (di alcuni ODG), esso conterebbe
molto più dei CD4 nel tarare i parametri, ottenendo un’ottima aderenza della curva del virus
a quella sperimentale, ma non altrettanto per le altre due. Allora si peserà meno il contributo
della carica virale, normalizzando per la deviazione standard inter-sequenze sperimentali
(lo stesso si fa per le altre due variabili, ottenendo così scarti non influenzati dall’ordine di
grandezza delle misure).6
Per eseguire la simulazione del modello, lo script main.m si modificherà semplicemente
così, premettendo al lancio della simulazione vera e propria la stima dei parametri non noti
da altre fonti tramite fmincon:

clear
close all
clc

global data dvstd tdata lambda d beta a k u T_f X0

% Caricamento dei parametri noti dallo script

model_parameters;

% Caricamento dei dati sperimentali per la taratura dei rimanenti parametri


% con data fitting. Si carica il file ’Experimental_data.mat’ contenente
% tre variabili: data ---> vettore dati sperimentali;
% tdata ---> vettore tempi di misurazione
% dvstd ---> vettore delle deviazioni standard inter-sequenze dei campioni

T_f = tdata(end); % Determina per comodità la lunghezza delle sequenze

% Grandezze necessarie all’ottimizzatore

Uvec0 = [5 0.1 0.1]’; % valori iniziali (di tentativo) dei parametri;


LB = [0 0 0]’; % vincoli inferiori (infatti nessuno dei 3 ha senso sia < 0)
UB = [10 1 1]’; % vincoli superiori (ragionevoli, da letteratura)

6 Poiché in questo esempio didattico si ha a disposizione una sola sequenza per variabile di stato, poiché –
come detto nella nota precedente – gli andamenti sono in realtà provenienti da simulazione, la deviazione
standard è assunta uguale ed unitaria per ogni sequenza, e quindi i pesi risulteranno uguali. Nella pratica ,
invece, si disporrà di più misurazioni di grandezze nel tempo, e si prenderà come sequenza su cui eseguire il
fitting quella media, accompagnata dai valori di deviazione standard, che plasmeranno i pesi dei contributi
all’ISE.

12
% Taratura dei parametri per data fitting

[U_vec,fval,exitflag] = fmincon(’c_fun’,Uvec0,[],[],[],[],LB,UB,[]);

% Assegnamento del punto di minimo di c_fun ai parametri da usare nel modello

lambda = U_vec(1);
a = U_vec(2);
u = U_vec(3);

% Simulazione del modello con i parametri identificati

tempo = 0:T_f;
[time,XE] = ode45(’fun’,tempo,X0);

% Plot dei grafici

grafici

Notare gli argomenti vuoti in fmincon e la richiesta dell’exit flag in uscita.


I valori iniziali dei parametri possono teoricamente essere qualunque, poiché l’algoritmo
usato in fmincon ha convergenza globale (supposto che l’ISE abbia un solo minimo locale,
come quasi sempre accade). Tuttavia, per ridurre i tempi di calcolo conviene porre come CI
dei valori ragionevoli, magari presi dalla letteratura per un caso di uso del modello in cui il
nostro non rientra.
Lanciando la simulazione e confrontando i valori di λ, a, u stimati per data fitting con
quelli originari, si vede che l’aderenza è molto migliore per il parametro virale u. Questo
perché, essendo le σ a disposizione unitarie (v. nota 6 nella pagina precedente), il contributo
del virus alla CF ha pesato molto di più, a causa del maggiore ODG. Bisognerebbe quindi
ridurre con altro criterio il peso della variabile virus libero, o incrementare quello dei CD4.
Comunque la stima parametrica raggiunge già buoni risultati, rispetto a quelli veri (da cui si
sono originati i dati)
Più fittamente campionate e numerose7 sono le sequenze dei dati sperimentali, più la
stima parametrica è verosimile (si avvicina ai valori «veri») – nel primo caso perché l’aderenza
agli andamenti sperimentali «veri», continui nel tempo, sarà migliore; nel secondo caso perché
la varianza dell’errore casuale si riduce quante più sequenze sono mediate.

7 Nel determinare la sequenza media, quella utilizzata nella taratura

13