In Italiano: Sistemi Automatici (Parte 1)
ASTRATTO: Gli appunti di seguito riportati traggono origine dalle lezioni tenute dall’autore, raccolte da un volume pubblicato negli anni 90, insieme agli altri due che completavano il corso di “SISTEMI e AUTOMAZIONE per ITI MECCANICI” Purtroppo il volume era datato: veniva trattato estesamente il sistema operativo MS DOS, sviluppato il programma TURBO-PASCAL ecc. Tolte le parti che non interessano più, ed effettuati alcuni ritocchi, il “tipo” di cui sopra l’autore ha deciso di aggiungere gli appunti così modificati a quelli del suo sito. La parte di elettrotecnica generale non è datata e quindi può essere utilizzata.
Introduzione
L’ingegneria dell’automazione o in inglese Control/System engineering è un ramo dell’ingegneria dell’informazione che si occupa principalmente della modellazione, simulazione e controllo di sistemi. Avendo un vasto campo di lavoro, l’ingegnere specializzato in questa materia deve avere ampie conoscenze in tutti i settori dell’ingegneria, e una visione di insieme delle leggi fisiche.
Ad esempio, la robotica, applicazione tipica di questo ramo dell’ingegneria, si occupa del controllo di quegli apparati automatici che riproducono il lavoro umano. Altre applicazioni dell’ingegneria dell’automazione riguardano gli azionamenti elettrici, le smart grids, il controllo di processi chimici, gli impianti manifatturieri, i sistemi elettronici di miglioramento delle prestazioni o della sicurezza a bordo dei veicoli (come ABS ed ESC) e la domotica.
Obiettivi
- Far sì che le macchine possano svolgere in autonomia lavori ripetitivi;
- Sviluppare macchine che possano compiere operazioni che un operatore umano non potrebbe compiere perché richiedono troppa potenza, precisione o velocità;
- Sviluppare macchine che possono lavorare in ambienti che sono ostili o pericolosi per l’uomo.
Nel passato i primi esempi di sistemi di controllo automatico riguardano la realizzazione, quindi il controllo, di orologi e dispositivi per orientare automaticamente i mulini a vento. L’automazione ha avuto un grande sviluppo con la rivoluzione industriale dell’Ottocento con l’introduzione dei telai automatici, delle macchine a vapore: uno dei primi esempi di regolatore industriale è il regolatore di Watt.
James Clerk Maxwell ne analizzò il funzionamento e pubblicò nel 1868 uno studio intitolato “On governors” che si può considerare uno dei primissimi articoli scientifici di controllo automatico. In questo articolo Maxwell dice: “Il regolatore è una parte della macchina attraverso la quale la velocità della macchina stessa è mantenuta costante a dispetto di variazioni della potenza erogata o della resistenza (al moto)”.
La parola “automazione” (nella forma inglese automation) è stata coniata negli Stati Uniti nel 1948 per designare alcuni procedimenti allora molto avanzati introdotti (particolarmente nell’industria automobilistica) e si è da allora largamente diffusa con il significato di impiego di macchine per far andare altre macchine. Con l’automazione si persegue l’obiettivo di controllare la potenza generata dalle macchine. Oggi, grazie alla miniaturizzazione e al basso costo dei calcolatori, il ricorso all’automatizzazione è sempre più elevato: si va dai termostati per regolare la temperatura delle abitazioni, ai sistemi che ci aiutano nella guida, all’hardware che permette la vita digitale.
Sistemi di Numerazione
Sistemi di numerazione per calcolatori
Il calcolatore è una macchina digitale. Il termine digitale proviene dall’inglese digit, che significa numero, a sua volta mutuato dal latino digitus (dito). La definizione deriva dal fatto che tutte le operazioni del calcolatore coinvolgono i numeri. Le informazioni, di qualsiasi natura esse siano, sono conservate in forma numerica e i processi di elaborazione, anche quelli che ci sembrano distanti dalla matematica, come l’elaborazione grafica, operano a livello di calcolo. Le informazioni conservate ed elaborate dai calcolatori si possono approssimativamente dividere in:
- Numeri, interi, frazionari e reali;
- Lettere, conservate tramite opportuni codici che associano a ogni lettera un numero;
- Istruzioni di programmazione, codificate mediante numeri di riferimento, affinché il calcolatore, letto il numero dell’istruzione, possa rintracciare nei suoi circuiti il blocco di sequenze operative adatto a eseguire l’istruzione;
- Informazioni grafiche delle figure rappresentate a video (posizione e colori dei pixel che compongono l’immagine), codificate numericamente;
- Brani audio, clip video, codificati come sequenze estese di numeri.
Tutte queste informazioni sono quindi riconducibili a una sola matrice comune: il numero. Ma come vengono rappresentati i numeri nel computer? Per capirlo, prima ancora di occuparci dei metodi di codifica digitale dei numeri, dobbiamo descrivere come funzionano i dispositivi destinati a registrare questi numeri, perché sono proprio le caratteristiche di questi circuiti, che hanno ispirato l’invenzione di una nuova aritmetica digitale. I numeri sono registrati nella memoria. L’unità più piccola di memoria è un dispositivo chiamato bistabile in figura, che può memorizzare solo due livelli di tensione:
La struttura della memoria impone quindi l’uso di due sole cifre, dette cifre binarie. Il termine cifra binaria, in inglese binary digit, ricorre tanto spesso che è stato coniato il termine sincretico bit (binary-digit). La codifica dei numeri avviene mediante gruppi di 8 bit che costituiscono il byte, l’unità base di memorizzazione dell’informazione. Il byte è sufficiente a conservare una minima quantità di dati, ad esempio una lettera dell’alfabeto. La figura seguente è uno spaccato della memoria del calcolatore: si noti la divisione a catasta dei byte in senso verticale, e la divisione del byte in bit in senso orizzontale.
Sistema di numerazione binario
A differenza del sistema decimale, che dispone di dieci simboli (dallo 0 al 9), nel sistema binario esistono solo due simboli: ‘0’ e ‘1’; per tale ragione il sistema si chiama anche sistema di numerazione in base 2. Nel sistema binario è possibile pertanto contare solo fino a 1; per le cifre superiori si sfrutta il principio della posizionalità: come nel sistema decimale, esaurite le cifre a disposizione, si aggiunge una cifra a sinistra riprendendo a destra il conteggio da 0. Così i numeri 0 e 1 sono codificati ancora come 0 e 1, il 2 come 10, il 3 come 11. Proseguendo nella numerazione con questo criterio si può dedurre la tabella a pagina seguente, che rappresenta la codifica in binario dei numeri decimali dallo 0 al 9. È bene studiarla attentamente e impararne a memoria le configurazioni.
A ogni posizione della cifra è associato un peso. Le cifre, spostandosi da destra a sinistra, hanno peso via via maggiore, ovvero sono più significative. In particolare, osservando la tabella dei pesi, si deduce che la cifra 1 in posizione n ha peso 2n . La seguente tabella dei pesi specifica chiaramente le posizioni delle cifre binarie e i rispettivi pesi.
Per trasformare un numero da binario a decimale, si calcola il peso di ciascuna cifra binaria e si sommano i contributi di tutte le cifre. Es. 10110(2) = ? 10 10110(2) = b0 x 20 + b1 x 2 1 + b2 x 2 2 + b3 x 2 3 + b4 x 2 4 = = 0 x 20 + 1 x 21 + 1 x 22 + 0 x 23 + 1 x 24 = 2 + 4 + 16 = 22(10) Si deduce che con 8 bit si copre l’intervallo numerico 0 ÷ 255, cioè si possono codificare 256 numeri. Questo risultato si potrebbe ottenere sfruttando la seguente regola: 1. Numeri codificabili = 2n con n= numero di bit; 2. Numero massimo codificabile = 2n -1 In questo caso n = 8 perciò risulta appunto: numeri codificabili = 28 = 256. Per convertire un numero decimale in un numero binario, si deve dividere il numero decimale ripetutamente per due, scrivendo nella seconda colonna di una tabella i resti della divisione. Questi danno, letti dal basso verso l’alto, il numero convertito in binario.
Es.
Si deve sempre completare anche l’ultimo passaggio, anche se 1 non è divisibile per due e fornisce sempre risultato 0 e resto 1. Si noti che la divisione per 2 di un numero porge necessariamente un resto ‘0’ oppure ‘1’, appunto una cifra binaria. La freccia indica la direzione di lettura del risultato. La spiegazione del procedimento è intuitiva; praticamente si compie il procedimento opposto rispetto a quello della conversione binario-decimale: mediante le successive divisioni per due si isolano i coefficienti delle singole potenze del 2, dalla cifra meno significativa verso quella più significativa. Consideriamo a scopo introduttivo il sistema decimale, riferendoci a numeri che hanno parte intera e parte frazionaria:
Sistema di numerazione esadecimale
Si è visto, parlando del sistema binario, che il numero di cifre necessarie per codificare un numero è molto più alto del corrispettivo decimale. Ciò introduce una difficoltà di ordine pratico nella rappresentazione dei numeri, che si presentano come lunghe sequenze di ‘1’ e ‘0’ e quindi favoriscono gli errori di trascrizione e lettura. Per esempio una rappresentazione tipica, a quattro byte, richiede 32 bit. Il sistema esadecimale rimedia a ciò fornendo una rappresentazione più compatta, nella quale gruppi di 4 bit si rappresentano con una singola cifra. Questo sistema prevede l’utilizzo di 16 simboli e, per convenzione, vengono usati i 10 simboli del sistema decimale e in aggiunta le sei lettere maiuscole dalla A alla F. L’insieme completo dei simboli è pertanto: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D,E, F. Anche questo sistema, come il binario e il decimale, si basa sul principio della posizionalità. Esaurite le cifre a disposizione per il conteggio, si aggiunge una cifra a sinistra riprendendo a destra il conteggio da 0. Il numero 15 decimale, ad esempio, è qui codificato con un solo simbolo: la lettera F. Passando al 16, non essendo più disponibili ulteriori simboli, si fa scorrere l’unità verso sinistra e si riazzera il conteggio nella posizione a destra. Il numero decimale 16 è quindi rappresentato, stranamente, dal numero 10. Si intuisce che i numeri crescono a una velocità di progressione minore rispetto al sistema decimale, data la maggiore disponibilità di cifre. La tabella della pagina seguente descrive la corrispondenza tra codifica decimale e esadecimale per i numeri fino a 32. Le prime 10 cifre coincidono nei due sistemi. I numeri dal 10 al 15 sono rappresentati da lettere, dopodiché si ha l’applicazione del criterio di posizionalità.
Osservando la tabella si deduce che la cifra 1 in posizione n ha peso 16n ; per questo il sistema esadecimale si chiama anche sistema in base 16. Questa osservazione ci suggerisce le regole di conversione immediata da esadecimale a decimale e viceversa. Le regole sono simili a quelle per il sistema binario, in questo caso sono interessate però le potenze del 16 anziché del 2. Per trasformare un numero da esadecimale a decimale, si calcola il peso di ciascuna cifra esadec. e si sommano i contributi di ciascuna cifra.
Es. conversione esadecimale-decimale
Per convertire un numero decimale in un numero esadecimale, si deve dividere il numero de cimale ripetutamente per sedici, scrivendo nella seconda colonna di una tabella i resti della di visione. Questi danno, letti dal basso verso l’alto, il numero convertito. Conversione decimale-esadecimale
Come già accennato, lo scopo del sistema esadecimale è di rappresentare lunghe sequenze di bit in forma più compatta rispetto al sistema binario, comprimendo quaterne di bit entro una sola cifra esadecimale. Proprio questa caratteristica è in grado di suggerirci il metodo di con versione simultanea da binario a esadecimale: si divide il numero binario in quaterne di bit, a partire dalla cifra meno significativa come mostrato nella figura che segue, e si converte direttamente ciascuna qua terna nella corrispondente cifra. Il metodo è immediato, non richiede alcun calcolo, in quanto la ripartizione in gruppi riduce il campo di variabilità a solo 16 combinazioni. Per la conversione da esadecimale a binario si applica lo stesso criterio in direzione opposta, convertendo ciascuna cifra in una quaterna di bit. Per agevolare la risoluzione dei problemi si riporta la tabella delle 16 cifre esadecimali nella figura che segue e la corrispondente codifica a quattro bit:
Il metodo della conversione simultanea rappresenta una specie di scorciatoia, in alternativa si dovrebbe operare indirettamente attraverso due fasi molto più elaborate. La conversione da binario a esadecimale comporterebbe in una prima fase il passaggio da binario a decimale e in una seconda fase da decimale a esadecimale.
Sistema di numerazione BCD
Nel sistema binario, per esteso binario naturale, la cifra in posizione n vale 2n, dove n indica il posto occupato da un bit, dalla cifra di peso 0 LSB (Least Significant Bit) alla cifra di peso maggiore MSB (Most Significant Bit). Nel sistema BCD (Binary Coded Decimal = decimale codificato in binario) ciascuna cifra decimale viene codificata isolatamente nel corrispondente binario. Ciascuna cifra richiede quattro bit in quanto la cifra decimale più alta, cioè il 9, viene codificata come 1001. Si consideri per esempio il numero decimale 198. A ogni cifra della figura seguente è associata la sua codifica binaria cioè:
Il numero 198 viene pertanto codificato in BCD come 000110011000. Si vede che il sistema è completamente diverso dal binario naturale e richiede in generale un numero di bit maggiore, nell’esempio 3 × 4 = 12 bit. Rappresentare il numero decimale 35 nel sistema di codifica binario naturale e BCD. In binario naturale risulta:
Nel sistema BCD invece risulta:
La presenza nel sistema BCD di cifre scomposte come nel sistema decimale agevola il trattamento dei dati nei sistemi orientati all’aritmetica decimale. Consideriamo per esempio il caso della visualizzazione su display a sette segmenti di un numero decimale a più cifre. Ciascun display è pilotato da un dispositivo decodificatore che accetta in ingresso la codifica BCD del numero da visualizzare. Le cifre BCD sono allora già “pronte” per l’inoltro al modulo hardware e la diretta visualizzazione.
Le quaterne di bit, conservate in una qualsiasi posizione di memoria, si affacciano ai tre integrati pilota per display, che attivano i segmenti opportuni per visualizzare il numero decimale. Lo svantaggio del sistema BCD è dato dalla necessità di effettuare la conversione da binario naturale a BCD. La codifica più comune dei sistemi di elaborazione è infatti il sistema binario naturale.
Algoritmi
Algoritmi e diagrammi di flusso
Prima di cimentarsi nello studio dei linguaggi di programmazione, è opportuno costruire delle fondamenta solide attraverso lo studio degli algoritmi. Una attenta analisi della logica strutturale generale dei programmi aiuta sicuramente a imparare a programmare con rigore logico e rendere fluidi i propri compiti di progettazione.
L’algoritmo è un insieme di passi semplici finalizzati alla risoluzione di un problema. In questo contesto il termine problema non è inteso nel significato restrittivo di elaborazione matematica, ma in quella più generale di processo. Pertanto soddisfano alla definizione di algoritmo anche situazioni comuni, di tutti i giorni, come preparare il caffè o acquistare il giornale, che contemplano una serie di passi distinti e ordinati.
ES. Prendiamo in esame proprio il processo di preparazione del caffè. Il processo può essere scomposto in una sequenza di azioni eseguite passo dopo passo in ordine logico:
- Mettere acqua e caffè nella caffettiera;
- Chiudere la caffettiera;
- Accendere il gas;
- Attendere la bollitura;
- Chiudere il gas;
- Versare il caffè nella tazza;
- Riporre la caffettiera su un materiale non combustibile.
L’algoritmo in generale:
- accetta un insieme di dati di ingresso;
- Li elabora;
- Restituisce un insieme di dati di uscita.
I dati di ingresso sono detti istanza del problema.
Il linguaggio comune è troppo generico per descrivere un algoritmo. Per questo si utilizzano i diagrammi di flusso. Un diagramma di flusso è una rappresentazione visuale del problema, esposta secondo opportune regole formali. L’implementazione del diagramma di flusso secondo un dato linguaggio di programmazione è il programma. Il programma viene eseguito dal calcolatore. L’esecuzione dell’algoritmo da parte del calcolatore è detta computazione. I dati di ingresso e uscita sono supportati da variabili: una variabile è un simbolo associato alla locazione di memoria che il sistema operativo del computer esecutore assegna al dato. L’algoritmo, per essere un metodo realistico di risoluzione di problemi, deve soddisfare i seguenti requisiti.
- Finitezza: l’algoritmo deve essere composto da un numero finito di passi elementari; in teoria non si pone limite né di tempo né di memoria impegnati per ogni passo, basta siano finiti. Nello sviluppo di un algoritmo è assolutamente necessario curare che non si verifichino cicli infiniti, ovvero ripetizioni con condizioni mai soddisfatte di uscita dal ciclo. Naturalmente è preferibile un algoritmo che spreca poche risorse, ma questo è un problema pratico di efficienza, che esula dalla finitezza.
- Non Ambiguità: l’algoritmo deve essere interpretabile in modo univoco da un qualsiasi esecutore. Il risultato deve essere deterministico, ovvero non deve portare a risultati diversi nel tempo, salvo il caso in cui il comportamento differenziato sia prestabilito. Il linguaggio utilizzato deve essere chiaro e attento, perciò viene utilizzato un formalismo rigoroso che non si ritrova nel linguaggio umano, spesso troppo approssimativo o viceversa appesantito da dettagli ininfluenti.
- Realizzabilità: l’algoritmo deve essere realizzabile con le risorse a disposizione del linguaggio.
I diagrammi di flusso sono mappe concettuali per la rappresentazione di algoritmi, che coniugano rigore concettuale a potenza espressiva. Le diverse sezioni dell’algoritmo sono rappresentate mediante simboli grafici collegati tramite frecce orientate, che specificano verso e direzione del flusso. I principali simboli convenzionali sono:
- Elaborazione: istruzione esecutiva;
- Inizializzazione: impostazione di valori iniziali alle variabili di input;
- Input/output: operazioni di lettura e scrittura;
- Condizione: test; 5. inizio: inizio algoritmo;
- Fine: fine algoritmo.
Le strutture di controllo fondamentali alla base degli algoritmi sono:
- Sequenza semplice;
- Selezione semplice o multipla;
- Iterazione postcondizionale, precondizionale, ciclo iterativo.
Sequenza semplice
Il flusso esecutivo procede dall’alto al basso in modo preordinato, come in figura, dove al blocco 1 segue il blocco 2.
Entro ciascun blocco si svolgono queste attività:
- Elaborazione di dati mediante calcoli aritmetico-logici;
- Copia di valori entro variabili o scambio del contenuto di variabili.
Selezione semplice o multipla Il flusso esecutivo può diramarsi in percorsi diversi, in funzione del verificarsi di una condizione. La condizione è rappresentata dal risultato di una espressione logica, che può avere solo due valori: TRUE o FALSE. Nella selezione multipla, come descritto dal diagramma di flusso sottostante, il programma percorre due diversi flussi alternativi, in funzione del risultato dell’espressione logica.
- Se la condizione è TRUE il programma percorre il ramo etichettato come VERO e incontra il blocco delle “istruzioni condizione vera”;
- Se la condizione è FALSE il programma percorre il ramo etichettato come FALSO e incontra il blocco delle “istruzioni condizione falsa”.
Nella selezione semplice il programma esegue il blocco delle “istruzioni condizione vera/falsa” se la condizione è vera/falsa, altrimenti procede in sequenza.
Iterazione postcondizionale, precondizionale, ciclo iterativo L’iterazione o ciclo è una ripetizione condizionata di una sequenza di istruzioni. A seconda della posizione della condizione rispetto alla sequenza di istruzioni da iterare si hanno:
- Cicli postcondizionali;
- Cicli precondizionali.
Nei cicli postcondizionali, detti anche a condizione finale:
- La condizione è controllata dopo l’esecuzione della sequenza di istruzioni;
- Pertanto la sequenza istruzioni viene eseguita almeno una volta.
Questa modalità è impiegata:
- Quando il risultato della condizione dipende da istruzioni che devono precederla;
- In particolare nella prima iterazione, la mancata esecuzione delle istruzioni potrebbe condurre a una condizione indeterminata.
Nei cicli precondizionali, detti anche a condizione iniziale:
- La condizione è controllata prima della sequenza di istruzioni;
- Pertanto non è sempre garantita l’esecuzione della sequenza di istruzioni, perché se la condizione è subito falsa il ciclo non viene mai eseguito.
Questa modalità è utile quando l’esecuzione o meno della sequenza di istruzioni deve essere subordinata a un controllo a priori.
Il ciclo iterativo è un caso particolare del ciclo precondizionale, che per la sua comodità viene implementato alla radice in tanti linguaggi di programmazione.
Il ciclo mette a disposizione una variabile interna I deputata al conteggio del numero di iterazioni. Quando I raggiunge il massimo numero prestabilito di iterazioni il ciclo termina. Osservando più da vicino lo schema di flusso si nota che, nell’ordine:
- I viene inizializzata a 0;
- Viene verificata subito la condizione I< MAX;
- Se la condizione è vera viene eseguita la “sequenza istruzioni”;
- . I viene incrementata: I = I + 1;
- Viene ripetuto il test.
L’effetto complessivo è la ripetizione MAX volte della “sequenza istruzioni”: questo è l’impiego più comune di questo tipo di ciclo.
La programmazione strutturata è un criterio che disciplina la stesura di programmi, imponendo l’utilizzo di tre soli tipi di strutture di controllo fondamentali:
- Sequenza;
- Selezione;
- Iterazione.
Con queste restrizioni la programmazione strutturata bandisce l’uso dei salti, che in passato erano un metodo piuttosto “anarchico” di scrittura di programmi. A fronte di una libertà assoluta per il programmatore i salti, implementati da istruzioni di tipo goto, rendevano ardua la comprensione dei programmi. Un programma ben strutturato: facilita la leggibilità, la comprensione, la verifica della funzionalità, la correzione, l’aggiornamento. Per sviluppare un algoritmo strutturato si applica il procedimento top down, che consiste nel:
- Partire da una formulazione generica delle sezioni principali dell’algoritmo;
- Espandere l’algoritmo per raffinamenti successivi;
- Esplicitare ogni passo mediante una struttura di controllo fondamentale.
Il teorema di Jacopini-Bohm assicura che qualsiasi diagramma di flusso può essere trasformato in un diagramma equivalente che utilizza solo le tre strutture di controllo fondamentali, pertanto i diagrammi di flusso strutturati sono adatti a risolvere ogni classe di problemi. Per capire se un diagramma di flusso rispetta i criteri della programmazione strutturata si applica al diagramma finito un procedimento di riduzione. Se con questo criterio il diagramma si semplifica progressivamente, incontrando solo strutture di controllo fondamentali, fino a ridursi a un singolo blocco, allora si tratta di un diagramma di flusso strutturato.
L’efficienza di un algoritmo si misura attraverso due parametri fondamentali di spazio e tempo:
- Spazio di memoria occupato o più in generale risorse impegnate;
- Tempo di esecuzione.
Il parametro spazio di memoria è stato un fattore importante in passato, ma la crescita enorme delle memorie a grande capacità e basso costo ha messo abbastanza in secondo piano questo problema.
Il fattore tempo è invece fondamentale, ma esso è a sua volta legato a altri due fattori:
- Numero di passi risolutivi;
- Tempo speso per ogni passo.
Mentre la seconda è una variabile che progressivamente si abbassa in funzione del progresso tecnologico, il numero di passi di esecuzione è legato solo a un fattore intellettuale, ovvero la capacità dell’uomo di individuare soluzioni sempre più brillanti e ottimali. Pertanto è sulla riduzione dei passi risolutivi che si spende la teoria degli algoritmi.
La Programmazione in Linguaggio C, C# e C++
Nonostante la sua età e la proliferazione di nuovi linguaggi, il C++ continua a rappresentare uno standard “de facto” per la programmazione di applicativi. La conoscenza dei suoi costrutti di base è il punto di partenza per l’apprendimento di linguaggi più specialistici, rivolti a Internet (JavaScript), alla robotica (ROBOTC), alla simulazione (MATLAB). Il C++ è inoltre diffuso in ambito accademico, infatti molti corsi propedeutici di informatica nelle università lo adottano come entry level; inoltre è il linguaggio ufficiale delle Olimpiadi di Informatica.
I dati manipolati dai programmi sono immagazzinati nella memoria del computer. La memoria è organizzata in bit e byte. L’indirizzo di memoria è il numero d’ordine della locazione di memoria. La memoria può immagazzinare sostanzialmente due tipi di dati di base:
- Numeri;
- Caratteri.
I numeri sono codificati in binario. Possono essere interi oppure reali, cioè con virgola. Un byte può contenere un numero compreso tra 0 e 255. Per valori superiori è necessario impiegare due byte (Word) o più.
I caratteri sono anch’essi codificati in binario, come sequenze di 8 bit, per mezzo del codice ASCII (American Standard Code for Information Interchange = Codice Standard Americano per lo Scambio di Informazioni), che si è imposto come codice di riferimento universale. Il codice ASCII è presente in due versioni:
- Il codice ASCII standard a 7 bit, che associa a ogni carattere un numero, compreso tra 0 e 127, e comprende le lettere dell’alfabeto minuscole e maiuscole e i vari segni di punteggiatura;
- Il codice ASCII esteso a 8 bit, che include anche i numeri compresi tra 128 e 255, per la codifica di alcuni simboli specifici delle diverse località geografiche. La tabella seguente è uno stralcio della tavola completa, facilmente reperibile in Internet. Vi sono elencate le codifiche esadecimale, decimale, binaria dei numeri dallo 0 al 9 e di alcuni caratteri.
Alcuni caratteri del codice standard sono dei comandi. Questo significa che non sono stampabili ma danno luogo ad azioni. Nel linguaggio C questi tipi di caratteri sono rappresentati mediante simboli detti sequenze di escape. La tabella nella pagina seguente riporta i più significativi, con la specifica dell’azione.
È possibile esprimere un carattere non presente nella tastiera mediante il simbolo \x seguito dal codice ASCII in esadecimale.
Il linguaggio C dispone di tipi di dati predefiniti, a disposizione dell’utente. I tipi differiscono per la dimensione, che è il numero di byte e per le modalità di memorizzazione.
I tipi base sono:
- Tipi interi e char;
- Tipi reali.
Per il tipo Integer valgono le seguenti regole:
- Con n bit si possono codificare 2n numeri interi;
- Un numero intero può essere con segno (signed) e senza segno (unsigned);
- A parità di numero di bit, un signed può registrare numeri più piccoli di un unsigned, perché l’insieme dei valori esprimibili deve essere condiviso dai positivi e negativi;
- A partire dai tipi base, si possono applicare i modificatori short e long, che permettono rispettivamente di contrarre o espandere la dimensione.
Il tipo char memorizza caratteri in codice ASCII a 8 bit. È equivalente al tipo unsigned short int. I tipi reali permettono la rappresentazione di numeri con virgola, nella forma: ±1, Mantissa • 2esponente I tipi base sono float e double, che differiscono per il numero di bit riservati a mantissa e esponente.
Le combinazioni dei tipi possono essere diverse e le dimensioni possono dipendere dal compilatore. La seguente tabella riassume i tipi più significativi supportati dal linguaggio C, con l’indicazione della dimensione e del range.
Variabili e Costanti
Una variabile è una porzione di memoria dove collocare un dato. La variabile viene rappresentata da un identificatore. L’identificatore è un nome che viene associato alla locazione di memoria assegnata al dato. Il meccanismo degli identificatori semplifica drasticamente il compito del programmatore che non deve preoccuparsi né di indicare l’indirizzo di collocazione in memoria del dato né del numero di byte che esso occupa. Queste operazioni sono completamente trasparenti al programmatore e vengono compiute dal programma di sviluppo in collaborazione con il sistema operativo. La dichiarazione di variabile è lo strumento utilizzato dal programmatore per creare una variabile di memoria. La sintassi della dichiarazione prevede di specificare il tipo della variabile seguito da un nome, detto identificatore. È possibile dichiarare più variabili dello stesso tipo, separandole con virgole. Dichiarazioni di diverso tipo devono essere separate dal punto e virgola.
ES. Dichiara una variabile di tipo int, di nome NUM.
Int NUM;
Int NUM1; NUM2 ;NUM3;
Int NUM; float RISULTATO;
L’identificatore per essere valido deve:
- Contenere lettere, numeri, simbolo underscore; non sono permessi spazi e punti;
- Iniziare con una lettera;
- Non coincidere con una parola riservata del linguaggio.
Il linguaggio C è “case sensitive”, ovvero distingue le lettere minuscole da quelle maiuscole. Pertanto due identificatori con lo stesso nome ma diversa collocazione delle minuscole/maiuscole, non sono equivalenti.
Es.
Dichiarazioni valide: int NUM3; float A123; int LATO_X;
Dichiarazioni NON valide: int LATO X; int 1LATO; int float;
Le costanti sono dotate di un nome e localizzate in memoria come le variabili, ma al contrario di queste non sono modificabili. Le costanti si dichiarano nella testata del programma mediante la parola chiave #define. Ad esempio #define PIgreco 3.14 dichiara una costante di nome PIgreco e valore 3.14.
La costante potrà essere utilizzata con il suo simbolo PIgreco nel corpo di programma, anche molte volte. Qualora si dovesse modificare il suo valore, si potrà correggerlo una volta sola nella dichiarazione, senza doverlo ritoccare in tutte le espressioni dove compare.
Operatori ed espressioni
Gli operatori mettono in relazione variabili e costanti. Si suddividono principalmente in operatori:
- Di assegnamento;
- Aritmetici;
- Relazionali;
- Logici;
- Orientati al bit.
L’operatore di assegnamento = serve in prima istanza ad assegnare un valore a una variabile, ma si utilizza anche per assegnare il valore di una variabile a un’altra variabile. La direzione di assegnamento è da destra a sinistra, ovvero: il dato presente a destra dell’uguale viene copiato nella variabile a sinistra.
Es. Assegnare il valore 3 alla variabile NUM Int NUM; NUM = 3
Assegnare il valore di NUM1 a NUM2 NUM2 = NUM1
Gli operatori relazionali sono operatori di comparazione che permettono di mettere a confronto i dati. Il risultato di una operazione relazionale è un valore booleano di vero o falso. Le espressioni fondono l’azione dei diversi operatori sugli operandi. Gli operatori aritmetici danno luogo a espressioni aritmetiche, gli operatori relazionali e logici a espressioni logiche. Dal punto di vista numerico i valori booleani true e false corrispondono rispettivamente a 1 e 0. Pertanto sono possibili anche espressioni miste. Le regole di priorità delle operazioni sono mutuate dalla matematica. È sempre possibile, come nell’algebra, alterare l’ordine di esecuzione con l’uso delle parentesi.
Le istruzioni di scrittura/lettura aggiungono al programma caratteristiche interattive. Le istruzioni di lettura trasferiscono i dati dall’esterno al computer, attraverso il dispositivo di input, che di default è la tastiera. Le istruzioni di scrittura trasferiscono i dati dal computer all’esterno, attraverso il dispositivo di output, che di default è lo schermo. Il C standard dispone delle seguenti due istruzioni di scrittura/lettura:
- printf;
- scanf.
Il C++ mette a disposizione: - cout;
- cin.
L’istruzione printf serve a rappresentare, sul video, messaggi e valori di variabili. Per rappresentare a video un messaggio basta mettere tra parentesi rotonde la stringa costante da visualizzare, racchiusa tra virgolette. Per rappresentare una o più variabili si deve:
- “prenotare” la posizione che le variabili devono occupare all’interno del messaggio, per mezzo di specificatori di formato. Il messaggio, in questo caso, prende il nome di stringa di formattazione, appunto perché definisce le caratteristiche del formato del messaggio;
- far seguire il messaggio dall’elenco delle variabili, separate da virgole. Lo specificatore di formato è un simbolo, preceduto da %, associato al tipo di variabile da rappresentare. La tabella sotto a sinistra riporta i vari specificatori di formato. Quella a destra riporta i modificatori di tipo, che servono a specificare un ulteriore attributo al tipo.
Un numero inserito in uno specificatore come %d tra il carattere % e il carattere d indica di quante posizioni il numero deve essere giustificato a destra. È utile per distanziare i numeri rappresentati.
Due numeri separati dal punto inseriti nello specificatore %f tra il carattere % e il carattere f indicano:
- Il primo lo spazio a disposizione per la stampa, con giustificazione a destra;
- Il secondo il numero di decimali visualizzati.
La scanf serve a acquisire dalla tastiera dei valori e assegnarli alle variabili. È necessario mettere tra virgolette gli specificatori di formato delle variabili, che vanno separati da virgole. Le variabili devono essere precedute dal simbolo & (ampersand). L’istruzione cout serve a stampare a video messaggi o valori di variabili. I messaggi devono essere racchiusi tra virgolette.
La cout è sempre abbinata all’operatore di inserzione <<È possibile impiegare una modalità mista, con più operatori di inserzione, per stampare a video combinazioni di messaggi e variabili. L’istruzione cin serve ad acquisire dalla tastiera dei valori e assegnarli alle variabili. La cin è sempre abbinata all’operatore di inserzione >>.
In C il programma deve essere racchiuso all’interno della funzione principale “main” mediante parentesi graffe aperta e chiusa. Ogni istruzione di norma deve essere separata dalla successiva dal punto e virgola. Per ragioni di chiarezza è opportuno inserire nel programma delle spiegazioni, dette commenti, che non hanno effetto sul programma.
I commenti possono essere specificati in due modi:
- Su singola riga con il simbolo //;
- Su più righe racchiudendo la frase di commento entro i simboli /* e */.
La clausola #include permette di incorporare funzioni implementate entro le librerie del compilatore. La clausola #define per la definizione di costanti permette di attribuire un nome a un valore costante.
La struttura condizionale
Una struttura condizionale permette di selezionare percorsi alternativi di esecuzione del programma, in funzione delle condizioni che si verificano. Si annoverano le seguenti strutture:
- IF-ELSE;
- IF;
- IF-ELSE nidificati;
- SWITCH.
Come descritto dal diagramma di flusso, il programma percorre due diversi flussi alternativi, in funzione del risultato di una espressione logica o condizione.
- Se l’espressione logica è TRUE il programma percorre il ramo etichettato come VERO e incontra il blocco delle “istruzioni da eseguire se espressione logica vera”.
- Se l’espressione logica è FALSE il programma percorre il ramo etichettato come FALSO e incontra il blocco delle “istruzioni da eseguire se espressione logica falsa”.
Se le istruzioni da eseguire se la condizione è vera/falsa sono più di una, è necessario racchiuderle tra le parentesi graffe aperta e chiusa. Si ha una struttura nidificata o annidata quando all’interno di un blocco IF-ELSE è racchiuso un altro blocco IF-ELSE. La struttura SWITCH viene utilizzata quando le condizioni da verificare sono numerose. Questa soluzione risulta più lineare e formalmente corretta rispetto all’adozione di diversi IF in cascata, che possono compromettere la leggibilità del programma.
I cicli
I CICLI sono strutture iterative, che permettono di ripetere ciclicamente sequenze di istruzioni, in funzione del verificarsi di determinate condizioni.
Tra i cicli si annoverano le seguenti strutture iterative:
- CICLO FOR;
- CICLI FOR NIDIFICATI;
- CICLI DO-WHILE e WHILE.
Il ciclo FOR è organizzato, nella sua veste più semplice e utile, mediante una variabile contatore, come la i, che viene inizializzata all’entrata nel ciclo e incrementata a ogni iterazione. È utilizzato, in questa veste, quando il numero di ripetizioni N della sequenza di istruzioni è noto a priori. La logica del ciclo for è descritta dallo schema a blocchi di figura.
Si ha una struttura nidificata o annidata quando all’interno di un ciclo FOR è racchiuso un altro ciclo FOR. I cicli DO-WHILE e WHILE ripetono una sequenza di istruzioni mentre (while) la condizione è vera. Nel DO-WHILE:
- La condizione è controllata dopo l’esecuzione della sequenza di istruzioni (post condizionale), pertanto la sequenza istruzioni viene eseguita almeno una volta;
- Questa modalità è impiegata quando il risultato della condizione dipende da istruzioni che devono precederla. In particolare nella prima iterazione la mancata esecuzione delle istruzioni potrebbe condurre a una condizione indeterminata. Nel WHILE:
1. La condizione è controllata prima della sequenza di istruzioni (precondizionale), pertanto non è garantita sempre l’esecuzione della sequenza di istruzioni, perché se la condizione è subito falsa il ciclo non viene mai eseguito;
2. questa modalità è utile quando l’esecuzione o meno della sequenza di istruzioni deve essere subordinata a un controllo a priori;
Vettori e matrici
Un vettore è una variabile che raggruppa un insieme omogeneo di dati, cioè dati dello stesso tipo: int, float… Un vettore ha un nome univoco, ma una molteplicità di contenuti: grazie a questo è possibile memorizzare N numeri diversi con un unico identificatore, anziché dichiarare N variabili diverse. Il vettore può essere rappresentato visivamente da un insieme di caselle; ogni casella è identificata da un indice, un numero che esprime la sua posizione d’ordine. Nella seguente figura è rappresentato a titolo esemplificativo un vettore di dimensione 8 nel quale:
- Le caselle sono numerate da 0 a 7;
- La sesta casella è individuata da INDICE = 5;
- Il contenuto della casella di indice 5 è 2.
La dichiarazione di un vettore prevede di specificare:
- Il tipo della variabile;
- Il nome della variabile;
- La estensione, cioè il numero di caselle.
L’accesso al contenuto di una casella può avvenire attraverso una variabile con indice i. Il valore dell’indice può essere comandato da un ciclo for. L’abbinamento di ciclo for e vettore crea una sinergia potentissima: con poche righe di codice è possibile eseguire innumerevoli operazioni. Una matrice è un vettore multidimensionale. In particolare una matrice bidimensionale, detta anche vettore di vettore, può essere rappresentata come una tabella di dimensione n righe e m colonne, come in figura.
La dichiarazione prevede la specifica del nome e, tra parentesi quadre, delle due dimensioni. Per accedere a una casella in lettura o scrittura, si devono specificare le sue coordinate. Una matrice può essere inizializzata direttamente in fase di dichiarazione, ponendo i valori delle caselle tra parentesi graffe, separati da virgole nell’ordine da sinistra a destra e dall’alto in basso. Nel caso di una matrice bidimensionale è necessario adottare due indici:
- Un indice i per l’identificazione della riga;
- Un indice j per l’identificazione della colonna.
Per scandire tutta la matrice è necessario muovere entrambi gli indici: per questo si fa ricorso ai cicli nidificati.
Funzioni
Una funzione è un modulo di programma autonomo, predisposto per svolgere compiti specifici. Il programma principale può chiamare una funzione, per richiederne l’ausilio nello svolgimento dell’elaborazione. Nel caso di funzioni senza passaggio di parametri, per definire una funzione basta darle un nome e specificare con “void” che essa non riceve e non restituisce nulla.
Es.
Void Funzione1 (void)
{
}
Il seguente programma principale chiama prima funzione 1 e poi funzione 2.
Nel caso di funzioni con passaggio di parametri:
- Il programma chiamante passa dei dati in ingresso alla funzione, detti parametri o argomenti di input;
- La funzione li elabora e restituisce al programma chiamante il risultato, detto valore di ritorno o valore restituito.
Dopo aver razionalizzato un programma con l’uso delle funzioni, è utile poterle organizzare all’interno di un menu di scelta. Il menu deve:
- Prevedere un insieme di scelte alternative;
- Consentire la scelta della funzione e attivare la sua esecuzione;
- Consentire di proseguire o terminare il programma.
Grazie alle funzioni un problema viene decomposto in sottoproblemi (sottoprogrammi o subroutine) di complessità ridotta, con vantaggi in termini di:
- Leggibilità:
• ogni funzione ha un nome che richiama i suoi compiti,
• si individuano facilmente le parti funzionali nel programma chiamante,
• si intuisce la struttura logica del programma chiamante; - Sviluppo:
• si possono utilizzare funzioni sviluppate da terze parti,
• i programmatori possono lavorare in team sullo stesso progetto con compiti diversi; - Manutenzione:
• si possono aggiornare solo i moduli che richiedono una revisione,
• si possono individuare direttamente i moduli che contengono dei bug; - Efficienza:
• la medesima funzione può essere riutilizzata nello stesso o in altri programmi,
• la medesima funzione può operare a ogni chiamata su insiemi di dati diversi.
Funzioni predefinite
Il linguaggio C mette a disposizione delle librerie di funzioni predefinite. Queste funzioni sono già scritte, il programmatore deve solo conoscere:
- La funzione che svolgono;
- Con quali modalità chiamarle;
- Quali parametri di input passare;
- Quale valore di ritorno ricevere.
Per utilizzare una funzione predefinita è necessario includere nel programma la libreria afferente, mediante la direttiva #include.
Consideriamo, per proseguire il ragionamento, la funzione SQRT (SQuaRe rooT = radice quadrata), che appartiene alla libreria math.h delle funzioni matematiche. Essa:
- Calcola la radice quadrata di un numero;
- Accetta come parametro di input il radicando di tipo float;
- Restituisce un valore di ritorno di tipo float.
Nel prototipo sono specificati:
- Il nome della funzione;
- Il tipo dei parametri di input e il nome (opzionale);
- Il tipo del valore di ritorno.
Per utilizzare la funzione si deve:
- Disporre tra parentesi la serie dei parametri di input separati da virgole;
- Assegnare la funzione a una variabile, tramite l’operatore di assegnamento =.
Funzioni utente
Una funzione utente non preesiste, ma è creata dal programmatore. Sviluppiamo il ragionamento attraverso un esempio. Si debba scrivere una funzione che accetti in input due numeri e restituisca in output il maggiore. L’implementazione è la seguente:
In essa si distinguono:
- Le dichiarazioni dei parametri di input A, B;
- Il tipo dei parametri di input, in questo int;
- La dichiarazione di una variabile interna MAX;
- Le istruzioni di elaborazione;
- La parola chiave return, che fissa il parametro di output.
Il programma principale, per utilizzare la funzione, deve:
- Chiamarla con il suo nome;
- Disporre tra parentesi la serie dei parametri di input separati da virgole;
- Assegnare la funzione a una variabile, tramite l’operatore di assegnamento =.
Nel programma principale la funzione può essere richiamata tante volte, ogni volta con parametri diversi.
- I parametri dell’istruzione chiamante, nell’esempio NUM1 e NUM2, sono detti parametri attuali, perché mutano di volta in volta.
- I parametri della funzione, nell’esempio A, B, sono detti parametri formali.
L’operazione di copia del valore dei parametri attuali nei parametri formali è detta passaggio di parametri. Il metodo delle funzioni può apparire inizialmente macchinoso, ma con la pratica si scopre che è imprescindibile. Senza le funzioni con passaggio di parametri una operazione complessa formata da migliaia di istruzioni dovrebbe essere riscritta tante volte quanti sono i diversi set di parametri che la chiamano.
Variabili locali e globali
In un programma scritto con funzioni coesistono blocchi di diverso livello:
- Un primo livello esterno al main;
- Un secondo livello, il main, che è esso stesso una funzione, la funzione principale;
- Un terzo livello delle funzioni utente.
Si definisce spazio di visibilità o validità (scope) di una variabile la regione del programma nella quale essa è visibile, ovvero utilizzabile.
Con riferimento ai diversi livelli si hanno le seguenti definizioni:
- Si definisce variabile globale una funzione dichiarata nel livello esterno;
- Si definisce variabile locale una variabile dichiarata in un sottolivello, per esempio una funzione.
Le corrispondenti regole di visibilità sono:
- Una variabile globale è visibile a tutti i livelli;
- Una variabile locale è visibile solo nel livello nel quale è dichiarata.
Per esempio nella funzione maggiore prima implementata è presente una variabile locale MAX. Essa è visibile all’interno della funzione MAGGIORE, ma non all’esterno.
I vantaggi delle variabili locali sono:
- Migliore leggibilità
➞ perché chi legge il programma rintraccia le variabili nell’ambiente dove sono utilizzate; - Portabilità delle funzioni
➞ perché ogni funzione reca con sé le proprie variabili quindi può essere riutilizzata in altri programmi senza pesanti modifiche; - Minore possibilità di errore
➞ perché altrimenti diverse funzioni potrebbero accedere erroneamente alla stessa variabile globale, con scopi diversi; - Minore occupazione di memoria
➞ perché vengono allocate in memoria solo all’inizio dell’esecuzione della funzione.
Stringhe
Una stringa è una variabile che raggruppa una sequenza di caratteri, pertanto è uno speciale vettore di caratteri. Nel complesso una stringa può accogliere singole parole o intere frasi. A differenza del vettore è conclusa dal carattere speciale ‘\0’ che ne delimita la fine, detto carattere terminatore o NULL. Grazie al carattere terminatore è possibile:
- Delimitare la fine della stringa in tutte le situazioni, senza alcuna ambiguità;
- Dichiarare una sola volta la stringa con una lunghezza prestabilita, ma memorizzare sequenze di caratteri più corte della effettiva lunghezza della stringa. La stringa, come il vettore, può essere rappresentata visivamente da un insieme di caselle, numerate a partire da 0. In figura è rappresentata una stringa di 8 caselle così caratterizzata:
1. le caselle sono numerate da 0 a 7;
2. ogni casella è identificata da un indice, un numero che esprime la sua posizione d’ordine;
3. per esempio la terza casella è individuata da INDICE = 2; il suo contenuto è la lettera ‘A’;
4. la stringa è conclusa dal carattere terminatore;
5. le caselle 5, 6, 7 sono vuote oppure, se hanno un contenuto, questo è ininfluente.
La dichiarazione di una stringa prevede di specificare:
- Il tipo della variabile, che è un char;
- Il nome della variabile;
- La estensione, cioè il numero di caselle.
ES.
Modalità di lettura/scrittura
Sono due le modalità di scrittura/lettura dei contenuti di una stringa:
- Lettura/scrittura di ogni singola casella;
- Lettura/scrittura dell’intera stringa.
Lettura/scrittura di ogni singola casella:
In questo caso l’accesso alla casella avviene, esattamente come in un vettore, specificando il nome della stringa con l’indice racchiuso tra parentesi quadre.
ES.
Lettura/scrittura dell’intera stringa:
Poiché le stringhe possono contenere intere frasi, per favorire l’immissione e la visualizzazione del contenuto si possono utilizzare istruzioni che leggono/scrivono intere frasi in un’unica soluzione, a prescindere dai cicli for.
Per la lettura e la scrittura di una stringa si usano rispettivamente le istruzioni gets (get string) e printf. L’utilizzo di printf avviene come di consueto, cambia solo lo specificatore di formato che è %s (s = iniziale di stringa).
Una stringa può essere inizializzata direttamente in fase di dichiarazione in due modi:
- ponendo i caratteri delle caselle tra parentesi graffe, racchiusi da apici e separati da virgole;
- specificando l’intera stringa tra virgolette.
Programmazione delle stringhe
La programmazione casella per casella si utilizza quando è necessario accedere individualmente a ciascuna casella, soprattutto all’interno di cicli. Se viene utilizzato un ciclo for, poiché non è nota a priori la frase che viene digitata, non è possibile stabilire a priori il numero di iterazioni del ciclo. L’uscita dal ciclo viene allora stabilita in coincidenza con l’incontro del carattere terminatore. Per controllare se la casella i-esima contiene tale carattere si utilizza l’espressione: stringa[i]! = ’\0’
Nel linguaggio C sono incorporate alcune funzioni di libreria per la manipolazione delle stringhe. Per utilizzarle è necessario includere la libreria string.h.
- Funzione strlen (STRINGA) Calcola la lunghezza di una stringa, ovvero il numero dei caratteri costituenti. Il termine strlen è la contrazione di string length = lunghezza stringa. La funzione accetta tra parentesi il nome della stringa e restituisce il numero di caratteri.
- Funzione strcat (STRINGA1, STRINGA2) Concatena due stringhe. La stringa risultante viene caricata in STRINGA1. Il termine strcat è la contrazione di string concatenation = concatenazione stringa. La funzione accetta due stringhe tra parentesi, le concatena e restituisce il risultato dell’operazione nella stringa a sinistra, che risulta pertanto sovrascritta.
- Funzione strcpy (STRINGA1, STRINGA2) Copia una stringa sorgente STRINGA 2 entro una stringa destinazione STRINGA1. Il termine strcpy è la contrazione di string copy = copia stringa. La funzione copia una stringa sorgente a destra nella stringa destinazione a sinistra.
- Funzione strcmp Confronta il contenuto di due stringhe. La funzione restituisce valore: 0 se STRINGA1 = STRINGA2 ovvero se le due stringhe sono uguali. > 0 se STRINGA1 > STRINGA2 ovvero se STRINGA1 segue STRINGA2 in ordine alfabetico.
Elenchi
Un elenco è un vettore nel quale ogni cella è occupata da una stringa. Ogni cella dell’elenco è pertanto a sua volta ripartita in celle di tipo carattere. La rappresentazione di un elenco è bidimensionale. Come si vede nella figura a pagina seguente, l’elenco viene descritto figurativamente come un insieme di righe.
- Ogni riga è una stringa.
- Ogni stringa è un insieme di caratteri.
Nel complesso un elenco si presenta allora come una matrice avente:
- Numero di righe pari al numero di stringhe;
- Numero di colonne pari al numero dei caratteri.
La dichiarazione di un elenco prevede di specificare:
- Il tipo della variabile, che è un char;
- Il nome della variabile;
- La estensione, intesa come numero di righe (parole) e colonne (caratteri per parola).
Modalità di lettura/scrittura
Tre sono le modalità:
- Lettura/scrittura di ogni singola casella;
- Lettura/scrittura di una intera riga;
- Lettura/scrittura dell’intero elenco.
Lettura/scrittura di ogni singola casella:
L’individuazione di una casella avviene specificando la sua posizione. La posizione è data dalle coordinate di riga e di colonna.
Lettura/scrittura di una intera riga: L’individuazione di una intera riga avviene specificando solo il numero di riga e omettendo il numero di colonna.
Lettura/scrittura dell’intero elenco: Non esiste la possibilità di acquisire o stampare a video un elenco in un’unica soluzione. L’operazione va compiuta riga per riga, entro un ciclo. Dato che ogni riga è una stringa, le modalità sono analoghe a quelle delle stringhe. L’elenco può essere inizializzato direttamente in fase di dichiarazione, ponendo tra parentesi graffe le stringhe di nomi, racchiuse da apici e separate da virgole.
Programmazione degli elenchi
La gestione degli elenchi avviene con le stesse modalità delle stringhe, ma in modo ricorsivo.
Struttura
Le strutture sono tipi di dati avanzati, che permettono di organizzare in modo strutturato una pluralità di dati eterogenei. A differenza di un elenco, che può solo memorizzare nomi, un vettore di struttura può contenere una intera agenda, completa di nomi, indirizzi, numeri di telefono… Una struttura è un tipo di dato adatto ad accogliere dati eterogenei. La struttura raggruppa sotto un singolo nome diversi elementi di memoria, detti campi.
Ogni campo può essere di tipo e dimensione diversa, a differenza dei vettori, che raggruppano dati omogenei.
Nella rappresentazione vengono evidenziati i diversi campi eterogenei che appartengono alla struttura. Ogni campo può essere formato da diversi elementi omogenei. Nella figura, una struttura di nome ALUNNO contiene i campi:
- COGNOME di tipo stringa ➞ memorizza il cognome dell’alunno;
- MATRICOLA di tipo stringa ➞ memorizza il suo codice alfanumerico di matricola;
- MEDIA di tipo int ➞ memorizza la media complessiva delle materie di studio.
La dichiarazione di una struttura prevede di specificare:
- Il NOME della struttura, preceduto dalla clausola struct;
- Tra parentesi graffe i campi, nella modalità consueta di dichiarazione di variabile.
Attenzione: ALUNNO è un nuovo tipo di dato definito dal programmatore, non una variabile. Per dichiarare una nuova variabile di tipo ALUNNO si deve specificare come di consueto: il tipo della variabile, che è ALUNNO, preceduta dalla parola chiave struct; il nome della variabile.
Per accedere a un campo di una variabile di tipo struttura si deve scrivere il nome della variabile, seguito da un punto e dal nome del campo che interessa. Per accedere a sottoelementi di ciascun campo si utilizzano le regole valide per il tipo di campo. È possibile inizializzare una struttura direttamente in fase di dichiarazione, ponendo tra parentesi graffe i dati, nell’ordine della sequenza dei campi. È sufficiente sapere che ai campi si accede mediante il simbolo del punto; per il resto sono valide le metodologie consuete.
Vettore di struttura
Un vettore di struttura è un insieme di caselle, contenenti ciascuna una intera struttura. I vettori di struttura sono strutture dati complete, con le quali implementare basi di dati. Nella rappresentazione ogni cella del vettore contiene una intera struttura. La struttura è univoca per tutte le celle. In figura è rappresentato un vettore di N caselle, contenente ognuna la struttura ALUNNO.
La dichiarazione prevede di specificare:
- Il tipo della struttura; 2. il nome della variabile; 3. la estensione, intesa come numero di CELLE del vettore.
Per accedere a un campo di una variabile strutturata si deve scrivere:
- Il nome della variabile vettore di struttura;
- Seguito dal numero della cella tra parentesi quadre;
- Seguito da un punto;
- Seguito dal nome del campo che interessa.
Per accedere a sottoelementi di ciascun campo si utilizzano le regole valide per il tipo di campo. La gestione delle strutture avviene all’interno di cicli. I singoli tipi di dati all’interno dei campi sono trattati con le specifiche metodologie.
File binari e file di testo
Dal punto di vista del computer tutti i file sono costituiti indistintamente da sequenze ordinate di byte. Dal punto di vista dell’utilizzatore invece di distinguono due categorie:
- File binari;
- File di testo.
File binari: I file binari contengono informazioni di qualsiasi tipo: dati, programmi, immagini, video, suoni. Queste informazioni, codificate come sequenze di byte, hanno senso solo all’interno dei programmi per i quali sono codificate. Ad esempio un file musicale in formato MP3 può essere ascoltato solo se si dispone del relativo programma di riproduzione.
File di testo: Contengono caratteri intelligibili, come lettere e segni di punteggiatura codificati in ASCII e alcuni caratteri di controllo, come quelli che comandano il ritorno a capo (line feed e carriage return). Non contengono alcuna informazione di formattazione (dimensione caratteri, colore…). Questa semplicità li rende esteticamente poveri ma in compenso ne permette la visualizzazione diretta in qualsiasi sistema operativo, senza l’uso di particolari programmi. A parità di informazioni contenute, un file di testo può essere meno compatto di un file binario, in quanto l’informazione è ricondotta sempre al formato di carattere. Per esempio il numero intero 65535 occupa due byte in un file binario, mentre in un file di testo è codificato necessariamente come una sequenza di 5 caratteri.
File binari
In generale la gestione di un file binario richiede una sequenza obbligata di operazioni:
- Dichiarazione di una variabile di tipo puntatore a file;
- Apertura del file;
- Lettura e/o scrittura del file;
- Chiusura del file.
1. FILE *gestorefile:
- la parola chiave FILE definisce il tipo della variabile gestorefile;
- l’asterisco specifica che tale variabile è un puntatore (indirizzo) alle informazioni contenute nel file.
2. gestorefile = fopen (nomefile, tipo operazione):
- nomefile è il nome fisico del file, che deve essere preceduto dal percorso di individuazione, nel caso il file si trovi in una directory diversa da quella di esecuzione corrente;
- tipo operazione può essere: rb, wb, r+ per l’apertura del file binario rispettivamente in modalità lettura, scrittura e lettura/scrittura;
- l’istruzione fopen restituisce NULL se l’apertura non va a buon fine.
3. Le due operazioni, di lettura e scrittura, sono speculari e il significato dei campi è lo stesso:
- fread (puntatore variabile dati, dimensione singolo dato, numero dati, gestorefile) fwrite (puntatore variabile dati, dimensione singolo dato, numero dati, gestorefile)
- puntatore variabile dati è l’indirizzo di memoria della variabile:
— che contiene i dati da scrivere su file nel caso di fwrite,
— di destinazione dei dati nel caso di lettura fread; - dimensione dato è la dimensione in byte di ciascun dato elementare, calcolata per mezzo dell’istruzione sizeof (). Per dato elementare si intende la frazione minima nella quale i dati possono essere partizionati;
- numero dati è il numero di dati elementari da leggere/scrivere;
- gestorefile è il puntatore al file in oggetto.
4. fclose (gestorefile):
- chiude il file liberando le risorse impegnate del sistema operativo;
- rende permanenti le modifiche operate sul file
Le operazioni di scrittura ovvero salvataggio di dati su file e di lettura, ovvero di ripescaggio dei dati, sono influenzate dalle dimensioni delle variabili:
- Variabile monodimensionale;
- Variabile pluridimensionale.
Variabile monodimensionale: Se la variabile che contiene i dati è monodimensionale, il puntatore alla variabile dati si ottiene anteponendo il simbolo & al nome della variabile. L’operazione di lettura della variabile i dal file avviene secondo le medesime regole.
Variabile pluridimensionale: In presenza di variabile pluridimensionale, contenente perciò una molteplicità di dati, quale un vettore, una stringa, un elenco, un vettore di struttura, il puntatore alla variabile dati si ottiene scrivendo il solo nome della variabile, privato delle parentesi quadre che ne definiscono la dimensione.
Es.
Con questa modalità si accede direttamente al record che interessa invece di leggere e scrivere l’intero file. Questa modalità implica un risparmio di memoria e di tempo, soprattutto nel caso di strutture dati imponenti.
La posizione delle informazioni in un file è specificato dall’indicatore di posizione. Per la sua gestione sono disponibili le seguenti funzioni:
- fseek;
- ftell;
- feof.
fseek (gestorefile, offset, origine) serve a posizionare l’indicatore di posizione sul record desiderato:
- offset indica di quanti byte saltare in avanti rispetto alla posizione di origine dell’indicatore di posizione;
- Origine permette di impostare la posizione di origine dell’indicatore di posizione.
In particolare:
• SEEK_SET = inizio del file;
• SEEK_END = fine del file;
• SEEK_CUR = posizione corrente.
ftell (gestorefile) restituisce il valore dell’indicatore di posizione.
feof (gestorefile) restituisce 1 (True) se l’indicatore di posizione ha raggiunto la fine del file, altrimenti restituisce 0 (False).
Qualora si debba ricercare un dato all’interno di un file è possibile:
- leggere l’intero file in un’unica soluzione e applicare la ricerca alla variabile letta;
- oppure leggere un record alla volta. In questo secondo caso si deve:
- posizionare l’indicatore di posizione all’inizio del file;
- scandire uno dopo l’altro i record alla ricerca del dato;
- il tutto entro un ciclo while che termina se il dato è stato trovato oppure se è stata raggiunta la fine del file.
In caso di sostituzione del dato è necessario prima far arretrare di 1 record l’indicatore di posizione, poiché questo dopo ogni operazione di lettura viene fatto automaticamente avanzare.
File di testo
Entro un file di testo vengono salvate comunemente delle stringhe di testo, concluse da un ritorno a capo. La sequenza operativa per gestire un file di testo è la stessa dei file binari:
- Dichiarazione di una variabile di tipo puntatore a file;
- Apertura del file;
- Lettura e/o scrittura del file;
- Chiusura file.
Cambiano le istruzioni necessarie a implementare il punto 3. Queste istruzioni, che fanno riferimento al modello delle istruzioni di scrittura-lettura da tastiera printf e scanf, sono:
- fprintf;
- fscanf.
fprintf (gestorefile, specificatori di formato, elenco variabili)
- Gestore file è il puntatore alle informazioni contenute nel file;
- Specificatori di formato è l’insieme, racchiuso tra virgolette, degli specificatori di formato delle variabili da salvare;
- Elenco variabili è l’insieme delle variabili da salvare. fscanf (gestorefile, specificatori di formato, elenco variabili) 1. è analoga a fprintf.
ES.
Teoria dei sistemi
Un sistema è un insieme complesso di elementi, non semplicemente aggregati ma organizzati, nel loro complesso di interazioni, in modo funzionale. Le singole parti del corpo umano, per esempio, che individualmente assolvono a funzionalità base, sono organizzate per assolvere a funzioni sistemiche. Si identificano infatti un sistema nervoso, un sistema cardiocircolatorio, un sistema respiratorio ecc. Spesso non serve conoscere peculiarmente il comportamento di tutte le parti interne di un sistema e il dettaglio delle leggi che regolano il funzionamento dei componenti, perché questo compito è assolto da discipline specifiche come la fisica e la matematica. È necessario invece elaborare dei modelli che permettano di analizzare il comportamento del sistema nell’interazione con l’area esterna. Nasce per questo la Teoria dei Sistemi, una disciplina complessa, nella quale confluiscono tutte le teorie delle specifiche discipline scientifiche che vengono riorganizzate, appunto, in un’ottica “sistemica”. La teoria dei sistemi opera attraverso il modello matematico, che permette di analizzare in modo rigoroso la realtà fisica. Per elaborare dei modelli matematici la teoria dei sistemi rende i problemi trattabili attraverso un meccanismo di semplificazione. È impossibile descrivere la realtà fisica nel suo vasto complesso di interazioni; perciò la teoria dei sistemi, per elaborare il modello matematico di un sistema:
- Trascura le grandezze che hanno una influenza debole nell’economia del sistema;
- Elegge le grandezze più rappresentative in relazione agli obiettivi del problema;
- Prende in considerazione un modello matematico ideale semplificato del sistema.
Gli elementi caratterizzanti un sistema sono:
- le variabili;
- I parametri;
- Il modello matematico;
- Il modello schematico.
Le variabili La chiave per inquadrare un sistema in termini matematici è la variabile. La variabile è un simbolo che si associa a una grandezza del sistema che interessa osservare. Le variabili, come suggerisce il termine, sono proprietà dinamiche del sistema, ne riassumono l’evoluzione temporale. Non solo si modificano da sole, ma spesso si interviene forzatamente per modificarle, manipolandole e assoggettandole a scopi di controllo del comportamento dinamico del sistema. In un sistema, anche se semplicissimo, le variabili in gioco sono tantissime, in teoria infinite. Al sistemista interessa isolare e descrivere solo quelle che hanno un interesse per il problema. Ad esempio, di un sistema di amplificazione non interessa descrivere tutti i dispositivi interni o addirittura le leggi elettriche e fisiche che li governano: questo studio è compito dell’elettronica e della fisica. Interessa invece sapere quanto vale l’amplificazione, qual è il rapporto tra il segnale d’ingresso, descritto dalla variabile Vi e il segnale d’uscita, descritto dalla variabile Vu.
I parametri
I parametri sono valori intrinseci di un sistema. Naturalmente anch’essi, come le variabili, influenzano il comportamento del sistema, entrando in gioco nelle leggi matematiche che ne descrivono l’evoluzione. Tuttavia sono concettualmente diversi dalle variabili, in quanto sono in genere immutabili; il loro valore permane costante nel tempo, quantomeno se osservati in un arco di tempo limitato. Inoltre, a differenza delle variabili, non sono condizionabili, cioè non si possono manipolare, ma anzi “condizionano”, nel senso che influiscono sul valore assunto dalle variabili. In altri termini i parametri descrivono le proprietà statiche di un sistema mentre le variabili ne descrivono le proprietà dinamiche. Quanto detto non vale in assoluto: non è detto che un parametro non possa subire alterazioni, anzi in pratica sono sempre presenti modificazioni delle proprietà di un sistema, per effetto dell’invecchiamento, della temperatura, del logorio. Quanto queste variazioni devono essere prese in considerazione? Dipende sempre dallo scopo dello studio, dall’incidenza che i parametri hanno sul modello teorico del sistema.
Il modello matematico
Dopo aver scelto le variabili, cioè le grandezze atte a descrivere in modo aderente il comportamento del sistema, si devono individuare le loro interrelazioni. Prendendo in prestito dalle varie discipline le leggi generali, si perviene alla formulazione di equazioni matematiche che mettono in relazione le variabili.
Queste relazioni, che nel complesso rappresentano il modello matematico di un sistema, sono così connaturate al sistema, seppure su un piano astratto, talmente aderenti al suo comporta mento naturale, che si dice che il sistema è governato da tali leggi, e che tali leggi ne descrivono il comportamento. Lo studio dei modelli matematici dei sistemi prende il nome di modellizzazione.
Modello matematico e schema a blocchi
Nell’accezione comune la parola modello richiama alla mente l’idea del modello in scala, dal quale si possono trarre valutazioni immediate (plastico di un nuovo quartiere) o la ricostruzione in scala di un sistema complesso sul quale fare osservazioni, per predirne l’evoluzione in risposta a sollecitazioni (ad esempio, la ricostruzione di una diga). Questo approccio può essere valido in certi casi, soprattutto quando il numero di elementi che partecipano fattivamente al processo sono tanti ed è difficile valutare il grado di interazione tra gli stessi. Il metodo più elastico, che dà risultati precisi e affidabili e che può essere raffinato fino ad aderire al comportamento reale, è però quello astratto matematico. Il processo viene descritto tramite le relazioni matematiche che intercorrono tra le grandezze in gioco, rappresentate con adeguati simboli che si definiscono variabili. L’insieme delle relazioni che descrivono l’evoluzione delle variabili di uscita in funzione di quelle di ingresso si definisce modello matematico e si chiama modellizzazione la disciplina che studia i modelli matematici. Per dare evidenza visiva al concetto, si disegna un blocco orientato con una linea entrante che rappresenta la sollecitazione di input e una linea uscente, che rappresenta la risposta di output e, quando possibile, si riporta la relazione matematica all’interno del blocco. Questa rappresentazione grafica costituisce il modello schematico, più modelli schematici tra loro combinati costituiscono uno schema a blocchi.
Per descrivere in modo organico il problema della modellizzazione e schematizzazione, riferiamoci a un sistema concreto: il sistema bicicletta. Stabiliamo le variabili di ingresso e uscita:
- Variabile di ingresso: numero di pedalate/secondo = NP;
- Variabile di uscita: velocità della bicicletta = V. Il modello matematico è la relazione che intercorre tra NP e V, come descritto in figura.
Dobbiamo ora attuare una semplificazione: possiamo assumere la velocità perimetrale della ruota posteriore uguale alla velocità di avanzamento del mezzo, pur di trascurare le sconnessioni del terreno, che immaginiamo idealmente rettilineo.
Per individuare la relazione matematica mettiamo in evidenza gli organi maggiormente interessati alla trasmissione del moto, cioè la corona, che è solidale ai pedali, il rocchetto del cambio e la catena.
Evidenziamo ora le seguenti notazioni, per le variabili e i parametri:
- Giricorona = numero di giri al secondo sviluppati dalla corona ovvero dai pedali = NP;
- Girirocchetto = numero di giri sviluppati al secondo dal rocchetto ovvero dalla ruota posteriore;
- R = raggio delle ruote in metri;
- Rapporto = (numero di denti della corona) / (numero di denti del rocchetto).
Il rocchetto ha sempre dimensioni inferiori alla corona. Poiché il movimento sviluppato dalla catena è lo stesso nei due perimetri di rocchetto e corona, il rocchetto si muoverà a velocità maggiore (costringendo il ciclista a imprimere una maggiore coppia quanto più piccolo è il rocchetto). Se, per esempio, si ha rapporto = 2, il perimetro della corona è doppio di quello del rocchetto e la velocità periferica del rocchetto è doppia di quella della corona. In generale risulterà:
girirocchetto = rapporto · giricorona = rapporto · NP
Dato il raggio, la ruota posteriore svilupperà il percorso a una velocità pari alla velocità della bici, espressa in m/s, di:
V = 2pR · girirocchetto = 2pR · rapporto · NP
In conclusione il sistema è modellizzabile con il seguente schema:
Al sistemista, in genere, interessa conoscere le relazioni funzionali tra ingressi e uscite. In generale, però, tra varia bile di ingresso e variabile di uscita è presente un reticolo di apparati, spesso molto complesso. Un approccio utile per ridurre la complessità di analisi è quello di dividere il sistema in più sottosistemi interconnessi, operazione che porta a formulare schemi con tanti blocchi inter connessi, detti schemi a blocchi. La divisione di un sistema in sottoblocchi semplifica la sua analisi, permettendo di focalizzare l’attenzione sul comportamento di una porzione del sistema. Una volta individuato il modello matematico di ciascuna porzione, è possibile condensare uno schema complesso in un solo blocco, mediante un processo di riduzione e semplificazione simile alla semplificazione algebrica. La disciplina che detta le regole di manipolazione di detti schemi si chiama algebra degli schemi a blocchi.
Il dominio del tempo
Nelle considerazioni e negli esempi precedenti è stata trascurata la presenza di una entità dominante nella teoria dei sistemi: il tempo. Gli esempi sono stati scelti ad hoc in modo che non risultasse essenziale il riferimento agli istanti di tempo nei quali si verificavano i fenomeni. Nel modello della bicicletta l’interesse si è focalizzato intorno alla determinazione di una relazione matematica tra il numero di pedalate e la velocità della bicicletta. Ci siamo mossi in una realtà astratta di tipo atemporale, immaginando di avere a che fare con variabili di ingresso fisse e di essere interessati al valore costante di velocità, per un dato valore costante del numero di pedalate. Siamo così giunti a formulare un semplice modello matematico statico. È facile capire che nella realtà fisica le grandezze variano continuamente: la velocità non è co stante, il ciclista deve applicare uno sforzo per lanciare la bicicletta a una determinata velocità che comunque continuerà a variare per effetto delle modificazioni del terreno, della pendenza, della propria condizione fisica. Insomma il sistema si evolve e le grandezze caratteristiche del processo cambiano in funzione del tempo. Il modello che prende in considerazione la variabile tempo è il modello matematico dinamico. L’analisi e la determinazione delle equazioni che descrivono l’evoluzione di un sistema dinamico, anche se a due sole ruote, come il sistema bicicletta, è un argomento che richiede un adeguato approfondimento ed è trasversale a tutto il corso di Sistemi. Per ora, nel prosieguo del paragrafo, ci limitiamo a evidenziare alcuni aspetti generali dei modelli matematici dinamici:
- Notazione delle variabili;
- Grafici cartesiani;
- Transitori e regime;
- Transitori di oscillazione;
- Condizioni iniziali e al contorno.
Quando si ragiona astraendosi dal tempo le grandezze sono da considerarsi costanti e vengono rappresentate con la lettera maiuscola. Nel caso del sistema bicicletta, associando al numero di pedalate il nome NP e alla velocità il simbolo V, il sistema risulta quindi descritto, come precedentemente dimostrato, dal seguente legame tra ingresso e uscita:
V = (2pR · rapporto) · NP
Se però valutiamo l’evolversi della situazione, le grandezze diventano funzioni del tempo, ovverossia a ogni istante di tempo si associa un valore della grandezza, funzione di quell’istante. Si sottolinea questo mediante la notazione minuscola riportando la variabile tempo tra parentesi rotonde.
Ovvero:
v(t) = velocità bicicletta
dove v è la variabile dipendente velocità e t la variabile indipendente tempo.
Analogamente:
np(t) = numero di pedalate
Il legame ingresso-uscita si rappresenta ora in questa forma:
v(t) = (2 · R · rapporto) · np(t)
In questa ottica assumono un ruolo centrale i grafici cartesiani, che danno una impressione immediata dell’andamento della variabile dipendente in funzione del tempo. Il tempo occupa l’asse delle ascisse e la variabile osservata, nel nostro esempio la velocità, l’asse delle ordinate.
Un fattore importante nell’analisi dell’evoluzione di un sistema nel tempo è la diversa caratterizzazione delle variazioni di assestamento, dette transitori, e il raggiungimento della condizione di equilibrio, detta regime. Tutti i sistemi presentano una inerzia alle variazioni. Se consideriamo il sistema bicicletta, in teoria a un dato numero di giri della corona dei pedali corrisponde un unico valore della velocità, una volta definito il modello matematico. In pratica si sa invece che questa condizione si raggiunge dopo un certo tempo: l’intervallo iniziale è speso a vincere l’inerzia del moto per cui, a parità di forza impressa dal ciclista, la velocità ha all’inizio un valore nullo e cresce progressivamente. Questo intervallo è detto transitorio. Raggiunta la velocità costante che è nelle intenzioni del ciclista, si ha la condizione di regime.
Si osservi la figura che segue: il tratto percorso è pianeggiante ma la velocità non è costante, bensì cresce portandosi da zero a un valore massimo di regime. Raggiunto questo valore, la velocità si mantiene costante; se eventualmente ci sono delle variazioni, le nuove condizioni di regime si raggiungono passando attraverso altrettanti transitori.
Valore nominale
Il valore nominale è il valore atteso di regime. Quando un sistema evolve verso una situazione di assestamento, la stabilizzazione deve avvenire al valore nominale. I progettisti di sistemi di controllo hanno come obiettivo quello di costruire apparati che, in varie condizioni di lavoro e per diverse sollecitazioni alle quali è sottoposto il sistema, provvedano a portare e mantenere il sistema nelle condizioni di lavoro desiderate, corrispondenti appunto al valore nominale. È interessante prendere in considerazione, in questa digressione su transitorio e valore a regime, i sistemi soggetti a fenomeni oscillatori. È questa una categoria molto ampia di sistemi. Quando sono soggetti a delle sollecitazioni, questi sistemi entrano in condizioni di oscillazione persistente oppure, il più delle volte, sviluppano una serie di periodi di oscillazione che tendono poi a smorzarsi e decadere fino a spegnersi. Possiamo anzi affermare che, in teoria, quasi tutti i sistemi hanno risposte oscillatorie, anche quelli apparentemente più rigidi. Moltissimi sistemi, nel passaggio da una condizione di equilibrio a un’altra, compiono delle oscillazioni: per esempio la frenata di una automobile causa l’oscillazione della scocca sugli ammortizzatori. Spesso queste oscillazioni sono indesiderate, perché sottopongono il sistema a sollecitazioni che possono causare traumi alla struttura, senza che ne derivi alcun vantaggio, dato che si tratta di un processo di assestamento del quale interessa solo la posizione raggiunta al termine. Uno dei compiti primari dei sistemi di controllo è quello di tenere sotto controllo le oscillazioni, snaturando il sistema e abbattendone il carattere oscillatorio. L’azione dei sistemi di controllo può sventare inoltre situazioni pericolosissime, nelle quali si creano le condizioni favorevoli perché le oscillazioni si autoesaltino, portando il sistema alla distruzione. Nella risposta di tipo oscillatorio è importante mettere in evidenza (figura a pagina seguente) le seguenti specifiche:
- Tempo di assestamento ST (settling time);
- Sovraelongazione (overshoot).
Tempo di assestamento (ST)
Dopo un certo intervallo le variazioni dell’oscillazione cominciano a ricadere all’interno di un’area di variazione massima ammessa, spesso espressa come scarto percentuale rispetto al valore nominale di regime. Il tempo che trascorre dall’istante zero fino a questa situazione è detto appunto tempo di assestamento (in inglese Settling Time).
Sovraelongazione
La sovraelongazione è la differenza tra il valore massimo della risposta, che in genere si verifica con il primo picco e il valore di regime nominale. È importante perché rappresenta il punto di massima sollecitazione per il sistema.
Variabili di stato
Nello studio dei sistemi dinamici, ovvero di quei sistemi che evolvono nel tempo, entra in gioco il concetto di variabile di stato. I concetti di variabile di ingresso e di uscita sono concetti evidenti, intuitivi. Si comprende facilmente che le variabili di uscita sono le grandezze che accompagnano l’osservazione del comportamento del sistema, mentre le variabili di ingresso sono quelle che ne influenzano direttamente il comportamento. Il concetto di variabile di stato è invece un nuovo concetto cardine che dobbiamo capire e assimilare, riflettendo bene sul suo significato. Non è una nozione tanto immediata, deve essere accostata con attenzione, se si ha interesse a conoscere il comportamento intimo dei sistemi. Possiamo, per dare evidenza visiva al nostro ragionamento, collocarle all’interno dello schema a blocchi di un sistema, come illustrato nella figura che segue. Pur essendo poste all’interno del blocco, le variabili di stato hanno un’influenza diretta sulle variabili d’uscita, unitamente alle variabili di ingresso.
La definizione è infatti la seguente: “le variabili di stato sono quelle la cui conoscenza, all’istante presente, unitamente alla conoscenza degli ingressi, permettono di prevedere matematicamente l’evoluzione futura del sistema”. Le variabili di stato sono la “memoria” del sistema. Può sembrare strano, ma anche i sistemi fisici, che sono inanimati, conservano una memoria del proprio stato interno. Consideriamo per esempio un serbatoio e assumiamo come ingresso la portata qi(t) di liquido entrante e come uscita l’altezza h(t) del liquido.
A una prima osservazione potremmo pensare che h(t) dipenda direttamente da qi(t) perché, se aumenta la quantità di liquido entrante, aumenta anche l’altezza, ma non è così. Consideriamo le due figure seguenti:
Anche se qi(t) è la stessa in entrambi i serbatoi, l’altezza è diversa, i due serbatoi partono infatti da due stati diversi: il primo è mezzo pieno, il secondo mezzo vuoto. Il sistema ha in memoria il proprio stato, che è il volume di partenza. Il volume di liquido è quindi la sua variabile di stato.
Classificazione dei sistemi
Nella precedente unità abbiamo inquadrato i sistemi in un modello generale astratto, che contempla i seguenti strumenti di analisi: parametri, variabili e modello matematico. Facciamo riferimento allo stesso criterio di divisione per ripartire la classificazione dei sistemi e approfondirne la comprensione attraverso la conoscenza diretta di varie tipologie. Nei sistemi a parametri distribuiti è presa in considerazione la dislocazione spaziale dei parametri. Il sistema, all’interno dell’area da esso occupata, varia le sue proprietà e il suo comportamento. Di conseguenza la variabile spazio ha un ruolo primario ed entra di diritto nelle relazioni matematiche che descrivono il comportamento del sistema. Nei sistemi a parametri concentrati non si fa riferimento allo spazio. Si ipotizza idealmente che i parametri siano concentrati in un punto. Lo studio delle caratteristiche e del comportamento del sistema prescindono dalla sua forma e dallo spazio occupato.
Es. Sistema a parametri distribuiti
Una linea elettrica di solito viene assimilata a un cavo di resistenza nulla, assumendo idealmente che il segnale venga propagato dal punto di partenza al punto di arrivo senza subire modificazioni. Sulle lunghe tratte, nelle inter connessioni di rete, un cavo, per effetto delle interazioni con l’ambiente e delle interferenze, equivale a un circuito costituito da resistenze e condensatori.
Questo tipo di circuito si dipana dall’inizio alla fine del cavo. Nei vari punti del cavo il segnale non è di conseguenza univoco, ma risponde alle leggi circuitali: il segnale immesso è diverso da quello in un punto intermedio e da quello terminale. Il sistema deve essere pertanto analizzato in tutti i suoi punti, e il suo modello matematico varia in funzione delle coordinate spaziali del punto osservato.
Es. Sistema a parametri concentrati
Un tipico esempio di approccio aspaziale si rintraccia in una delle prime nozioni che si apprendono nello studio della fisica: la nozione di baricentro. Il baricentro è, in campo fisico, il punto dove si immagina sia concentrata tutta la massa di un corpo. Per l’indagine teorica è ininfluente la distribuzione della massa in un corpo: il bilancio delle forze può prescindere dalla forma e dimensione del corpo, che si può immaginare concentrato in un unico punto, detto punto materiale. Si consideri per esempio un oggetto (figura a) sul quale si esercita in modo uniforme la forza di gravità, e si voglia determinare la forza di contrasto che lo mantiene in equilibrio. La figura b) rappresenta il modello a parametri distribuiti: è quello aderente alla realtà perché descrive la forza peso come distribuita uniformemente in tutto il volume del corpo. Risulta però più agevole, soprattutto in problemi più complessi di questo, immaginare concentrata la somma Fp di tutte le forze peso in un unico punto (figura c). In tal caso il calcolo è immediato perché la forza di sostegno Fs, applicata allo stesso punto, è esattamente uguale e contraria alla forza peso Fp ovvero: Fs = –Fp.
Abbiamo già detto che i parametri si distinguono dalle variabili per il fatto di essere immutabili: questa affermazione può a volte rivelarsi ambigua. Il carattere di immutabilità infatti non è valido in assoluto, ma solo se l’analisi del sistema si compie in un arco relativamente ristretto di tempo, per cui è possibile ritenere trascurabili le modificazioni parametriche dovute all’invecchiamento e alle diverse condizioni ambientali. In questa ottica si definisce invariante un sistema per il quale i parametri sono effettivamente costanti o si possono assumere costanti. In questo caso il sistema, mantenendo invariate le sue caratteristiche, mantiene invariato anche il proprio comportamento. Più precisamente ciò significa che la risposta del sistema a una data sollecitazione di ingresso non muta nel tempo. Il tempo non è quindi argomento dei parametri all’interno del modello matematico. Viceversa se il sistema è variante i suoi parametri sono funzioni del tempo e il sistema modifica nel tempo il suo comportamento.
Classificazione dettata dalle proprietà delle variabili
Un sistema si dice statico se non evolve nel tempo. Questo avviene se le variabili che ne de scrivono l’evoluzione rimangono congelate a valori fissi. Si faccia attenzione a non confondere un sistema statico con uno invariante: nel primo caso sono le variabili ad avere carattere di staticità, nel secondo i parametri. In un sistema statico il tempo non è argomento delle relazioni che lo descrivono. Se nella descrizione del sistema entrano in gioco variabili che si evolvono nel tempo, il sistema si dice dinamico. La maggior parte dei sistemi che si incontrano nella teoria dei sistemi sono di tipo dinamico: è proprio una vocazione di questa materia analizzare l’evoluzione dei fenomeni. È questa una disciplina che ha l’ambizione di studiare sistemi reali e noi sappiamo che la realtà è in continuo divenire. Ciò non significa che i sistemi statici non siano importanti e interessanti da studiare. Questo compito però è affidato a discipline specifiche: si pensi ad esempio alla Scienza delle costruzioni e alle sue complesse regole di calcolo statico delle strutture. La distinzione tra sistemi discreti e sistemi continui costituisce una classificazione riguardante l’insieme dei valori che possono assumere le grandezze interessate, cioè le variabili. Nei sistemi continui le grandezze variano con continuità: non ci sono “salti” istantanei tra due valori. Una conseguenza di questo, che è anche un diverso modo di definire un sistema continuo, è che un intervallo congloba infiniti valori (figura sotto). Sono ascrivibili a questa categoria i sistemi hi-fi come gli amplificatori e le casse acustiche, i radioricevitori, i televisori, anche se si registra una progressiva migrazione al digitale anche in questo settore.
Nei sistemi discreti i valori delle grandezze sono in numero finito e distanziati tra loro: i segnali pertanto passano istantaneamente da un valore all’altro determinando una discontinuità (figura sotto). A differenza dei sistemi continui, un intervallo congloba un numero finito di valori.
Es. Un interruttore è un sistema discreto. L’insieme dei valori si compone di soli due stati. Si ha un passaggio a “salti” dallo stato OFF allo stato ON.
Es. Un amplificatore è un sistema continuo. Presenta un ingresso e una uscita. All’ingresso è presente la sorgente sonora da amplificare, ad esempio un microfono; il segnale di uscita pilota un altoparlante, che riproduce le onde sonore amplificate.
Nella figura seguente è descritto l’andamento delle onde elettriche in ingresso e in uscita. Come si vede, l’onda di uscita ha un livello più alto, essendo amplificata. Il profilo di entrambe le onde è continuo e questo caratterizza il sistema amplificatore come sistema di tipo continuo.
Classificazione dettata dalle proprietà del modello matematico
Nei sistemi deterministici il legame I/O è univocamente determinato, si può cioè stabilirne con certezza l’evoluzione futura in base alle condizioni iniziali e all’entrata. Il comportamento del sistema è cioè prevedibile e analizzabile a priori sulla base di regole matematiche assolute. I sistemi probabilistici sono soggetti alle leggi del caso. Non è possibile prevederne l’evoluzione in termini assoluti, ma questo non significa che il sistema non possa essere studiato matematicamente: il comportamento del sistema può essere studiato con la teoria della probabilità. Per ogni esperimento infatti, data una eccitazione di ingresso, pur non potendo prevedere in termini assoluti l’andamento dell’uscita, si può stabilire qual è il grado di probabilità che i livelli dell’uscita cadano entro determinati intervalli. I sistemi deterministici si dicono anche causali, per la legge causa-effetto che assicura che a una determinata causa si lega un effetto che si può predire con certezza. I sistemi probabilistici invece si dicono anche casuali in quanto l’effetto è conseguenza del caso. Sono lineari i sistemi per i quali vale il principio della sovrapposizione degli effetti. Una possibile definizione di sovrapposizione degli effetti, volutamente descrittiva, è la seguente. “Date due o più sollecitazioni a un sistema, l’effetto dell’applicazione contemporanea di queste sollecitazioni è uguale alla somma degli effetti ottenuti applicando singolarmente ciascuna sollecitazione”. Nei sistemi con memoria l’evoluzione del sistema si dipana nel tempo in funzione di uno stato interno, che il sistema registra appunto nella propria memoria. Nei sistemi senza memoria l’evoluzione ha luogo senza tenere alcuna traccia delle situazioni passate: i valori assunti dalle grandezze che caratterizzano il comportamento del sistema dipendono solo dalle condizioni presenti.
Es. L’orologio Un orologio, sia esso digitale o analogico, è necessariamente un sistema con memoria, in quanto la determinazione dell’orario a un dato istante non dipende solo dall’istante medesimo ma da tutti quelli passati. Se per esempio un orologio elettronico a un dato istante indica il seguente orario:
nell’istante successivo, ipotizziamo dopo un minuto, mostrerà il seguente orario:
Chiaramente i due momenti di visualizzazione non sono disgiunti. Il secondo momento è costruito sulla base della memoria che i circuiti interni dell’orologio elettronico dispongono del primo momento.
Studio e simulazione dei sistemi nel dominio del tempo
Questo capitolo è una introduzione allo studio dei modelli matematici dei sistemi. Le metodologie trattate qui permettono di:
- Scrivere le formule matematiche discrete che governano un processo;
- Simulare il processo implementando le formule con un linguaggio di programmazione.
Queste metodologie trasformano pesanti equazioni differenziali in formule alternative numeriche, che per essere calcolate non richiedono una particolare intelligenza, ma solo una grande capacità di calcolo, proprio ciò di cui dispone il computer. La materia di Sistemi, per sua vocazione, tratta processi fisici che si svolgono nel dominio del tempo: per analizzare il comportamento di un processo fisico, lo riveste con un modello matematico. I modelli qui trattati sono di tipo discreto, il che significa che “fotografano” l’evoluzione del processo a intervalli regolari Δt. La serie di istantanee raccolte è sufficiente a descrivere, con buona approssimazione, l’intera evoluzione di un processo, dall’istante iniziale t = 0 fino a t ➞ ∞. Alla base dei modelli matematici discreti ci sono i seguenti concetti:
- Le variazioni o differenze finite;
- Il rapporto incrementale.
Differenze Finite
Le variazioni si rappresentano per mezzo del simbolo Δ: per esempio Δt indica una variazione temporale, Δx una variazione spaziale, Δv una variazione di velocità e ΔT di temperatura. Le variazioni sono date dalla differenza tra due valori: un valore finale o futuro meno uno iniziale o attuale. Per questo si chiamano anche differenze finite. Con riferimento ad esempio alla variabile tempo t, fissato arbitrariamente l’inizio del processo all’istante t = 0, detti t1 e t2 due istanti di osservazione del processo, con t2 valore finale e t1 valore iniziale si ha:
L’intervallo finito Δt è appunto la differenza finita. Analogamente, per le variazioni spaziali, si definisce Δx = x2 — x1 e così per le altre tipologie di variazioni. In genere le grandezze variano in funzione di altre grandezze. Matematicamente questa dipendenza è descritta da una funzione y = f(x) in cui x è la variabile indipendente e y quella dipendente. In questa ottica la variazione Δy della variabile dipendente y è legata alla variazione Δx di quella indipendente dall’espressione:
Δy = y (x + Δ x) — y(x)
Infatti, come si può comprendere osservando il grafico in figura: 1. Δx è la differenza tra il valore finale x + Δx e quello iniziale x; 2. Δy è la differenza tra il corrispondente valore finale y (x + Δx) e quello iniziale y(x).
Rapporto incrementale
Nella formulazione dei problemi, in genere, le variazioni non compaiono isolatamente, bensì all’interno di rapporti algebrici. Anzi, l’evoluzione di un sistema è legata all’entità di questi rap porti, ed è attorno a essi e al legame con le grandezze caratteristiche del sistema che si muoverà la nostra trattazione. Il rapporto Δy/Δx tra la variazione Δy della variabile dipendente e quella Δx della variabile indipendente si chiama rapporto alle differenze finite o, più sinteticamente, rapporto incrementale. Una proprietà molto importante del rapporto incrementale è che esso varia, esattamente come la variabile dipendente, in funzione della variabile indipendente. I fenomeni fisici si svolgono principalmente in ambito temporale: in tal caso la variabile indipendente è il tempo, le relazioni tra le grandezze sono espresse da funzioni del tempo del tipo y(t) = f(t) e il rapporto incrementale diventa Δy/Δt.
Le equazioni alle differenze finite
I sistemi reali sono descritti matematicamente da equazioni alle differenze finite. In una equazione alle differenze finite:
- L’incognita è una funzione y(x);
- L’incognita compare entro un rapporto incrementale.
Es. L’equazione x — 1 = 0 è una equazione di tipo tradizionale: la sua soluzione è un singolo numero ovvero x = 1. L’equazione
è alle differenze finite. La sua soluzione è l’intera funzione y(x) = x che è l’equazione di una retta inclinata di 45°. Infatti se in questa retta andiamo a misurare il rapporto tra la variazione della quota y e la variazione della quota x, troviamo, come visualizzato nella figura, che esso vale 1 in qualsiasi punto della retta.
Gli infinitesimi e la derivata
Nella trattazione precedente è stato detto che un generico sistema fisico è trattabile matematicamente mediante l’equazione alle differenze finite che lo descrive. Abbiamo visto anche che queste equazioni sono di tipo discreto, cioè descrivono l’evoluzione del sistema per intervalli finiti distanziati fra loro da un intervallo di tempo Δt. Inoltre queste equazioni sono risolvibili mediante passaggi algebrici e producono formule risolutive iterative, che possono essere efficacemente affidate all’elaborazione numerica attraverso opportuni algoritmi passopasso. Ora, considerare il comportamento del sistema a intervalli discreti può funzionare bene in molte situazioni, soprattutto laddove le variazioni sono lente, quindi le approssimazioni introdotte dal procedimento di discretizzazione sono limitate. Dovendo però affrontare il problema da un punto di vista generalizzato, secondo modelli matematici effettivamente aderenti alla realtà, è necessario ricorrere ai concetti di infinitesimo e di derivata. Per capire da dove nasce questa necessità, riferiamoci a un problema di cinematica. Consideriamo un’automobile che percorra una autostrada. Supponiamo che la distanza da casello a casello, pari a 180 km, venga percorsa in 2 ore. Questo significa che l’automobile ha mantenuto una velocità di crociera pari a:
180 km / 2 h = 90 km/h
Il risultato è la velocità, pari al rapporto V = S/T tra spazio percorso S e tempo impiegato T, misurata in chilometri all’ora. È ben noto però che questa velocità rappresenta solo un bilancio medio; la macchina potrebbe essere meno veloce all’inizio e più veloce verso la conclusione del percorso e il calcolo eseguito non lo metterebbe in risalto. Per calcolare in modo più preciso la velocità in un istante generico t rappresentiamo lo spazio x(t) percorso su un grafico temporale:
Possiamo allora applicare una formula alle differenze finite:
Se per esempio nell’intervallo tra il minuto 20 e il minuto 25 lo spazio percorso sale da 10 km a 12 km si ha:
Il valore della velocità così calcolato è più accurato rispetto alla velocità calcolata nelle 2 ore perché è valutato in una finestra temporale più stretta, ma si tratta ancora di un valore medio, poiché nell’intervallo Δt la velocità non è costante ma crescente. Per calcolare la velocità istantanea è necessario rendere Δt molto piccolo. La nozione di “molto piccolo” è però relativa: per un sistema come per esempio un controllo di temperatura ambiente, che presenta variazioni molto lente nell’arco della giornata, può essere assunta come unità di tempo base anche l’unità oraria. Per un sistema nucleare, dove i fenomeni hanno luogo in spazi e tempi ridottissimi, l’unità di tempo deve avere molti zeri dopo la virgola. In un’ottica matematica generalizzata il valore finito Δt non trova quindi accreditamento, ma è necessario ricorrere alla nozione di infinitesimo dt. C’è una grande distanza concettuale tra Δt e dt: l’infinitesimo non è, come appare a una prima comprensione superficiale, meramente un valore di Δt molto piccolo, ma è un’idea limite di infinitesimamente piccolo. Un intervallo infinitesimamente piccolo, nella nostra percezione, è però un intervallo nullo. Come può un valore nullo produrre un risultato non nullo quando viene utilizzato in una for mula come quella del rapporto incrementale? Attenzione: non si tratta di calcolare un inter vallo assoluto bensì un rapporto tra due intervalli. Inoltre il rapporto non è calcolato tra due grandezze praticamente nulle, il che restituirebbe una forma di indeterminazione del tipo 0/0, ma tra due grandezze legate tra loro da una funzione.
Tornando per esempio alla nostra automobile, lo spazio da essa percorso è esprimibile in funzione del tempo attraverso la funzione x(t). Per rendere il calcolo della velocità assolutamente preciso è necessario portare Δt a un valore infinitesimamente piccolo, calcolando il limite del rapporto tra gli intervalli finiti Δx e Δ t, con Δt ➞ 0:
Questo limite viene chiamato derivata della variabile spazio rispetto al tempo. In generale la derivata è il limite del rapporto incrementale tra la variazione della variabile di pendente e la variazione della variabile indipendente di una funzione. La derivata si indica simbolicamente in diversi modi; noi scegliamo il seguente:
che evidenzia il significato concettuale di rapporto tra infinitesimi.
Es. Gli stessi concetti espressi per la velocità si applicano anche all’accelerazione, che è la variazione della velocità in un dato intervallo di tempo diviso l’intervallo stesso:
Sistemi elettrici
Nei sistemi elettrici le grandezze fondamentali sono la tensione v(t) e la corrente i(t). Desideriamo limitare l’analisi ai casi in cui sussistono caratteristiche di linearità; a questa condizione il campo dei componenti di interesse si restringe molto e possiamo limitarci solamente a: resistori, condensatori, induttori e generatori. I primi tre sono componenti passivi, cioè non hanno una capacità autonoma di generare energia elettrica. La tabella seguente mostra i simboli dei componenti e le rispettive unità di misura.
I generatori sono componenti attivi e si dividono in generatori di tensione e di corrente.
Per il resistore vale una legge lineare, la legge di Ohm, per la quale:
che può essere utilizzata in due modi: 1. nota la tensione ai capi di R si può ricavare la corrente con la formula inversa; 2. nota la corrente si può ricavare la caduta di tensione. Le dimensioni delle grandezze in gioco sono volt [V] per v(t), ampere [A] per i(t) e ohm [W] per R. Si noti che la legge rimane valida anche per segnali variabili nel tempo. La formulazione della legge del condensatore, valida per segnali variabili, aumenta notevolmente le difficoltà. Il problema non risiede tanto nella difficoltà della dimostrazione, quanto nella formula dimostrata, che introduce un modo inusuale di descrivere le relazioni fra le grandezze. Ma andiamo per gradi, cominciando ad analizzare gli aspetti fisici di base, per poi passare alla formulazione matematica. Il condensatore, il cui simbolo è dato in figura a), è costituito da due armature (due conduttori), separati da un isolante (o dielettrico).
Immaginiamo di collegare una batteria al condensatore come in figura b). Il condensatore dunque, sottoposto a una tensione E, viene interessato da una circolazione di elettroni che vengono spinti dalla forza dovuta al campo elettrico, dal punto a potenziale maggiore della batteria (punto A) verso il punto a potenziale minore (punto B): gli elettroni dunque, con il loro moto si ammassano sull’armatura contrassegnata con il — (armatura sinistra nella figura), mentre l’armatura di destra, impoverita di elettroni, si carica positiva mente. Si instaura quindi una differenza di potenziale V a cavallo delle due armature. Quando V giunge a eguagliare E, il flusso di elettroni si esaurisce. Verifichiamo che cosa accade a livello analitico. Si dimostra che la quantità di carica accumulata sulle armature è proporzionale alla tensione fra le due armature:
Q = CV
dove C, la costante di proporzionalità, è la capacità del condensatore, misurata in coulomb/volt, cioè in farad, [F]; C è un parametro che dipende dalle dimensioni e dal dielettrico utilizzato. Cerchiamo ora, a partire da questa formula, di individuare un legame tensione-corrente. Se la tensione passa da un valore V1 a un valore V2 possiamo scrivere:
Q1 = CV1 e Q2 = CV2
Sottraendo fra loro Q2 e Q1 si ha:
Q2 — Q1 = CV2 — CV1
e, se definiamo:
Q2 — Q1 = ΔQ e V2 — V1 = ΔV
si ha che: ΔQ = CΔV
È questo un legame alle differenze finite, cioè tra le variazioni di tensione ΔV e carica ΔQ. Se ora Q1 è stata misurata sul condensatore all’istante di tempo t1 e Q2 è stata misurata sul condensatore all’istante di tempo t2, possiamo ricercare qual è il legame tra ΔQ nell’intervallo Δt = t2 — t1 di osservazione e la corrente Im che fluisce mediamente nel circuito nello stesso intervallo di tempo. Per definizione la corrente è la carica che fluisce in un secondo; pertanto in Δt secondi fluirà e si accumulerà su una armatura del condensatore una carica pari a:
ΔQ = Im · Δ t
Eguagliando il secondo membro delle ultime due formule si ricava:
Questa formula va analizzata con attenzione e interpretata correttamente. Si noti che non esprime un legame assoluto tra corrente e tensione, come ad esempio per la resistenza dove v(t) = R · i(t): in quest’ultimo caso la tensione a un dato istante è direttamente funzione della corrente al medesimo istante. Nella formula del condensatore non compare il valore della tensione v(t) a un dato istante bensì il valore della variazione di tensione ΔV, cioè la differenza tra la tensione all’istante futuro v(t + Δ t) e la tensione all’istante presente v(t). Il rapporto tra la variazione ΔV della tensione e la variazione del tempo Δt si chiama rapporto incrementale. Si noti che quello rappresentato è un rapporto incrementale finito, cioè utilizza le differenze finite ΔV e Δ t delle grandezze. Come detto, il valore così calcolato della corrente è però quello medio, valutato nell’intervallo Δt. Se si vuole conoscere il valore istantaneo i(t) è necessario considerare un intervallo di tempo infinitesimamente piccolo dt e la corrispondente variazione infinitesima di tensione dv. Si scrive allora:
dove iC(t) e vC(t) sono rispettivamente corrente e tensione istantanee del condensatore. Questa formula è omologa a quella alle differenze finite e va letta così: la corrente in un condensatore è proporzionale alla derivata della sua tensione. Nel corso dell’unità faremo riferimento essenzialmente alla formulazione alle differenze finite, in quanto la formulazione con la derivata implica conoscenze avanzate di matematica. In pratica verrà dunque utilizzata la formula alle differenze finite:
Configurazioni circuitali fondamentali
Analizziamo il circuito RC. È un circuito di fondamentale importanza, perché racchiude, nella sua semplicità, tutti i concetti di base. Si potrebbe scrivere un libro e imperniare attorno a questo circuito tutta la trattazione dei metodi matematici per lo studio dei sistemi. Esso inoltre riflette il comportamento di numerosi sistemi, anche di natura non elettrica: per esempio una stanza che si riscalda è modellizzabile come un circuito RC, come si vedrà nell’unità sui sistemi termici.
Vogliamo studiare l’andamento della tensione di uscita, coincidente con la tensione VC(t) del condensatore, per un ingresso di tensione a gradino, cioè che sale istantaneamente da 0 al valore massimo costante E. La tensione E è bilanciata dalle cadute di tensione su R e su C, quindi possiamo scrivere l’equazione alla maglia:
L’incognita del nostro problema è VC(t): proviamo allora a elaborare la VR(t) fino a esprimerla in funzione di VC(t). Grazie alla legge di Ohm, osservando che IR(t) = IC(t) possiamo scrivere:
La corrente IC(t) si può invece ricavare dall’equazione caratteristica del condensatore:
Pertanto l’espressione di VR(t) è la seguente:
che, sostituita nell’equazione alla maglia, porge una equazione che contiene una sola incognita, appunto VC(t):
Il prodotto R ⋅ C ha le dimensioni di un tempo e caratterizza fortemente il comportamento temporale del circuito. Si chiama per questo costante di tempo e si indica con il simbolo t. Sostituendo t a RC e portando al secondo membro il termine forzante, cioè l’ingresso E, si perviene all’equazione della carica del condensatore, nell’incognita VC(t):
Ora dobbiamo risolvere questa equazione, applicando il metodo numerico. Esprimendo la variazione ΔVC(t) in funzione dei valori presente e futuro della variabile:
si ottiene:
Portando al numeratore il termine Δt:
Isolando ora il termine VC(t + Δt) al primo membro:
e dividendo tutto per t si ottiene:
È questa la formula discreta per il calcolo ricorsivo dei valori di tensione ai capi del condensatore. Noto il valore iniziale VC(0) della tensione sul condensatore, è possibile, applicando ricorsivamente la formula, calcolare i successivi valori della tensione. Come già più volte accennato, il metodo ricorsivo è approssimato e i risultati sono tanto più fedeli quanto minore è l’intervallo scelto Δt di campionamento del fenomeno, detto passo di simulazione. Concentriamoci ora sulla curva di carica del condensatore. È importante analizzarla bene, per ché si ritrova in tutti i tipi di sistemi ed è il paradigma per tutte le metodologie di studio dei sistemi. La curva è descritta dal seguente grafico.
Per un elettronico questa curva è lo specchio del mondo; noi qui ci limitiamo a segnalare due sue importantissime proprietà:
- La VC(t) tende al valore di regime E per t tendente a infinito;
- La velocità di crescita della VC(t) è strettamente dipendente dalla costante di tempo. Se la t è piccola la carica ha luogo rapidamente e viceversa.
Per giustificare la prima proprietà occorre scrivere l’equazione differenziale che regge il sistema e risolverla. L’equazione differenziale è uguale all’equazione alle differenze finite per il circuito RC, con la derivata al posto del rapporto incrementale:
Si può dimostrare che l’equazione ha soluzione:
Facendo tendere t a infinito, il termine esponenziale tende a zero, poiché ha il segno meno, pertanto risulta:
Questo mostra che il valore di regime vale E. Passiamo ora a giustificare la seconda proprietà. Il diagramma della VC(t) presenta una importante proprietà geometrica, dimostrabile mediante la derivata: l’intersezione tra la retta tangente alla funzione VC(t) spiccata dall’origine e l’asintoto orizzontale v = E è un punto a distanza t dall’asse delle ordinate. È consigliabile seguire questo ragionamento avendo sotto gli occhi il grafico figura in pagina seguente.
Si può allora assumere che la funzione raggiunga un valore prossimo al valore E di regime dopo un tempo pari circa a t = 5 ⋅ t; tale valore è assunto indicativamente e convenzionalmente come istante di regime. Si può dimostrare che in questo istante la curva raggiunge il 99% del valore massimo, mentre dopo t = 3 ⋅ t raggiunge già il 95%. Questo dati mostrano pertanto che t è un buon indice della velocità di evoluzione del sistema. In generale un sistema con alte costanti di tempo è un sistema lento, che impiega molto tempo a raggiungere il regime.
SISTEMI MECCANICI
Nei sistemi meccanici le grandezze essenziali sono la forza f(t), grandezza appunto “forzante” e la velocità v(t), grandezza dipendente. I sistemi che analizziamo sono costituiti da tre componenti, capaci di modellizzare la gran parte dei sistemi. Essi sono la massa, la molla e lo smorzatore. Vogliamo procedere a descrivere le caratteristiche di questi componenti e individuare le leggi matematiche che li governano. In particolare ci interessa la relazione che sussiste in ciascun componente tra la risultante delle forze agenti f(t) e la velocità del movimento v(t), detta equazione caratteristica. La massa è l’elemento inerziale, è in grado cioè di assorbire energia, ma lentamente, a una velocità imposta, condizionando la velocità di evoluzione del processo di appartenenza. È responsabile dei transitori, cioè dei processi che fanno guadagnare un nuovo punto di equilibrio in modo lento e progressivo. Sappiamo che applicando una forza anche molto elevata a una massa, questa rimane inizialmente ferma e comincia a muoversi, appunto con inerzia, nei successivi istanti. Contraria mente a quanto detterebbe l’intuito, a uno stimolo costante la massa non reagisce con velocità costante; l’entità costante è invece l’accelerazione. La figura seguente mostra una massa che si muove con accelerazione costante a(t), sotto l’azione della forza f(t) costante.
Il legame tra forza e accelerazione è espresso dalla ben nota formula di Newton:
Nota l’espressione alle differenze finite:
si ricava l’equazione caratteristica della massa:
La formula esprime il legame tra la forza impressa alla molla e l’estensione x(t), valutata rispetto alla sua posizione di riposo. La figura seguente mostra questo concetto: x(t) è la distanza tra la posizione finale assunta dall’estremo della molla e la posizione x(0) che la molla assume a riposo, cioè quando non è sollecitata.
Diciamo subito che, pur essendo importante a livello concettuale avere chiarito il significato di lunghezza a riposo, il valore di questa entità non entra mai a far parte delle equazioni del moto di un sistema elastico, in quanto interessano essenzialmente i movimenti relativi. Sempre con riferimento alla figura, per esempio, basta disporre l’origine dell’asse del movimento nella posizione x(0) = 0, per seguire i movimenti ignorando le condizioni a riposo, o meglio assumendole come nulle. Queste considerazioni ci portano a immaginare una molla ideale adimensionale, cioè che non occupa spazio ma assolve comunque ai propri compiti, e a riposo è talmente piccola da scomparire. Oltre a ciò la molla è ideale, cioè si suppone che il suo coefficiente di elasticità sia costante, indipendente dall’allungamento. Sappiamo che questo in pratica non è vero, perché una molla allungata cambia le proprie qualità elastiche. Mantenendo l’analisi del moto entro limiti opportuni, si può assumere costante tale parametro. Scrivendo l’espressione precedente alle differenze finite si ottiene:
e, dividendo primo e secondo membro per Δt:
da cui, con la formula inversa si ricava l’equazione caratteristica della molla:
Lo smorzatore è l’elemento passivo, in quanto, a differenza dalla molla e della massa che accumulano energia e possono quindi restituirla, lo smorzatore la dissipa solamente. L’energia viene dissipata in una forma irrecuperabile, di solito in calore. Elementi dissipatori possono essere presenti in qualsiasi sistema meccanico, anche non intenzionalmente; basti pensare a tutte le forme di attrito indesiderate, che incidono sul rendimento finale. Nei nostri modelli faremo però riferimento a un dissipatore appositamente realizzato, in modo da poter concentrare l’effetto di dissipazione in un solo elemento e poter condurre un’analisi matematica mirata. Facciamo riferimento allo smorzatore a pistone, un sistema che introduce una frizione con un mezzo viscoso, entro il quale si muove un pistone. La figura che segue introduce una schematizzazione intuitiva: il fluido viscoso presente nella camera oppone una resistenza al moto del pistone, la cui energia cinetica viene parzialmente dissipata.
Nella figura che segue è rappresentato il simbolo dello smorzatore utilizzato nelle schematizzazioni.
La maggiore o minore azione frenante è riassunta nel parametro ka, il coefficiente di viscosità. La forza di contrasto è dettata da questo coefficiente, ma anche dalla velocità del pistone, perciò: FR(t) = –ka · v(t). Considerando, al posto della forza di contrasto, l’uguale ma opposta forza attiva, scompare il segno meno e si ottiene:
che è l’equazione caratteristica dello smorzatore.
Equazione del moto nei sistemi meccanici
Studiare il comportamento di un sistema meccanico significa essenzialmente determinare l’equazione che ne descrive il movimento, detta equazione del moto. L’equazione è sempre del tipo alle differenze finite e presenta una o più incognite, che sono le specifiche del movimento del sistema da analizzare. Le incognite non sono dei semplici numeri, come in una normale equazione algebrica, bensì delle funzioni del tempo, dato che descrivono un’evoluzione dinamica. Le incognite, una volta estratte, possono essere visualizzate nel loro corso temporale mediante diagramma cartesiano, riportando i diversi valori della funzione calcolati nei diversi istanti di tempo. L’equazione alle differenze finite fornisce una soluzione numerica, cioè una formula iterativa che permette di calcolare, a partire dal valore noto della funzione all’istante iniziale, tutti i valori successivi, a istanti di tempo intervallati dal tempo di campionamento Δt. L’analisi può essere divisa, per chiarezza di esposizione, nelle seguenti tre fasi:
- Scrittura dell’equazione del moto;
- Risoluzione numerica dell’equazione del moto;
- Simulazione numerica.
Analizziamo le varie fasi.
Si consideri un sistema costituito dai seguenti componenti elementari: una massa sospesa per mezzo di una molla, ancorata a un vincolo, in presenza di forza di gravità.
In condizioni di equilibrio la massa è ferma. In effetti, se la si abbandona lentamente, essa tende ad abbassarsi e a provocare l’allungamento della molla; all’aumentare dello stiramento della molla aumenta la sua forza elastica. Quando la forza statica elastica di richiamo impressa dalla molla eguaglia la forza peso della massa, dovuta alla forza di gravità, si determina un equilibrio statico. In questa situazione si dice che la massa è “a riposo”. Dato che il sistema è lineare, si può analizzare il moto scorporando dall’analisi l’effetto del pe so. Osserviamo cioè quello che accade a partire dallo stato “a riposo”, immaginando una situazione di partenza dove tutte le forze siano azzerate. Immaginiamo cioè che la massa non abbia peso e la molla non debba quindi contrapporre una forza di contrasto. In questa situazione sembra che il complesso non esprima delle forze; in realtà basta muovere forzatamente la massa verso il basso e rilasciarla, perché abbia inizio un movimento e nascano delle forze. Per proseguire lo studio fissiamo la coordinata X del movimento in coincidenza con la posi zione di riposo come nella figura che segue. Le coordinate non sono infatti dei riferimenti assoluti, non esistono in natura, sono dei modelli mentali comodi per analizzare i fenomeni fisici. Scopo del nostro studio sarà ora analizzare il moto della massa; lo spazio da essa percorso sarà opportunamente descritto dalla variabile x(t), corrispondente appunto alla coordinata x (diretta verso il basso).
Si supponga ora di spostare la massa dalla sua posizione di equilibrio e successivamente abbandonarla. L’esperienza ci suggerisce che in questo caso essa comincia a oscillare, sotto l’azione della forza elastica della molla. Quando la molla è nel suo punto di massimo allungamento, imprime infatti una forza di richiamo tale da vincere la forza di inerzia della massa e farla risalire; quando la massa è in alto la molla ha ceduto tutta la sua energia, mentre la massa possiede l’energia potenziale che la spinge nuovamente verso il basso. In ogni istante è rispettato assolutamente l’equilibrio delle forze: la forza elastica della molla Fe eguaglia la forza di inerzia posseduta dalla massa. In altre parole si deve iniziare dall’equazione di Newton:
Sviluppiamo ora questa espressione di base facendo appello alle equazioni caratteristiche dei componenti. La forza elastica della massa è proporzionale al suo allungamento, attraverso il coefficiente elastico della molla, legato alle sue caratteristiche costruttive, quindi:
In questa equazione sono presenti due incognite: lo spazio x(t) e l’accelerazione a(t). In realtà l’equazione è esprimibile in funzione di una sola delle due variabili, perché queste sono interdipendenti. Abbiamo visto in precedenza che spazio, velocità e accelerazione sono legati da espressioni alle differenze finite: riprendiamo, tra quelle, la relazione tra accelerazione e spazio, che fa al nostro caso:
Sostituendola nell’ultima equazione otteniamo l’equazione del moto:
Si preferisce solitamente ordinare i termini dell’equazione secondo uno schema comune, che prevede che i termini di ordine maggiore, cioè quelli con esponenti di grado maggiore, vengano scritti prima di quelli di grado minore. In tal caso l’equazione si presenta scritta in questo modo:
Risoluzione numerica dell’equazione del moto
Prima di iniziare questa nuova ricerca, cerchiamo di semplificare il procedimento, togliendo di mezzo i termini concettualmente non essenziali cioè i parametri m e k e. A questo scopo circostanziamo il problema, assegnando ai parametri dell’equazione dei valori definiti, in modo che l’equazione assuma una forma più sobria. Supponiamo per esempio che sia:
Risulta allora:
e, semplificando:
Per poter risolvere il problema attraverso la simulazione a computer è opportuno però man tenere due equazioni distinte, una nella variabile v(t) e l’altra nella variabile x(t). Queste variabili sono le variabili di stato, perché a partire dal loro valore a un dato istante è possibile conoscere l’evoluzione del sistema negli istanti successivi. L’equazione del moto è quindi convertita nel seguente sistema, che si dice del secondo ordine, perché descritto da due variabili di stato:
esprimendo il termine
in funzione della velocità :
Ma la variazione della velocità nell’intervallo Δt è pari al valore v(t + Δt) che essa possiede nell’istante t + Δt meno il valore v(t) all’istante t, come descritto dal grafico:
Si può scrivere perciò:
Ripetendo lo stesso ragionamento per lo spazio si ottiene:
Sostituendo queste espressioni nel sistema si ottiene:
Traslando il termine Δt al secondo membro:
Infine, traslando i termini v(t) e x(t) al secondo membro, si ottiene il sistema di equazioni iterative del moto:
Il sistema di equazioni iterative del moto costituisce il modello matematico discreto del problema sotto analisi. Discreto significa analizzato a salti, non in modo continuo. Si può osservare infatti che, noto un valore all’istante t, le equazioni permettono di ricavare i valori delle variabili Δt istanti dopo. In particolare, noti i valori iniziali x(0) dello spazio e v(0) della velocità, è possibile determinare con la prima equazione i valori successivi della velocità e con la seconda quelli dello spazio. In questa simulazione si sono imposti i seguenti valori iniziali:
- Massa inizialmente ferma, quindi v(0) = 0;
- Massa trascinata verso il basso di 1 metro e rilasciata, quindi: x(0) = 1 m.
È stato utilizzato un passo di simulazione Δt = 0,001 molto piccolo, per ragioni di precisione del calcolo della risposta, quindi per la simulazione di quasi due periodi sono state utilizzate circa 2000 celle. L’immagine che segue visualizza solo le prime celle. Le formule utilizzate sono:
- Colonna v(t): D4 = D3–100 * E3 * $H$19
- Colonna x(t): E4 = E3 + D3 * $H$19
Analogie tra processi elettrici e meccanici
Esistono delle similitudini obiettive tra sistemi con caratteristiche apparentemente molto di verse, aventi diversa natura fisica. A condizione di trovare delle associazioni tra le variabili in gioco, sistemi di natura diversa rivelano una uguale fisionomia e sono strettamente imparentati da relazioni matematiche equivalenti. Un sistema meccanico può essere descritto da un’equivalente circuito elettrico, un sistema elettrico può essere descritto da equazioni coincidenti con l’analogo meccanico. È sempre di grande aiuto, nello studio di un sistema meccanico, tenere aperto un doppio canale, riportando anche le corrispondenti leggi elettriche e il circuito equivalente. Questo è il criterio che applicheremo in questa sezione, prendendo come esempio configurazioni meccaniche comuni e di particolare interesse concettuale. Le analogie non si fermano a queste due classi di sistemi, ma investono varie categorie, come i sistemi termici e quelli idraulici. Ci si può allora astrarre dalla natura del sistema, cioè dalle sue caratteristiche fisiche, e condurre uno studio su un piano puramente astratto. Per esempio, un sistema termico può essere studiato analizzando l’analogo sistema elettrico; una stanza che si riscalda per l’azione del caminetto è equivalente al condensatore che si carica in un circuito RC. Questo procedimento introduce delle notevoli semplificazioni pratiche, data la maggiore facilità di montaggio e la maggiore economicità dei circuiti elettrici, rispetto a complessi apparati meccanici. Noto il modello matematico comune è sempre possibile affidarne lo studio al calcolatore, attraverso una simulazione informatica, che ha notevoli caratteristiche di flessibilità nello studio degli effetti di modifica dei parametri, tracciamento di grafici e quant’altro. Allo scopo di costruire un sistema di analogie coerente si inizia con l’associare le variabili essenziali dei due sistemi. La forza è assimilabile alla tensione, in quanto entrambe sono cause scatenanti, la velocità è assimilabile alla corrente. L’analogia tra due grandezze è rappresentata dal simbolo ‘≡’, pertanto possiamo scrivere:
f(t) ≡ v(t) dove: f(t) = forza; v(t) = tensione
v(t) ≡ i(t) dove: v(t) = velocità; i(t) = corrente
Passiamo ora a esaminare le analogie tra componenti elettrici e meccanici. Facciamo riferimento, come paradigma, al caso della massa. Applicando una forza a una massa, questa inizia a muoversi con una data velocità; le due grandezze sono legate dalla nota espressione:
Analogamente, applicando una differenza di potenziale ai capi di una induttanza, circola una corrente legata alla tensione dalla nota espressione:
Si capisce a questo punto che massa e induttanza sono due componenti analoghi, perché de scritti dalla stessa equazione. Cambiano solo i simboli e le unità di misura. Con i medesimi ragionamenti si arriva a definire la seguente tabella delle analogie tra i componenti dei sistemi meccanico ed elettrico. Nella terza colonna sono riportate le analogie tra i parametri dei componenti.
Affrontiamo ora il problema della trasformazione di un sistema meccanico nel circuito elettrico equivalente, facendo riferimento al sistema della figura che segue. Il procedimento può essere suddiviso in tre fasi:
- Individuazione numero e posizione nodi;
- Tracciamento rete meccanica;
- Conversione in rete elettrica.
Individuazione numero e posizione nodi
Il primo passo consiste nell’individuazione delle posizioni spaziali indipendenti, o nodi. Ogni nodo rappresenta un grado di libertà del sistema, perché la sua coordinata spaziale non è rigidamente relazionata alla posizione degli altri nodi, ma dipende anche dalle azioni dei componenti collegati. Le coordinate spaziali dei nodi si valutano rispetto a un nodo di riferimento, che è convenientemente localizzato in corrispondenza del vincolo. Nel sistema sotto osservazione, le posizioni xa e xb sono due nodi perché si muovono liberamente e con velocità va e vb, diverse, rispetto al riferimento O. La posizione xb è svincolata da O per la presenza, in mezzo, dello smorzatore, che si deforma; la posizione xa è svincolata dalla xb per la presenza della molla. Si noti che il numero dei gradi di libertà coincide con il numero dei componenti reattivi, cioè quelli che hanno la caratteristica di poter accumulare e cedere energia. La regola vale in generale; in questo sistema particolare i componenti reattivi sono due: la massa e la molla. Si dice anche che il sistema è del secondo ordine.
Tracciamento rete meccanica
Si conferisce al sistema l’aspetto di un circuito, come visualizzato in figura, fissando i nodi circuitali, cioè i punti di connessione di due o più componenti, al posto dei nodi spaziali.
Si disegnano quindi i componenti che fanno capo a questi nodi, connettendo i terminali degli elementi che si muovono all’unisono rispetto al riferimento di zero. Osservando il disegno può sembrare ci sia un errore nel collegamento tra massa e smorzatore, che sono in parallelo, mentre nel disegno meccanico sono allacciati in serie.
È invece esatto, perché lo smorzatore è collegato alla massa e, essendo questa indeformabile, l’estremo dello smorzatore si muove all’unisono con il punto xb. Del resto la massa viene disegnata per comodità come un rettangolo, ma in teoria è un punto materiale, cioè un elemento aspaziale. L’estremo dello smorzatore è quindi collegato virtualmente con lo stesso nodo xb al quale è collegata la massa.
Conversione in rete elettrica
Già dal punto precedente si è profilata una rete con una fisionomia di tipo elettrico. In effetti la rete elettrica è simile a quella meccanica: è sufficiente sostituire a ogni componente meccanico l’equivalente elettrico, in base alla tabella delle equivalenze tra i componenti.
Sistemi Idraulici
Nei sistemi idraulici le grandezze che giocano un ruolo fondamentale sono due: la differenza di altezza e la portata. La differenza di altezza è la causa scatenante, poiché se due liquidi a diversa altezza sono posti in due serbatoi comunicanti, ha luogo uno spostamento del liquido fino a pareggiare l’altezza (principio dei vasi comunicanti). È possibile utilizzare la pressione al posto dell’altezza, ma in tal caso si introduce un elemento in più: il coefficiente che lega le due grandezze. Definiamo ora il significato delle grandezze introdotte.
Differenza di altezza
Disegnare un sistema idraulico non è proprio come disegnare un circuito elettrico, a meno di non ricorrere a simbologie che non ci aiuterebbero sul piano concettuale. Per mettere in evidenza il significato di differenza di altezza non resta che disegnare tout-court i due recipienti con i diversi livelli di liquido. Il primo rappresenta una specie di “generatore di altezza”, paragonabile al generatore elettrico, il secondo è l’utilizzatore (di altezza).
La differenza di altezza vale, nel caso in figura, hi — hu [m].
Portata
Si definisce portata q di una condotta il volume liquido che entra in una sua sezione nell’unità di tempo. Per determinare il suo valore ci si mette all’uscita della condotta con un secchio e un orologio. Si misura il volume ΔV del liquido che finisce nel secchio e il tempo Δt trascorso.
Rapportando questi valori si ottiene appunto la portata q:
I componenti fondamentali sono:
- La resistenza idraulica;
- La capacità idraulica.
Resistenza idraulica
La velocità di passaggio del liquido non dipende solo dalla differenza di altezza: conta che la viscosità del liquido, la forma e il materiale delle condotte ecc. Diciamo che nel complesso una condotta oppone al liquido che l’attraversa una resistenza, pertanto la portata è inversamente proporzionale alla resistenza idraulica, che compare al denominatore della formula:
È evidente l’analogia con il caso elettrico:
La relazione è valida a condizione di stabilire le seguenti associazioni tra le grandezze fondamentali idrauliche ed elettriche:
h = altezza ≡ v (tensione)
q = portata ≡ i (corrente)
Le dimensioni della resistenza idraulica sono
Capacità idraulica
La capacità idraulica ha senso se ci riferiamo al componente “serbatoio” rappresentato in figura, e diamo un breve elenco di definizioni simboliche:
ΔV = volume di liquido riversato nel recipiente;
Δh = variazione di livello del liquido;
Δt = intervallo di osservazione della variazione di livello.
La capacità idraulica CI è il volume di liquido necessario per innalzare il livello del serbatoio di 1 metro.
Matematicamente e dimensionalmente:
Osserviamo che CI ha le dimensioni di una superficie ovvero che la capacità idraulica di un serbatoio è la sua sezione. Ricavando ΔV dalle formule della portata e della capacità ed eguagliando i risultati si ottiene la:
Da questa relazione si ricava la formula caratteristica del serbatoio:
Ovvero: la portata del liquido che affluisce in un serbatoio è pari alla capacità idraulica dello stesso moltiplicata per la velocità di variazione dell’altezza. È evidente che se il serbatoio ha un’ampia superficie, a parità di flusso entrante, il livello si alza lentamente. Si noti la completa analogia con il caso del condensatore, per il quale risulta:
È allora immediato collegare il concetto di capacità idraulica di un serbatoio a quello di capacità elettrica di un condensatore ovvero stabilire l’analogia:
Nel complesso sussistono delle strette analogie tra sistemi idraulici e sistemi elettrici, che vengono raccolte nella seguente tabella.
Equazioni dei sistemi idraulici
Si considerino due serbatoi comunicanti mediante una condotta di interconnessione che oppone una resistenza RI al flusso del liquido. Il flusso è diretto dal serbatoio di livello hi più alto al serbatoio di livello hu più basso. Il livello del serbatoio “generatore” si suppone mantenuto fisso. Siamo interessati a seguire l’evoluzione temporale della altezza hu(t) del serbatoio “utilizzatore”.
Facciamo appello alle due formule fondamentali: la formula caratteristica del serbatoio:
e la formula inversa della resistenza idraulica:
Isolando il termine hi nella seconda e sostituendo l’espressione qi della prima si ricava:
Ora ordinando a partire dal termine di grado maggiore e definendo la costante di tempo idraulica RI · CI = t, si ottiene:
Questa è l’equazione del processo idraulico nell’incognita hu(t), perfettamente analoga all’equazione elettrica della carica del condensatore. Speriamo, a questo punto, di avere mostrato quanto importante sia questo tipo di equazione e come accomuni fenomeni disparati. Ormai dovrebbe essere noto che la soluzione è l’esponenziale hu(t) di figura, che tende asintoticamente ad hi. Questo significa che il primo serbatoio alimenta il secondo fino a pareggiare i due livelli a regime.
Sistema idraulico con foro di afflusso a portata costante
È un serbatoio alimentato da una pompa, che assicura una portata di ingresso costante.
Per la formula caratteristica del serbatoio si può scrivere:
da cui:
L’interpretazione di questa formula è immediata: la variazione di livello del serbatoio è proporzionale al tempo trascorso. Al crescere del tempo, il livello cresce linearmente, come descritto dal grafico in basso.
Il risultato è intuitivo, se vogliamo piuttosto banale: essendo alimentato da un flusso costante, il li vello del serbatoio cresce con velocità costante, aumentando indefinitamente. L’analogo processo elettrico è un condensatore che si carica a corrente co stante. Si mettano a confronto le formule valide per il caso elettrico con quelle del caso idraulico, e si osservi la loro perfetta aderenza.
Svuotamento serbatoio
Non servono molte descrizioni per spiegare il problema rappresentato in figura, mentre
è più arduo dimostrare la legge di variazione di hu(t) per effetto del deflusso del liquido. Ricorriamo alla solita formula caratteristica del serbatoio, anteponendo il segno meno alla portata, per via della direzione uscente dal serbatoio:
La portata può essere espressa anche in funzione della resistenza idraulica:
Sostituendo la seconda nella prima si ha:
Portando RI al numeratore e ponendo t = RICI, si ottiene poi:
da cui:
Quest’ultima è l’equazione alle differenze finite del processo idraulico sotto esame. La funzione hu(t) risolutiva è un esponenziale decrescente, come quello in figura.
L’interpretazione è la seguente: il serbatoio si svuota e il livello del liquido tende asintoticamente a 0. Un condensatore che si scarica su una resistenza segue esattamente le stesse leggi matematiche, quindi rappresenta l’analogo elettrico del processo idraulico studiato. Si riportano di seguito le formule corrispettive.
Equazioni dei sistemi termici
Si consideri un corpo a temperatura Ti = 0, messo a contatto con un corpo a temperatura Te maggiore come nella figura. Si supponga che Te venga mantenuta costante, per effetto di un intervento esterno. Tra i due corpi inizia uno scambio di calore; il corpo a maggiore temperatura cede calore al corpo a temperatura inferiore, finché giungono all’equilibrio termico. Siamo interessati a seguire l’evoluzione della temperatura Ti, dall’istante t = 0 di contatto in avanti.
Il flusso di calore è, come noto, proporzionale alla differenza delle temperature e inversamente proporzionale alla resistenza termica della sezione di contatto delle due pareti secondo la formula:
Lo stesso flusso, entrando nel corpo a temperatura Ti, determina l’innalzamento di quest’ultima secondo la formula:
Isolando Te nella prima e sostituendo FQ si ricava:
Il prodotto RTCT è la costante di tempo termica del sistema; posto allora:
e ordinando l’equazione a partire dal termine di grado maggiore si ricava:
Questa è l’equazione alle differenze finite nell’incognita Ti(t), che governa il processo di riscaldamento (figura a immagine pagina seguente). È assolutamente analoga all’equazione della carica di un condensatore per tensione di ingresso costante relativo alla figura.
La soluzione è la stessa e porta all’andamento descritto dal grafico di figura b. Questo mostra che la temperatura Ti del corpo sale da 0 con andamento esponenziale, tendendo asintoticamente a Te. La velocità di riscaldamento è tanto maggiore quanto più piccola è la costante di tempo.
Raffreddamento di un corpo
Un corpo a temperatura iniziale T(0) è lasciato raffreddare nell’ambiente a temperatura TA che per semplicità ipotizziamo pari a zero. Vogliamo studiare la variazione della T(t) nel tempo. È chiaro che T(t) diminuisce, ma secondo quale legge matematica?
Ricorriamo alla solita legge della variazione di temperatura in funzione della capacità del corpo, anteponendo il segno meno al flusso di calore, per via della direzione uscente dal corpo:
Il flusso di calore può essere espresso anche in funzione della temperatura e della resistenza termica cioè:
Sostituendo la seconda nella prima:
Portando RT al numeratore e ricordando che RT · CT = , si ha:
Quest’ultima è l’equazione alle differenze finite del processo termico sotto esame. La funzione T(t) risolutiva è un esponenziale decrescente, come quello della figura.
L’interpretazione è che il corpo si raffredda tendendo a raggiungere l’equilibrio termico con l’ambiente per t ➞ ∞, ovvero tendendo asintoticamente alla temperatura TA. Un condensatore che si scarica su una resistenza segue esattamente le stesse leggi matematiche, quindi rappresenta l’analogo elettrico del processo termico studiato. Si riportano di seguito le formule corrispettive del caso termico studiato.
Microcontrollori e Microprocessori
L’avvento dei microprocessori ha determinato una svolta nel progetto dei sistemi logici, decretando il passaggio dalla tradizionale logica cablata alla logica programmata. Per logica cablata si intende un approccio progettuale di tipo hardware, nel quale un sistema viene progettato assemblando diversi componenti e moduli circuitali, in funzione dell’applicazione richiesta. Tali moduli sono circuiti a bassa o media scala di integrazione (SSI = Small Scale Integration, MSI = Medium Scale Integration), il che significa che integrano un numero basso o medio di componenti elettronici. La logica cablata soffre di diversi svantaggi:
- ogni funzione operativa richiede una propria struttura circuitale, di conseguenza il progetto risulta poco flessibile e dispendioso;
- nel caso di sistemi complessi la struttura hardware diventa imponente, di conseguenza è alto il rischio di errori nel progetto e nell’assemblaggio dei componenti e si hanno alti costi di progettazione e di produzione. Per logica programmata si intende un approccio progettuale ibrido hardware-software, nel quale:
• è presente uno strato hardware strutturato in modo permanente;
• allo strato hardware si sovrappone uno strato software;
• lo strato software non è rigidamente determinato come quello hardware, ma può essere adattato alle specifiche del progetto.
L’integrazione software-hardware dona un elevato grado di flessibilità e semplifica la progettazione dei sistemi, infatti:
- la funzionalità operativa è dettata dal software, quindi per apportare modifiche al progetto basta modificare il software, senza alterare l’hardware;
- agendo sul software è semplice correggere il progetto in fase di sviluppo, nonché tenerlo aggiornato;
- il progettista non deve preoccuparsi dei dettagli costruttivi dello strato hardware. Nella logica programmata i moduli hardware vengono realizzati mediante sistemi LSI e VLSI (LSI = Large Scale Integration; VLSI = Very Large Scale Integration) detti microprocessori e microcontrollori. Un microprocessore è un dispositivo complesso che integra funzionalità sia hardware sia software:
• dal punto di vista hardware è dotato di circuiti organizzati per le funzionalità interne e per l’interfacciamento con dispositivi esterni;
• dal punto di vista software è dotato di capacità di calcolo di base logiche e aritmetiche, ma soprattutto può leggere ed eseguire programmi.
Un programma è una sequenza di istruzioni che comandano al microprocessore l’esecuzione di operazioni elementari. Combinando le operazioni elementari si possono assegnare al microprocessore compiti molto complessi, che esso esegue a velocità elevatissime, incomparabilmente superiori alla velocità di calcolo umana. Il microprocessore è basilarmente dotato di una intelligenza, la CPU, e una unità aritmeticologica, la ALU, per le operazioni. Esso si appoggia a unità esterne, come per esempio memorie di massa, tastiera, video, per scambiare le informazioni da elaborare. Il microcontrollore è un dispositivo completo e autosufficiente; esso integra entro un unico chip, oltre ai componenti propri del microprocessore, dispositivi aggiuntivi quali memorie, porte di interfacciamento, timer e contatori…Questa differenza architetturale si riverbera sulle modalità di utilizzo e i campi di applicazione. Il microprocessore è:
- legato al mondo dei computer, molto potenti ma anche ingombranti e appesantiti da una serie di sovrastrutture (schermo, tastiera) che ne rallentano il funzionamento;
- adatto ad applicazioni di uso generale (general purpose), come internet e pacchetti applicativi, dove sono necessarie ampie risorse visuali ma non particolari livelli di miniaturizzazione. Il microcontrollore invece:
- è specializzato, cioè spesso destinato a una sola funzione nel suo ciclo di vita; nella sua memoria interna viene infatti inciso un programma permanente che attraverso i pin svolge funzioni di controllo dei sistemi con i quali è interfacciato;
- può essere direttamente incorporato (embedded) entro schede elettroniche di tutti i generi, da sistemi robotici a sistemi per la gestione del traffico a giochi, essendo progettato per la massima autosufficienza funzionale;
- proprio perché incorporato in schede di gestione di processi è progettato per lavorare in tempo reale (real-time), ovvero interagire alla massima velocità con il processo.
I microcontrollori sono progettati per specifiche applicazioni, e questo fa sì che si possano massimizzare le prestazioni in un determinato campo e contemporaneamente minimizzarne i costi. Attualmente sono presenti sul mercato microcontrollori di tutte le fasce di prezzo, differenziati per varietà e numero di dispositivi incorporati. Basilarmente, di un microprocessore si possono isolare i seguenti moduli fonda-mentali:
- CPU;
- sezioni di memoria (RAM, ROM….);
- sezioni di input-output.
- La CPU=Central Processing Unit = Unità Centrale di Elaborazione, è il cuore e l’intelligenza del microcontrollore. Essa:
• interpreta ed esegue il programma;
• gestisce l’UnitàAritmetico-Logica (ALU=ArithmeticLogicUnit) per l’esecuzione delle istruzioni di programma;
• attiva e sincronizza i dispositivi che cooperano all’esecuzione del programma. - Le sezioni di memoria sono destinate al mantenimento del programma che la CPU ha in carico e dei dati sui quali la CPU opera. In particolare si distinguono:
• memoria ROM dove sono incisi dati strutturali dell’elaboratore;
• memoria RAM dove è memorizzato il programma che la CPU deve eseguire e i dati sui quali deve operare. - Le sezioni di input-output fungono da interfaccia tra la CPU e le unità esterne al microprocessore. In particolare si distinguono:
• porte di INPUT, per esempio per la lettura dello stato di interruttori;
• porte di OUTPUT, per esempio per il comando di led e relè.2.2
I dati che circolano in un microcontrollore sono di tipo binario. Essi transitano in parallelo su gruppi di linee digitali, delle quali ognuna trasporta un bit. Un gruppo di linee è denominato bus, a indicare il fatto che a esso è affidato il trasporto contemporaneo di più dati. Per semplificare la schematizzazione, le linee appartenenti a un bus vengono raggruppate e rappresentate da una traccia spessa. La CPU è interconnessa con innumerevoli dispositivi. Un collegamento punto a punto tra la CPU e ciascun dispositivo comporterebbe una proliferazione di linee digitali. Per questo viene utilizzata la tecnica del collegamento a bus. In essa lo stesso gruppo di linee è condiviso sia dalla CPU sia da tutti i dispositivi a essa interconnessi, secondo la cosiddetta tecnica della multiplazione. Questa soluzione:
- semplifica il collegamento riducendo drasticamente il numero di collegamenti;
- permette in teoria una espansione illimitata, senza bisogno di cablare nuove interconnessioni. Per impedire che si verifichino sovrapposizioni di segnali in una medesima linea è necessario che un solo dispositivo alla volta sia abilitato al colloquio con la CPU. Per questo la CPU deve svolgere compiti di arbitrato e definire il dispositivo abilitato al colloquio. In linea di principio, facendo riferimento all’architettura di base, le informazioni sono canalizzate entro tre distinti bus:
1. bus dati;
2. bus indirizzi;
3. bus controlli.
Il bus dati supporta le informazioni scambiate tra CPU e dispositivi. Esso è di tipo bidirezionale, ovvero convoglia i dati sia dalla CPU ai dispositivi, sia in senso opposto. Questa proprietà è evidenziata nella figura da due frecce dirette in senso opposto. In particolare:
- le istruzioni sono dirette dalla memoria alla CPU;
- i dati sono diretti dalla memoria alla CPU se letti e viceversa se salvati.
Il bus indirizzi trasmette in modo monodirezionale uscente dalla CPU gli indirizzi di selezione delle locazioni di memoria e di selezione del dispositivo abilitato al colloquio. Il bus controlli è formato da linee specializzate che individualmente attivano delle funzioni nei dispositivi, come la lettura (read) e la scrittura (write). Sulle linee dei bus transitano le informazioni digitali scambiate tra CPU e dispositivi. Per osservare la logica e la tempistica della tecnica di comunicazione basata sui bus e il ruolo di ciascun tipo di bus, esemplifichiamo attraverso il processo di lettura di un dato nella memoria, da parte della CPU, che rispetta la successiva sequenza:
- La CPU pone l’indirizzo della locazione di memoria da leggere (ad esempio 101 = 5) sul bus indirizzi;
- La CPU invia il segnale di read alla memoria attraverso il bus controlli;
- La locazione viene letta e il suo contenuto 01010101 viene posto sul bus dati. Da qui la CPU lo legge e lo ingloba al suo interno.
La tecnica a bus è essenziale per il risparmio delle linee digitali. Per contro richiede una attenta disciplina dei collegamenti, che assicuri che un solo dispositivo alla volta possa colloquiare con la CPU. Se più dispositivi accedono al bus contemporaneamente infatti, si genera un conflitto di bus.
Il conflitto di bus viene risolto grazie all’attività di governo della CPU, che gestisce opportunamente l’abilitazione dei dispositivi. L’abilitazione viene comandata attraverso il terminale di selezione dispositivo CS (Chip Select).
In ragione del valore di CS, il dispositivo si comporta in questi due modi:
- se CS = 0 la logica three state all’uscita viene posta in condizione buffer con circuito aperto, pertanto le uscite risultano virtualmente scollegate;
- se CS = 1 le uscite sono libere di porre i valori digitali 0 o 1 sui terminali che fanno capo al bus.
La CPU, nella sua funzione di arbitrato, porta alto solo uno dei terminali CS, quindi abilita al colloquio un solo dispositivo; i dispositivi che ricevono CS = 0 risultano virtualmente scollegati. Il componente che presiede alla tecnica del collegamento virtuale è il buffer. È un componente digitale rappresentato come una porta Not, senza la negazione all’uscita, per il quale risulta Y = X, ovvero uscita = ingresso. Questo in condizioni normali, infatti un terzo terminale, detto di controllo, permette di mandare la sua uscita in alta impedenza, per cui Y non è più né 0 ne 1, ma risulta equivalente a un circuito aperto e non carica la linea del bus alla quale è collegata. Nel caso di linee multiple si possono utilizzare integrati che incorporano gruppi di buffer con un solo terminale di controllo comune. La seguente figura visualizza un buffer a 8 linee di ingresso, 8 linee di uscita e un solo terminale di controllo.
La selezione dei dispositivi attraverso i segnali CS viene attuata a opera di una parte della logica di controllo che genera gli opportuni segnali di selezione dispositivo, con la tecnica di decodifica indirizzi. A questo scopo le linee del bus indirizzi sono divise in due parti. Una parte viene utilizzata per la selezione delle locazioni di memoria, la parte rimanente viene utilizzata per la selezione del dispositivo. Allo scopo di comandare il maggior numero di dispositivi dirottando il minor nu-mero di linee, le linee vengono decodificate.
Linguaggio macchina e assembler
Il microprocessore è il centro nevralgico dei sistemi di calcolo:
- è dotato di capacità di calcolo e logiche;
- svolge attività di governo delle varie periferiche e apparati a esso connessi.
Non si può dire però che il microprocessore disponga di una intelligenza propria, infatti i compiti che deve svolgere vengono assegnati attraverso un programma. Un programma in generale:
- contiene istruzioni che il microprocessore deve eseguire;
- fa riferimento a dati che il microprocessore deve manipolare.
Il microprocessore preleva le istruzioni di programmazione dalla memoria e le esegue una dopo l’altra. Grazie alla sua potenza di calcolo, esegue i compiti con velocità elevatissima, quindi in tempi brevissimi. Il microprocessore parla il linguaggio dei bit, quindi tanto le istruzioni quanto i dati devono essere sotto forma di codice binario. Ogni istruzione è quindi codificata come una serie di ‘0’ e ‘1’; inoltre una istruzione può occupare uno o più byte. Il linguaggio dei microprocessori, costituito da codici binari, è detto linguaggio macchina. Ogni istruzione in linguaggio macchina riflette una operazione elementare che l’hardware del microprocessore è in grado di eseguire. Le operazioni elementari sono attività estremamente semplici, come per esempio: la copia di un registro di memoria entro un altro registro di memoria, la somma di due registri e il confronto di due registri. Dato lo stretto connubio tra codice macchina e struttura hardware della macchina, ogni famiglia di microprocessori è dotata di un diverso insieme di istruzioni in codice macchina. Tuttavia i principi generali, trattati nel presente capitolo, sono comuni. Un programma in codice macchina è una fotografia diretta della memoria ed evidenzia:
- una sequenza di parole di memoria con i codici delle istruzioni;
- la specifica dell’indirizzo a lato di ogni parola di memoria.
In alternativa, allo scopo di rendere il codice più compatto, si fa uso della rappresentazione esadecimale per il codice. Il segmento può essere così tabellato:
La programmazione in linguaggio macchina in codice numerico, sia binario sia esadecimale, non è per nulla agevole per le seguenti ragioni:
- è difficile digitare delle sequenze numeriche senza compiere errori di battitura;
- il codice numerico non è facile da memorizzare;
- il codice numerico non fornisce alcuna indicazione sul significato dell’istruzione.
Per questo si utilizza il linguaggio assemblatore che codifica ogni istruzione in codice macchina mediante un nome simbolico abbreviato, avente le seguenti caratteristiche:
- il nome simbolico richiama, con una dizione vicina all’inglese, il significato dell’istruzione;
- il nome simbolico è facile da ricordare, per questo il codice assemblatore, in inglese assembler, è detto anche codice mnemonico. In assembler anche l’indirizzo di una istruzione è codificato con un nome simbolico, detto etichetta o label. Una istruzione in assembler solitamente è formata da due campi: il campo codice operativo e il campo operando. Di questi il codice operativo specifica una azione e l’operando specifica il dato al quale è riferita l’azione. A una sola istruzione in codice assembler possono corrispondere in codice macchina:
• istruzioni a un solo byte;
• istruzioni a due o più byte.
Nelle istruzioni a un solo byte nel corpo dell’istruzione è compresa sia la specificazione dell’azione, sia il dato al quale è riferita l’azione. Le istruzioni a due byte solitamente fanno riferimento a un dato presente in memoria, pertanto è necessario specificare:
- entro il primo byte il codice operativo, che specifica l’operazione da compiere;
- entro il secondo byte l’operando, che di volta in volta varia, oppure l’indirizzo dell’operando. Le istruzioni a tre byte tipicamente sono istruzioni di salto nelle quali, nel caso del set 8051:
• il primo byte è il codice operativo dell’istruzione;
• il secondo byte è la parte alta (8 bit) dell’indirizzo di salto a 16 bit (linee A15 ÷ A8 del bus indirizzi);
• il terzo byte è la parte bassa (8 bit) dell’indirizzo di salto a 16 bit (linee A7 ÷ A0del bus indirizzi).
Il listato o rappresentazione disassemblata di un programma è una modalità completa di rappresentazione del programma dove sono specificate entro diverse colonne:
- Le etichette degli indirizzi;
- Le istruzioni in assembler;
- Gli indirizzi delle istruzioni;
- Il codice esadecimale delle istruzioni;
- Il codice binario delle istruzioni.
Quando in ambito informatico si parla di linguaggio di basso livello e alto livello, si fa riferimento al binomio uomo-macchina:
- basso livello significa linguaggio vicino alla struttura hardware della macchina e alla sua logica operativa;
- alto livello significa linguaggio vicino al livello della lingua parlata e compresa dall’uomo. Procedendo nella direzione dei linguaggi dal basso verso l’alto livello troviamo:
• linguaggio macchina: costituito da codice binario;
• linguaggio assemblatore: sostituisce il codice mnemonico al codice binario;
• linguaggi di alto livello come C e Basic.
Il linguaggio macchina è interpretato direttamente dal microprocessore, mentre i linguaggi di livello superiore richiedono sempre un programma traduttore.
- il programma per tradurre il linguaggio assembler in linguaggio macchina si chiama assemblatore;
- il programma per tradurre il linguaggio di alto livello in linguaggio macchina si chiama compilatore;
Un terzo strumento risulta di grande utilità nello sviluppo di applicazioni: il de-bugger. Dall’inglese bug (baco) questo strumento permette al programmatore di analizzare l’applicazione che sta sviluppando e individuarne gli errori. Il vantaggio del linguaggio di basso livello è la bassa occupazione di memoria che si traduce in alta velocità di esecuzione. Mentre i vantaggi dei linguaggi di alto livello sono l’indipendenza dal tipo particolare di microprocessore e la relativa facilità di stesura del programma. Pertanto il linguaggio di alto livello viene impiegato quando si debba:
- semplificare la scrittura del programma;
- applicare modifiche al programma in modo agevole;
Mentre il linguaggio di basso livello, per la sua essenzialità, risulta il più adatto per:
- sistemi che lavorano in tempo reale, nei quali è richiesta la massima prontezza;
- l’ambito didattico, perché permette di studiare a fondo il microprocessore.
Il codice di programmazione sviluppato con un sistema “vicino” all’uomo si chiama codice sorgente. Il corrispondente programma in linguaggio macchina si chiama codice oggetto.
Architettura interna della CPU
Non esiste un modello univoco di CPU in quanto ogni famiglia di microprocessori ha struttura hardware e soluzioni software diverse; inoltre con l’evoluzione dei microprocessori, le CPU hanno nel tempo assunto architetture sempre più complesse e sfuggenti, allo scopo di ottimizzarne l’efficacia e la velocità. Il nostro scopo è cercare di isolare alcuni tratti ricorrenti. Per questo riferiamoci alla seguente figura, dove sono evidenziati i bus interni alla CPU e i registri e dispositivi principali.
Da un punto di vista concettuale possiamo ascrivere i registri e i dispositivi a tre categorie:
- Registri deputati al prelievo delle istruzioni: program counter e stack pointer, che servono a individuare la posizione dell’istruzione nella memoria;
- Registri e dispositivi deputati al riconoscimento delle istruzioni: registro istruzioni, decodifica istruzioni, controllo, temporizzazione che servono a interpretare l’istruzione e diramare gli ordini agli apparati esecutivi;
- Registri e dispositivi deputati all’esecuzione delle istruzioni: accumulatore, registri, ALU, flag, che servono a mettere in atto fattivamente le operazioni comandate dall’istruzione.
Approfondiamo ora il significato di ciascun registro o dispositivo.
- Registri deputati al prelievo delle istruzioni. Program counter PC: indica a quale indirizzo di memoria prelevare l’istruzione ancora da eseguire. Una volta eseguita l’istruzione, accade che:
• il PC viene incrementato, per puntare alla successiva istruzione;
• nel caso si debba eseguire un salto, il PC viene forzato al nuovo indirizzo cui saltare.
Stack pointer: in esso la CPU deposita l’indirizzo di ritorno, nel caso di salti causati da chiamate a sottoprogrammi. In particolare:
• l’indirizzo dell’istruzione corrente viene caricato dal PC entro lo SP;
• al ritorno dalla chiamata a sottoprogramma SP ripristina l’indirizzo in PC;
• in caso di chiamate nidificate, gli indirizzi vengono accatastati (stack significa appunto catasta);
• la modalità di salvataggio e ripescaggio degli indirizzi accatastati è del tipo LIFO (Last In First Out = ultimo a entrare, primo a uscire). - Registri e dispositivi deputati al riconoscimento delle istruzioni
Registro istruzioni: in esso viene depositato il codice operativo dell’istruzione da eseguire. Decodifica istruzioni: qui la CPU compara l’istruzione con una lista interna che contiene il set di istruzioni, ovvero l’insieme delle istruzioni che la CPU riconosce. Nella lista, per ogni istruzione, è registrato un microprogramma di implementazione, che viene eseguito. Controllo: in questa sezione vengono generati i segnali destinati al bus controlli, necessari per completare la lettura dell’istruzione. Temporizzazione: questa sezione genera sequenze predefinite di impulsi, con un ritmo dettato dal segnale di clock, per comandare elettronicamente i dispositivi coinvolti nell’istruzione. Clock: è un segnale a onda quadra che ritma l’operato del microcontrollore. - Registri e dispositivi deputati alla esecuzione delle istruzioni Accumulatore: è il principale registro di memoria, innervato con tutti gli altri registri, infatti:
• quasi tutte le istruzioni lo utilizzano come registro per i dati in ingresso;
• quasi tutte le istruzioni depositano in esso il risultato. Flag: è un registro che segnala (flag = bandiera) mediante ogni singolo bit delle particolari condizioni; per esempio:
• il flag di zero è un bit che segnala, mediante il suo stato 1 o 0, se una operazione ha dato risultato uguale o diverso da zero;
• il flag di carry è un bit che registra il valore del riporto generato da una somma. ALU Arithmetic Logic Unit = Unità Aritmetico Logica: esegue operazioni aritmetiche e logiche.
Registri: sono registri di memoria utilizzati per depositare dati in modo temporaneo, nel corso dell’esecuzione delle operazioni.
Fasi di Fetch ed Execute
Per comprendere come cooperano i vari elementi della CPU è necessario innanzi-tutto sapere che il microprocessore passa di continuo attraverso due fasi operative:
- fase di fetch: in essa la CPU acquisisce dalla memoria l’istruzione (fetch = ricerca);
- fase di execute: in essa la CPU esegue l’istruzione.
Le due fasi sono composte da una serie di operazioni elementari, che vengono ora descritte, con riferimento alla figura sopra. La fase di fetch contempla i passi seguenti:
- Nel Program Counter viene impostato l’indirizzo dell’istruzione da reperire in memoria. In particolare dopo il reset il PC vale solitamente 0000h, cioè punta alla cima della memoria.
- Il contenuto del PC viene inviato sul bus indirizzi, diretto a selezionare la locazione di memoria.
- La CPU attiva il controllo Read per comandare un’operazione di lettura in memoria.
- La CPU legge la parola di memoria attraverso il bus dati e la deposita nel Registro Istruzioni.
- L’unità di decodifica riconosce il codice operativo presente nel Registro Istruzioni. Supponiamo che l’istruzione sia ADD A, B che significa “somma l’accumulatore A al registro temporaneo B”. In tal caso la fase di execute contempla i seguenti passi successivi.
- La CPU trasferisce il contenuto dell’accumulatore nella ALU.
- La CPU trasferisce il contenuto del registro temporaneo B nella ALU.
- La CPU comanda alla ALU di effettuare la somma.
- La CPU comanda il trasferimento del risultato nell’accumulatore; il dato precedente è soprascritto.
Successivamente, non essendo presenti salti in questo esempio, la CPU incrementa il PC, per predisporre la lettura della locazione successiva di memoria, dando inizio alla nuova fase di fetch. Qualora una istruzione sia composta da più parole di memoria (che specifichino un dato o un indirizzo) la fase di fetch prevede più cicli di lettura in sequenza, per il reperimento degli operandi.
Interfacciamento Microprocessori
Oggigiorno i microprocessori sono diffusissimi, essendo presenti nei computer, negli apparati industriali e anche negli oggetti più comuni, come i telefonini, i giochi, i lettori MP3, gli elettrodomestici.
Ciascuno di questi apparati ha una propria specificità, è interessato da segnali di diversa natura e quindi necessita di uno specifico tipo di interfaccia, per comunicare con la CPU. Lo scopo di questa unità è di introdurre il tema, con riferimento alle interfacce digitali di tipo parallelo, note come porte di input/output. Una porta di output è essenzialmente costituita da un dispositivo in grado di congelare in uscita i bit che la CPU presenta sul bus dati, in modo che essi si mantengano fino alla successiva operazione di memorizzazione e nel frattempo la CPU rimanga svincolata.
Descriviamo per passi la funzionalità di una porta di output, con riferimento allo schema di principio della figura, nel quale compare il latch, un dispositivo di memorizzazione a 8 bit, che è l’elemento fondamentale:
- La CPU presenta un byte sul bus dati;
- La CPU comanda una operazione di scrittura sul terminale write del latch, tramite il bus controlli;
- I livelli logici presenti sugli ingressi D7 D6 D5 D4 D3 D2 D1 D0 vengono trasferiti e memorizzati sulle uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0;
- La sezione di decodifica indirizzi tramite il terminale enable abilita il latch, che abbandona lo stato di alta impedenza;
- I livelli logici rimangono impressi sui dispositivi collegati alle uscite, nel caso dell’immagine sottostante caso 8 led.
Una porta di input è costituita da un dispositivo in grado di leggere e congelare i bit presenti in input a un dato istante, in modo che la CPU possa gestirli anche se si modificano nel tempo. In questo caso i passi sono i seguenti:
- La CPU comanda un’operazione di lettura sul terminale write del latch, tramite il bus controlli;
- I livelli logici D7 D6 D5 D4 D3 D2 D1 D0 presenti sugli ingressi, che in questo caso sono degli interruttori, vengono trasferiti e memorizzati sulle uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0 dove rimangono a disposizione della CPU;
- La CPU tramite il terminale enable abilita il latch, che abbandona lo stato di alta impedenza;
- Le uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0 si presentano sulle corrispondenti linee del bus dati;
- La CPU incorpora gli 8 bit dei dati.
Interfacciamento Microcontrollori
Nei microcontrollori le porte di I/O sono già presenti all’interno del chip; chi programma non deve fare altro che:
- scrivere i dati sul latch di uscita mediante una operazione software di output;
- salvare i dati nel latch di ingresso mediante una operazione software di input.
I segnali di temporizzazione per condurre in porto queste operazioni vengono automaticamente generati dalla CPU. La figura mostra l’organizzazione di una porta di IO, limitatamente a un solo bit. La porta è organizzata per fungere sia da porta di input sia da porta di output. Si nota la presenza dei seguenti elementi per la conservazione del bit:
- un latch di uscita di nome Data Latch per il salvataggio del bit in uscita;
- un latch di ingresso rivolto in senso opposto per il salvataggio del bit in ingresso;
- il pin I/O pin, che supporta sia bit di input sia bit di output;
- un TTL Input Buffer.
Sono presenti altri elementi che servono a scindere la scrittura dalla lettura, perché queste operazioni non possono essere contemporanee, e sono:
- un latch di nome TRIS Latch, che serve a selezionare o la lettura o la scrittura;
- una porta AND e una OR; un FET tipo P e uno tipo N;
- un buffer di input.
Il registro TRIS Latch serve a programmare la porta come input o come output:
- Q TRIS Latch = 0 output
- Q TRIS Latch = 1 input
La CPU abilita la scrittura entro TRIS Latch mediante la linea WR TRIS. Inoltre la CPU può anche leggere lo stato di questo registro, mediante la linea RD TRIS. È importante notare che la linea Data Bus del bus dati è comune a tutti i latch e buffer, tranne il TTL Input Buffer. Per chiarezza, nel disegno è stata aggiunta una linea tratteggiata che separa lo schema in due regioni:
- regione OUT: elementi adibiti a operazioni di scrittura;
- regione IN: elementi adibiti a operazioni di lettura.
Ora possiamo descrivere come viene salvato un bit in scrittura e come viene prelevato un bit in lettura.
Scrittura (OUT)
La tabella descrive in modo esaustivo la catena dei segnali: si vede che alla fine risulta I/O pin = Data Bus, ovverosia, il dato presente sul bus dati viene memorizzato sul pin di uscita. La scrittura entro il Data Latch è comandata dalla CPU attraverso la linea WR Port.
Lettura (IN)
La CPU abilita la memorizzazione del dato presente sul pin di input con un livello basso su RD Port, che giunge negato al terminale EN attivo alto del latch di ingresso. Si noti dalla tabella che la modalità di scrittura sul pin risulta disabilitata, in quanto entrambi i FET si trovano in alta impedenza.
Microcontrollori PIC
I PIC (Peripheral Interface Controller = Controllore di Periferiche Programmabile) sono una famiglia di controllori estremamente versatili, equipaggiati con dispositivi e periferiche, che ne esaltano l’autosufficienza funzionale. Il PIC, come ogni microcontrollore oltre alla CPU, che è il cervello del sistema, è dotato di un insieme di apparati che lo rendono autosufficiente per una larga fascia di applicazioni. Di seguito si elencano le più importanti.
- Memorie — memoria flash RAM, ROM, EPROM.
- Periferiche — dispositivi che integrano le funzionalità della CPU quali Timer e conv. ADC.
- Interfacce — soluzioni per il dialogo con apparati esterni come porte di ingresso/uscita, interfaccia seriale e parallela.
Il PIC, una volta programmato, può iniziare a interagire con i sistemi nei quali è incorporato, grazie ai terminali che fungono da interfaccia. Per consentire una analisi approfondita e puntuale il modulo ruoterà intorno a un microcontrollore particolarmente noto: il PIC 16F84A. Il PIC16F84A appartiene alla fascia dei microcontrollori con bus dati 8 bit e architettura media a bus programma di 14 bit. È dotato di due porte di I/O, la PORTA a 5 bit e la PORTB a 8 bit. Il contenitore, di cui possiamo vederne una immagine nella pagina seguente, ha 16 pin:
L’architettura dei PIC è di tipo Harvard a bus separati. In questo tipo di architettura i dati di memoria e le istruzioni di programmazione transitano su linee separate, a differenza dell’architettura classica von Neumann, nella quale dati e istruzioni condividono le stesse linee. Osservando in figura lo schema interno semplificato, si nota appunto che la CPU:
- comunica con la memoria programma tramite il bus programma;
- comunica con la memoria dati tramite il bus dati.
Poiché, grazie alla separazione dei bus, la dimensione del bus programma non deve adattarsi alla dimensione del bus dati, la memoria di programma può essere realizzata con parole di memoria estese (a 14 bit nel caso dei PIC di architettura media), che includono in una sola Word codice operativo e operando. Per questo tutte le istruzioni, con pochissime eccezioni, vengono eseguite in un solo ciclo. Di conseguenza le dimensioni dei programmi risultano ridotte e pertanto la velocità esaltata rispetto ad altre famiglie di microchip. Un altro elemento che contribuisce alla velocità è l’architettura di tipo RISC (Reduced Instruction Set Computer = Computer con Set Istruzioni Ridotto), caratterizzata da un set ridotto di istruzioni molto semplici e veloci, in contrapposizione all’architettura CISC (Complex Instruction Set Computer = Computer con Set Istruzioni Complesse) con istruzioni più elaborate. La CPU (Central Processing Unit = Unità Centrale di Elaborazione) è il cervello del microcontrollore, riceve le istruzioni dalla memoria programma attraverso il bus programma. Le istruzioni sono selezionate dal Program Counter PC. La CPU decodifica l’istruzione, ovvero interpreta il suo significato e impartisce i comandi per eseguirla. In questo compito è supportata dal registro accumulatore WREG, centro nevralgico per la circolazione dei dati e dalla ALU (Arithmetic and Logic Unit = Unità Aritmetico Logica), centralina di calcolo matematico. La memoria programma, nei PIC di ultima generazione, è di tipo flash, una me-moria permanente a cancellazione e riprogrammazione rapida. La memoria dati si suddivide in memoria RAM e memoria EPROM.
- La RAM contiene i File Registers (registri archivio) che conservano l’“impronta” del sistema. Se la CPU è il cervello del sistema, i file register ne sono il cuore.
- Sulla EEPROM possono essere salvati dati da conservare. Non esiste un vero e proprio bus indirizzi, in quanto gli indirizzi delle istruzioni sono diramati in modi distinti:
- la memoria dati RAM e in parte la EPROM ricevono l’indirizzo della locazione da leggere/scrivere attraverso il bus dati;
- la memoria programma Flash riceve l’indirizzo dell’istruzione da eseguire dal Program Counter PC, a sua volta collegato al bus dati. Come tradizione la CPU gestisce l’istruzione di programma in due fasi: la fase di fetch e la fase di execute:
— nella fase di fetch avviene il prelievo dell’istruzione dalla memoria (fetch = ricerca);
— nella fase di execute ha luogo l’esecuzione vera e propria del comando impartito dall’istruzione.
Nel PIC è possibile una parziale sovrapposizione delle due fasi (pipeline), con risparmio di tempo e conseguente aumento della velocità. Infatti, mentre nei microprocessori originari le istruzioni e i dati viaggiavano sullo stesso bus, il bus dati, nel PIC, grazie alla separazione tra bus programma e bus dati:
- mentre è ancora in corso l’esecuzione di una istruzione, con il coinvolgimento del bus dati.
- la CPU può iniziare la lettura dell’istruzione successiva attraverso il bus programma.
Struttura della memoria
Una conoscenza puntuale della struttura e del contenuto delle memorie è indispensabile per cimentarsi nella programmazione.
Come si può osservare dalla figura, in generale i dispositivi PIC sono dotati di tre distinte aree di memoria: programma, dati, EEPROM. Nella memoria di programma viene riversato, al momento della programmazione, il codice macchina.
- La memoria di programma nei dispositivi di ultima generazione è di tipo flash, una memoria non volatile programmabile e cancellabile elettricamente fino a 100000 volte.
- All’indirizzo 0000h è collocato il vettore di reset. A questa locazione si dispone il PC al momento del reset; da qui inizia l’esecuzione del programma.
- Uno o più indirizzi sono riservati ai vettori di interrupt.
- Sono presenti alcuni livelli di stack (catasta) entro i quali il programma salva (push) l’indirizzo di ritorno da sottoprogramma e lo ripristina (pop) all’uscita dal sottoprogramma.
Nella memoria DATI di tipo RAM, veloce ma volatile, vengono registrati i dati di gestione dei dispositivi del microcontrollore e i dati manipolati dal programma. Da un punto di vista logico è divisa in due aree.
- Registri uso generale GPR (General Purpose Registers) a disposizione per la registrazione dei dati manipolati dal programma, normalmente noti come “variabili”.
- Registri funzione speciale SFR (Special Function Registers) impiegati dalla CPU per controllare il comportamento dei dispositivi del microcontrollore, come il Timer e le porte di I/O. Una ulteriore suddivisione riguarda i registri SFR:
• tipo “core”: contengono informazioni che disciplinano il comportamento del sistema nel suo insieme;
• tipo “periferica”: mantengono memorizzate le informazioni di configurazione delle periferiche interne.
I byte presenti nella memoria dati vengono spesso identificati in letteratura come File Registers, ovvero registri archivio, intendendo che sono i registri dell’archivio dei dati. Sono simbolizzati in generale dalla lettera “f”. La memoria EEPROM, acronimo di Electrically Erasable Programmable Read Only Memory (Memoria di sola Lettura Cancellabile e Programmabile Elettricamente), è una memoria di tipo non volatile, impiegata per la conservazione di dati importanti per il processo gestito dal microcontrollore, il cui contenuto permane anche a microcontrollore spento. Anche se il suo contenuto è permanente, è possibile cancellarla e riprogrammarla con opportune istruzioni, che agiscono elettricamente nei suoi circuiti interni, senza la necessità, come nelle EEPROM, di esposizione a raggi ultravioletti per la cancellazione.
Progetto e simulazione di automi
Riferendosi a una persona che compie una successione di azioni cicliche, si dice che egli agisce come un automa. In effetti questa idea comune si avvicina alla definizione tecnica, o almeno rappresenta un primo gradino per individuare compiutamente il concetto di automa, che sarà esaminato nella presente unità.
Ingressi, Uscite e stati
A un primo livello di analisi, limitandoci al concetto immediato che la parola “automa” evoca nella nostra mente, possiamo affermare che l’attività di un automa si esplica come successione di azioni, secondo una gamma fissa preregistrata (automa stupido ma utile) op pure in risposta a sollecitazioni esterne (automa intelligente). Le azioni si susseguono in sequenza, il sistema evolve da una fase operativa alla successiva; pertanto l’automa è prima di tutto un sistema dinamico o sequenziale, ovvero un sistema che modifica il proprio stato con l’avanzare del tempo. Le azioni non hanno luogo con continuità bensì a scatti; dopo una breve fase di transito da uno stato al successivo, segue una fase di mantenimento di durata maggiore. Le azioni sono cioè separate da intervalli di tempo finiti, perciò l’automa è anche un sistema discreto. Nel compiere il suo ciclo di lavoro l’automa transita attraverso diverse situazioni in-terne, dette stati. Nel corso di un ciclo si verifica una successione di stati e il passaggio da uno stato all’altro è imposto sia dalla logica operativa intrinseca della macchina, sia da eventuali sollecitazioni esterne che condizionano il flusso operativo. Per poter descrivere il funzionamento di un automa in modo preciso e rigoroso, non è sufficiente ricorrere all’approccio descrittivo con il quale abbiamo esordito, è necessario rappresentare simbolicamente gli elementi che ne identificano il comportamento e descrivere le relazioni che li correlano. Gli elementi fondamentali sono l’insieme degli ingressi, che influenzano l’evoluzione del sistema, l’insieme degli stati, che originano le sequenze operative, e l’insieme delle uscite, che sono gli elementi utili. Un insieme di elementi prende il nome di alfabeto. Gli elementi di questi insiemi vengono definiti variabili. Per economia di scrittura, spesso ci si riferisce a un insieme di variabili con un solo simbolo, anzi ché enumerarle a una a una. I simboli compatti sono:
- insieme variabili di ingresso: I(t);
- insieme variabili di uscita: U(t);
- insieme variabili di stato: X(t).
A un primo approccio possiamo rappresentare schematicamente l’automa generico mediante un blocco, evidenziando le variabili di ingresso e uscita:
L’introduzione sembra aver fatto luce sul concetto di automa. Eppure manca un tassello importante. Abbiamo detto che lo stato è responsabile dell’evoluzione del sistema, descrivendo le transizioni attraverso situazioni, ovvero stati interni, differenti. Dove sono le variabili di stato nello schema a scatola chiusa? Lo schema a blocchi con l’evidenziazione di ingressi e uscite non è sufficiente, dobbiamo mettere il sistema sotto una lente di ingrandimento “concettuale”. Lo schema seguente si riferisce al nostro caso:
Il sistema descritto dallo schema si compone di tre sezioni fondamentali:
- sezione di memoria: memorizza lo stato attuale;
- sezione logica: prepara lo stato futuro;
- sezione di temporizzazione (clock): sincronizza l’evoluzione.
Per poter avanzare attraverso la sequenza dei propri stati, una macchina automatica sequenziale deve ricordare lo stato nel quale si trova (per esempio un orologio ricorda l’ora indicata) e avere una logica, un’intelligenza, che le permetta di costruire, a partire dalla conoscenza dello stato attuale, lo stato futuro, cioè quello successivo. La macchina genera allora le uscite (output) in base alle sollecitazioni di ingresso (input) e allo stato interno, registrato nella propria memoria. Affinché il meccanismo sia cadenzato, è necessario poi un segnale che disciplini l’emissione delle sequenze, cioè blocchi il sistema nel proprio stato per un dato intervallo di tempo, dopodiché dia via libera alla transizione allo stato successivo. Nello schema questa azione è assegnata simbolicamente a un interruttore, che si immagina co-mandato da un segnale periodico (il bilanciere nel caso di un orologio meccanico). Il segnale di clock svolge il ruolo di temporizzazione, chiudendo e aprendo il circuito, quindi bloccando o rilasciando il processo di avanzamento degli stati.
La funzione di memoria è strettamente correlata con lo stato. È la memoria del sistema a conservare lo stato, la condizione attuale. La successione passata degli stati rappresenta la “storia” del sistema; in base a questa storia si costruiscono gli stati futuri. Gli stati si indicano simbolicamente con la lettera maiuscola S seguita da un indice numerico progressivo, ovvero S0, S1, S2, … A dire il vero noi avevamo detto che l’alfabeto di stato si indica con X e ciascuna delle sue variabili di stato con x0(t), x1(t), x2(t), … xN — 1(t). La notazione che fa uso della S è una mera rappresentazione simbolica, mentre le X(t) sono le variabili interne che fisica mente codificano lo stato. Il lettore potrà capire meglio questa differenza quando affronteremo le modalità di progettazione degli automi.
Lo stato presente viene chiamato stato attuale e indicato come S(t), lo stato al passo successivo viene chiamato stato futuro e indicato come S(t + 1). Si noti che si è parlato di passo e non di istante di tempo. Questo perché il sistema è discreto e gli istanti di tempo sono distanziati tra loro di un intervallo finito. L’intervallo può avere diverse durate: per esempio, nel caso di un orologio digitale le cifre dei secondi sono intervallate di un secondo e quelle dei minuti di un minuto (lapalissiano). Il funzionamento di un automa è però indipendente dall’entità del passo. L’intervallo tra un passo e l’altro è di solito imposto da un segnale a onda quadra, detto clock, che gestisce la temporizzazione. Cambiando la frequenza di clock cambia il ritmo, ma il processo intimo rimane inalterato. Per queste ragioni, al posto della variabile t, si usa spesso la variabile naturale i, volendo intendere con S(i) lo stato iesimo, senza fare riferimento a un istante di tempo reale.
Definizione e rappresentazione schematica formale
Si definisce automa un sistema discreto (le variabili che lo caratterizzano possono assumere un numero limitato di valori) e dinamico (le sue variabili evolvono in modo automatico secondo una logica interna predefinita). Le variabili caratterizzanti il suo funzionamento si possono classificare in:
- variabili di ingresso, appartenenti all’insieme I(t): sono le sollecitazioni esterne, che non sono prodotte dal sistema ma ne condizionano il funzionamento;
- variabili di uscita, appartenenti all’insieme U(t): sono le grandezze interne del sistema che interessa osservare e utilizzare;
- variabili di stato, appartenenti all’insieme X(t): sono le grandezze che descrivono le varie tappe dell’evoluzione del sistema.
Note le variabili di stato a un certo istante e noti gli ingressi, è possibile conoscere lo stato successivo del sistema. La nozione di variabile di stato implica la presenza nel sistema di parti con funzionalità di memoria. Il sistema, grazie alla conoscenza del proprio stato presente o attuale, memorizzato a un dato istante t, riesce con la propria logica interna a generare lo stato futuro all’istante t + 1.
Questo concetto è evidenziato dallo schema sintetico di figura.
In esso distinguiamo tre blocchi fondamentali: MEM, FTS e FTU. L’elemento di memoria MEM conserva lo stato X(t) all’istante t. La logica interna FTS prende il nome di Funzione Transizione di Stato. Questa ha un compito importantissimo, quello di costruire, a partire da X(t) e dall’ingresso allo stesso istante I(t), lo stato futuro X(t + 1).#
Questo verrà successivamente memorizzato e assumerà il ruolo di stato presente. Ma quando avviene questa sostituzione? Bisogna sapere che all’elemento MEM è associata una funzionalità temporale: la memorizzazione dell’ingresso X(t + 1) e il conseguente trasferimento all’uscita viene comandato da una logica di temporizzazione (figura a).
Nella maggior parte dei casi il passaggio è sincronizzato con un segnale uniforme generato internamente, detto clock, e può avere luogo per esempio, in coincidenza con l’evento di transizione basso → alto (figura b).
In altri casi il blocco MEM può essere semplicemente associato a un ritardo prefissato. È questa la modalità sfruttata nelle simulazioni con il programma LabVIEW, dove viene intercalato un ritardo impostato a piacere, a seconda del ritmo di lavoro che vogliamo conferire all’automa, tra lo stato presente e lo stato futuro. D’ora in poi adotteremo sempre il simbolo indicato nella figura seguente, indipendentemente dal reale sistema implementativo, perché riteniamo sia quello che condensa in modo chiaro il ruolo di conservazione dello stato e di temporizzazione.
Il simbolo è autoesplicativo: MEM rappresenta la funzionalità di memoria, il disegno dell’orologio la funzionalità di temporizzazione. L’altro blocco fondamentale FTU rappresenta la Funzione Trasformazione di Uscita.
Esso genera le uscite all’istante t, a partire dagli stati all’istante t ed eventualmente dagli ingressi all’istante t. Si distinguono a questo proposito due tipi di automi:
- automa di Moore: le uscite all’istante t dipendono solo dallo stato all’istante t (sistema proprio);
- automa di Mealy: le uscite all’istante t dipendono dallo stato all’istante t e anche dagli ingressi all’istante t (linea tratteggiata, sistema improprio). Possiamo definire un livello maggiore di dettaglio, evidenziando la molteplicità di ingressi, uscite e stati, come nello schema espanso qui riportato.
Il concetto non cambia: il blocco FTS costruisce gli stati futuri x0(t + 1), x1(t + 1), …, xN — 1(t + 1) a partire dagli stati presenti x0(t), x1(t), …, xN — 1(t) e dagli ingressi i0(t), i1(t), …, iM — 1(t). Il blocco FTU genera le uscite, u0(t), u1(t) …, uL — 1(t) a partire dagli stati attuali ed eventualmente, nel caso della macchina di Mealy, dagli ingressi attuali i0(t), i1(t), …, iM — 1(t). Le linee tratteggiate sono relative appunto alla macchina di Mealy.
Automazione Industriale
Questa unità è una estrema sintesi della programmazione dei PLC industriali con il linguaggio ladder. Il LADDER (detto anche “linguaggio a contatti” o “linguaggio degli elettricisti”) è un linguaggio di tipo grafico ed è storicamente il primo che è stato adottato per programmare il PLC, in quanto consentiva una traduzione quasi immediata tra schemi funzionali di potenza e/o comando e programma per lo stesso. Nelle attuali versioni, molto evolute rispetto a quelle iniziali, gli elementi principali del linguaggio sono:
Elementi di tipo “elettrico”:
- Binari (o linee) di potenza (power rail);
- Contatti elettrici NA o NC;
- Bobine di uscita (chiamate anche “relè” o “coil”);
- Relè “interni” e “speciali”.
Elementi di tipo “blocco funzione”:
- Contatori;
- Temporizzatori;
- Funzioni matematiche, logiche, di trattamento dati ecc. (le tipologie dipendono largamente dal modello di PLC utilizzato).
Struttura base di un programma LADDER
Il programma si articola in linee orizzontali dette “rung”, che si sviluppano tra i due binari di potenza sinistro e destro.
- Ogni rung inizia obbligatoriamente dal binario di potenza sinistro, mentre il collegamento col binario di potenza di destra è spesso facoltativo (generalmente i software di programmazione effettuano di default questa connessione laddove è richiesta);
- Ciascun rung può contenere contatti, bobine di uscita, blocchi funzione, relè di uscita interni o speciali ecc…
Contatti
I contatti sono in genere associati a dispositivi di ingresso fisicamente connessi al PLC (pulsanti, interruttori, finecorsa, sensori di prossimità ecc), ma possono anche essere riferiti ad altri elementi come bobine di uscita, relè interni, locazioni di memoria, blocchi funzione (contatori, temporizzatori ecc.). Ad ogni contatto viene associata una variabile binaria interna alla memoria del PLC che rappresenta lo stato elettrico del contatto stesso (ON/OFF). I contatti possono essere di due tipi, rappresentati dai simboli grafici illustrati nelle figure:
- Contatto NA: la corrente circola quando il contatto viene azionato (a riposo essa non circola);
- Contatto NC: la corrente circola con il contatto in posizione di riposo (a contatto azionato essa non circola);
Bobine di uscita
Le bobine (o relè) di uscita sono il modo più comune con il quale si termina un rung di linguaggio ladder: come si vede infatti dalle figure esse hanno uno dei terminali collegato al binario di potenza destro (a volte tale collegamento è sottinteso oppure viene effettuato in automatico dai software di programmazione);
La bobina NA (normalmente aperta) si attiva quando nel rung corrispondente circola corrente, mentre la bobina NC (normalmente chiusa) si attiva in caso contrario. Generalmente le bobine vengono riferite a:
- uscite fisiche del PLC: in questo caso determinano lo stato del dispositivo di uscita corrispondente, attraverso il quale viene comandato il relativo attuatore;
- Relè o aree di memoria interne al PLC: in questo caso hanno la funzione di memorizzare il risultato dell’elaborazione di un determinato rung di programma da utilizzare successivamente.
I contatti e le bobine di uscita sono sicuramente le istruzioni ladder più utilizzate nella programmazione dei PLC, in quanto fanno riferimento, rispettivamente, a dispositivi di input (pulsanti, finecorsa, sensori di prossimità, fotocellule ecc.) o di output (lampade di segnalazione, elettrovalvole, teleruttori ecc,) praticamente sempre presenti in qualunque tipo di impianto. Le regole che normalmente si utilizzano per la scrittura di rung con contatti e bobine sono le seguenti:
- In ogni rung (che, ricordiamo, inizia sempre dal binario di potenza sinistro) può essere inserito un numero teoricamente illimitato di contatti, che possono essere connessi tra loro in modo da ottenere le funzioni logiche AND e OR:
- Due o più contatti connessi in serie realizzano la funzione logica AND;
- Due o più contatti connessi in parallelo realizzano la funzione logica OR.
- Ogni rung termina generalmente con una sola bobina di uscita connessa al binario di potenza destro; le bobine non possono essere collegate tra loro in serie, ma si possono inserire più bobine di uscita in parallelo in modo che il rung le possa comandare contemporaneamente.
La figura mostra un rung nel quale è presente una combinazione di 4 contatti di ingresso che comandano una bobina di uscita (è sottintesa la connessione con il binario di potenza destro). I contatti e la bobina vengono contrassegnati da un indirizzo che li identifica univocamente all’interno del PLC CP1L: p. es. 0.00 sta ad indicare il punto di ingresso 00 del modulo di input 0; 100.00 sta ad indicare il punto di uscita 00 del modulo di output 100. Tenendo presente che i contatti in serie realizzano la funzione logica AND, quelli in parallelo la funzione OR e che tutti i contatti sono di tipo NA, lo stato della bobina di uscita è dato dalla tabella di verità riportata in basso.
Contatori a decremento
Il blocco funzione CNT (Counter) permette di inserire nel programma un contatore a decremento con settaggio del valore iniziale;
Il contatore presenta due ingressi:
- Count input: viene connesso al dispositivo che manda gli impulsi al contatore (p. es. la fotocellula che rileva il passaggio di una persona attraverso una porta); ad ogni impulso presente sull’ingresso il contatore decrementa di 1 il valore corrente;
- Reset input: viene connesso al comando che permette di resettare il contatore al valore iniziale (p. es. un pulsante).
Quando si inserisce un contatore in un programma si forniscono:
- Il numero del contatore al quale si fa riferimento (da 0 a 4095 per il CP1L);
- Il valore iniziale di settaggio del contatore (da 0 a 9999).
Il funzionamento del contatore è descritto dai grafici sotto riportati
- Un impulso sull’ingresso reset input pone PV = S (PV: valore corrente del contatore);
- Ad ogni impulso presente su count input PV viene decrementato di 1;
- Quando PV = 0 il contatore si attiva, eccitando in questo modo la bobina ad esso collegata;
- Il contatore può essere resettato in qualunque momento portando alto l’ingresso reset input.;
- Se reset input viene mantenuto alto il conteggio è bloccato.
Contatori reversibili (Up/Down)
I contatori reversibili (Up/Down) permettono di ottenere sia il conteggio a incremento (UP) che quello a decremento (DOWN).
Come risulta della figura a fianco sono del tutto simili ai precedenti, ad eccezione del fatto che sono dotati di 3 terminali di ingresso:
- Increment input: conteggio in avanti (UP);
- Decrement input: conteggio all’indietro (DOWN);
- Reset input: reset del contatore al valore iniziale (SV);
Il funzionamento del contatore è illustrato dai grafici nella pagina seguente:
- (1) — Il valore corrente del contatore (PV) può “fluttuare” tra 0 ed il valore di settaggio (SV);
- (2) — Nel conteggio UP il contatore incrementa di 1 ad ogni impulso: raggiunto il valore di settaggio si ha l’attivazione del contatore al successivo impulso che ne determina l’azzeramento;
- (3) — Nel conteggio DOWN il funzionamento è del tutto simile a quanto detto sopra, con la differenza che il contatore decrementa di 1 ad ogni impulso.
Temporizzatori (Timer)
I timer vengono utilizzati per creare un ritardo all’eccitazione con precisione di 0.1s rispetto all’attivazione di un segnale di comando.
Il timer ha un solo ingresso, al quale va connesso il contatto che corrisponde al segnale di attivazione del timer stesso.
Quando si inserisce un timer in un programma occorre specificare:
- Il numero del timer N (da 0 a 4095);
- Il valore di settaggio S, che determina il ritardo all’eccitazione.
Ci sono due tipi di timer, che differiscono tra loro per il valore max del ritardo all’eccitazione:
TIM — 0.1s x 9999 = 999.9s;
TIMX — 0.1s x 65535 = 6553.5s;
Il ritardo all’eccitazione (in secondi) si ottiene moltiplicando S per 0.1; ad esempio con S =100 si ottiene un ritardo di 0.1s x 100 = 10s;
Il funzionamento dei timer è illustrato nei grafici riportati qui in basso:
- (1) — Quando il segnale di input viene portato alto il valore corrente del timer inizia a decrementare partendo da S: quando PV raggiunge il valore 0 il timer si attiva e rimane in questo stato fino a che l’ingresso ritorna basso;
- (2) — Se l’ingresso viene riportato basso prima dell’azzeramento di PV il timer viene resettato al valore iniziale senza che si abbia alcuna eccitazione.
Temporizzatori veloci (High Speed Timer)
I timer veloci funzionano con le stesse modalità dei precedenti ma con valori di precisione più bassi: questo significa che essi sono in grado di realizzare ritardi all’eccitazione con maggiore accuratezza rispetto ai precedenti. I timer TIMH e TIMHX hanno una precisione di 10ms. I timer TIMHH e TIMHHX hanno una precisione di 1ms; inoltre, come risulta dalla figura in basso, per essi N (numero del timer) varia tra 0 e 15.
Schemi Industriali cablati e con PLC
In questa unità vengono trattati gli schemi elettrici industriali per l’azionamento dei motori asincroni trifase. Accanto agli schemi in logica cablata vengono parallelamente studiati gli schemi con l’ausilio del PLC, per un utile confronto e una comprensione a tutto tondo.
Cenni sul motore Asincrono Trifase
I sistemi trifase sono universalmente utilizzati perché più efficienti di quelli mono-fase in tutti i settori, dalla generazione alla trasmissione alla distribuzione dell’energia elettrica. Un generatore trifase è equivalente a tre generatori monofase di tensione sinusoidale con un morsetto N in comune detto neutro, come nella figura a sinistra. Un sistema trifase si dice simmetrico se, come visualizzato nella figura a destra, le tensioni di fase 𝐸1 ⃗⃗⃗ ,𝐸⃗ 2, 𝐸⃗ 3:
- hanno uguale valore efficace e frequenza;
- sono sfasate di 120° tra loro.
Si noti che per ragioni di simmetria spaziale la somma vettoriale delle tre tensioni di fase è zero.
Dal punto di vista temporale le tensioni di fase appaiono diagrammate come nella figura seguente.
La figura seguente mostra il classico collegamento a stella del carico trifase al generatore trifase. Se il carico è simmetrico risulta nulla la corrente 𝐼𝑁 ⃗⃗⃗ nel ramo del neutro, che si può omettere.
Il motore è una macchina che converte l’energia elettrica in energia meccanica, per imprimere il moto agli organi meccanici. È diffuso in tutti i settori industriali in un’ampia varietà di generi e taglie.
Struttura di principio
Come illustrato nella figura a) di pagina seguente in linea di principio il motore in corrente alternata è costituito da uno statore e un rotore, separati da uno spazio vuoto chiamato traferro. Il rotore è in sostanza una elettrocalamita formata da un nucleo attorno al quale è avvolto un solenoide; la corrente che percorre le spire genera un polo sud e un polo nord; la direzione del campo magnetico H è perpendicolare alle spire e il verso è individuato dalla regola della vite destrogira. Lo statore è un pacco di lamierini metallici supportati da una carcassa fissata al basamento. Nei lamierini statorici sono praticati canali detti cave per l’alloggiamento dei conduttori. Le parti terminali dell’avvolgimento giungono su una morsettiera per l’allacciamento all’alimentazione.
Funzionamento
Gli avvolgimenti distribuiti nelle cave percorsi dalle correnti trifase I1, I2 e I3 generano [fig. b] tre campi magnetici H1, H2, H3 perpendicolari agli avvolgimenti, quindi diretti rispettivamente come gli assi radiali A3, A1, A2 reciprocamente sfasati spazialmente di 120°. Gli avvolgimenti sono alimentati da una terna sinusoidale di tensioni sfasate elettricamente di 120°. In virtù di questo duplice sfasamento elettrico e meccanico si viene a creare un campo magnetico rotante che si muove a velocità costante intorno all’asse geometrico del motore. Il rotore, affacciandosi con le espansioni polari al bordo dello statore, si orienta nella direzione del campo magnetico rotante e viene da questo trascinato in rotazione.
Campo magnetico rotante
Un campo magnetico sinusoidale H di frequenza f (pulsazione ω= 2ϖf) orientato in direzione costante come in figura a) può essere scomposto nella somma di due campi rotanti simmetrici:
- un campo HO con velocità di rotazione costante w e direzione oraria;
- un campo HA con la medesima velocità di rotazione w ma direzione antioraria. Il legame tra la lunghezza del vettore risultante H e quella dei vettori componenti è:
H = 2 × HA × senωt
considerando la costruzione geometrica e l’uguaglianza dei due angoli ωt alterni interni.
Azionamento del motore asincrono trifase
L’azionamento è l’insieme degli apparati industriali di alimentazione e controllo del motore. Oggigiorno il controllo del motore è assistito elettronicamente per regolare in modo ottimale coppia, velocità e posizione dell’albero motore. Alla base dei sistemi di azionamento si annoverano i circuiti di avviamento, che realizzano il collegamento tra le fasi L1, L2 e L3 dell’alimentazione trifase e i morsetti U, V, W del motore asincrono trifase. Lo schema di base prende il nome di teleavviamento diretto. L’impianto di teleavviamento diretto realizza un collegamento diretto dei morsetti U, V, W del motore alle fasi L1, L2 e L3. Come visualizzato nella figura a pagina seguente gli elementi utilizzati nel circuito di comando sono:
- contattore KM1 per la marcia avanti provvisto di:
• tre contatti di potenza.
• Un contatto ausiliario; - pulsante di marcia PM e pulsante di arresto PA.
Gli elementi utilizzati nel circuito di potenza sono:
• gruppo contatti KM1;
• fusibili di protezione F1.
I due circuiti interagiscono nel modo seguente.
- Premendo il pulsante PM normalmente aperto viene alimentata la bobina di KM1.
- Il contatto ausiliario di KM1 posto in parallelo a PM mantiene la bobina alimentata, nonostante il rilascio di PM.
- La conseguente chiusura dei tre contatti di KM1 determina l’allacciamento della rete ai morsetti del motore e il conseguente avvio.
- L’interruzione dell’alimentazione può essere comandata tramite l’intervento su PA.
Questa modalità di avviamento è la più semplice ma anche quella più pregna di difetti infatti:
- allo spunto mentre il motore è ancora fermo il campo magnetico rotante ruota già alla frequenza di alimentazione; questo scostamento elevato determina una elevata corrente di avviamento, fino a 10 volte quella nominale;
- la coppia di spunto essendo di molto superiore alla coppia resistente determina un avvio rapido del motore ma non dolce;
- le elevate punte di corrente sollecitano molto gli avvolgimenti, pertanto questo tipo di inserzione è utilizzato per potenze ridotte, dell’ordine di qualche kW.
Lo schema ladder PLC per il teleavviamento diretto programmato è il classico schema di marcia-arresto.
La teleinversione di marcia realizza l’inversione del senso di rotazione mediante due pulsanti che agiscono nel circuito di comando a bassa tensione. Due contattori provvedono poi a trasmettere i comandi alla sezione di potenza. Lo schema base per la teleinversione di marcia illustrato nella figura realizza l’inversione del senso di marcia invertendo il senso di rotazione del campo magnetico.
La manovra avviene commutando due delle tre fasi ai morsetti di alimentazione del motore, mediante due teleruttori che realizzano i seguenti collegamenti:
- teleruttore KM1: U = L1; V = L2; W = L3 rotazione in un senso;
- teleruttore KM2: U = L3; V = L2; W = L1 rotazione in un senso opposto.
Nella sezione di segnalazione due spie attivate dai contatti ausiliari indicano il senso di rotazione.
Lo schema ladder PLC per la teleinversione di marcia programmata è una doppia configurazione marcia-arresto.
Con il sistema di teleinversione di marcia è necessario porre attenzione a non manovrare contemporaneamente i due contattori, in quanto si determina un corto-circuito tra le fasi invertite L1-L3.
Con lo schema di interblocco è impedito l’azionamento contemporaneo dei due contattori, qualora venga azionato in modo intempestivo un contattore mentre l’altro è ancora chiuso. Il circuito di comando prevede due contatti di interblocco in serie ai due rami delle bobine.
In particolare:
- un secondo contatto ausiliario NC KM2 è posto in serie alla bobina KM1;
- un secondo contatto ausiliario NC KM1 è posto in serie alla bobina KM2.
Per comprenderne il funzionamento si supponga che sia attivato KM1. Nel ramo della bobina KM2 il contatto NC KM1 impedisce la circolazione di corrente nel caso in cui venga premuto anche il tasto PM2.
Lo schema ladder PLC per la teleinversione di marcia programmata è una doppia configurazione marcia-arresto con due contatti NC comandati dalle variabili KM1e KM2 nei rami antagonisti. In altri termini KM1 negato è inserito nel secondo ramo e KM2 negato è inserito nel primo ramo.
Trasformata e antitrasformata di laplace
Per analizzare il comportamento dei sistemi non è possibile procedere in modo empirico, ma serve dotarsi di adeguati strumenti matematici, come la trasformata di Laplace, che all’inizio possono apparire ostici, ma poi risultano imprescindibili. La trasformata è un operatore matematico che, applicato a una funzione del tempo f(t), la trasforma in una funzione F(s) della variabile complessa s = α+ jω. Simbolicamente si scrive:
Normalmente un problema sistemico nasce formulato nel dominio del tempo: la trasformata trasferisce il problema nel dominio delle trasformate, come rappresentato in figura. Il passaggio inverso, dalla F(s) alla corrispondente f(t) si ottiene applicando l’operazione inversa, che è l’antitrasformata.
La corrispondenza tra le funzioni f(t) ed F(s) è biunivoca, ovvero, data una f(t), esiste una sola F(s) che, antitrasformata, riconduce alla stessa f(t).
Nel dominio delle trasformate sono possibili alcune operazioni estremamente difficili nel do minio del tempo. Come dimostreremo in seguito, un’operazione integro-differenziale nel do minio del tempo si trasforma, nel dominio della trasformata, in una più semplice operazione algebrica di tipo polinomiale. La figura a pagina seguente mostra il percorso logico che si attua. Il punto di partenza è un problema analitico formulato nel dominio del tempo. Anziché risolverlo direttamente si procede in modo indiretto:
- Si trasferisce il problema nel dominio delle trasformate;
- Lo si manipola applicando le diverse regole computazionali e lo si risolve;
- Si antitrasforma la soluzione restituendo la soluzione nel dominio del tempo
Il vantaggio del metodo indiretto è controbilanciato dalla difficoltà della determinazione della trasformata e antitrasformata; come si vedrà in pratica, queste operazioni risultano abbastanza agevoli, perché sfruttano una tabella delle corrispondenze che viene calcolata una volta per tutte e alcuni teoremi che semplificano il procedimento. L’operazione matematica di trasformazione è la seguente:
Si tratta dell’integrale di una funzione di due variabili: la variabile t e la variabile s. La variabile tempo viene assorbita sviluppando l’integrale, pertanto il risultato è una funzione della sola variabile s. I limiti di integrazione sono 0 e ∞, pertanto i valori della funzione f(t) per t < 0 sono ininfluenti. Dobbiamo ora entrare maggiormente nel merito, per imparare a calcolare trasformate e anti trasformate e, in un secondo tempo, applicare il metodo per risolvere problemi concreti di sistemi. Non è difficile: conoscendo la trasformata di pochissime funzioni e le sue principali proprietà è possibile calcolare nuove trasformate e risolvere diversi problemi. Approfondiamo lo studio suddividendo la trattazione in due parti:
- tabella minima delle principali trasformate e dimostrazioni;
- teoremi della trasformata.
La tabella che segue specifica le trasformate dei principali ingressi ai quali può essere assoggettato un sistema. Nella colonna dei commenti sono sottolineate alcune specifiche sulla forma dei segnali e sulle modalità di calcolo delle trasformate.
Per quanto riguarda le dimostrazioni delle trasformate della tabella ci limitiamo a un solo caso, perché il calcolo integrale non è materia di questo testo; inoltre molte trasformate di questa tabella si possono ottenere indirettamente, come vedremo, applicando i teoremi.
La tabella a pagina seguente riporta i principali teoremi accompagnati da una breve spiegazione.
Ricavare nuove Trasformate dalla tabella minima e dai Teoremi
Solitamente, la trasformata viene considerata un argomento avanzato, molto più delle derivate e degli integrali, quindi difficile da somministrare a studenti di un indirizzo di scuola superiore. Questo è vero per quanto concerne gli aspetti teorici, e infatti non ci siamo soffermati sulla definizione, ma dal punto di vista computazionale il metodo si rivela facile da apprendere. Una volta imparata bene la tabella delle trasformate minime e capiti i teoremi, è possibile, con poco sforzo, ricavare un larghissimo numero di nuove trasformate. Spesso i libri riportano tabelle con numerosissime trasformate da applicare in modo immediato, questo però non abitua lo studente a riflettere sulle opzioni di calcolo ed espone a difficoltà qualora la funzione da trasformare non sia compresa nella tabella.
Applicazione della trasformata alla risoluzione di equazioni differenziali
Gli operatori differenziali di derivazione e integrazione si trasformano nel dominio di s in semplici prodotti/rapporti per il termine s. Per la stessa ragione una equazione integrodifferenziale si trasforma, nel dominio di s, in una equa zione algebrica di tipo polinomiale. Naturalmente è molto più semplice risolvere un’equazione algebrica piuttosto che un’equa zione differenziale, non solo per le obiettive difficoltà del calcolo differenziale, ma anche per ché la trasformata mantiene una fisionomia univoca qualsiasi sia il termine forzante, mentre l’equazione differenziale cambia completamente fisionomia e tipologia di risoluzione. Per risolvere un’equazione è necessario migrare temporaneamente nel dominio della trasformata, estrarre la soluzione e infine antitrasformare. Il procedimento si può descrivere pertanto con lo schema della figura a in basso.
Dobbiamo ora, necessariamente, fare riferimento a un problema specifico, per descrivere i passi di risoluzione. Consideriamo l’equazione differenziale del circuito RC omologa di quella alle differenze finite:
con la condizione al contorno
Trasformiamo ambo i membri:
e applichiamo le proprietà di linearità della trasformata:
e il teorema della derivata:
Abbiamo sotto gli occhi un’equazione algebrica nell’incognita VC(s). Risolviamola, tenendo conto anche della condizione al contorno:
Dobbiamo antitrasformare VC(s) per ottenere vC(t). Per questo è necessario scomporre l’equazione in due frazioni, come mostrato di seguito:
Proseguiamo applicando il m.c.m.:
Raccogliendo i coefficienti di pari grado si ha:
e ripescando la VC (s) di partenza si ha:
Eguagliamo ora i coefficienti di s0 e s1 dei due membri e risolviamo il sistema:
Abbiamo ora la VC (s) scomposta:
Possiamo quindi procedere con l’antitrasformazione:
La soluzione è:
Antitrasformata di Laplace
L’antitrasformata di Laplace è l’operatore matematico inverso della trasformata di Laplace. L’adozione di questi due operatori nello studio dei modelli matematici permette di formulare i problemi in modo matematicamente comodo. La trasformata sposta i problemi in una realtà parallela, l’antitrasformata li ricolloca nel dominio del tempo, nella realtà alla quale appartengono.
Metodo di scomposizione mediante sistema
Nel caso si abbia un’espressione di primo grado, il calcolo dell’antitrasformata è immediato; basta risalire alla primitiva per mezzo dei teoremi e delle trasformate di base. Se l’espressione da antitrasformare è un polinomio, è necessario scomporlo in frazioni parziali. Descriviamo il metodo di scomposizione passo dopo passo, esemplificandolo mediante una specifica funzione di s, come la seguente:
- Si esprime la funzione come somma di frazioni; ciascuna frazione è costituita al denominatore da uno dei termini di primo grado del denominatore della U(s), mentre al numeratore presenta un valore costante. Il problema è la determinazione delle costanti che rendono equivalenti le due forme prima e dopo l’uguale:
2. Si riduce allo stesso m.c.m. e si isolano i termini di pari grado:
3. Si confrontano ora l’espressione di partenza da scomporre e l’ultima, imponendo che siano uguali:
I due denominatori sono già uguali, è necessario che lo siano anche i due numeratori. Giacché essi sono funzioni della variabile s, l’uguaglianza sussiste se è verificata per ogni valore di s. Questo è possibile a condizione che siano uguali i coefficienti dei termini di pari grado della variabile s, cioè i coefficienti di s0 e s1 . Si ricava il seguente sistema:
4. Si risolve il sistema ottenendo la U(s) scomposta: