Dispense Scilab
Transcript
Dispense Scilab
Sergio Frasca Uso di per il Laboratorio di Meccanica 1 Versione 2 - 18/02/2015 2 Sommario Introduzione ................................................................................................................................................................ 5 Istallazione.................................................................................................................................................................... 7 Comandi di base.......................................................................................................................................................... 8 Creazione e assegnazione di variabili.......................................................................................................... 10 Operazioni sulle variabili ................................................................................................................................. 11 Istruzioni di controllo ........................................................................................................................................ 13 Grafica ...................................................................................................................................................................... 14 Gestione input/output....................................................................................................................................... 16 Script ........................................................................................................................................................................ 17 Funzioni e librerie ............................................................................................................................................... 18 Altre .......................................................................................................................................................................... 19 Operazioni con Excel (o fogli elettronici). ............................................................................................. 19 File di startup ................................................................................................................................................... 20 Varie ..................................................................................................................................................................... 20 Applicazioni per il Laboratorio di Meccanica................................................................................................ 21 Simulazione di dati ............................................................................................................................................. 21 Lancio di dadi (o monete) ........................................................................................................................... 21 Estrazione di un campione da una distribuzione ............................................................................... 22 Simulazione di misure con errori ............................................................................................................. 23 Montecarlo per la valutazione dell’incertezza in modo semplificato ......................................... 25 Lettura di dati da file .......................................................................................................................................... 28 Fit ............................................................................................................................................................................... 32 Derivata col fit ...................................................................................................................................................... 38 Elaborazione di dati: lo smoothing ............................................................................................................... 40 Analisi statistica dei dati ................................................................................................................................... 41 Istogramma ....................................................................................................................................................... 41 Percentili ............................................................................................................................................................ 43 Coefficiente di correlazione e scatter-plot ............................................................................................ 44 Test del chi quadro......................................................................................................................................... 46 Valutazione dell’incertezza col metodo di Montecarlo ......................................................................... 47 Function di servizio ............................................................................................................................................ 52 Esperienze .............................................................................................................................................................. 53 3 Molla .................................................................................................................................................................... 53 Risonanza........................................................................................................................................................... 55 Fluidi .................................................................................................................................................................... 57 Pendolo fisico ................................................................................................................................................... 58 Volano ................................................................................................................................................................. 58 Uso avanzato .............................................................................................................................................................. 59 Alcuni comandi ..................................................................................................................................................... 59 Ancora sulle funzioni ......................................................................................................................................... 60 Funzioni con argomenti variabili ............................................................................................................. 60 Funzioni definite dinamicamente ............................................................................................................ 61 Efficienza ............................................................................................................................................................ 61 GUI ............................................................................................................................................................................. 63 Strutture, list, mlist, cell array, etc. ............................................................................................................... 65 Appendici .................................................................................................................................................................... 67 Consigli pratici ...................................................................................................................................................... 67 Differenze con Matlab ........................................................................................................................................ 68 Esercizi .................................................................................................................................................................... 69 Altri utili documenti ........................................................................................................................................... 70 4 Introduzione Nell’uso del computer in ambito tecnico e scientifico sono spesso utili l’uso specifici linguaggi di programmazione orientati al tipo di problemi tipici di questi ambiti. In questo modo si ha così un molto più veloce e semplice sviluppo di programmi rispetto all’uso di linguaggi di più basso livello come il C e il Fortran. Tali linguaggi avanzati spesso sono accompagnati da particolari ambienti di sviluppo che ne rendono ancora più conveniente l’uso. Tra questi linguaggi (e ambienti) si è affermato in particolare, oramai da molti anni, Matlab1, sviluppato inizialmente da università americane e in seguito dalla The MathWorks. Attualmente esso è un prodotto commerciale, usato da milioni di utenti nella ricerca e nell’industria. Dopo il successo di Matlab, sono stati sviluppati vari software analoghi, quasi suoi “cloni”, spesso gratuiti e open source. Tra questi GNU Octave, FreeMat, JMathLib, Sysquake e Scilab. Scilab è un pacchetto di programmi gratuiti per il calcolo numerico sviluppati dallo INRIA e dallo ENPC in Francia, e poi da Scilab Consortium in seno alla Fondazione Digiteo. Oggi Scilab è sviluppato da Scilab Enterprises. Esso, come Matlab, consente di manipolare matrici, visualizzare funzioni e dati, implementare algoritmi, creare interfacce utente grafiche, e interfacciarsi con altri programmi. Scilab è stato ampiamente impiegato in alcuni progetti industriali e di ricerca, ed è questo il motivo (oltre alla gratuità e al fatto che supporta i principali sistemi operativi) per cui lo proponiamo in questo corso. Scilab è un linguaggio di programmazione interpretato2. Ciò, se da un lato ne riduce, in taluni casi, l’efficienza di calcolo, dall’altro ne rende possibile un uso interattivo: cioè si può vedere immediatamente il risultato di un singolo comando. La sintassi è simile a quella di MATLAB ma ci sono delle differenze, anche se esiste un convertitore nel pacchetto di Scilab, che opera, con qualche problema, la conversione tra programmi Matlab e Scilab. Scilab include anche un pacchetto chiamato Xcos, per la simulazione e la costruzione di modelli di sistemi dinamici, includendo sia sotto-sistemi continui che discreti. Altri pacchetti applicativi esterni, gli ATOMS, possono essere installati. Scilab è disponibile gratuitamente per vari sistemi operativi, tra cui Windows, Mac OS X e Linux e può scaricarsi gratuitamente dal sito http://www.scilab.org/ . In questa guida si suppone che lo studente abbia una conoscenza elementare della programmazione (come acquisita, per esempio, nel corso di Laboratorio di calcolo). 1 Vedi http://www.mathworks.it/ e http://it.wikipedia.org/wiki/MATLAB . Cioè i programmi non vengono “compilati” (cioè tradotti in linguaggio macchina) quando li si fanno girare sul computer. 2 5 Queste brevi note hanno l’unico scopo di fornire rapidamente le nozioni di Scilab necessarie per il corso di Laboratorio di Meccanica. Se, come auspicabile, si volesse andare oltre nella conoscenza di questo strumento di programmazione, si può trovare in rete molta documentazione di guida e tutorial, come indicato nell’ultimo capitolo. In particolare per qualsiasi uso “evoluto” di Scilab è fondamentale un testo come introscilab.pdf (lo si trova con Google o nel sito di Scilab) o simili. 6 Istallazione Una volta scaricato il pacchetto relativo al proprio sistema operativo da http://www.scilab.org/, seguire le semplici istruzioni interattive. Sul sito sono presenti anche vari file di aiuto. Tra gli altri siti con risorse utili, vedi http://www.openeering.com/ . A corredo di questo corso, sono state scritte alcune funzioni e script che sono raccolte nel file Per_LM_Scilab.zip (che si può scaricare dal sito del corso) e descritte in questo manuale. Per un comodo utilizzo, una volta installato Scilab, lo spazio di lavoro3 può essere strutturato opportunamente, con una cartella LM con le funzioni della raccolta di Per_LM_Scilab.zip. Va quindi caricata la libreria (col comando “lib”) ed è comodo creare un file di “startup” che viene automaticamente eseguito ogni volta che si fa partire Scilab. Per maggiori dettagli, vedere l’Appendice “Consigli pratici”. 3 In Windows, tipicamente la cartella Documenti\Scilab. 7 Comandi di base Aprendo Scilab appare un “ambiente di lavoro” (working environment) molto simile a quello di Matlab. Ambiente di lavoro di Scilab Questo, che può essere configurato in vari modi, è composto di varie sotto-finestre e cioè: Il “Terminale di Scilab”, dove si danno i comandi L’”Esplorazione file” che mostra la cartella in cui si sta lavorando Il “Navigatore delle variabili” che mostra le variabili in uso e permette di modificarle La “Cronologia dei comandi” che mostra gli ultimi comandi dati (anche in sessioni precedenti) È disponibile una breve presentazione (per la versione 5.4.0) su Youtube4 in http://www.youtube.com/embed/_gkmDUmZSZI . I comandi sono eseguiti in genere riga per riga, come è nei linguaggi interpretati. Il risultato viene visualizzato immediatamente, a meno che il comando non venga terminato con un punto e virgola ( ; ). 4 Su Youtube c’è un intero “canale dedicato a Scilab; vedi http://www.youtube.com/user/ScilabChannel 8 Uno o più comandi possono essere scritti in un file di testo, costituendo così un programma (più correttamente, uno “script”). A questo scopo è comodo usare l’editor di Scilab, chiamato SciNotes; per aprirlo si può usare il comando editor o lo si può far partire dall’icona della barra delle applicazioni, o anche dal menu Applicazioni. I file di script hanno normalmente estensione .sce . Con SciNotes si possono editare più file contemporaneamente. I comandi di uno script vengono eseguiti col comando exec nomescript Il file con lo script deve essere presente nella cartella su cui è aperto Scilab. Alternativamente possono essere messi in esecuzione direttamente dall’editor SciNotes, per esempio dal menu a discesa _Esegui e poi scegliendo “Salva ed esegui”. Ecco la finestra dell’editor: ________________________________________ Non è qui riportata una descrizione dettagliata dei comandi (che può trovarsi nell’help o nei manuali). Si mostreranno alcuni esempi che si consiglia di ripetere sul proprio “terminale Scilab”. Gli esempi sono in file .sce, scaricabili dal sito del corso. Altri esempi di uso pratico possono ricavarsi nei programmi riportati nei prossimi capitoli. 9 Creazione e assegnazione di variabili Le variabili hanno nomi che possono avere qualsiasi lunghezza, ma solo i primi 24 caratteri sono considerati da Scilab; essi possono essere composti da lettere, maiuscole e minuscole, numeri e i simboli %, _, #, $, ! e ? , ma con la condizione che il primo carattere non sia un numero. Una variabile può contenere numeri reali, numeri complessi, numeri interi (a 8, 16 e 32 bit) o stringhe di caratteri. Una variabile può contenere insiemi di questi valori (array). Ecco alcuni esempi di variabili (file assegnazione.sce). A differenza del C le variabili sono create al momento dell’assegnazione: a=34+12 B=3*2.43; c='ciao' d=1:10 d2=1:0.1:10; e=[1 3 5.2 7 2.34] e0=e+%i e1=e0' e2=e0.' b=ones(2,3) bb=testmatrix('magi',4) // // // // // // // // // // // calcola 34+12 e assegna il valore a a calcola l'espressione e l'assegna a B assegna la stringa di carattert ciao a c crea l'array d con i valori da 1 a 10 crea l'array d2 con i valori da 1 a 10 a passi di 0.1 crea l'array e con i valori indicati crea l'array complesso sommando l'array e a i crea l'array e1 come trasposto coniugato di e crea l'array e1 come trasposto di e crea la matrice b, composta di 1, di 2 righe e 3 colonne crea una matrice "quadrato magico" di 4x4 elementi Note: %pi indica pi greco, %e indica la base dei logaritmi naturali, %i l’unità immaginaria; %t e %T indicano il valore booleano “vero” (“true”), %f e %F il valore booleano “falso”, %inf o Inf è infinito. Gli array (o vettori) sono matrici con una sola riga o una sola colonna. Gli elementi di un array o di una matrice sono indicati racchiusi tra parentesi quadre, separati da spazi o virgole; il punto e virgola separa le varie righe. ones(m,n) è una funzione che crea una matrice di 1 di m righe ed n colonne. Analogamente zeros(m,n) crea una matrice di zeri. Se si scrive un comando senza assegnazione a una variabile (il nome della variabile e il segno di uguale), viene creata di default la variabile ans. 10 Operazioni sulle variabili Le operazioni sulle variabili sono sempre operazioni matriciali, quindi possono essere fatte se sono “coerenti”; per esempio la somma di due matrici può farsi se le due matrici hanno lo stesso numero di righe e colonne, il prodotto se il numero di colonne della prima è pari al numero di righe della seconda). Fa eccezione il caso in cui una delle matrici ha una sola riga e una sola colonna, cioè è una variabile semplice: in tal caso l’operazione si intende fatta tra il numero e tutti gli elementi della matrice. Oltre alle operazioni +, -, *, /, ^, ci sono anche le .*, ./ e .^ che operano elemento per elemento. Operazioni più complesse vengono realizzate tramite funzioni. Queste funzioni possono essere fornite direttamente dal sistema, come cos, sin, exp,…, sia dall’utente che le costruisce per i propri scopi. Esse possono in genere operare su matrici e produrre matrici (ma ovviamente anche su singoli numeri, che sono un caso particolare). Ecco uno script in cui sono eseguite alcune operazioni esemplificative (si consiglia vivamente di mandarlo in esecuzione): // operazioni A=10 B=1:4 C=[1 0 2.5 -2] D=rand(2,4) E=rand(4,4) // matrice con numeri a caso tra 0 e 1 // matrice casuale quadrata a=A+B b=B+C // c=B*C c1=B*C' c2=B.*C //d1=B/C' //d2=B./C d3=B/C e1=B^A //e2=B^C e3=B.^C e4=A^B // ERRORE ! // ERRORE ! // ERRORE ! operazione incoerente operazione incoerente divisione per zero // ERRORE ! //f=1/0 // dovrebbe dare %inf che è infinito (dipende dalla versione, altrimenti dà errore) f=%inf f1=f+100 f2=f/100 f3=1/f f4=f/f2 // si ha NaN che significa "not a number" g1=D*D' g2=D'*D g3=D*E g4=g2.*E 11 g5=E^2 g5=E^2.5 x=0:0.1:5; y=cos(x*2*%pi); 12 Istruzioni di controllo Le istruzioni di controllo di Scilab sono simili a quelle del C, ma con delle differenze sintattiche. L’istruzione di controllo condizionale, come in C, ma con una sintassi un po’ diversa. if … then … else …. end In Scilab I loop sono molto meno usati che in C. Ciò poiché operare direttamente su vettori e matrici è molto più veloce. Come in C, il loop tipico viene eseguito tramite il for, ma con una diversa sintassi: for i = 1 : n … end Il select è simile al switch del C select … case … … case … … case … … else … end Un loop in cui non sono noti a priori il numero di cicli, può essere realizzato, similmente al C, con un’istruzione while. while … … end Infine l’istruzione break interrompe un loop, mentre l’istruzione continue interrompe il ciclo, passando al ciclo successivo (se c’è). Il return interrompe una function. L’istruzione pause interrompe l’esecuzione dei comandi e dà il controllo alla tastiera; è molto utile in fase di debugging. 13 Grafica Il comando base per la grafica 2D è plot (e la sua variante plot2d): // grafica2d x=0:0.01:4; y=exp(-(x)); y1=cos(x*3*%pi); y2=sin(x*3*%pi); figure;plot(y); figure;plot(x,y) set(gca(),"grid",[1 1]) title("spostamento in funzione del tempo") xlabel('t'),ylabel('s') figure;plot2d('nl',x,y),title('logy'),set(gca(),"grid",[1 1]) figure;plot2d('ln',x+0.01,y),title('logx'),set(gca(),"grid",[1 1]) figure;plot2d('ll',x+0.01,y),title('loglog'),set(gca(),"grid",[1 1]) figure;plot(x,y1) set(gca(),"grid",[1 1]) // crea una griglia set(gca(),"auto_clear","off") // permette di mettere più grafici su una finestra plot(x,y1,'r.') plot(x,y2,'g') set(gca(),'zoom_box',[min(x),-1.2,max(x),1.2]) // cambia la finestra visibile Notare la modifica della finestra grafica eseguita tramite la modifica delle proprietà degli oggetti. gca() dà un “handle” (un “manico”) per modificare le proprietà dell’oggetto axes (assi); vengono modificate le proprietà grid (gestisce la griglia), auto_clear (gestisce la cancellazione del plot) e zoom_box (gestisce la finestra di zoom). Per cambiare lo zoom sulla figura, si può anche usare zoom_rect() (vedi i dettagli con l’help). Se si dà semplicemente il comando gca(), vengono visualizzate tutte le proprietà dell’oggetto axes. Per conoscere il valore di una proprietà occorre usare il comando get: per esempio, per conoscere il valore della proprietà ‘zoom_box’, si usa il comando val=get(gca(),'zoom_box') . La gestione delle proprietà degli assi (e delle figure) può farsi direttamente dalla figura, tramite il menu Modifica. Alternativamente si può far partire l’editore grafico col comando ged (ged(action, fignum)). Ci sono altre funzioni per la grafica 2D: plot2d2 fa un plot a gradini plot2d3 fa un plot con barre verticali plot2d4 fa un plot con frecce polarplot plot in coordinate polari errbar plot con barre di errore 14 Per la grafica 3D presentiamo l’uso dei comandi contour e surf: // grafica3D function f=campana(x1, x2) // una funzione utente f = exp(-x1.^2 - x2.^2); endfunction nlevels=6; x=-4:0.1:4; figure;contour(x,x,campana,nlevels) set(gca(),"grid",[1 1]) n=length(x) for i = 1:n y(i)=x(i); z(i,:)=campana(x,y(i)); end figure;surf(x,y,z) figure;surf(x,y,log(z)),title('logz') figure;contour(x,x,z,nlevels),set(gca(),"grid",[1 1]) figure;contour(x,x,log(z),nlevels),set(gca(),"grid",[1 1]) 15 Gestione input/output Qui vengono mostrati dei semplici esempi di input/output su file di testo e su schermo. I comandi essenziali sono analoghi a quelli del C, con qualche differenza funzionale. Ecco quelli che abbiamo qui usato: mopen e mclose per l’apertura e chiusura dei file msprintf per scrivere dati formattati su una stringa disp per mandare a schermo una stringa mfprintf per scrivere dati formattati su un file mfscanf per leggere dati formattati da un file // inpoutput N=10; k=1:N; n=6; tabn=k*6; for i = 1:N disp(msprintf('%d x %d = %d\n',n,k(i),tabn(i))) // output sul display end fid=mopen('tabellina.dat','wt'); // apre un file testo per scrivere mfprintf(fid,'Tabellina del %d \n\n',n) for i = 1:N mfprintf(fid,'%d x %d = %d\n',n,k(i),tabn(i)) end mclose(fid) fid1=mopen('dati.dat','wt'); // apre un file testo per scrivere for i = 1:2*N mfprintf(fid1,'%d %f %e \n',i,rand(1,2)) end mclose(fid1) fid2=mopen('dati.dat','r'); // apre un file per leggere, vengono creati nuovi array ii=zeros(N,1);aa=ii;bb=ii; for i = 1:N [nn,ii(i),aa(i),bb(i)]=mfscanf(fid2,'%d %f %f '); end mclose(fid2) 16 Script Più comandi possono essere raccolti in un file (detto “script”) ), normalmente con estensione .sce . Per creare uno script occorre un qualsiasi editor (come, per esempio, il notepad), oppure l’editor interno di Scilab, SciNotes, che si può far partire dal menù File della finestra principale o col comando editor. Per mandare in esecuzione questi comandi si può dare il comando exec nomescript oppure farlo partire dal menù _Esegui di SciNotes. In uno script (o in una funzione) la doppia sbarra // inizia un commento nella riga. Se si vuole continuare un comando su più righe, basta interrompere ciascuna riga con tre punti successivi (…). 17 Funzioni e librerie Una funzione è un insieme di comandi racchiusi dai due comandi function ed endfunction. La forma è la seguente: function [out1, ..., outm] = nomefunzione(input1, ..., inputn) comandi endfunction Gli input1, ..., inputn sono gli argomenti di ingresso dati alla funzione e out1, ..., outm gli argomenti di uscita, prodotti dalla funzione. Essa può essere richiamata dalla linea di comando o da uno script o da un’altra funzione. Una funzione viene normalmente salvata in un file di testo (come uno script), normalmente con estensione .sci, e può essere eseguita anche più volte con diversi argomenti di input. Per poter usare una funzione questa va caricata in memoria, cosa che viene fatto con il comando exec nomefunzione , o, più comodamente, direttamente da SciNotes, dal menù _Esegui col comando “Salva e esegui”. Un modo più comodo per gestire più funzioni è costruire una libreria. Per far ciò occorre raccogliere in una stessa cartella (per esempio base) tutte e sole le funzioni di cui vogliamo costruire una libreria e quindi dare il comando genlib('baselib','C:\Users\SergioF\Documents\Scilab\base\') in questo caso si è creata una libreria di nome baselib, contenente le funzioni che abbiamo messo nella cartella C:\Users\SergioF\Documents\Scilab\base\5. In questa cartella compariranno la forma binaria delle nostre funzioni, più altri file di controllo. Quando vogliamo utilizzare la libreria la carichiamo con baselib=lib('C:\Users\SergioF\Documents\Scilab\base') e quindi possiamo usarne le funzioni. Come vedremo in seguito, le librerie di nostro interesse possono essere caricate automaticamente allo startup di Scilab. ATTENZIONE ! In Scilab (a differenza di Matlab e altri linguaggi di programmazione) l’ambiente esterno non comunica con l’interno della funzione solo tramite gli argomenti di input, ma l’ambiente della funzione “vede” le variabili esterne (ma non viceversa). 5 Ovviamente va messo il vero indirizzo della cartella che si sta utilizzando. 18 Altre Operazioni con Excel (o fogli elettronici). Scilab ha dei comandi che permettono di leggere e scrivere dati in file Excel di tipo xls. Per la lettura, il comando [fd,SST,Sheetnames,Sheetpos] = xls_open('Test1.xls') apre un file Excel di nome Test1.xls e ne acquisisce la struttura. Col comando [Value1,TextInd1] = xls_read(fd,Sheetpos(1)); vengono letti i dati nel primo foglio, creando la matrice Value1. I dati numerici vengono posti pari a NaN. Per quanto riguarda la scrittura, essendo M una matrice numerica, csvWrite(M,'test.csv') crea un file in formato “comma separated variables”, cioè “variabili separate da virgole”, di nome test.csv, che può essere importato all’interno di un foglio Excel. Una guida su tutte le funzioni disponibili riguardo ai fogli elettronici si ottiene con il comando help.Spreadshhet 19 File di startup Quando viene fatto partire Scilab, vengono eseguiti i comandi che si trovano nei file SCIHOME/.scilab , SCIHOME/scilab.ini , e SCI/ scilab.star, dove SCIHOME è il nome simbolico della cartella di partenza e SCI di quella di istallazione di Scilab. (Per vedere a cosa corrisponde ciascun nome simbolico, battere al prompt di Scilab il nome simbolico.). È comodo mettere in uno di questi file (si consiglia scilab.ini), dei comandi che per esempio portano alla cartella di lavoro normalmente usata e istallano la/le librerie d’uso, se ce ne sono. Per esempio le due righe: cd C:\Users\SergioF\Documents\Scilab // si posiziona sulla cartella di lavoro baselib=lib('C:\Users\SergioF\Documents\Scilab\base') // istalla la libreria nella cartella “base” Varie clear cancella tutte le variabili nel workspace, liberando la memoria. clear x1 x2 clock cancella le variabili x1 e x2 crea un array con la data corrente come anno, mese, giorno, ora, minuto, secondo xs2jpg, xs2pdf,… xpause(n) “esporta” figure in file di vario tipo interruzione di un programma per n microsecondi 20 Applicazioni per il Laboratorio di Meccanica Le function e gli script Scilab qui presentati sono utili per svolgere alcuni esercizi e alcune esperienze di laboratorio. Possono inoltre costituire esempi di programmazione in linguaggio Scilab. Tutti sono scaricabili dal sito del corso. Gli studenti sono incoraggiati a modificarli e/o a svilupparne altri. Simulazione di dati Lancio di dadi (o monete) Per la simulazione usiamo la funzione rand, generatore di numeri casuali distribuiti uniformemente tra 0 e 1. // dadiec simulatore di dadi e monete n=50; u0=rand(1,n,"uniform"); // uniforme da 0 a 1 d=ceil(u0*6); // uscite dadi figure;plot(d,'.'); title("Lancio di dadi - prove ripetute") aa=gca(); aa.data_bounds = [0,0.5;n,6.5] set(gca(),"grid",[1 1]); figure;histplot(0.5:6.5,d,normalization=%f); title("Lancio di dadi istogramma") d_med_sper=mean(d); d_med_teor=mean(1:6); d_devst_sper=stdev(d); d_devst_teor=sqrt(sum(((1:6)-d_med_teor).^2)/6); disp(msprintf('Lancio di %d dadi',n)) disp(msprintf('media sperimentale %f (teorica %f)',d_med_sper,d_med_teor)) disp(msprintf('dev.st. sperimentale %f (teorica %f)',d_devst_sper,d_devst_teor)) disp('') m=round(u0)*2-1; // uscite moneta figure;plot(m,'.'); title("Lancio moneta - prove ripetute") aa=gca(); aa.data_bounds = [0,-1.5;n,1.5] set(gca(),"grid",[1 1]); figure;histplot(2,m,normalization=%f); title("Lancio moneta - istogramma") figure;plot(cumsum(m)); title("Lancio moneta - camminata casuale") set(gca(),"grid",[1 1]); m_med_sper=mean(m); m_med_teor=mean([-1 1]); m_devst_sper=stdev(m); m_devst_teor=sqrt(sum(([-1 1]-m_med_teor).^2)/2); 21 disp(msprintf('Lancio di %d monete',n)) disp(msprintf('media sperimentale %f (teorica %f)',m_med_sper,m_med_teor)) disp(msprintf('dev.st. sperimentale %f (teorica %f)',m_devst_sper,m_devst_teor)) disp('') Per il lancio della moneta si associa 1 a testa e -1 a croce. Notare la “passeggiata casuale” eseguita facendo un passo in avanti e a destra per ogni testa e un passo indietro e a destra per ogni croce. Estrazione di un campione da una distribuzione Per generare campioni estratti da una popolazione con una certa distribuzione di probabilità si usa la function grand. In genere, per generare una matrice A di campioni casuali di dimensione m*n, si usa il comando A=grand(m,n,’sigla_distribuzione’,par1,par2,…) Per una descrizione completa di questa funzione si rimanda all’help (“Visualizzatore dell’aiuto”). Presentiamo un semplice script in cui si generano array di dati estratti da varie distribuzioni. I dati vengono poi analizzati facendone un istogramma e calcolandone la media e la deviazione standard. // stat_intro : introduzione alla statistica n=1000; low=4;high=6; u=grand(1,n,"unf",low,high); // uniforme figure;histplot(10,u,normalization=%f); title('uniforme') mu=10;sig=2; g=grand(1,n,"nor",mu,sig); // normale figure;histplot(20,g,normalization=%f); title('normale') N=20;p=0.2; b=grand(1,n,"bin",N,p); // binomiale figure;histplot(0:N,b,normalization=%f); title('binomiale') mu=10; p=grand(1,n,"poi",mu); // poissoniana figure;histplot(0:30,p,normalization=%f); title('poissoniana') media(1)=mean(u); media(2)=mean(g); media(3)=mean(b); 22 media(4)=mean(p); devst(1)=stdev(u); devst(2)=stdev(g); devst(3)=stdev(b); devst(4)=stdev(p); mprintf('distr. mprintf('distr. mprintf('distr. mprintf('distr. uniforme normale binomiale poissoniana media media media media = = = = %f %f %f %f devst devst devst devst = = = = %f %f %f %f \n',media(1),devst(1)); \n',media(2),devst(2)); \n',media(4),devst(3)); \n',media(4),devst(4)); Simulazione di misure con errori La function LM_misure simula misure fisiche di una certa grandezza, con errori di vario tipo. In input abbiamo il valore vero e le caratteristiche dei vari errori, in uscita, array contenenti le misure e le varie componenti di errore; è possibile anche impostare un trend. function [mis, el, es, ec, tr, dist]=LM_misure(valv, errlet, errsist, errcas, trend, pr_dist, amp_dist) // LM_MISURE simulazione misure // // [mis el es ec tr dist]=LM_misure(valv,errlet,errsist,errcas,trend,pr_dist,amp_dist) // // valv valore vero (array; se 2 elementi, primo valv, secondo numero // di misure) // errlet errore di lettura (p. es. 0.001) // errsist errore sistematico (di taratura) [b a]: b*vv+a // errcas deviazione standard del rumore casuale // trend trend (aumento del valore per misura) // pr_dist probabilità dei disturbi occasionali // amp_dist ampiezza media disturbi occasionali mis=[]; el=[]; es=[]; ec=[]; tr=[]; dist=[]; mode(0); ieee(1); if max(size(valv))==2 then valv = valv(1)*ones(valv(2),1); end; n = max(size(valv)); tr = (0:n-1)'*trend; es=(valv+tr).*errsist(1)+errsist(2); ec = errcas*rand(n,1,"normal"); i = find(rand(n,1) < pr_dist)'; dist = zeros(n,1); dist(i)=laplrnd(amp_dist,length(i),1); mis0=valv+tr+es+ec+dist; mis = round(mis0/errlet)*errlet; el = mis-mis0; endfunction 23 È stato realizzato anche lo script I_LM_misure che utilizza in modo “comodo” e interattivo la LM_misure. Vengono proposti dei valori per i parametri di ingresso (che possono modificarsi interattivamente), vengono prodotti dei grafici con le misure, gli errori e i loro istogrammi e viene creato un file con tutti i dati, che può essere aperto con qualsiasi editor di testi (attenzione però, perché contiene molte colonne e quindi ci possono essere problemi di allineamento). // I_LM_misure mode(0); ieee(1); answ = x_mdialog('Parametri di misure ripetute',["Numero misure";"Valore vero";"Errore di lettura";"Errore sistematico (alfa)";"Errore sistematico (beta)";"Errore casuale";"Trend";"Probabilità disturbi";"Ampiezza disturbi"],["60";"10";"0.1";"0.2";"0.01";"0.4";"0.0";"0.04";"3"]); Nmis = evstr(answ(1)); valv = evstr(answ(2)); errlet = evstr(answ(3)); esalf = evstr(answ(4)); esbet = evstr(answ(5)); errcas = evstr(answ(6)); trend = evstr(answ(7)); pr_dist = evstr(answ(8)); amp_dist = evstr(answ(9)); [mis,el,es,ec,tr,dist] = LM_misure([valv,Nmis],errlet,[esbet,esalf],errcas,trend,pr_dist,amp_dist); figure;plot(mis),set(gca(),"auto_clear","off"),plot(mis,"r."),set(gca(),"grid",[1,1]) title("Misure ripetute"),xlabel("Numero d''ordine") figure;plot(el),set(gca(),"auto_clear","off"),plot(es,"r"),plot(ec,"k"),set(gca(),"grid", [1,1]) plot(el,"."),plot(es,"r."),plot(ec,"k.") title("Errori"),xlabel("Numero d''ordine"), legend("Errori di lettura","Errore sistematico","Errori casuali"); figure;plot(tr),set(gca(),"auto_clear","off"),plot(dist,"k"),set(gca(),"grid",[1,1]) plot(tr,"."),plot(dist,"k.") title("Disturbi e trend"),xlabel("Numero d''ordine"), legend("Trend","Disturbi"); mea = mean(mis,"m"); sd = stdev(mis); messagebox([msprintf("media = %f",mea),msprintf("st.dev. = %f",sd)],"Statistica Misure") figure;histplot(100,mis,normalization=%f),title("Istogramma delle misure") figure;histplot(round(sqrt(Nmis)),el,normalization=%f) title("Istogramma errori di lettura") figure;histplot(round(sqrt(Nmis)),ec,normalization=%f) title("Istogramma errori casuali") figure;histplot(round(sqrt(Nmis)),es,normalization=%f) title("Istogramma errori sistematici") timstr = snag_timestr(now()); fid = mopen("misure_"+timstr+".dat","wt"); mfprintf(fid," Simulazione di misure \r\n\r\n"); mfprintf(fid," Errore di lettura %f \r\n",errlet); mfprintf(fid," Errore casuale %f \r\n",errcas); mfprintf(fid," Errore sistematico alfa e beta %f %f \r\n",esalf,esbet); mfprintf(fid," Trend %f \r\n",trend); mfprintf(fid," Disturbo (prob,amp) %f %f\r\n",pr_dist,amp_dist); 24 mfprintf(fid,"\r\n N disturbo \r\n"); misura if errlet > 0 then ndig = ceil(log10(1/errlet)); else ndig = 6; end; format = msprintf("%%4d %%12.%df err.lett. %%10f %%10f err.cas. %%10f %%10f err.sist. %%10f trend \r\n",ndig); for i = 1:Nmis mfprintf(fid,format,i,mis(i),el(i),ec(i),es(i),tr(i),dist(i)); end; mfprintf(fid,"\r\n media %f %f %f %f %f %f \r\n",mean(mis,"m"),mean(el,"m"),mean(ec,"m"),mean(es,"m"),mean(tr,"m"),mean(dist,"m")); mfprintf(fid," dev.st. %f %f %f %f %f %f \r\n",stdev(mis),stdev(el),stdev(ec),stdev(es),stdev(tr),stdev(dist)); mclose(fid) Montecarlo per la valutazione dell’incertezza in modo semplificato Talvolta si valuta l’incertezza (sulla singola misura) di una misura ripetuta tre volte prendendo la semidifferenza tra la massima e la minima. Quale è la validità di questa procedura ? Per valutarlo è stato realizzato un montecarlo che valuta l’incertezza con la stima (non distorta) della deviazione standard e con il metodo della semidifferenza tra massima e minima. I dati simulati sono distribuiti secondo una normale standardizzata, quindi l’incertezza aspettata, assimilata alla deviazione standard è 1. Sono graficate la distribuzione delle medie per ciascuna tripletta, la distribuzione della stima della deviazione standard delle triplette eseguita con il metodo normale e la distribuzione della stima dell’incertezza fatta col metodo semplificato. Ecco il semplice programma in Scilab: // monte_sign3 montecarlo per la valutazione dell'incertezza in modo semplificato // per 3 misure nval=3; N=10000; me=zeros(1,N); sd=me; sd1=sd; for i = 1:N r=grand(1,nval,'nor',0,1); // nval numeri casuali con dist. norm. standard me(i)=mean(r); sd(i)=stdev(r); sd1(i)=(max(r)-min(r))/2; end 25 mean(me) stdev(me) figure,histplot(100,me),title('Distribuzione della media'),gridon mean(sd) stdev(sd) figure,histplot(100,sd),gridon title('Distribuzione della stima della deviazione standard') mean(sd1) stdev(sd1) figure,histplot(100,sd1),gridon title('Distribuzione della stima dell’’incertezza semplificata') Ed ecco i risultati: Incertezza valutata σ sull’incertezza In teoria 1 - Stima della dev.st. 0.886 0.463 Metodo semplificato 0.846 0.444 Ed ecco gli istogrammi dei dati ottenuti: Possiamo ora domandarci come vanno i due metodi di valutazione dell’incertezza se invece che operare su 3 misure lo si fa su un altro numero N. Ecco il programma: // monte_sign // montecarlo per la valutazione dell'incertezza in modo semplificato al variare del numero di misure N=2000; sd=zeros(1,N); sd1=sd; msd=zeros(1,9); msd1=msd; for j = 1:9 for i = 1:N r=grand(1,j+1,'nor',0,1); // j+1 numeri casuali con distribuzione normale standardizzata 26 sd(i)=stdev(r); sd1(i)=(max(r)-min(r))/2; end msd(j)=mean(sd); msd1(j)=mean(sd1); end figure,plot(2:10,msd),holdon,plot(2:10,msd,'.') plot(2:10,msd1,'r'),plot(2:10,msd1,'r.'),gridon plot(ones(1,10),'g'),xlabel('Numero di misure') ylabel('Incertezza stimata') title('Blu sigma, Rosso (max-min)/2, Verde valore teorico') e i risultati: Si noti che la stima dell’incertezza fatta con la semi-differenza tra la massima e la minima misura è abbastanza ragionevole nel caso in cui N è uguale a 3 o a 4 (simile o migliore alla stima della deviazione standard, mentre per N>4 dà risultati in eccesso. Per N-2 una stima ragionevole dell’incertezza è prendere semplicemente la differenza tra la massima e la minima misura (il valore aspettato è circa 1.13). 27 Lettura di dati da file Presentiamo due function per leggere dati da file. leggi_xyinc per leggere dati da un file testo. Il formato in cui i dati sono scritti nel file, per ogni riga, è x incertezza_di_x y incertezza_di_y ATTENZIONE ! usare il punto o la virgola come separatore decimale a seconda dello standard del computer in uso. Suggerimento: settare il proprio computer in modo da usare come separatore decimale il punto (uso standard internazionale). Possono essere inserite righe di commento, inizianti per %. Le righe vuote sono ignorate. I dati devono essere scritti usando il punto come separatore decimale (non la virgola !). La funzione può essere in due modi: o col nome (col path se è in un’altra cartella) del file da leggere [x,dx,y,dy]=leggi_xyinc(“nomefile”); o senza argomento d’ingresso (sarà richiesto interattivamente il file( [x,dx,y,dy]=leggi_xyinc(); I dati saranno nei quattro vettori x,dx,y,dy di lunghezza il numero delle righe di dati. function [x, uncx, y, uncy]=leggi_xyinc(fil) [nout,nin]=argn(); // indica quanti sono gli argomenti di uscita e di ingresso if nin < 1 then [fnam,pnam]=uigetfile('*',' ',"Quale file aprire ?"); fil=pnam+filesep()+fnam; end fid=mopen(fil,'r'); err=0; i=0; while err == 0 line=mgetl(fid,1); err=meof(fid); disp(line) if length(line) > 0 then if part(line,1) ~= '%' then i=i+1; 28 a=msscanf(line,' %g %g %g %g'); x(i)=a(1); dx(i)=a(2); y(i)=a(3); dy(i)=a(4); end end end mclose(fid); endfunction I dati così conservati possono essere visualizzati con la function plot_unc: function plot_unc(x, uncx, y, uncy) // Grafica dati con incertezze // x,uncx,y,uncy dati e incertezze // se c'è un solo argomento, viene inteso come il nome del file con i dati // se non ci sono argomenti, cerca il file [nout,nin]=argn(); if nin == 1 then [x,uncx,y,uncy]=leggi_xyinc(x); end if nin == 0 then [x,uncx,y,uncy]=leggi_xyinc(); end figure n=length(x); for i = 1:n plot([x(i)-uncx(i),x(i)-uncx(i),x(i)+uncx(i),x(i)+uncx(i),x(i)-uncx(i)],... [y(i)-uncy(i),y(i)+uncy(i),y(i)+uncy(i),y(i)-uncy(i),y(i)-uncy(i)],'r') plot([x(i),x(i)],[y(i)-uncy(i),y(i)+uncy(i)]); plot([x(i)-uncx(i),x(i)+uncx(i)],[y(i),y(i)]); end plot(x,y,'.') set(gca(),"grid",[1 1]) endfunction producendo un grafico come (vedi file dati_con_inc.dat): 29 leggi_pasco per leggere dati da un file prodotto dal sistema Pasco, usato per alcune esperienze. I dati in questo file sono spesso scritti usando la virgola come separatore decimale (dipende dal settaggio del computer), quindi si è dovuto realizzare una ulteriore function (readascii_comma) che cambia le virgole in punti. La funzione può essere in due modi: o col nome (col path se è in un’altra cartella) del file da leggere [t,s,dt,n]=leggi_pasco(“nomefile”); o senza argomento d’ingresso (sarà richiesto interattivamente il file) [t,s,dt,n]=leggi_pasco(); I dati saranno nei vettore t (i tempi di acquisizione) e s (misura, p.es. distanza o peso); dt indica il tempo di campionamento (non sempre esattamente, come si può controllare vedendo i dati in t) e n è il numero di misure (dimensione di t e s). function [t, s, dt, n]=leggi_pasco(fil) [nout,nin]=argn(); if nin < 1 then [fnam,pnam]=uigetfile('*',' ',"Quale file aprire ?"); fil=pnam+"\"+fnam; end disp(fil) A=readascii_comma(fil,2,2); t=A(:,1); 30 s=A(:,2); n=length(t); dt=(t(n)-t(1))/(n-1); endfunction function a=readascii_comma(fil, ncomments, ncol) //READASCII_comma reads an ASCII file to a vector, with comma-to-dot conversion // // a=readascii(file,ncomments,ncol) // // ncomments is the number of lines containing comments (skipped and displayed) // ncol is the number of the columns of the output array // (must be a sub-multiple of the total number of the data) [fid,message]=mopen(fil,'r'); if fid == -1 disp(message); end for i = 1:ncomments line=mgetl(fid,1); disp(line); end c=mgetl(fid); c=strsubst(c,',','.'); a=msscanf(-1,c,' %g %g'); mclose(fid); endfunction 31 Fit Sono qui raccolti alcune function Scilab per fare fit di dati sperimentali. La function gen_lin_fit permette di fare fit polinomiali, armonici o generici, col metodo della massima verosimiglianza (minimo chi quadro). Nel caso dei polinomi, va fornito il grado come parametro. Nel caso della combinazione lineare di funzioni sinusoidali, vanno fornite come parametri le frequenze. Nel caso generale il parametro è la matrice nxM dei valori delle M funzioni base per gli n punti di ascissa. Se la variabile ipl è maggiore di zero, vengono prodotti anche i grafici. function [a, covarout, F, res, chiq, ndof, err, errel]=gen_lin_fit(x, y, unc, ic, par, ipl) // GEN_LIN_FIT general linear fit // // [a,covarout,F,res,chiq,ndof,err,errel]=gen_lin_fit(x,y,unc,ic,par,ipl) // // x abscissa value (length n) or gd // y ordinate value (length n) or nothing // unc y uncertainty (length n; if single number, all equal) // ic type of linear fit: // 0 -> general; par the matrix [n,M] // 1 -> polynomial; par the order // 2 -> sinusoidal; par the frequencies // ipl = 1 -> plot // // a fit parameters (length M) // covarout covariance matrix // F base functions // res residuals // chiq chi-square value // ndof degrees of freedom // err mean square error // errel mean square relative error // Modalità mostra mode(0); // Mostra un avviso per una eccezione in virgola mobile ieee(1); // Inizializzazione delle variabili in uscita (non trovate nelle variabili in ingresso) a=[]; covarout=[]; F=[]; res=[]; chiq=[]; ndof=[]; err=[]; errel=[]; n = max(size(x)); if max(size(unc))==1 then const = unc; unc(1:n) = const; end; 32 [nout,nin]=argn(); if nin < 6 then ipl = 0; end; x=x(:);y=y(:);unc=unc(:); select ic case 0 then A = par; [n,M] = size(A); case 1 then M = par+1; for i = 0:par A(1:length(x .^(par-i)),i+1) = x.^(par-i); end; case 2 then nfr = max(size(par)); M = nfr*2; ii = 0; for i = 1:nfr if par(i) > 0 then A(1:n,ii+1)=cos(((2*%pi)*par(i))*x); A(:,ii+2) = sin(((2*%pi)*par(i))*x); ii = ii+2; else A(1:n,ii+1)=cos(((2*%pi)*par(i))*x); ii = ii+1; M = M-1; end; end; end; F = A; for i = 1:M A(:,i) = A(:,i) ./unc; end; y1 = y ./unc; B = A'*A; b = A'*y1; covarout = inv(B); a = covarout*b; chiq = sum((y1-A*a).^2); ndof = n-M; y2 = F*a; res = y2-y; for i = 1:n f = F(i,:); err(1,i) = (f*covarout)*f'; end; err = sqrt(err); err = sqrt(sum(err.^2)/n); errel = err/sqrt(sum(y .^2)/n); if ipl > 0 then figure; plot(F), set(gca(),"grid",[1,1]), 33 title("base functions") figure; plot(x,y,"."), set(gca(),"auto_clear","off"), plot(x,y2,"r"), set(gca(),"grid",[1,1]), title("fit") figure; plot(x,res,"."), set(gca(),"grid",[1,1]), title("residuals") end; endfunction La funzione data_polyfit permette di fare il fit polinomiale in modo interattivo: mostra il grafico dei dati disponibili, quindi richiede di scegliere i pezzi da analizzare e, se non viene specificato prima, quale deve essere il grado del polinomio. Per ilcalcolo del fit, usa gen_lin_fit. Sono prodotti alcuni grafici e i risultati dettagliati sono contenuti in un array di strutture (una sola struttura se si sceglie un solo pezzo). function data=data_polyfit(x, y, unc) // DATA_POLYFIT analyzes x-y data // // data=data_polyfit(x,y,unc) // // x,y input data // unc uncertainty on y data (costant) // // data(i).iclog iclog // data(i).x the x of the selection // data(i).y the y // data(i).a the polynomial coefficients (starting from higher power) // data(i).aunc uncertainty on the polynomial coefficients // data(i).F base functions // data(i).res the residuals // data(i).err the mean square error // data(i).errel the relative error // data(i).chiq chi square // data(i).ndof number of degrees of freedom // Inizializzazione delle variabili in uscita (non trovate nelle variabili in ingresso) // Modalità mostra mode(0); // Mostra un avviso per una eccezione in virgola mobile ieee(1); //[iin,iout]=argn(); iclog=0; x1 = x; y1 = y; out=struct(); [xx,ii] = sel_absc(x,y); [i1,i2] = size(ii); for i = 1:i1 out.iclog = iclog; out.x = x1(ii(i,1):ii(i,2)); out.y = y1(ii(i,1):ii(i,2)); x2 = x(ii(i,1):ii(i,2)); y2 = y(ii(i,1):ii(i,2)); plot(x2,y2,"."), set(gca(),"grid",[1,1]); result=x_dialog('grado del polinomio ?','2'); par=eval(result); [a,covarout,F,res,chiq,ndof,err,errel] = gen_lin_fit(x2,y2,unc,1,par,0); polyfit_res_plot(x2,y2,a,res) 34 out.a = a; for j = 1:length(a) out.aunc(j) = sqrt(covarout(j,j)); end; out.covar = covarout; out.F = F; out.unc = unc; out.meanres = mean(res,"m"); out.stdres = stdev(res); out.res = res; out.err = err; out.errel = errel; out.chiq = chiq; out.ndof = ndof; data(i)=out; end; endfunction Questa funzione è molto comoda per lavorare con i dati della strumentazione Pasco. Ecco un esempio: - leggere i dati di esempio nel file esem_pasco.txt col comando [t,s,dt,n]=leggi_pasco(); - dare il comando data = data_polyfit(t,s,0.001); Compare una finestra con i dati graficati, su cui si può scegliere un segmento (col mouse); una fatta la scelta (più di una volta, se si vuole), appare il grafico con la (le) parti scelte evidenziate in rosso: 35 Quindi, per ogni segmento scelto viene chiesto il grado del polinomio con cui fare il fit: e infine appare una finestra con i dati scelti con sovrapposto il fit e i “residui” (la differenza tra il fit e i dati): 36 In uscita viene prodotta un array di “mlist” (in pratica, strutture), una per ogni segmento scelto. Ciascuna contiene i dati e i risultati del relativo fit, e cioè, per il k-esimo segmento, data(k).x e data(k).y contengono ascisse e ordinate dei punti selezionati nel segmento data(k).a contiene i coefficienti del polinomio del polinomio interpolante, a partire da quello della potenza più alta data(k).aunc contiene le incertezze per i vari coefficienti data(k).covar la matrice di covarianza per i coefficienti data(k).F le funzioni base del fit (in questo caso, semplicemente le potenze di x) data(k).res i residui del fit Ci sono poi, ma spesso non sono interessanti, data(k).err l’errore quadratico medio data(k).errel l’errore quadratico medio relativo data(k).chiq il chi quadro data(k).ndof il numero di gradi di libertà 37 Derivata col fit A volte occorre stimare la derivata di dati campionati (non necessariamente in modo uniforme). Per far ciò esistono vari algoritmi, più o meno raffinati. La tecnica che proponiamo si basa sull’esecuzione del fit polinomiale dei dati campionati (eseguito con data_polyfit) e sulla derivazione algebrica del polinomio trovato. Nella funzione che segue si può scegliere l’ordine della derivata che si vuole (che non ha senso sia maggiore del grado del polinomio del fit). function data=derifit(x, y, unc, ord) // derivata col fit // // x,y input data // unc uncertainty on y data (costant) // ord order of derivative (def 1) // // data(i).iclog iclog // data(i).x the x of the selection // data(i).y the y // data(i).a the polynomial coefficients (starting from higher power) // data(i).aunc uncertainty on the polynomial coefficients // data(i).F base functions // data(i).res the residuals // data(i).err the mean square error // data(i).errel the relative error // data(i).chiq chi square // data(i).ndof number of degrees of freedom // // data(i).dord order of derivative // data(i).dy derivative of y // data(i).da coefficients of the derivative [lhs,rhs]=argn(); if rhs < 4 then ord=1; end str=msprintf('Derivata di ordine %d',ord); data = data_polyfit(x,y,unc); [n,nn]=size(data); for i = 1:n data(i).dord=ord; a=data(i).a; x=data(i).x; for j = 1:ord a=polyder(a); end data(i).da=a; dy=calcpoly(x,a); data(i).dy=dy; figure;plot(x,dy),holdon,gridon,plot(x,dy,'r.'),title(str) end endfunction 38 Si noti che alla struttura “data” sono stati aggiunti tre elementi: data(k).dord ordine della derivata data(k).dy valori della derivata data(k).da coefficienti della derivata Alla fine viene visualizzato il plot della derivata. Ecco le due piccole funzioni di servizio che calcolano la derivata di un polinomio e i valori di un polinomio: function dpol=polyder(pol) // Calcola la derivata di un polinomio // // pol coefficienti del polinomio (dalla potenza più slta alla 0-esima) // // dpol coefficienti della derivata (dalla potenza più slta alla 0-esima) N=length(pol)-1; dpol=pol(1:N)*0; if N == 0 then dpol=0; end for i = 1:N dpol(i)=(N-i+1)*pol(i); end endfunction function y=calcpoly(x, pol) // Calcola un polinomio nei punti x // // pol coefficienti del polinomio (dalla potenza più slta alla 0-esima) N=length(pol)-1; y=pol(N+1)*(x*0+1); for i = N:-1:1 y=y+x*pol(i); x=x.*x; end endfunction 39 Elaborazione di dati: lo smoothing Lo “smoothing” (smussamento) dei dati campionati spesso è usato per ridurre l’errore di campionamento (o di lettura) e l’errore casuale. È un particolare tipo di “filtraggio” e consiste nel fare opportune medie pesate nell’intorno di ciascun campione. La function easy_smooth esegue lo smoothing di dati campionati; gli argomenti sono x (i dati da “smussare”) e n, la lunghezza della finestra di smoothing (un numero piccolo, per esempio 2). function y=easy_smooth(x, n) // EASY_SMOOTH data smoothing // // x input data // n smoothing depth (positive integer) // // y smoothed data y=[]; mode(0); ieee(1); if ~exists("n") then n = 1; end; n = round(n); if n < 1 then n = 1; end; win=1:n+1; win(2*n+1:-1:n+2)=1:n; y=conv(x,win)/(n+1)^2; y=y(n+1:length(y)-n); endfunction 40 Analisi statistica dei dati Le funzioni per l’analisi statistica dei dati sono molte, ma spesso non sono adeguate all’analisi delle misure fisiche. Tra quelle più utili mean(x) calcola la media del vettore x median(x) calcola la mediana del vettore x stdev(x) calcola la deviazione standard (non distorta) del vettore x cmoments(x,ord) calcola il momento centrale di ordine ord del vettore x histplot(n,data, normalization=%f) disegna un istogramma; se non si pone “normalization=%f”, l’istogramma viene normalizzato come se fosse una distribuzione di probabilità continua. Realizziamo alcuni esempi di funzioni per l’analisi statistica. Istogramma La funzione histplot non è molto comoda da usare ed inoltre è solo grafica, cioè non produce in uscita i valori dell’istogramma. La funzione hist_LM istogramma i dati contenuti in una matrice. I parametri dell’istogramma, contenuti in x, possono essere dati in quattro diversi modi: dando solo il numero di bin dando l’inizio del primo bin e la larghezza dei bin dando l’inizio del primo bin, la larghezza e il numero dei bin dando gli estremi dei vari bin (utile se i bin hanno larghezze differenti) function [h, xh, xb]=hist_LM(x, data) // // x parametri dell'istogramma: // se ha una componente, numero dei bin // se ha due componenti, inizio del primo bin e larghezza dei bin // se ha tre componenti, inizio del primo bin, larghezza dei bin e numero di bin // se ha più componenti, queste indicano gli estremi dei successivi bin // data dati (in genere una matrice) // // h valori dell'istogramma // xh valori centrali dei bin dell'istogramma // xb valori dei bordi dei bin dell'istogramma if isstruct(data) then data=data.y; end data=data(:); lx=length(x); select lx 41 case 1 then m=floor(x); dm=x-m; xmin=min(data); xmax=max(data); dx=(xmax-xmin)/m; case 2 xmin=x(1); dx=x(2); m=ceil((max(data)-xmin)/dx)+1; xmax=xmin+m*dx; case 3 xmin=x(1); dx=x(2); m=x(3); xmax=xmin+m*dx; end if lx <= 3 then xh=(xmin+dx/2):dx:xmax; x=[xmin xmin+(1:m)*dx]; k=floor((data-xmin)/dx)+1; kk=find(k>m); k(kk)=m; kk=find(k<1); k(kk)=1; fr=nfreq(k); h=zeros(m,1); h(fr(:,1))=fr(:,2); else m1=length(x); m=m1-1; xh=(x(2:m1)+x(1:m1-1))/2; h=xh*0; for i = 1:m k=find(data>=x(i) & data < x(i+1)); h(i)=length(k); end k=find(data >= x(i+1)); h(m)=h(m)+k; k=find(data < x(1)); h(1)=h(1)+k; end figure for i = 1:m plot([x(i),x(i)],[0,h(i)]); plot([x(i),x(i+1)],[h(i),h(i)]); plot([x(i+1),x(i+1)],[h(i),0]); end plot([x(m+1),x(m+1)],[h(1),0]); xb=x; endfunction 42 Percentili Per un certo campione (o insieme di dati) è spesso utile conoscere quale è il valore al di sotto del quale c’è una certa percentuale dei dati. È questo in un certo senso una generalizzazione della mediana (che è il valore al di sotto del quale è il 50 % dei dati). Ecco una funzione che esegue questo calcolo: function y=percentile(x, p) // Calcola i percentili di un campione // // x dati // p percentuale (da 0 a 100; anche array) x=gsort(x); y=p*0; N=length(x(:)); for i = 1:length(p) ii=round(N*p(i)/100+0.5); if ii < 1 then ii=1; end if ii > N then ii=N; end y(i)=x(ii); end endfunction 43 Coefficiente di correlazione e scatter-plot Supponiamo di avere n misure di una grandezza x e altrettante di una misura y, contenute nei due array x e y. Possiamo farne lo “scatter-plot” e calcolarne il coefficiente di correlazione. Abbiamo simulato 20 valori di x e y. Eccone lo scatter-plot: Per calcolare il coefficiente di correlazione e valutarne la significatività abbiamo realizzato la seguente function: function [ro, sd0]=corr_coeff(x, y, N) // Coefficiente di correlazione con incertezza tra x e y // // N dimensione del montecarlo (def = 1000) // ro coefficiente di correlazione // sd0 deviazione standard dell'auto-simulazione [n1,n2]=argn() if n2 == 2 then N=1000; 44 end n=length(x); sx=stdev(x); sy=stdev(y); ro=corr(x,y,1)/(sx*sy); ro1=zeros(1,N); for i = 1:N ii=rand_perm(n); ro1(i)=corr(x(ii),y,1)/(sx*sy); end figure,histplot(100,ro1,normalization=%t) sd0=stdev(ro1); endfunction Essa calcola prima il coefficiente di correlazione tra x ed y (la function corr di Scilab calcola la covarianza) e in seguito lo calcola N volte avendo permutato casualmente gli elementi di x: ciò permette di valutare la significatività del valore di ro, poiché si suppone che la permutazione casuale abbia “distrutto” la correlazione. inc0 è la deviazione standard dei valori del coefficiente di correlazione con i dati permutati. Con i dati usati per lo scatter-plot troviamo ro=0.741 e sd0=0.218 e la distribuzione dei ro per i dati permutati è 45 Test del chi quadro Se sono dati i valori teorici, i valori sperimentali, le incertezze su questi, il numero di gradi di libertà da sottrarre al numero di misure e la significatività voluta per il test, la seguente funzione valuta il test del chi quadro, producendo la variabile logica test (“vera” se il test è superato); vengono anche prodotti il valore del chi quadro calcolato e il valore del chi quadro limite. function [test, chiq, chiqlim]=test_chiq(yteor, ysp, unc, mdof, sig) // Test del chi quadro // // yteor valori teorici // ysp valori sperimentali // unc incertezze (=0 -> sqrt(yteor)) // mdof numero di gradi di libertà da sottrarre // sig significatività del test (p.es. 0.05) if length(unc) == 1 then unc=sqrt(yteor); end dof=length(yteor)-mdof; chiq=sum(((ysp(:)-yteor(:)).^2)./unc(:).^2); X=cdfchi("X",dof,1-sig,sig); if chiq < X then test=%T; else test=%F; end endfunction 46 Valutazione dell’incertezza col metodo di Montecarlo Quando una misura indiretta dipende da molte misure dirette in modo complesso, può risultare non conveniente valutare l’incertezza della misura col metodo delle derivate parziali. È questo per esempio il caso della misura di g con il pendolo fisico. In casi di questo genere è comodo valutare l’incertezza della misura con il metodo di Montecarlo. In pratica, se la nostra misura indiretta dipende da n misure dirette, la ricalcoliamo un gran numero di volte, in ognuna delle quali mettiamo come valori delle misure dirette un valore casuale scelto sulla base della misura fatta e della sua incertezza: se la misura diretta era dominata dall’errore di lettura, per questa prendiamo un valore distribuito uniformemente nell’intervallo di misura, se invece la misura diretta era dominata dall’errore casuale, per questa prendiamo un valore distribuito gaussianamente con valore aspettato la nostra misura e deviazione standard la sua incertezza. Studiamo quindi la statistica dei risultati ottenuti. Ecco la funzione: function [unc, yhist, yphist]=lm_uncert(funinp, arginp) // lm_uncert computes uncertainty for a given function // // [unc yhist yphist]=lm_uncert(funinp,arginp) // // funinp name of the function (it must be created and "executed") // (see for example the exfun_lm_uncert) // arginp arguments of the function with [value uncertainty type] // (see for example the driver_exfun_lm_uncert) // // // typ = 0 gauss (statistical error) // typ = 1 uniform (resolution error) // typ = 2 exponential // typ = 3 user-defined distribution (the user should provide the function usernd) // // unc.y value // unc.yy mean value // unc.ymedian median // unc.dy total uncertainty // unc.sig1 ± unc, equalized to 1 gaussian sigma in prob (0.15865 and 0.84135) // unc.py(k) partial mean value // unc.pdy(k) partial uncertainties funinp='y='+funinp+'('; N=100000; NP=10000; sigm=0.15865; sigp=0.84135; indeq=strindex(arginp,'='); indap=strindex(arginp,'['); indcl=strindex(arginp,']'); indpv=strindex(arginp,';'); nvar=length(indeq); nomevar=list(nvar); valvar=list(nvar); ini=1; for i = 1:nvar 47 nomevar(i)=part(arginp,ini:indeq(i)-1); valvar(i)=part(arginp,indap(i)+1:indcl(i)-1); ini=indpv(i)+1; end strcom=funinp; str1=strcom; r=zeros(nvar,N); y=zeros(1,N); for i = 1:nvar vars(i)=nomevar(i); execstr('aa=['+valvar(i)+'];'); val(i)=aa(1); uncer(i)=aa(2); typ(i)=aa(3); select typ(i) case 0 then r(i,:)=val(i)+grand(1,N,'nor',0,uncer(i)); case 1 then r(i,:)=val(i)+(grand(1,N,'unf',-uncer(i),uncer(i))); case 2 then r(i,:)=val(i)+grand(1,N,'exp',uncer(i)); // case 3 then // r(i,:)=val(i)+usernd(N)*uncer(i); end if i == 1 strcom=strcom+msprintf('r(%d,:)',i); str1=str1+msprintf('val(%d)',i); else strcom=strcom+msprintf(',r(%d,:)',i); str1=str1+msprintf(',val(%d)',i); end end strcom=strcom+');'; str1=str1+');'; kk=strindex(str1,','); kk0=strindex(str1,');'); kk=[kk kk0]; execstr(strcom); unc.yy=mean(y); unc.dy=stdev(y); [yhist x]=hist_LM(200,y,0); dx=x(2)-x(1); yhist=yhist/(N*dx); aaa=percentile(y,[sigm 0.5 sigp]*100); unc.ymedian=median(y); unc.sig1=[aaa(1)-aaa(2) aaa(3)-aaa(2)]; figure,plot2d2(x,yhist),gridon figure,plot2d2('nl',x,yhist),gridon aaa=gca(); poly1= aaa.children(1).children(1); poly1.thickness = 2; execstr(str1); unc.y=y; bi=length(funinp); y=zeros(1,NP); yphist=list(); figure;holdon for i = 1:nvar select typ(i) case 0 then 48 r=val(i)+grand(1,NP,'nor',0,uncer(i)); case 1 then r=val(i)+(grand(1,NP,'unf',-uncer(i),uncer(i))) case 2 then r=val(i)+grand(1,NP,'exp',uncer(i)); // // end str2=part(str1,1:bi)+'r'+part(str1,(kk(i):length(str1)));//disp(str2) bi=kk(i);//disp(str2) execstr(str2); unc.py(i)=mean(y); unc.pdy(i)=stdev(y); yhist1=hist_LM(x,y,0)/(NP*dx); col=rotcol(i); plot2d2('nl',x(1:length(x)-1),yhist1+0.5),gridon // ATTENZIONE WORKAROUND aaa=gca(); poly1= aaa.children(1).children(1); polyl.foreground=col; yhist1=gd(yhist1); yhist1=edit_gd(yhist1,'ini',x(1),'dx',x(2)-x(1)); yphist(i)=yhist1; end title('Dispertion due to single variables') unc.vars=vars; unc.varsval=val; unc.varsunc=uncer; unc.varstyp=typ; mprintf('\n') mprintf(' Output value: %f \n',unc.y) mprintf(' mean value: %f \n',unc.yy) mprintf(' median: %f \n',unc.ymedian) mprintf(' symmetrical uncertainty: %f \n',unc.dy) mprintf('asymmetrical uncertainties: %f %f\n',unc.sig1) if unc.y ~= 0 mprintf(' relative uncertainty: %f \n\n',unc.dy/abs(unc.y)) end mprintf(' mprintf(' Partial uncertainties \n\n') variable value type unc. relunc part.unc. weight\n') for i = 1:nvar select typ(i) case 1 then str='uniform'; // un=uncer(i)/sqrt(3); else str='normal '; // un=uncer(i); end un=uncer(i); relun=un/abs(val(i)); weig=unc.pdy(i)/(relun*unc.y); mprintf(' %7s %f %s %f %f %f %f\n',vars(i),val(i),str,un,relun,unc.pdy(i),weig) end endfunction Ed ecco la funzione di input e il driver di esempio: function [g, I, M0, x0, r]=exfun_lm_uncert(Ix, Mb, lb, b, M1, r1, r2, h, T0) // pend_nobloc da usare per lm_uncert x0=lb-(lb/2-b)-h/2; I=Ix+(Mb.*lb.^2)/12+Mb.*b.^2+(M1/12).*(3*(r1.^2+r2.^2)+h.^2)+M1.*x0.^2; M0=Mb+M1; r=(Mb.*b+M1.*x0)./(M1+Mb);//disp(size(I));disp(size(M0));disp(size(T0));disp(size(r)) 49 g=4*%pi.^2.*I./(T0.^2..*M0.*r); endfunction // driver_exfun_lm_uncert arginp='... Ix=[42.1 2.6 0];... Mb=[27.23 0.01 1];... lb=[38.10 0.01 1];... b=[16.50 0.01 1];... M1=[75.51 0.01 1];... r1=[0.79/2 0.01 1];... r2=[2.53/2 0.01 1];... h=[2.025 0.010 1];... T0=[1.1545 0.0002 0];' funinp='y=exfun_lm_uncert(' funinp='exfun_lm_uncert' [unc,yhist,yphist]=lm_uncert(funinp,arginp); execstr(arginp); [g,I,M0,x0,r]=exfun_lm_uncert(Ix(1),Mb(1),lb(1),b(1),M1(1),r1(1),r2(1),h(1),T0(1)) Ed ecco I risultati: Output value: 977.346230 mean value: 977.346515 median: 977.346561 symmetrical uncertainty: 0.389589 asymmetrical uncertainties: 0.391204 -0.392572 relative uncertainty: 0.000399 Partial uncertainties variable Ix Mb lb b M1 r1 r2 h T0 value 42.100000 27.230000 38.100000 16.500000 75.510000 0.395000 1.265000 2.025000 1.154500 type normal uniform uniform uniform uniform uniform uniform uniform normal unc. 2.600000 0.010000 0.010000 0.010000 0.010000 0.010000 0.010000 0.010000 0.000200 50 relunc 0.061758 0.000367 0.000262 0.000606 0.000132 0.025316 0.007905 0.004938 0.000173 part.unc. 0.025056 0.008527 0.085872 0.152624 0.003012 0.000836 0.002677 0.074504 0.338662 weight 0.000415 0.023757 0.334757 0.257667 0.023272 0.000034 0.000347 0.015437 2.000239 51 Function di servizio Altre funzioni usate negli esempi: y=polyval(p,x) equivale alla polyval di Matlab, calcola i valori di un polinomio p coefficienti del polinomio (dal grado più alto) x array dei valori in cui calcolare il polinomio. [xx,ii] = sel_absc(x,y) seleziona interattivamente parti di dati; x e y sono i due array contenenti i dati per le ascisse e le ordinate. polyfit_res_plot(x,y,a,res) usato in congiunzione con gen_lin_fit per graficare I risultati i=indexofarr(arr,val) trova l’indice di un array di valori più vicino ad un dato valore. m=nfreq(x) calcola la frequenza dei valori nel vettore x; se in x ci sono n diversi valori, eventualmente più volte ripetuti, la matrice m ha n righe e 2 colonne, nella prima delle quali ci sono i vari valori, nell’ordine in cui si sono presentati la prima volta, e nella seconda quante volte ciascun valore è presente. p=rand_perm(n) produce una permutazione dei primi n numeri naturali. xout=invfun(yin,x,y) inverte una funzione monotona crescente. dpol=polyder(pol) calcola la derivata di un polinomio y=calcpoly(x,pol) calcola i valori di un polinomio (col metodo di Horner) Funzioni utili: gridon() pone una griglia nella figura corrente; equivalente al grid on di Matlab. holdon() permette di aggiungere dati da plottare in una figura. holdoff() non permette di aggiungere dati da plottare in una figura, cancella i precedenti. 52 Esperienze Sono qui riportate alcune procedure dell’uso di Scilab e delle funzioni sviluppate per questo corso, come ausilio allo svolgimento di alcune prove di laboratorio. Per la descrizione delle prove di laboratorio, si fa riferimento alle dispense del corso. Molla Vediamo come graficare le misure per il caso di “T2 vs M” e “ΔL vs ΔM”. Innanzitutto vanno fatte le misure e messe in un file testo del tipo leggibile con leggi_xyinc.sce, quindi si realizza uno script del tipo: // analisi_molla [DM,uncDM,DL,uncDL]=leggi_xyinc('DLvsDM.dat'); plot_unc(DM,uncDM,DL,uncDL);xlabel('Delta M (g)'),ylabel('Delta L (cm)') [a1,covarout1,F1,res1,chiq1,ndof1,err1,errel1] = gen_lin_fit(DM,DL,uncDL,1,1,0) x1=0:max(DM)+20; y1=a1(1)*x1+a1(2); plot(x1,y1,'r') [M,uncM,T,uncT]=leggi_xyinc('TvsM.dat'); plot_unc(M,uncM,T.^2,2*uncT.*T);xlabel('M (g)'),ylabel('T^2 (s^2)') a=get("current_axes"); b=a.data_bounds; mpmax=50; limx=-mpmax*1.5; b(1,1)=limx; b(1,2)=0; a.data_bounds=b; [a2,covarout2,F2,res2,chiq2,ndof2,err2,errel2] = gen_lin_fit(M,T.^2,2*uncT.*T,1,1,0) x2=limx:max(M)+20; y2=a2(1)*x2+a2(2); plot(x2,y2,'r') ksp=4*%pi^2/a2(1); gsp=ksp*a1(1); mpsp=a2(2)/a2(1); mprintf('k = %f g = %f mp = %f',ksp,gsp,mpsp) Usando i dati di simulati che sono nei file DLvsDM.dat e TvsM.dat (con parametri diversi da quelli della vera esperienza), troviamo 53 e i valori (senza considerare l’incertezza) k = 20100.418217 g = 983.762410 54 m_parass = 39.834967 Risonanza Per impostare la velocità del motore passo-passo è stata creata la seguente funzione (che necessita dell’ATOM toolbox Serial che gestisce una porta seriale) : function frout=set_freq(frin) // frin frequenza richiesta (in Hz) // <= 0 -> chiude il canale seriale (reset microprocessore) // // frout frequenza effettiva com=1; xp=1000000; verso=0; SLOPE=0.01797; global h334 // // // // // porta seriale ritardo in us verso di rotazione (0 orario, 1 antiorario) Hz/N incertezza relativa 0.016 dichiara globale la variabile closeserial(h334); xpause(xp); // pausa 1 s if frin <= 0 then frout=-1; disp("stop") return end N=round(frin/SLOPE); if N < 0 then N=0; end if N > 99 then N=99; end frout=N*SLOPE; c1=floor(N/10); c2=N-c1*10; h334=openserial(com,"9600,n,8,1"); xpause(2*xp); // pausa 2s writeserial(h334,"s"+ascii(13));// inizia xpause(xp); // pausa 1s writeserial(h334,ascii(48+c1)+ascii(13));// velH xpause(xp); // pausa 1s writeserial(h334,ascii(48+c2)+ascii(13));// velL xpause(xp); // pausa 1s writeserial(h334,"0"+ascii(13));// rotazione oraria xpause(xp); // pausa 1s endfunction Per impostare la frequenza desiderata del motore (in Hz), basta metterla come argomento della funzione. In uscita si ha la frequenza effettiva (ci sono 100 possibili valori effettivi, tra 0 e 1.8 Hz). 55 L’impostazione della frequenza può farsi in modo interattivo più comodo con la seguente funzione: function x_set_freq() sfrin=x_dialog(['Frequenza ?';' frin=msscanf(sfrin,'%f'); da 0 a 1.8 Hz; 0 ferma, -1 esce'],'0'); while frin >= 0 frout=set_freq(frin); str=msprintf('%f',frout); sfrin=x_dialog(['Frequenza ?';' frin=msscanf(sfrin,'%f'); end endfunction da 0 a 1.8 Hz; 0 ferma, -1 esce'],str); 56 Fluidi Nell’esperienza dei fluidi si devono identificare i regimi laminare e vorticoso nel moto di acqua in alcuni tubicini. Le misure sperimentali sono le misure della massa dell’acqua uscita dai tubicini. Da queste si ricava l’altezza dell’acqua nel serbatoio (tubo verticale) e quindi la pressione all’ingresso dei tubicini, la velocità del flusso dell’acqua nei tubicini e da questa il Numero di Reynolds. Quindi, essendo S la sezione del tubo verticale, h0 il livello iniziale dell’acqua, s la sezione del tubicino orizzontale, d la sua lunghezza e avendo preso 1 g/cm3 la densità dell’acqua, eta=0.009 poise la sua viscosità a 25° e l’accelerazione di gravità g=980.35 cm/s2, possiamo procedere come segue6: costanti: porre le costanti S, s, h0, d, eta e g ai valori corretti (in CGS) massa: leggere i dati del file pasco con l’istruzione [t,m,dt,n]=leggi_pasco(); i dati si possono graficare con figure;plot(t,m),holdon,plot(t,m,’r.’),gridon pressione: calcolare l’altezza del pelo dell’acqua come h=h0-m/S; e da questa la differenza di pressione tra ingresso e uscita del tubicino come P=h*g; velocità: usare derifit per calcolare la derivata di m (avendo fatto un fit del quarto ordine) con data=derifit(t,m,0.05); e quindi calcolare la velocità con v=data.dy/s;. A questo punto si può graficare la velocità in funzione della pressione con figure; plot(P,v); numero di Reynolds: il numero di Reynolds si ricava come Re=d*v/eta; e lo si può graficare in funzione della pressione possiamo ora scegliere un valore di pressione e calcolare le costanti A e B per ciascun tubicino. Se si vogliono fare grafici singoli per più tubicini, si possono assegnare per ciascun tubicino nomi diversi per le varie misure; per esempio per il primo s1, d1, m1, h1, P1, v1, Re1, per il secondo s2, d2, m2, h2, P2, v2, Re2, e così via. 6 Usiamo il sistema CGS 57 Pendolo fisico Volano 58 Uso avanzato Per una programmazione avanzata in Scilab si consiglia “Programming in Scilab” di Michael Baudin, che si trova in rete. Qui riportiamo alcuni comandi e spunti per un uso più avanzato di Scilab. Alcuni comandi [n1,n2]=size(A) pone in n1 il numero di righe e in n2 il numero di colonne della matrice A. length(A) indica il numero totale di elementi della matrice A. gsort(x) ordina (in genere in modo crescente) gli elementi di x, con l’algoritmo quick sort. evstr(s) valuta il risultato del comando Scilab presente nella stringa s; può operare su array di stringhe. execstr(str) esegue i comandi presenti nella stringa str. browsevar(), browsehistory(), filebrowser() visualizza le finestre del browser (Navigatore) delle variabili, della Cronologia dei comandi e del file browser (Esplorazione file); queste finestre sono aperte in default alla partenza di Scilab e sono “agganciate” (“docked”) alla finestra principale. Per eseguire il docking di finestre sganciate, in Windows, selezionare col mouse la sbarra col “?” della finestra sganciata e portarla nella posizione voluta della finestra principale. editvar(“x”) visualizza la finestra dell’editor della variabile x; la finestra si apre cliccando su una variabile nel Navigatore delle variabili. 59 Ancora sulle funzioni Funzioni con argomenti variabili Una funzione può essere definita in modo “flessibile”, con un numero non fisso di argomenti di input e/o di output. All’interno della funzione, il comando [nout,ninp]=argn() pone in nout e ninp il numero effettivo di argomenti di uscita e di ingresso. Nella definizione della funzione, ci si avvale delle liste varargin e varargout. Ecco un esempio: function varargout=var_io(varargin) [nout,ninp]=argn() mprintf('%d argomenti input, %d argomenti di output \n',ninp,nout) for i = 1:ninp k(i)=evstr(varargin(i)); varargout(i)=cumsum(k(1:i)); end endfunction Dando il comando [a b c]=var_io(1,2,3) , si ha 3 argomenti input, 3 argomenti di output c = b 1. 3. 6. = a 1. 3. = a(1) 1. a(2) 2. a(3) 3. Gli argomenti in ingresso a una funzione possono essere variabili non solo in numero, ma anche in tipo, e si può far sì che esegua procedure diverse a seconda del tipo di un argomento. 60 Funzioni definite dinamicamente Talora è comodo definire in modo “dinamico” una funzione, cioè definirla da programma. Per questo si usa il comando deff , come nel seguente esempio: // uso_di_deff deff('[m1, m2]=minemax(v)',['m1=min(v)';'m2=max(v)']) [a1 a2]=minemax([1 -2 3 4.2 9]) Come si vede, deff ha due stringhe per argomenti, la prima contiene l’header della funzione e la seconda il corpo, che può essere o una stringa, o un array di stringhe. Efficienza Quando si devono fare calcoli complessi o comunque “lunghi”, occorre una programmazione efficiente. Per ciò innanzitutto si devono, per quanto possibile, eseguire i calcoli in forma vettorializzata, e non con loop tipo for. Ecco un esempio sulla differenza di velocità tra la modalità vettorializzata e tramite un ciclo for: // test_veloc N=100000; tic() x1=1:N; t1=toc() tic() for i = 1:N x2(i)=i; end t2=toc() mprintf('t1 = %f t2 = %f rapporto = %f\n',t1,t2,t2/t1) Il risultato è t1 = 0.002000 t2 = 25.402000 rapporto = 12701.000000 cioè il calcolo vettorializzato è, in questo caso, oltre 10000 più veloce dell’uso del for. 61 Notare l’uso dei comandi tic e toc per far partire e fermare un cronometro e quindi valutare quantitativamente la velocità di esecuzione di un codice. Una valutazione più completa dell’efficienza di un codice può ottenersi tramite il “profiling” interno di Scilab. 62 GUI L’uso standard di Scilab prevede l’interazione con i programmi tramite il “terminale” (la finestra principale di Scilab). Scilab offre tuttavia varie funzioni per interagire graficamente con un programma. Una “Graphical User Interface” (GUI) rende più comodo l’uso di un programma. Per esempio, tramite l’uso di x_mdialog , answ = x_mdialog('Parametri di misure ripetute',["Numero misure";"Valore vero";"Errore di lettura";"Errore sistematico (alfa)";"Errore sistematico (beta)";"Errore casuale";"Trend";"Probabilità disturbi";"Ampiezza disturbi"],["60";"10";"0.1";"0.2";"0.01";"0.4";"0.0";"0.04";"3"]); Nmis = evstr(answ(1)); valv = evstr(answ(2)); errlet = evstr(answ(3)); esalf = evstr(answ(4)); esbet = evstr(answ(5)); errcas = evstr(answ(6)); trend = evstr(answ(7)); pr_dist = evstr(answ(8)); amp_dist = evstr(answ(9)); si apre una finestra grafica che richiede alcuni parametri, offrendone i valori di default: Ci sono vari comandi per usare GUI, per esempio: messagebox visualizza un messaggio xmatrix permette l’editing interattivo di una matrice uimenu crea un menu per una figura 63 rubberbox permette di selezionare parte di un grafico uigetfile permette di scegliere interattivamente un file uigetcolor permette di scegliere interattivamente un colore Esiste anche un pacchetto esterno, guibuilder, gestito tramite ATOMS, il sistema di packaging di Scilab, per la costruzione di complesse interfacce grafiche. Per usarlo, va installato, partendo dal gestore di moduli ATOMS a cui si accede dal menu delle Applicazioni di Scilab (una volta installato, va fatto ripartire Scilab). Una volta fatto partire, compaiono due finestre, una di comando e una su cui si costruirà la nuova GUI: 64 Strutture, list, mlist, cell array, etc. In Scilab ci sono molti differenti tipi di dati. Eccone una lista: I comandi type e typeof operanti su una variabile, indicano il tipo di appartenenza. In particolare, in Scilab sono disponibili diverse “data structures” (raccolte organizzate di dati): le matrici (e le ipermatrici che sono simili, ma hanno più di due dimensioni, che saranno obsolete come tipo diverso dalle matrici prossimamente), le liste (list), le tlist (o typed list), le mlist (o matrix-oriented list), le strutture (simili a quelle del C) e i cell array. Ecco una tabella che riporta le principali proprietà delle data structures di Scilab: 65 66 Appendici Consigli pratici È importante strutturare in modo comodo per le proprie necessità la cartella di lavoro base Per esempio, per Windows, usando la cartella Scilab creata automaticamente in Documenti, copiarci le cartelle e i file contenuti in Per_LM_Scilab.zip (cartella LM) e aggiungere una o più cartelle di lavoro personali. Evitare quindi di mettere o modificare file nella cartella LM e sottocartelle, in modo da fare confusione, soprattutto per le modifiche future che potrebbero esserci nei file di LM (creati per questo corso). È poi conveniente costruire librerie delle funzioni normalmente usate con, per esempio: genlib('baselib','C:\Users\SergioF\Documents\Scilab\LM\base\') e quindi creare un file di startup in SCIHOME/scilab.ini , dove SCIHOME è una cartella che dipende dal sistema e che può essere identificata dando il comando SCIHOME da Scilab. Nel file scilab.ini vanno messi i comandi che si vuole siano eseguiti automaticamente all’apertura di Scilab. Per esempio scilab.ini può contenere cd C:\Users\nomeutente\Documents\Scilab baselib=lib('C:\Users\nomeutente\Documents\Scilab\LM\base') simlib=lib('C:\Users\nomeutente\Documents\Scilab\LM\sim') che automaticamente apre Scilab nella cartella di lavoro voluta e carica le librerie. nomeutente è il nome dell’utente su quel computer. Users può essere rinominato come Utenti su talune versioni di Windows. 67 Differenze con Matlab Lo sviluppo di Scilab è dichiaratamente ispirato a Matlab. Tuttavia ci sono parecchie differenze dal modello, alcune delle quali essenziali. Una differenza particolarmente notevole è che l’ambiente interno di una funzione “vede” le variabili definite esternamente ad essa. Nell’Help di Scilab, all’argomento “Matlab to Scilab Conversion Tips” si trovano tutti i dettagli delle differenze nelle varie funzioni. Qui diamo alcuni esempi: Matlab eval fopen fgetl fscanf fclose sscanf strrep reshape grid on hold on nargin str_out=str_in(v) inputdlg msgbox Fprintf,sprintf Scilab evstr mopen mgetl mscanf mclose msscanf strsubst matrix set(gca(),"grid",[1 1]) set(gca(),"auto_clear","off") argn(2) str_out=part(str_in, v) x_dialog o x_mdialog messagebox mfprintf,mprintf,msprintf Note diversa Per le stringhe C’è una funzione di Scilab, mfile2sci, che traduce un m-file di Matlab in una funzione (o in uno script) di Scilab. 68 Esercizi 1. Realizzare una function in grado di leggere dati da un file contenente nella prima riga l’incertezza comune per tutti i dati, e nelle altre i dati stessi, uno per ogni riga. 69 Altri utili documenti Due utili documenti sono introscilab.pdf e Scilab_beginners.pdf, che possono scaricarsi da http://www.scilab.org/resources/documentation/tutorials Manuali in Italiano: http://www.docente.unicas.it/gianluca_antonelli/scilab http://www.dii.unisi.it/~giannibi/teaching/materiale/psc/dispensascilab.pdf Manuali in Inglese: http://forge.scilab.org/index.php/p/docintrotoscilab/downloads/ http://forge.scilab.org/index.php/p/docprogscilab/downloads/ Altro: http://wiki.scilab.org/Tutorials Help online http://help.scilab.org/docs/5.4.0/en_US/index.html Scilab da Matlab http://wiki.scilab.org/Tutorials?action=AttachFile&do=get&target=Scilab4Matlab.pdf 70 Indice delle funzioni % I %e; 10 %f; 10 %inf; 10 %pi; 10 %t; 10 if; 13 inpoutput; 16 L lib; 18; 20 A M assegnazione.sce; 10 mclose; 16 mfprintf; 16 mfscanf; 16 mopen; 16 msprintf; 16 B break; 13 C O clear; 20 clock; 20 contour; 15 csvWrite; 19 ones(m,n); 10 P D pause; 13 plot; 14 plot2d2; 14 plot2d3; 14 plot2d4; 14 polarplot; 14 disp; 16 E endfunction; 18 errbar; 14 exec; 9 R return; 13 F S figure; 14 File di startup; 20 for; 13 function; 18 select; 13 set(gca(),"auto_clear","off"); 14 set(gca(),"grid",[1 1]); 14 set(gca(),'zoom_box',[min(x),1.2,max(x),1.2]); 14 surf; 15 G ged; 14 genlib; 18 grafica3D; 15 T testmatrix; 10 title; 14 H help; 19 71 xs2pdf; 20 W while; 13 Y ylabel; 14 X xls_open; 19 xls_read; 19 xpause; 20 xs2jpg; 20 Z zeros(m,n); 10 zoom_rect(); 14 72