Coefficienti della serie di Fourier 1. Introduzione 1 2. Esempio 1 3. Algoritmo risolutivo 2 4. Due esecuzioni del programma 3 4.1. Funzione dispari 4.2. Funzione oscillante 4 6 5. Codice dell’unità principale 7 6. Codice del modulo 9 1. Introduzione. Data una funzione 1.1) f : [ L, L] R si dimostra che sotto alcune ipotesi di regolarità della stessa, allora la successione di funzioni trigonometriche 1.2) a0 kx kx a k cos bk sin 2 k 1 L L converge totalmente verso la funzione f in [ L, L] ; i coefficienti in 1.2 si ottengono dalle seguenti integrazioni 1.3) ak 1 kx f x cos dx L L L 1.4) bk 1 kx f x sin dx L L L L L per k 1,2,3... 2. Esempio. Si consideri la funzione 2.1) f x, x [3,3] e si vogliano calcolare diciamo i primi 7 coefficienti dello sviluppo 1.2. Si osserva intanto che essendo la 1.5 una funzione dispari, ed essendo il coseno una funzione pari, segue che anche gli integrandi delle 1.3 sono funzioni dispari; quindi il valore dei coefficienti 1.3 è nullo. Ci restano quindi da calcolare i primi 3 coefficienti 1.4, per i quali si ha 1 3 3 3 3 1 1 1 x x x x b1 x sin dx xd cos x cos cos dx 3 3 3 3 3 3 3 3 3 1 3 6 3 cos 3 cos sin sin 1.9 1 1 2x b2 x sin dx 3 3 2 3 3 1 2x 3 xd cos 3 2 3 3 3 2 x 2x x cos cos dx 3 3 3 3 1 3 sin 2 sin 2 6 0.95 3 cos2 3 cos 2 2 2 2 3 x cosx 33 cosx dx 3 1 1 2 3 cos3 3 cos 3 sin 3 sin 3 0.63 3 1 1 3x b3 x sin dx 3 3 3 3 3 1 1 4x b4 x sin dx 3 3 3 3 3 3 1 3 xd cosx 3 1 4x 3 xd cos 3 4 3 3 3 4 x 4x x cos cos dx 3 3 3 3 1 1 sin 4 sin 4 6 0.47 3 cos4 3 cos 4 4 4 4 Quindi abbiamo ottenuto lo sviluppo 2.2) x 2x 3x 4x b1 sin b2 sin b3 sin b4 sin 3 3 3 3 essendo i coefficienti dati da 2.4) 6 b1 1.9 b 6 0.95 2 2 b 2 0.63 3 6 b4 0.47 4 3. Algoritmo risolutivo. Il programma in Fortran qui discusso è costituito dai seguenti elementi: il programma principale fourier_main il quale si occupa di chiedere all’utente di inserire la funzione da sviluppare, di utilizzare le subroutine di modulo e di stampare sullo schermo i coefficienti calcolati; 2 il modulo fourier_mod il quale contiene una stima del pi greco e le dimensioni degli array, oltre alle seguenti subroutine: coeff_coseno che si occupa di calcolare i coefficienti del coseno; coef_seno che si occupa di calcolare i coefficienti del seno; diagramma che plotta le funzioni inviate (quella da sviluppare, e quella sviluppata). Si precisa che i coefficienti sono calcolati integrando col metodo numerico di Cavalieri_Simpson. Il diagramma di flusso complessivo del programma è il seguente: Inizio L’unità chiamante fourier_main chiede il semiperiodo i valori della funzione nei nodi il numero di coefficienti da calcolare invoca diagramma per disegnare la funzione da sviluppare in serie diagramma invoca coeff_coseno per calcolare i coefficienti delle funzioni coseno coeff_coseno invoca coeff_seno per calcolare i coefficienti delle funzioni seno coeff_seno calcola lo sviluppo in serie mettendolo in un array in funzione della ascissa diagramma invoca diagramma per disegnare lo sviluppo in serie scrive sullo schermo i valori dei coefficienti di Fourier calcolati fine 4. Due esecuzioni del programma. Vediamo ora come si comporta il programma in due diverse esecuzioni; nel primo caso inserisco la funzione sviluppata nel paragrafo 2, così a poter confrontare i coefficienti forniti dal programma con quelli calcolati analiticamente, nel secondo caso inserisco una funzione oscillante con tratti rettilinei. 3 4.1. Funzione dispari. Fornisco al programma i valori della funzione 2.1 e chiedo di calcolare 13 coefficienti, ottenendo i seguenti valori, che riporto direttamente dal Prompt: I coefficenti del coseno sono a 0 = 1.9272168E-8 a 1 = -6.548746E-7 a 2 = 7.616324E-7 a 3 = -6.594555E-7 a 4 = 8.252311E-7 a 5 = -5.588875E-7 a 6 = 4.1913088E-7 I coefficenti del seno sono b 1 = 1.9098659 b 2 = -0.9549813 b 3 = 0.63679826 b 4 = -0.47789773 b 5 = 0.38284233 b 6 = -0.31986767 4 Si può osservare che quelli del coseno, pur essendo la funzione dispari, non sono nulli; ma sono comunque piccolissimi; questo naturalmente è dovuto alla integrazione numerica; che in genere fornisce valori non nulli anche per integrali che sono analiticamente pari a zero. Buona invece la concordanza con i coefficienti del seno calcolati in 2.4. Il grafico della funzione da sviluppare è anch’esso fornito dal codice ed è riportato sopra. Quello dello sviluppo in serie di Fourier di 13 funzioni sinusoidali è invece riportato qui sotto. Si possono notare i raccordi ai due estremi i quali sono legati alla struttura della serie di Fourier, che perviene alla costruzione di una funzione continua su tutto R, di periodo 2L. 5 4.2. Funzione oscillante. Fornisco al programma i valori di una funzione che oscilli tra -3 e 3, descrivendo una spezzata. La funzione non è pari, né dispari, dunque si prevedono coefficienti del coseno e del seno in generale non nulli. Il grafico della funzione da sviluppare è sopra. I coefficienti di Fourier che ottengo, che prendo direttamente dal Prompt, sono i seguenti I coefficenti del coseno sono a 0 = 10. a 1 = 6.521652E-7 a 2 = -0.0000017741673 a 3 = -0.000003436954 a 4 = 0.000003346504 a 5 = -0.0000026000405 a 6 = 0.000002361434 I coefficenti del seno sono b 1 = -0.39804778 b 2 = 1.8445204 b 3 = 2.2338054 b 4 = -0.820715 b 5 = 0.51045585 b 6 = -0.34598902 Ed ecco il grafico dello sviluppo in serie di Fourier, di 13 addendi: 6 5. Il codice della unità principale. Riporto lo script del main program. PROGRAM fourier_main USE fourier_mod USE DISLIN !sezione dichiarativa IMPLICIT NONE INTEGER::k INTEGER::i,j REAL::L REAL::ak,bk REAL::h INTEGER::m REAL:: somma !il numero dei coefficenti del seno !indici di ciclo !semiperiodo della funzione !i coefficienti k-mi !la distanza fra i nodi !il numero totale di coefficenti REAL,DIMENSION(n+1)::x !ascissa REAL,DIMENSION(n)::f !i valori della funzione in corrispondenza dei nodi REAL,DIMENSION(0:100)::a !i coefficienti del coseno REAL,DIMENSION(1:100)::b !i coefficienti del seno REAL,DIMENSION(p)::x_f !ascissa della funzione sviluppata REAL,DIMENSION(p)::f_f !funzione sviluppata CHARACTER(len=28):: titolo !titolo dei grafici CHARACTER(len=20):: chiusura !serve per chiudere il programma !sezione esecutiva WRITE(*,*) "La funzione da sviluppare in serie di Fourier" WRITE(*,*) "si intende definita in [-L,L] con periodo 2L." WRITE(*,*) " " WRITE(*,*) "Indica il semiperiodo L della funzione." WRITE(*,*) " " READ(*,*) L h = (2*L)/(n-1) !calcola il passo x(1)= -L !valore dell'ascissa del primo nodo !inizializza la funzione ciclo_f: DO i=1,n,1 WRITE(*,*) "Inserisci il valore della funzione in", x(i) READ (*,*) f(i) x(i+1) = x(i) + h END DO ciclo_f titolo = "funzione da sviluppare " CALL diagramma (f,n,titolo,L) !disegna la funzione in [-L,L] WRITE(*,*) " " WRITE(*,*) "Indica il numero di coefficienti della serie di Fourier da calcolare." WRITE(*,*) "Si precisa che e' richiesto un numero dispari." WRITE(*,*) " " 7 READ(*,*) m k = (m-1)/2 !inizializza m !calcola k !calcolo i coefficienti del coseno ciclo_cos: DO i=0,k,1 CALL coeff_coseno (i,L,f,ak) a(i)=ak END DO ciclo_cos !calcolo i coefficieinti del seno ciclo_sen: DO i=1,k,1 CALL coeff_seno (i,L,f,bk) b(i)=bk END DO ciclo_sen !scrive sullo schermo i coefficienti del coseno WRITE(*,*) " " WRITE(*,*) "I coefficenti del coseno sono" ciclo_write_cos: DO i=0,k,1 WRITE(*,*) " " WRITE(*,*) "a",i,"=",a(i) WRITE(*,*) " " END DO ciclo_write_cos !scrive sullo schermo i coefficienti del seno WRITE(*,*) " " WRITE(*,*) "I coefficenti del seno sono" ciclo_write_sin: DO i=1,k,1 WRITE(*,*) " " WRITE(*,*) "b",i,"=",b(i) WRITE(*,*) " " END DO ciclo_write_sin !calcola la funzione sviluppata in serie di fourier x_f(1)=-L ciclo_fourier: DO i=1,p,1 somma = 0 ciclo_interno: DO j=1,k,1 somma = somma + a(j)*cos(REAL(j)*pi*(x_f(i)/L)) + b(j)*sin(REAL(j)*pi*(x_f(i)/L)) END DO ciclo_interno f_f(i) = (a(0)/2) + somma x_f(i+1)= x_f(i)+((2*L)/(p-1)) END DO ciclo_fourier titolo = "sviluppo in serie di Fourier" CALL diagramma (f_f,p,titolo,L) !disegna lo sviluppo di fourier in [-L,L] !scrive sullo schermo i coefficenti dello sviluppo della funzione in serie di Fourier WRITE(*,*) " " WRITE(*,*) "I coefficienti trovati si intendono relativi allo sviluppo:" WRITE(*,*) " " 8 WRITE(*,*) "f(x)= a0/2 + sommatoria in k (ak*cos(k*pi*x/L) + bk*sin(k*p*x/L)) da 1 a", m WRITE(*,*) " " !operazioni di chiusura WRITE(*,*)"Premi un tasto per chiudere il programma. In questo caso la finestra del prompt" WRITE(*,*)"si chiudera' e perderai tutti i dati." READ(*,*) chiusura STOP END PROGRAM fourier_main 6. Il codice del modulo. Riporto lo script del modulo. MODULE fourier_mod !sezione dichiarativa IMPLICIT NONE REAL, PARAMETER:: pi=3.1415927 !una approssimazione del pi greco INTEGER,PARAMETER::n=41 !il numero di nodi INTEGER,PARAMETER::p=100 !il numero di punti in cui calcola lo sviluppo CONTAINS !-------------------------------------------------------SUBROUTINE coeff_coseno (k,L,f,ak) !integra la funzione inviata con il metodo di Cavalieri !(detto anche della parabola) IMPLICIT NONE !dichiaro gli argomenti fittizi REAL,INTENT(IN),DIMENSION (n)::f INTEGER,INTENT (IN)::k REAL,INTENT (IN)::L REAL,INTENT(OUT)::ak !dichiaro le variabili locali INTEGER::i !indice del ciclo REAL::h !passo REAL, DIMENSION (n):: primitiva REAL, DIMENSION (n):: integrando REAL, DIMENSION (n+1):: x !sezione esecutiva !calcola la distanza fra i nodi h = (2.*L)/REAL(n-1) !calcola la funzione integranda x(1)=-L 9 ciclo_integranda: DO i=1,n,1 integrando(i)=f(i)*COS((REAL(k)/L)*pi*x(i)) x(i+1)=x(i)+h END DO ciclo_integranda primitiva(1)= 0 !inizializza il primo valore !calcolo la primitiva (elementi dispari dell'array) ciclo_integra: DO i=1,n-2,2 primitiva(i+2) = primitiva(i) + ( (integrando(i+2) + (integrando(i+1)*4) + integrando(i))*(h/3.) ) END DO ciclo_integra !calcolo il coefficiente ak ak = primitiva(n)/L RETURN END SUBROUTINE coeff_coseno !-------------------------------------------------------SUBROUTINE coeff_seno (k,L,f,bk) !integra la funzione inviata con il metodo di Cavalieri !(detto anche della parabola) IMPLICIT NONE !dichiaro gli argomenti fittizi REAL,INTENT(IN),DIMENSION (n)::f INTEGER,INTENT (IN)::k REAL,INTENT (IN)::L REAL,INTENT(OUT)::bk !dichiaro le variabili locali INTEGER::i !indice del ciclo REAL::h !passo REAL, DIMENSION (n):: primitiva REAL, DIMENSION (n):: integrando REAL, DIMENSION (n):: x !sezione esecutiva !calcola la distanza fra i nodi h = 2*L/(n-1) !calcola la funzione integranda x(1)=-L ciclo_ascissa: DO i=1,n-1,1 x(i+1)=x(i)+h 10 END DO ciclo_ascissa ciclo_integranda: DO i=1,n,1 integrando(i)=f(i)*SIN((REAL(k)/L)*pi*x(i)) END DO ciclo_integranda primitiva(1)= 0 !inizializza il primo valore !calcolo la primitiva (elementi dispari dell'array) ciclo_integra: DO i=1,n-2,2 primitiva(i+2) = primitiva(i) + ( (integrando(i+2) + (integrando(i+1)*4) + integrando(i))*(h/3.) ) END DO ciclo_integra !calcolo il coefficiente bk bk = primitiva(n)/L RETURN END SUBROUTINE coeff_seno !------------------------------------------------------SUBROUTINE diagramma (f,int,titolo,L) !traccia il diagramma della f IMPLICIT NONE !dichiaro gli argomenti fittizi REAL,INTENT(IN),DIMENSION (int)::f !da plottare INTEGER, INTENT(IN)::int CHARACTER(len=28), INTENT(IN)::titolo REAL,INTENT(IN)::L !dichiaro le variabili locali INTEGER::j,i !indici di ciclo REAL ::h !passo REAL ::max !valore massimo della funzione REAL ::min !valore minimo della funzione REAL, DIMENSION (int):: x !contiene i valori delle ascisse !sezione esecutiva h=2*L/(int-1) !inizializzo l'array delle ascisse x(1)=-L ciclo_ascisse: DO i=2,int,1 x(i)=x(i-1)+h 11 END DO ciclo_ascisse !inizializzo l'array della funzione da plottare CALL METAFL ('bmp') !indico il formato dell'output CALL SCRMOD ('revers') !scritta nera su fondo bianco CALL DISINI CALL TEXMOD ('ON') !chiedo di poter scrivere le formule in maniera grafica CALL PAGERA !traccio un bordo per il piano xy CALL DUPLX !font a doppio spessore CALL AXSPOS (450,1800) !coordinate angolo basso sinistra CALL AXSLEN (2200,1500)!lunghezza dei due assi in pixel CALL NAME ('x','x') !nome delle ascisse CALL NAME ('y','y') !nome delle ordinate CALL TITLIN (titolo,1) !prima riga del titolo max=MAXVAL(f) !il massimo della funzione min=MINVAL(f) !il minimo valore della funzione CALL GRAF (-L,L,-L,5*h,min,max,min,max/5) CALL TITLE !stampa il titolo di cui sopra CALL CURVE (x,f,int) !plotto la funzione CALL DASH !tratteggio per gli assi coordinati CALL XAXGIT !traccio la retta y=0 CALL YAxGIT !traccio la retta x=0 CALL DISFIN RETURN END SUBROUTINE diagramma !-------------------------------------------------------END MODULE fourier_mod 12