Università degli Studi di Ferrara REALIZZAZIONE DI UN MO
Transcript
Università degli Studi di Ferrara REALIZZAZIONE DI UN MO
Università degli Studi di Ferrara Corso di Laurea in Ingegneria Elettronica Tesi di Laurea REALIZZAZIONE DI UN MO-DEMODULATORE NUMERICO PASSABANDA SU DSP Relatore: Laureando: Prof. Ing. Gianluca Mazzini Raffaele Rugin Correlatori: Prof. Ing. Michele Zorzi Dott. Ing. Alessandra Giovanardi A.A. 2001/2002 Facoltà di Ingegneria INDICE 1 Prefazione 5 1.1 Scopo della Tesi ...................................................................................................... 5 1.2 Metodo di Lavoro ................................................................................................... 5 1.3 Risultati Ottenuti..................................................................................................... 6 1.4 Organizzazione della tesi........................................................................................ 7 2 Introduzione ai DSP 9 2.1 Introduzione ............................................................................................................ 9 2.2 Architettura ........................................................................................................... 10 2.3 Formato Aritmetico .............................................................................................. 13 2.4 VLIW e Superscalari ............................................................................................. 15 2.5 Prestazioni ............................................................................................................ 19 3 Scelta dell’ Hardware 21 3.1 Considerazioni Iniziali ......................................................................................... 21 3.2 Il TMS320C6711 DSK .......................................................................................... 23 3.3 IL Multiconverter .................................................................................................. 27 3.4 Il THS1206 EVM .................................................................................................. 30 3.5 Circuito interfaccia............................................................................................... 32 4 Dimensionamento 34 4.1 Filtri di trasmissione e ricezione .......................................................................... 34 Teoria ............................................................................................................................. 34 Progettazione del filtro digitale.................................................................................... 40 Caratteristiche filtri realizzati ..................................................................................... 44 4.2 Demodulatore coerente ........................................................................................ 46 Metodi per generare una forma d’onda periodica ..................................................... 46 Realizzazione digitale di un PLL ................................................................................. 49 Il Costas Loop................................................................................................................ 56 Implementazione nel demodulatore ............................................................................ 62 2 4.3 Recupero sincronismo di simbolo......................................................................... 64 Sincronizzatore Early - Late ........................................................................................ 64 5 Modulatore 69 5.1 Introduzione .......................................................................................................... 69 5.2 Struttura del Progetto ........................................................................................... 70 5.3 Strutture dati ......................................................................................................... 73 5.4 Descrizione Procedure ......................................................................................... 76 Procedura main ............................................................................................................. 76 Procedure Gen_Tab_sen e Gen_Tab_cos..................................................................... 77 Procedura Cancella_Buffer .......................................................................................... 77 Procedura set_interrupts_edma .................................................................................... 77 Procedura SWI_Modulatore ......................................................................................... 78 Procedura Genera_Bit .................................................................................................. 78 Procedura Matched_Filter ............................................................................................ 79 Procedura Cancella_Delay_Lines ................................................................................ 80 Procedura Scegli_Uscita ............................................................................................... 80 Procedura PN_Generator ............................................................................................. 80 5.5 Funzionamento complessivo ................................................................................. 81 Ping Pong Buffer ........................................................................................................... 81 Generazione della modulazione ................................................................................... 87 6 Demodulatore 89 6.1 Introduzione .......................................................................................................... 89 6.2 Struttura del Progetto ........................................................................................... 90 6.3 Strutture dati ......................................................................................................... 94 6.4 Descrizione Procedure ......................................................................................... 96 Procedura main ............................................................................................................. 96 Procedura Cancella_Buffer .......................................................................................... 96 Procedura set_interrupts_edma .................................................................................... 97 Procedura Gen_Tab_sen............................................................................................... 97 Procedura SWI_Alta_Priorità ...................................................................................... 97 Procedura SWI_Bassa_Priorità.................................................................................... 98 Procedura Carrier_Recovery_and_Demodulator ........................................................ 98 Procedura Matched_Filter ............................................................................................ 99 3 Procedura Symbol_Clock_Recovery_and_Sample .................................................... 100 Procedura Decision_and_Decode ............................................................................... 100 Procedura Error_Block............................................................................................... 101 Procedura PN_Generator ........................................................................................... 102 Procedura Cambia_Fase_PLL ................................................................................... 102 6.5 Funzionamento complessivo ............................................................................... 103 Ping Pong Buffer ......................................................................................................... 103 Gestione della demodulazione .................................................................................... 104 7 Simulazioni 107 7.1 Introduzione ........................................................................................................ 107 7.2 Modulatore ......................................................................................................... 108 7.3 Demodulatore ..................................................................................................... 112 8 Misure 119 8.1 Metodo di misura ................................................................................................ 119 8.2 Spettri del segnale elaborato .............................................................................. 120 8.3 Segnali generati .................................................................................................. 123 8.4 Diagrammi ad occhio e di scatter ...................................................................... 124 9 Conclusioni 127 9.1 Considerazioni finali .......................................................................................... 127 Bibliografia 129 Appendice 131 Listati software modulatore ...................................................................................... 131 Listati software demodulatore .................................................................................. 145 4 Capitolo 1 Prefazione 1.1 Scopo della Tesi L’obiettivo di questa tesi è stata la realizzazione di un sistema di trasmissione numerico passabanda interamente in software su DSP che permettesse di supportare facilmente modifiche agli algoritmi di modulazione e demodulazione. Nella implementazione ci si è prefissi il fine di ottenere una struttura il più possibile modulare e ottimizzata in grado di operare su frequenze portanti sufficientemente elevate rispetto alla bit rate impiegata. Dal punto di vista della programmazione si è cercato di realizzare una gestione hardware il più possibile indipendente che garantisse altresì eccellenti prestazioni e basso consumo nel tempo di elaborazione. 1.2 Metodo di Lavoro Inizialmente dopo aver valutato tra varie alternative, si è fatta una scelta sul tipo di DSP e sui convertitori D/A e A/D più adatti per la realizzazione. Il software è stato realizzato impiegando il CCS v2.0 (Code Composer Studio) che rappresenta l’ambiente di sviluppo e debug per tutti i DSP prodotti dalla Texas Instruments, fornito a corredo con i TMS320C6711 DSK impiegati. La documentazione principale è stata reperita nei manuali forniti con i dispositivi ed in rete nel sito della ditta produttrice. Per il calcolo dei filtri e le simulazioni, inerenti soprattutto al recupero della portante e del sincronismo di simbolo, si è utilizzato il Simulink integrato nell’ambiente Matlab 6.1 al fine di verificare il corretto funzionamento degli algoritmi prima dell’implementazione finale. 5 Per la realizzazione del sistema completo si è inizialmente ricercata la modalità migliore per gestire proficuamente il flusso di dati in ingresso e uscita verso i convertitori. Risolti i numerosi problemi che si sono presentati si è passati alla realizzazione del modulatore. Un circuito di adattamento è stato costruito per amplificare in corrente e adattare i livelli dei segnali tra il convertitore D/A montato sul DSP modulatore e l’A/D presente nel ricevitore. Per quanto riguarda il demodulatore è stato necessario simularne il comportamento per poterne prevedere eventuali malfunzionamenti prima della implementazione finale; sarebbe stato altrimenti molto difficile individuarne la causa. Sul sistema si sono infine eseguite delle misurazioni per rilevare l’occupazione spettrale del segnale trasmesso. Sono stati inoltre ottenuti i diagrammi ad occhio e di scatter per verificare la qualità dell’intero sistema di comunicazione. 1.3 Risultati Ottenuti Dopo una iniziale difficoltà dovuta soprattutto alla comprensione del funzionamento dell’hardware e a una notevole dispersione delle informazioni nella documentazione tecnica allegata, è stato possibile realizzare un sistema completo e funzionante di trasmissione e ricezione operante con modulazione 4-QASK totalmente modulare, in grado di valutare le prestazioni del collegamento. Si sono inoltre simulati sistemi per costellazioni di ordine superiore ma non è stato possibile ottenere una struttura sufficientemente stabile e veloce da realizzare nei due DSP. Si è infine sperimentato per paragonarne le prestazioni, un differente metodo di recupero del sincronismo di simbolo che ha evidenziato un comportamento pressoché identico all’Early–Late implementato. 6 1.4 Organizzazione della tesi Nel secondo capitolo è riportata una breve trattazione sulle caratteristiche e sull’evoluzione dei DSP. Si sono inoltre evidenziate le differenze tra i vari modelli e i metodi per valutarne le prestazioni. Nel terzo capitolo sono riportate le motivazioni che hanno portato alla scelta di questa particolare configurazione hardware, e la descrizione delle potenzialità dei dispositivi utilizzati. Il quarto capitolo affronta il problema del dimensionamento dei filtri e la scelta degli algoritmi di demodulazione. In particolare sono esaurientemente trattati il PLL usato per il demodulatore coerentemente, e il rigeneratore del sincronismo di simbolo. I capitoli cinque e sei descrivono particolareggiatamente la struttura dei due programmi che implementano il modulatore e il demodulatore prestando particolare attenzione alla gestione dell’hardware. Si è inoltre riportata una completa documentazione relativa alla funzione delle varie procedure. Il capitolo sette riporta parte delle simulazioni e relativi risultati, che sono state necessarie per verificare il corretto funzionamento dei PLL presenti nel demodulatore. E’ riportato un’ulteriore schema non implementato, che è stato utilizzato per studiare la fattibilità di un demodulatore per costellazioni di ordine superiore. Sono inoltre comparati due metodi per rigenerare il sincronismo di simbolo, e proposti i diversi diagrammi di scatter. Il capitolo otto accenna le problematiche che si sono incontrate nella misura del segnale generato e riporta le effettive misure realizzate per via numerica, impiegando i campioni acquisiti al demodulatore. Si sono inoltre riportati i diagrammi ad occhio e di scatter ottenuti al demodulatore in due diverse condizioni di filtraggio dei simboli trasmessi. 7 Capitolo 2 Introduzione ai DSP 2.1 Introduzione I DSP (Digital Signal Processor) sono dispositivi particolarmente ottimizzati per elaborare digitalmente le informazioni provenienti dal mondo reale . Negli ultimi anni si stanno imponendo come soluzione ideale in un sempre più vasto campo di utilizzi, tra i quali solo alcuni esempi sono l’analisi e la sintesi di segnali vocali, l’elaborazione di immagini, l’automazione e la strumentazione biomedicale. I fattori che ne hanno incentivato lo sviluppo sono legati all’enorme vantaggio derivante dall’elaborare digitalmente le informazioni; vengono eliminate tutte le possibili cause di disturbo nel trattamento del segnale dal punto in cui viene acquisito, la ripetibilità e la stabilità dell’elaborazione sono garantite anche dopo anni di funzionamento (i problemi inerenti il fattore termico o l’invecchiamento dei componenti molto critici nei sistemi di elaborazione analogici scompaiono); inoltre con l’algoritmo implementato in software il DSP permette una grande flessibilità e la possibilità di realizzare facilmente funzioni complesse. L’impiego dei DSP in prodotti di largo consumo e l’avanzare della tecnologia hanno permesso di incrementarne enormemente le prestazioni in termini di velocità e bassi consumi, e ridurne moltissimo il prezzo rendendoli particolarmente competitivi nella telefonia cellulare in sistemi wireless e nei modem. Attualmente i DSP, soprattutto in applicazioni di bassa complessità, possono operare come dispositivi “stand alone” implementando oltre agli algoritmi di calcolo anche la gestione dell’interfacciamento con altre periferiche, come ad esempio avviene in molti modem commerciali. In impieghi più critici dove è necessario l’uso di un processore per la manipolazione dei dati, i DSP vengono spesso impiegati come co-processori per eseguire tutti i calcoli numerici ripetitivi liberando il microprocessore di un notevole carico di lavoro. L’uso di un processore ‘general purpose’ accoppiato a un DSP porta a un significativo vantaggio sia in termini di costo che di consumo di potenza; è infatti possibile scegliere 9 un processore con caratteristiche inferiori e devolvere tutta la mole di calcoli matematici a un DSP, strategia ampiamente impiegata nella telefonia cellulare. 2.2 Architettura Gli ultimi anni hanno mostrato come i computer siano estremamente efficienti in due campi: manipolazione dei dati, ad esempio la gestione di database, e il calcolo matematico usato in scienza, ingegneria e in “Digital Signal Processing”. Tutti i microprocessori possono eseguire tutte e due le operazioni sopraelencate, però è difficile e soprattutto costoso realizzare dispositivi ottimizzati per entrambe. Esistono dei compromessi a livello di progettazione hardware come ad esempio la dimensione del set di istruzioni che impediscono di ottenere un dispositivo ottimo per entrambi i campi di applicazione. Per questi motivi, pur esistendo processori con istruzioni per elaborazioni DSP (ad esempio la serie MMX dei Pentium), questi vengono ottimizzati principalmente per manipolare dati, mentre i DSP vengono ottimizzati per effettuare calcoli matematici necessari nel “Digital Signal Processing”. Particolare rilievo nei DSP riveste l’implementazione direttamente in hardware di un operazione fondamentale per il trattamento digitale dei segnali che prende il nome di MAC (Multiplay and accumulate) e permette in un ciclo di clock di effettuare una moltiplicazione e accumulare il risultato in un registro accumulatore. Tale operazione viene ampiamente utilizzata sia nel filtraggio dei segnali che nel calcolo di FFT. Figura 1 : Operazione matematica MAC 10 Figura 2 : Schema per l'implementazione hardware di un’istruzione MAC Nella figura seguente si può vedere come in un filtro FIR, ogni campione in uscita sia calcolato attraverso più operazioni di tipo MAC, moltiplicando i campioni del segnale d’ingresso per i coefficienti del filtro, e accumulando il risultato. Figura 3 : Schema delle operazioni eseguite durante un filtraggio con filtro FIR 11 Possedere un supporto hardware per eseguire tale istruzione in un solo ciclo di clock, unitamente a una diversa architettura del bus del DSP, permette di eseguire operazioni di filtraggio digitale molto più velocemente di un processore, rendendo possibili applicazioni di elaborazione in “real time”. L’architettura interna dei DSP in commercio è molto variata da quando sono stati introdotti sul mercato e, soprattutto ultimamente, si stanno osservando diverse novità. La struttura di base, anche se sono state apportate alcune migliorie, è restata sostanzialmente quella studiata per la prima volta all’Università di Harvard negli anni 40’. Una delle più grosse problematiche nell’esecuzione di algoritmi DSP è il trasferimento di informazioni con la memoria. Queste informazioni comprendono: i dati (campioni del segnale di ingresso e coefficienti del filtro) e le istruzioni del programma che deve essere eseguito. In una tradizionale architettura di Von Neumann con una sola memoria e un solo bus per trasferire i dati da e verso la CPU, moltiplicare due numeri richiede almeno tre cicli di clock per portare nel processore gli operandi e l’istruzione da eseguire. Con una architettura di tipo Harvard invece la CPU possiede due bus, uno per i dati e uno per il programma con due spazi di memoria (almeno teoricamente) separati; in questo modo può caricare parallelamente l’istruzione e i dati su cui operare. a) Architettura di Von Neumann (Memoria unica) Memoria Dati e Istruzioni Bus Indirizzi CPU Bus Dati b) Architettura Harvard (Doppia Memoria) Memoria Programma MP Bus Indirizzi MD Bus Indirizzi CPU MP Bus Dati Memoria Dati MD Bus Dati S olo Istruzioni S olo Dati Figura 4 : Confronto tra l’architettura di Von Neumann e l'architettura Harvard 12 In dispositivi più performanti, oltre al doppio bus, si utilizzano anche cache separate per dati e codice, al fine di incrementare le prestazioni; se si tiene conto che gli algoritmi impiegati sono spesso formati da cicli, è evidente come sia possibile raggiungere un notevole aumento delle performance e una riduzione dei trasferimenti sui bus. Bisogna inoltre considerare le ottimizzazioni che vengono effettuate a più basso livello sui DSP. Nel set di istruzioni molte operazioni o almeno le più frequenti, sono studiate per essere eseguite in un singolo ciclo di clock; la struttura dei bus inoltre è ottimizzata per gestire efficientemente trasferimenti di grosse dimensioni, spesso con l’integrazione di dispositivi di DMA in grado di raggiungere transfer rate di qualche Gb/s nei dispositivi attualmente più performanti. 2.3 Formato Aritmetico Nella scelta di un DSP una delle caratteristiche fondamentali da prendere in considerazione è rappresentato dal formato aritmetico con cui è in grado di operare. Principalmente esistono due categorie: Fixed point e Floating point che si differenziano per la possibilità di elaborare o meno numeri in virgola mobile. Il DSP con formato aritmetico fixed point è più complesso dal punto di vista della programmazione ma è un dispositivo meno costoso e ciò lo rende ideale in tutte quelle applicazioni di larga scala nelle quali non sia richiesto di gestire segnali con elevata dinamica; attualmente è comunque il più utilizzato. Tipicamente i DSP fixed point hanno lunghezze di parola di almeno 16 bit, presentano però l’inconveniente di poter utilizzare solo numeri interi pur essendo possibile impiegare notazioni frazionarie per aggirare la restrizione. Questo limite impone al programmatore l’utilizzo di tutta una serie di accorgimenti per evitare che si verifichino degli overflow nei registri macchina, compatibilmente però con il mantenimento del massimo della precisione. Nel caso di un filtro FIR è necessario scalare i valori delle moltiplicazioni per evitare di saturare il registro di accumulazione; così facendo però viene introdotto del rumore di discretizzazione che potrebbe degradare enormemente il segnale elaborato. In casi più 13 estremi potrebbe addirittura capitare che tale rumore porti all’instabilità un algoritmo. Bisogna quindi essere molto accorti nella progettazione di software per questi dispositivi. Per risolvere in parte il problema si utilizzano nei DSP dei registri accumulatori di lunghezza superiore alla lunghezza di parola, tipicamente 32 o 40 bit in modo da poter sommare il risultato con una precisione nettamente superiore, e solo al termine, prendendo i bit significativi, utilizzarlo per le elaborazioni successive. I DSP con formato aritmetico floating point al contrario essendo in grado di operare con numeri in virgola mobile (IEEE 754 o altri) permettono una dinamica e una facilità di programmazione nettamente superiori. Rappresentando i numeri con mantissa ed esponente si ha il grosso vantaggio che i valori della rappresentazione non sono equamente distribuiti. Per valori grandi la distanza è maggiore che per valori molto piccoli; in questo modo si riesce a esprimere una enorme dinamica del segnale mantenendo nel contempo il massimo della precisione. Per questo motivo non è più necessario scalare i valori su cui operare in quanto il risultato avrà sempre la massima accuratezza permessa dalla rappresentazione numerica senza incorrere in pericoli di overflow. Per contro, il dispositivo è più complesso a livello di hardware e deve essere costruito per operare altresì con numeri in virgola fissa in quanto in ogni caso i convertitori che si interfacciano con il mondo reale operano con numeri interi. Il costo è superiore e il suo utilizzo è attualmente relegato a applicazioni dove sia richiesta una notevole velocità ed una superiore precisione nella gestione di segnali ad elevata dinamica. La superiore precisione delle unità floating point deriva dalla maggiore lunghezza di parola che tipicamente è di 32 bit, in quanto se andassimo a considerare una rappresentazione fixed point con lo stesso numero di bit si osserverebbe una precisione maggiore perché i numeri sono molto più ravvicinati ma la dinamica gestibile sarebbe comunque enormemente inferiore. 14 2.4 VLIW e Superscalari L’evoluzione dei DSP nella ricerca di sempre più elevate prestazioni ha visto ultimamente apparire sul mercato due architetture sostanzialmente diverse che sfruttano un aumento del parallelismo del processore per ottenere superiori potenze di calcolo. Per una data tecnologia costruttiva se si vogliono incrementare le prestazioni è necessario aumentare il numero di istruzioni eseguite per unità di tempo. Le strade percorribili sono due: o si aumenta la frequenza di funzionamento del dispositivo o si struttura il processore in modo che sia in grado di eseguire in parallelo più istruzioni. La prima non è una soluzione vantaggiosa perché con la frequenza aumenta linearmente anche la dissipazione di potenza e soprattutto in apparecchiature portatili l’energia è un bene prezioso da utilizzare con parsimonia. La seconda invece comporta l’impiego di un maggiore numero di transistor per realizzare una struttura hardware più complessa ma opera a frequenze minori e alla fine risulta l’alternativa vincente. Nella struttura dei primi DSP che rispecchiavano molto bene nell’architettura il modello di Harvard, in grado di eseguire un’operazione MAC per ciclo di clock, si è pensato di aumentare il numero di ALU (Aritmetic logic unit) presenti nel processore in modo da poter eseguire in parallelo più operazioni. Il risultato di tale modifica ha portato a dei DSP migliorati che oltre a mantenere tutte le caratteristiche comuni dei primi quali: la possibilità di eseguire istruzioni fondamentali in un solo ciclo macchina, possiedono un hardware dedicato per certi tipi di indirizzamento (Buffer circolari), una memoria on-chip con accesso multiplo, hardware dedicato per i loop e tutta una serie di interfacce di I/O integrate ‘on chip’. L’aggiunta di una ALU ha permesso di eseguire istruzioni SIMD (Single Istruction Multiple Data) rendendo possibile l’elaborazione parallela di più dati contemporaneamente. Il miglioramento delle prestazioni però viene a discapito di una struttura hardware più complessa. La necessità di dover tener conto dell’interazione tra i dati calcolati ma soprattutto l’ esigenza di disporre in modo opportuno i dati in memoria perché siano elaborati in parallelo rendono molto difficile una programmazione diretta in codice assembler. 15 Queste famiglie di DSP vengono progettati soprattutto per campi applicativi specifici in quanto l’hardware viene altamente specializzato all’applicazione e portano spesso integrati co-processori per eseguire filtraggi FIR o implementare decodifiche come quella di Viterbi. Alcuni esempi sono rappresentati dal Lucent DSP16xxx o dall’ADI ADSP-2116x. Gli svantaggi elencati portano un oggettiva difficoltà nella realizzazione di applicazioni efficienti soprattutto in termini di tempo di sviluppo; diviene quindi essenziale poter disporre di un buon compilatore, in grado di realizzare del codice con un alto livello di ottimizzazione. L’ulteriore evoluzione è stata quella di far corrispondere le istruzioni della memoria con le unità di esecuzione disponibili sul processore. Nascono quindi le architetture VLIW e superscalari. Quello che si cerca di ottenere è il cosiddetto ILP (Instruction Level Parallelism), al fine di ottenere una parallelizzazione delle istruzioni. L’approccio Vliw (Very Large Istruction Word) ha come caratteristica di prendere dalla memoria tante istruzioni contemporaneamente e di considerarle come una singola. Vliw è riferito al fatto di voler considerare blocchi da 4 o da 8 istruzioni alla volta come una singola istruzione, questo è reso possibile da una certa disposizione delle stesse in memoria. Il grosso del lavoro di parallelizzazione viene eseguito dal compilatore. Nella filosofia vliw l’architettura viene sviluppata parallelamente al compilatore e, in pratica, è questo che si occuperà di svolgere gli affiancamenti delle istruzioni in memoria in modo da non creare conflitti o data hazard (lettura di dati prima che questi siano effettivamente disponibili). Se vengono caricate N istruzioni alla volta (significa che ci sono N unità di esecuzione) e tra queste ce ne saranno un buon numero eseguibili in parallelo già predisposte dal compilatore. Questo è possibile grazie alla rappresentazione interna dei dati e dell’uso di un’unità di controllo che decide l’esecuzione delle istruzioni. Il parallelismo non viene risolto via hardware, ma anteriormente l’esecuzione all’ atto della compilazione. 16 Figura 5 : Data Path di un DSP VLIW della famiglia C6x dalla Texas Instruments. Le architetture Vliw hanno la prerogativa di poter eseguire più operazioni indipendenti per ciclo macchina, essere più regolari e di possedere un ampio set di registri. Il vantaggio della regolarità della struttura comporta una maggiore semplicità nella realizzazione di compilatori, ma anche una maggiore scalabilità (ovvero la possibilità di aumentare le unità di esecuzione senza stravolgere l’architettura). Esistono però alcuni svantaggi: diviene difficilissimo programmare “a mano” il DSP perché bisogna tenere conto dello scheduling delle istruzioni, aumenta la dimensione del codice e la presenza di molti registri interni incrementa sensibilmente la dissipazione di potenza. Alcuni esempi di DSP Vliw sono la serie C6x della Texas. Nell’approccio superscalare l’esigenza dell’ILP è risolto via hardware. In pratica, esiste un meccanismo di individuazione della dipendenza dei dati run-time, durante l’esecuzione del codice. Le istruzione vengono disposte in modo tale da essere eseguite in parallelo. La metodologia descritta apparteneva alla corrente di ideatori dei supercalcolatori (computer ad alto potere computazionale). Con questa si raggiunge un elevato grado di parallelismo, paragonabile a quello dei vliw. 17 Figura 6 : Schema funzionale di un DSP con architettura superscalare Alcuni esempi di architetture superscalari per applicazioni DSP sono: ZSP ZSP164xx, Siemens TriCore. L’ utilizzo di architetture superscalari porta un altissimo incremento delle prestazioni con il grosso vantaggio che il programmatore (o il compilatore) non deve tenere conto dello scheduling delle istruzioni, diviene così molto più semplice la programmazione “a mano”. La dimensione del codice risulta inoltre ridotta rispetto al caso Vliw. Tra gli svantaggi oltre al maggiore consumo di energia (per la maggiore circuiteria interna del processore) è il comportamento dinamico del processore che rappresenta il più grosso fattore limitante. Il meccanismo di decisione sull’ opportunità o meno di fare eseguire un istruzione opera tenendo conto dei data hazard che si verificano, non si sa se certe istruzioni verranno eseguite dopo altre e il tempo di esecuzione è variabile; diventa allora difficile ottimizzare il codice e sarà necessario usare un DSP con capacità di calcolo superiore a quella richiesta dall’applicazione per aggirare il problema. Tutto ciò è in antitesi con la filosofia di utilizzo dei DSP, che prevede la scelta di dispositivi il più possibile “tagliati” in termini di potenza di calcolo, per la specifica applicazione soprattutto per motivi di costo. E’ per questo motivo che la architettura più largamente impiegata è la Vliw. 18 2.5 Prestazioni La scelta di un DSP per una determinata applicazione è legata a molti fattori: il consumo, la quantità di memoria, i dispositivi di I/O, ma soprattutto la potenza computazionale occorrente. E’ molto difficile valutare le prestazioni di un DSP; esistono dei benchmark che sono spesso forniti dalle ditte produttrici, ma rispecchiano le prestazioni del dispositivo solo per certi particolari algoritmi o operazioni, quindi in modo ben diverso rispetto a una applicazione reale più articolata. Tipicamente le caratteristiche che si vanno a testare sono il tempo di esecuzione per routine di FFT o di filtraggio con filtri FIR. I valori ottenuti sono però molto legati al tipo di DSP e alle ottimizzazioni hardware integrate, uno stesso algoritmo potrebbe fornire valori molto diversi se non tenesse conto di tali particolarità. Molto in uso, sebbene dia un indicazione relativa, è la classificazione secondo il numero di istruzioni per secondo che il processore è in grado di eseguire. Viene fatta una distinzione tra processori in virgola mobile e fissa: per i primi si utilizza l’unità di misura MIPS (milioni di istruzioni per secondo) mentre per i secondi si vanno a valutare i MFLOPS (milioni di istruzioni in virgola mobile per secondo). Figura 7 : Confronto tra alcuni DSP prodotti dalla Texas Instruments In ogni caso per una corretta scelta che sia il più possibile misurata con ciò che si desidera implementare, è necessaria una notevole esperienza pratica. A tale scopo risulta di grandissimo aiuto l’osservazione di quanto già realizzato da altri ricercatori o dalla ditta produttrice stessa per rendersi conto se un particolare DSP può o meno essere appropriato per svolgere efficientemente 19 la particolare funzione desiderata. Capitolo 3 Scelta dell’ Hardware 3.1 Considerazioni Iniziali Al fine di realizzare un sistema completo di trasmissione e ricezione si è dovuto scegliere tra i vari dispositivi in commercio il DSP più adatto e con un buon rapporto prezzo-prestazioni, che garantisse altresì una facile interfacciabilità con dispositivi periferici. Dopo una veloce ricerca tra i modelli disponibili, soprattutto tra quelli prodotti dalla Texas Instruments, si è optato per il TMS320C6711 in quanto oltre a possedere prestazioni computazionali decisamente elevate è in grado di operare con numeri in virgola mobile. Si è scelto di utilizzare un sistema completo già montato che integrasse oltre al DSP, le memorie e le periferiche necessarie per realizzare un minimo di sperimentazione. Nella selezione di questo particolare modello ha molto pesato la disponibilità di due connettori di espansione che hanno permesso di collegare al sistema base dei convertitori aggiuntivi per poter operare con frequenze sufficientemente elevate e supportare una modulazione passabanda. Il TMS320C6711 viene montato su due tipi di piattaforme dimostrative prodotte direttamente dalla Texas Instruments che differiscono notevolmente per prezzo e prestazioni: lo Starter Kit e l’Evaluation Board. Tra le due versioni disponibili è stato scelto lo Starter Kit in quanto permette una più facile maneggevolezza per il montaggio di schede di espansione non richiedendo il collegamento a uno slot PCI, e mantiene almeno in parte le prestazioni della ben più costosa Evaluation Board. Uniche differenze abbastanza significative riguardano il codec montato nella versione PCI che permette di raggiungere 96 Khz di ‘sample rate’ contro gli 11 Khz dello Starter Kit, e il tipo di collegamento tra il PC e la scheda del DSP. L’Evaluation Board permette con l’interfacciamento diretto al bus PCI una maggiore banda passante nel trasferimento di dati da e verso il DSP, e soprattutto per quanto riguarda il debug prestazioni superiori. Lo Starter Kit d’altro canto garantisce un 21 funzionamento soddisfacente sfruttando un collegamento parallelo bidirezionale con il PC (IEEE 1284), e una buona velocità complessiva nella gestione del sistema. Eventualmente sfruttando un adattatore esterno è possibile collegarsi al connettore denominato JTAG che permette un notevole incremento nelle capacità di debug del sistema. Figura 8 : Rappresentazione dello Starter Kit La frequenza di campionamento del codec integrato sulla scheda madre del DSP risulta insufficiente per una modulazione passa banda; si è reso quindi necessario ricorrere a dei convertitori addizionali per risolvere il problema. La scelta è stata alquanto impegnativa e alla fine alquanto limitativa nei confronti dei progetti iniziali. Originariamente l’idea era di realizzare una daughterboard contenente sia convertitori D/A che A/D che permettesse al DSP di disporre di un numero sufficientemente elevato di ingressi e uscite molto veloci, ma già nella scelta dei dispositivi più adatti si era evidenziata la necessità di dover operare con componenti SMD. Inoltre l’ esigenza di realizzare il prototipo in più pezzi e l’obbligo di utilizzare un PCB multistrato per ridurre i disturbi avrebbe reso l’autorealizzazione molto critica e dispendiosa in termini di tempo. 22 Si è quindi scelto di puntare principalmente sullo sviluppo del software, utilizzando come convertitori i dispositivi montati in alcune Evaluation Board realizzate dalla Texas Instruments per permettere di testare tali componenti. Tra le varie scelte possibili si è subito evidenziata una notevole limitazione: le schede adatte per il montaggio sui connettori di espansione del TMS320C6711 non permettevano di acquisire e di generare segnali su un numero sufficientemente elevato di canali rendendo quindi impossibili certe applicazioni ideate inizialmente che prevedevano al ricevitore la visualizzazione diretta su oscilloscopio di certi segnali significativi quali ad esempio il diagramma ad occhio o la costellazione ricevuta. Dopo un attenta valutazione si sono infine selezionate due Evaluation Board in particolare i modelli THS1206 EVM e il modello Multiconverter che garantivano prestazioni sufficienti per la realizzazione del sistema di trasmissione pur con le limitazioni sopraelencate. Nella realizzazione pratica si sono impiegati due Starter Kit: il primo equipaggiato con il Multiconverter e funzionante da modulatore mentre il secondo con montato il THS1206 EVM è stato utilizzato come demodulatore. Infine un circuito di interfaccia ha permesso il corretto collegamento dei due sistemi. 3.2 Il TMS320C6711 DSK Il TMS320C711 DSK, come si può vedere in figura 8, integra oltre al DSP TMS320C6711 tutta una serie di dispositivi esterni che ne rendono possibile un impiego immediato senza la necessità di realizzare hardware aggiuntivo in molte applicazioni. Il DSP TMS320CC6711 montato è un dsp floating point a 32 bit realizzato in tecnologia 0.18 µm con 5 livelli di metallizzazione, il clock è di 150 Mhz ed è in grado di operare a 900 MFLOPS. La particolare struttura interna di tipo VelociTITM VLIW contiene otto unità di calcolo indipendenti: • 4 ALU in grado di operare indifferentemente con numeri fixed o floating point; 23 • 2 ALU fixed point; • 2 Moltiplicatori fixed e floating point. Figura 9 : Core del TMS320C6711 (Sono visibili le ALU e i Moltiplicatori) In tal modo è possibile l’esecuzione contemporanea teorica di otto istruzioni per ciclo macchina; sono inoltre presenti 32 registri general porpose e il supporto hardware per operare con numeri in formato IEEE in singola o doppia precisione. Nello stesso chip sono integrate due memorie cache di livello 1 da 4KB per programma e dati; inoltre è disponibile una seconda memoria cache di livello 2 da 64KB unificata, che può essere eventualmente disabilitata e utilizzata come una piccola memoria RAM interna. 24 Come visibile in figura 10 il DSP contiene al suo interno tutta una serie di dispositivi che gli permettono di interfacciarsi in modo veloce ed efficiente con periferiche esterne. In particolar modo sono presenti: Una interfaccia EMIF a 32 Bit (External Memory Interface) che permette grazie a una gestione molto sofisticata e totalmente programmabile degli spazi e dei segnali di indirizzamento, il collegamento glueless di chip di memoria esterni (SRAM, EPROM, SDRAM, SBSRAM). Lo spazio di memoria esterna indirizzabile è di 512 MB e la possibilità di settare in opportuni registri tutte le tempistiche di accesso a dispositivi periferici permette un facile collegamento anche con convertitori non particolarmente veloci; Un controllore DMA chiamato in questo caso EDMA (Enhanced DirectMemory-Access) con 16 canali programmabili in grado di operare trasferimenti di dati in una grande varietà di modi, senza l’intervento del processore e a velocità molto elevata; Due porte seriali denominate McBSP (Multichannel Buffered Serial Ports) in grado di operare serialmente trasferimenti a più di 30 Mbit per secondo, compatibili con gli standard AC97, SPI e capaci di gestire fino a 256 canali ognuna; Due timer di utilizzo generale a 32 Bit per generare temporizzazioni utili per dispositivi esterni; Un generatore di clock basato su un circuito PLL (Gia usato nel DSK per ottenere i 100 Mhz di clock per la SDRAM e quindi non disponibile!); La circuiteria necessaria per il debug e l’analisi del sistema anche in run-time come da specifiche IEEE 1149.1 (JTAG). 25 Figura 10 : Struttura interna del DSP TMS320C6711 Oltre a ospitare il chip del DSP TMS320C6711 la scheda dello Starter Kit contiene: Due alimentatori switching necessari per fornire le tensioni di +3.3V e +1.8V per il core del processore e per le memorie; 16 MB di memoria RAM per dati e programma e una memoria flash da 128 KB, nella quale è possibile memorizzare un programma da eseguire all’ accensione del sistema. La circuiteria di interfaccia per permettere il collegamento dati e il debug tramite la porta parallela con il PC. E’ comunque presente un connettore JTAG che opzionalmente consente con un adattatore prestazioni superiori; Un codec di qualità vocale TLC320AD535 con una sample rate massima di 11Ksps collegato alla porta McBSP0 con due uscite a bassa impedenza e un ingresso entrambi con guadagni variabili; Due connettori di espansione (Memory e Peripheral Connector) che permettono il collegamento con schede aggiuntive; le specifiche meccaniche ed elettriche di 26 tali connettori sono state standardizzate dalla Texas Instruments e riportate nel documento [24] disponibile in rete; Tre led e dip-switch utilizzabili a discrezione dall’ utente. L’ unica piccola lacuna è la mancanza delle tensioni di +12V e –12V sui connettori di espansione. E’ essenziale nel caso si utilizzino circuiti che richiedano tale alimentazione come il Multiconverter l’uso di un alimentatore esterno che la fornisca. Nella scheda madre del DSP è presente lo spazio per montare un connettore aggiuntivo come quello presente negli alimentatori per PC che permetterebbe di fornire contemporaneamente i +5V,+12V,-12V ma non si è impiegato per non rischiare di danneggiare con saldature la scheda madre dello Starter kit. 3.3 IL Multiconverter Caratteristica peculiare di questa scheda è la possibilità di accogliere su due appositi zoccoli sia convertitori D/A che A/D e quindi permettere al DSP di elaborare segnali provenienti dal mondo esterno. La circuiteria della scheda è alquanto elaborata e comprende oltre ai due convertitori tutta una serie componenti tra i quali un generatore di funzioni, tre PLA che permettono di indirizzare i due convertitori e, settando gli opportuni jumper, di testare la scheda Stand-alone. I dispositivi che possono essere montati sono dispositivi seriali, che grazie ai due zoccoli è possibile sostituire facilmente, le prestazioni ottenibili sono comunque limitate dall’utilizzo del collegamento seriale, che se da una parte semplifica la realizzazione del circuito, dall’altra limita la velocità massima di trasferimento dei dati. Attualmente sono montati il convertitore D/A TLV5636 le cui caratteristiche sono: • 1 Canale • 12 bit di risoluzione • 1 µS settling time • 1.2 Msps teorici sul collegamento seriale 27 e il convertitore A/D TLC2551: • 1 Canale • 12 bit di risoluzione • 400Ksps. Con N=12bit si raggiunge secondo la formula: SNR = (6.02 N + 1.76)dB proposta da [3], un rapporto segnale rumore di circa 70dB più che sufficiente come prestazione per l’applicazione che si desidera implementare. Nella realizzazione del modulatore l’A/D non è stato utilizzato in quanto si è scelto di usare come sorgente un generatore di sequenze di massima lunghezza, che permetta al ricevitore di valutare gli errori del collegamento. E’ possibile inoltre montare dei convertitori a due canali (gia forniti a corredo con il MultiConverter) per generare due segnali contemporaneamente che potrebbero essere utili ad esempio per fornire a dei circuiti esterni i due segnali in quadratura da modulare. Sono inoltre presenti un connettore di alimentazione al quale bisogna fornire due tensioni di +12V e –12V per alimentare i convertitori e i buffer di uscita, e tutta una serie di test point, nei quali sono possibili misure sulle forme d’onda generate dalla scheda. Il collegamento con il DSP avviene come gia accennato precedentemente per via seriale, sfruttando una periferica denominata McBSP che gestisce le trasmissioni seriali del TMS320C711. Nel chip del DSP sono integrati due canali seriali; il primo è già utilizzato dal codec presente sulla scheda madre, mentre il secondo attraverso i connettori di espansione, é collegato al MultiConverter. Tale periferica è in grado di gestire comunicazioni seriali in modo molto complesso permettendo a più di 256 dispositivi compatibili con tale standard di dialogare condividendo le stesse linee di trasmissione e ricezione. In questo caso la trasmissione avviene in modo molto semplificato, per la presenza di un unico dispositivo collegato al canale. 28 Nella implementazione del modulatore il Multiconverter viene gestito a livello di hardware in questo modo: La periferica McBSP1 viene programmata per trasmettere dati di 16 Bit di Lunghezza; Viene abilitato il chip select del convertitore D/A; Il dato da trasmettere (16 bit: 4 parola controllo +12 dati) viene trasferito dal DSP nel registro di trasmissione del McBSP1; La periferica McBSP1 genera su due opportuni pin di uscita due segnali di sincronizzazione: un segnale di clock per ogni bit trasmesso e un segnale di frame che si porta alto per un periodo di clock ogni volta che si inizia la trasmissione di una nuova parola. Tutte le tempistiche sono programmabili dall’utente agendo su opportuni registri. Figura 11 : Tipico collegamento di un dispositivo seriale alla McBSP Ogni volta che il segnale di frame si porta alto la periferica inizia a trasmettere la parola contenuta nel registro di trasmissione su un apposito pin; sincronizzando i bit con il segnale di clock. L’uscita è prelevata tra i pin 1 e 2 del connettore J8 e presenta un impedenza di uscita di circa 4.7KΩ 29 Figura 12 : Temporizzazioni del trasferimento dati seriale 3.4 Il THS1206 EVM Per la realizzazione del demodulatore si è scelto di impiegare una daugtherboard prodotta dalla Texas e basata sul convertitore A/D THS1206. Tale scheda possiede caratteristiche decisamente elevate derivantegli dall’ impiego di un convertitore ad alte prestazioni come il THS1206; riassumendo in breve: • 6Msps frequenza massima di campionamento; • 12 bit risoluzione; • 4 Canali Single-ended a campionamento simultaneo utilizzabili accoppiati per realizzare 2 canali differenziali; • Fifo interna di 16 campioni gestita come buffer circolare; • Interfaccia di trasferimento dati parallela. La scheda monta alcuni connettori BNC per i canali di ingresso dell’A/D; tutti gli ingressi sono caricati su 50Ω, bufferati per traslare il livello analogico di ingresso da – 1V, +1V a +1.5V, +3.5V, e filtrati passa basso con un semplice filtro RC avente frequenza di taglio di circa 3MHz. 30 I 4 ingressi denominati AINP, AINM, BINP, BINM sono ingressi single ended, mentre ADIFF, BDIFF sono gli ingressi differenziali che impiegano due canali di conversione e risultano accoppiati a trasformatore. L’ingresso utilizzato nel demodulatore è AINP perché gli ingressi differenziali che inizialmente si volevano utilizzare, presentano a causa del trasformatore in ingresso, un impedenza molto inferiore ai 50Ω a 37.5KHz di frequenza. E’ inoltre prevista la possibilità di alimentare il convertitore con un alimentatore esterno e di poter fornire esternamente anche il clock di conversione. Per qualsiasi modifica delle impostazioni bisogna oltre a modificare la posizione dei jumper anche cambiare i parametri nella routine di inizializzazione del convertitore nel software del demodulatore. La connessione di tale scheda con il DSP avviene innestando i due connettori negli omologhi connettori di espansione presenti nella piastra madre del DSP. Il collegamento avviene per via parallela attraverso il bus di espansione, da tale bus vengono prelevati oltre ai primi 12 bit del bus dati anche i segnali di lettura e scrittura, il clock di conversione, il chip enable, e il segnale di interruzione 4. Per quanto riguarda la parte hardware, il funzionamento si può schematizzare come segue: Il convertitore THS1206 viene inizializzato con una parola di controllo che setta i canali da utilizzare, il numero di campioni da memorizzare nella fifo prima di chiederne lo svuotamento e come interpretare i segnali di controllo (read, write, ecc.). Viene settato e inizializzato il Timer1 in modo da generare il clock di conversione, tale timer è contenuto internamente al chip del DSP ed è collegato alla daughterboard tramite i connettori di espansione. Attualmente il clock di conversione è stato fissato a 200KHz . Viene settata la EMIF (External Memory Interface) per gestire il CS (Chip Select) del convertitore e garantire i tempi corretti di accesso al dispositivo. 31 Viene abilitato il segnale di interruzione numero 4. A tale interruzione è agganciata la temporizzazione dell’EDMA come sarà più chiaro in seguito. Il convertitore sul fronte di salita del clock campiona il segnale di ingresso lo quantizza in 12 bit e lo carica nella fifo interna; quando nella fifo ci sono un certo numero di campioni (fissato in fase di inizializzazione, ma comunque inferiore a 14) l’A/D alza il segnale sul pin INT 4, tale interruzione viene recepita dall’EDMA che si preoccupa senza l’intervento del DSP di spostare tutti i campioni della fifo in un buffer presente in memoria principale. 3.5 Circuito interfaccia Per connettere trasmettitore e ricevitore si è dovuto impiegare un buffer per adattare l’impedenza e i livelli del segnale in uscita dal modulatore, con quelli richiesti in ingresso dal demodulatore. Si è scelto l’operazionale TL081 che garantisce un Slew Rate e una corrente di uscita sufficienti; se si desidera comunque un incremento delle prestazioni è possibile un upgrade del circuito semplicemente sostituendo l’operazionale con un altro modello ad esempio l’AD711 o meglio l’AD845, che garantiscono correnti di uscita maggiori e minore rumore. Figura 13 : Vista dall’alto del PCB realizzato La configurazione utilizzata è quella di un sommatore non invertente a guadagno unitario; i due ingressi hanno resistenze diverse di 56Ω e 4,7KΩ; il primo viene 32 impiegato per il segnale in uscita dal D/A il secondo invece può essere usato per inserire del rumore per poter valutare le prestazioni del collegamento in condizioni più reali. La scelta delle due resistenze è stata fatta per avere approssimativamente la stessa impedenza di ingresso per le due entrate, in quanto il D/A monta un resistore da 4,7KΩ in serie al buffer di uscita. Gli ingressi sono accoppiati in continua e filtrati passa basso con il condensatore da 220pF per limitare lo spettro del segnale in ingresso e evitare possibili auto-oscillazioni del circuito; sono stati inoltre montati due condensatori di bypass sulle linee di alimentazione per eliminare eventuali disturbi presenti. Figura 14 : Schema elettrico del circuito di interfaccia Il segnale di 4Vpp (con un offset di +2V rispetto a massa) in ingresso viene amplificato in corrente dal circuito e accoppiato in alternata all’uscita con un condensatore di 2.2µF in modo da ottenere un segnale centrato rispetto a massa; un resistore da 47Ω adatta l’impedenza di uscita in modo da avere, una volta caricato il buffer, un segnale ai capi dell’ingresso del A/D di 2Vpp che permette di sfruttare tutta la dinamica del convertitore. L’Alimentazione viene fornita con un connettore a tre poli garantendo così le tensioni di +12V e -12V necessarie; un secondo connettore permette di alimentare direttamente il Multiconverter senza ulteriori collegamenti. 33 Capitolo 4 Dimensionamento 4.1 Filtri di trasmissione e ricezione Teoria In un sistema di comunicazione assume estrema importanza la banda del segnale trasmesso che deve risultare il più possibile ridotta per sfruttare al massimo il mezzo disponibile. Per un 4-QASK le transizioni da un simbolo al successivo portano a delle forti discontinuità nella fase e quindi a dei significativi lobi secondari nello spettro del segnale modulato. Nella pratica soprattutto nel caso in cui ci si trovi a operare su tratte radio divise in canali adiacenti, è essenziale ridurre l’interferenza reciproca e operare con segnali molto ben limitati nella banda scelta. E’inoltre molto importante poter controllare la dispersione dell’energia dei simboli trasmessi per effetti parassiti o imperfezioni del mezzo, che potrebbero portare a grossi problemi nella decisione corretta dei simboli al ricevitore. Per trovare una soluzione esistono tipicamente due metodi di approccio: Effettuare un filtraggio a frequenza intermedia sul segnale modulato; Filtrare in banda base i simboli da trasmettere. Il primo metodo permette un perfetto controllo dello spettro del segnale; per contro l’elaborazione avviene a elevata frequenza con la necessità di impiegare filtri con notevoli caratteristiche di linearità. L’implementazione digitale è molto onerosa e nel nostro caso poco consigliata perché impiegherebbe buona parte delle potenzialità di elaborazione del DSP. Nel secondo caso invece lo spettro viene controllato sagomando opportunamente i simboli da trasmettere in banda base rendendone particolarmente conveniente l’utilizzo in una realizzazione software come quella presentata. E’ per questo motivo che si è scelto tale metodo. 34 Poiché l’operazione di filtraggio in banda base allarga i simboli nel tempo, può causare una significativa interferenza intersimbolo (ISI) se il filtro non è progettato correttamente. Il metodo di Nyquist per eliminare l’ISI richiede che la funzione di trasferimento del sistema di trasmissione includendo i filtri di TX e RX sia del tipo: 1 1 f He ( f ) = ∏ = Rs Rs 0 dove Rs è la frequenza di simbolo e T = se f ≤ 1 2T altrove 1 . Rs La risposta all’impulso di H e ( f ) è del tipo: he (t ) = sin (πRs t ) πRs t Tale filtraggio ottimo che produce la minima larghezza di banda non è però realizzabile fisicamente per l’infinita pendenza della funzione di trasferimento; inoltre la decadenza dei lobi nel dominio del tempo risulta essere molto lenta e potrebbe dare grossi problemi se il ricostruttore del sincronismo di simbolo non opera perfettamente. Per non avere interferenza intersimbolo in realtà basta che sia verificata la condizione: H(0) 1 1 He + f + He − f = 2T 2T 0 1 2T altrove 0≤ f ≤ un filtro che soddisfa questa condizione è il filtro a coseno rialzato la cui risposta in frequenza è la seguente dove α è il fattore di roll-off. 35 T πT 1 − α T H e ( f ) = 1 + cos f − 2T α 2 0 se 0 ≤ f ≤ se 1−α 2T (1 + α ) (1 + α ) ≤ f ≤ 2T 2T se f ≥ 1+α 2T |He(f)| α=1 1 α=0.5 α=0.75 0.5 f/Bit rate 0 0.5 Figura 15 :Risposta in frequenza di un filtro a coseno rialzato La banda del filtro a –6dB è Rs/2 mentre la banda totale e: B= 1+α Rs 2 che raddoppia nel caso del segnale modulato. Il sistema è allora in grado di supportare una frequenza di simbolo massima di: Rs = 2B 1+α 36 La risposta all’impulso del filtro a coseno rialzato è del tipo: t παt sin cos T T he (t ) = t α 2t 2 1 − 4 2 T T Figura 16 : Risposta all’impulso al variare di α di un filtro a coseno rialzato Maggiore è il fattore di roll-off α, maggiore è la banda occupata ma minore è la durata dell’impulso nel dominio del tempo. Al limite per α=0 si ha una funzione sinc di durata infinita. Al ricevitore se l’interferenza intersimbolo è eliminata il problema maggiore è il rumore presente nel collegamento; è allora conveniente aggiungere un filtro in ricezione per ridurlo. Dalla teoria è noto che la probabilità di errore in un canale con rumore additivo gaussiano bianco se non è presente ISI dipende unicamente dal rapporto segnale rumore (SNR). ( Pe = Q SNR ) Il filtro di ricezione è allora dimensionato per massimizzare l’SNR all’istante di campionamento per l’impulso di trasmissione impiegato. In pratica il filtro adattato elimina il rumore presente a frequenze maggiori della sua frequenza di taglio per la sua caratteristica passa basso. Correlando il segnale ricevuto con la forma dell’impulso impiegato nel trasmettitore si ottiene un guadagno per il segnale utile che viene 37 integrato nel periodo; il rumore invece se supponiamo di operare in un canale di tipo AWGN risulta mediato e darà un contributo nullo. Abbiamo allora due criteri per ottimizzare i filtri di trasmissione e ricezione: Rispettare il criterio di Nyquist (per garantire zero ISI); Realizzare il filtro di ricezione adattato (per minimizzare il rapporto SNR al ricevitore) che è ottimo solo se non ho ISI. Per verificare entrambe le condizioni si consideri una coppia di risposte all’impulso per le quali valga: g (t ) = hT (t ) ∗ hR (t ) = hT (t ) ∗ hT (− t ) dove i pedici T e R stanno a indicare il ricevitore e il trasmettitore. Nel dominio della frequenza possiamo esprimere g(t) come: G ( f ) = H T ( f )H T* ( f ) = H T ( f ) 2 un possibile metodo di progetto consiste nel supporre G(f) funzione del tipo di Nyquist a valori reali positivi e scegliere: H T ( f ) = H R ( f ) = G( f ) Se per G(f) utilizziamo una funzione del tipo a coseno rialzato si ottengono i due filtri ottimi da inserire nel trasmettitore e nel ricevitore che saranno identici e verranno in seguito indicati con il nome SRRC (Square root raised cosine). 38 La risposta frequenziale del filtro SRRC sarà: T πT 1− α T cos HT ( f ) = H R ( f ) = f − α 2 2 2 T 0 se 0 ≤ f ≤ se 1−α 2T 1−α 1+ α ≤ f ≤ 2T 2T se f ≥ 1+α 2T mentre nel dominio del tempo si ricava: 1 − α + 4α π 2 π 2 π α hT (t ) = hR (t ) = 1 + π sin 4α + 1 − π cos 4α 2 t t t sin π (1 − α ) + 4α cos π (1 + α ) T T T 2 t t π 1 − 4α T T Figura 17 : Risposta all’impulso del filtro SRRC al variare di α 39 se t = 0 se t = ± T 4α altrove Si può notare come in un filtro SRRC non si hanno zeri in corrispondenza degli istanti temporali multipli del periodo di simbolo, ma è la cascata dei due filtri che posside tale caratteristica annullando in tali punti l’interferenza intersimbolo. Progettazione del filtro digitale Per realizzare digitalmente il filtro SRRC sopra descritto esistono varie metodologie. La più utilizzata impiega filtri FIR perché i simboli filtrati danno una risposta limitata nel tempo dalla lunghezza del filtro, che è proprio quello che si vuole ottenere al fine di ridurre l’interferenza tra i simboli adiacenti. Un filtro IIR pur permettendone egualmente la realizzazione avrebbe grossi problemi a ottenere la stessa risposta per la sua forma intrinseca oltre che a una indubbia maggiore sensibilità alla rappresentazione numerica finita del DSP. L’impiego di un numero limitato di tappi porta ad un’inevitabile troncamento della risposta temporale del filtro e quindi a una distorsione. Bisogna quindi valutare quale sia il migliore compromesso tra le prestazioni desiderate e l’ordine del filtro. Per calcolare correttamente i coefficienti di un filtro digitale partendo da una fissata finestra nel dominio della frequenza il metodo più semplice consiste nel campionare a intervalli costanti la curva desiderata e applicare a tale serie la trasformata di Fourier inversa discreta. Le specifiche di progettazione sono le seguenti: Tb - durata del simbolo α - fattore di roll-off (determina la pendenza del filtro) Fs - frequenza di campionamento (deve essere almeno 2/ Tb) N - fattore di risoluzione in frequenza (determina il numero di campioni della risposta in frequenza utilizzati per il disegno del filtro) Nt - Ordine del filtro. Maggiore è il fattore N e maggiore è l’accuratezza con cui il filtro approssima la risposta desiderata; tipicamente N è specificato come un numero dispari. 40 Il numero di tappi con cui è composto il filtro limita il fattore di roll-off minimo realizzabile; se indichiamo con BW la banda di transizione normalizzata alla frequenza di campionamento è possibile utilizzare la relazione seguente: N≈ 4 BW che stabilisce un criterio di massima per la scelta della lunghezza del filtro. Tale formula non tiene conto del tipo di finestra impiegata e quindi da un valore molto indicativo che deve essere necessariamente verificato durante la progettazione. Il valore di N viene preso spesso come numero dispari per favorire la sincronizzazione al ricevitore. Teoricamente è anche possibile realizzare filtri con un numero di tappi pari, ma la presenza nella risposta all’impulso di due coefficienti attorno al punto di massimo crea dei problemi nel rivelare al demodulatore il giusto istante di campionamento. Per ricavare i coefficienti è possibile seguire la procedura seguente: • Passo 1 : Si campiona la risposta in frequenza del filtro SRRC H T ( f ) = H R ( f ) = H ( f ) a intervalli regolari pari a ∆f = Fs / N per i primi (N − 1) / 2 campioni. H d (k ) = H (kFs / N ), k = 0 ,1,K ,N − 1 • Passo 2 : Per avere una risposta all’impulso a valori reali la risposta in frequenza deve sottostare alla seguente condizione di simmetria: H d (k ) = H d ( N − k ), i rimanenti (N − 1) / 2 k = 0,1, K , N − 1 campioni (da (N + 1) / 2 a N − 1 ) sono calcolati sfruttando la relazione di simmetria soprascritta. • Passo 3 : Applicando la trasformata inversa di Fourier discreta ai campioni si ottiene: N −1 hd (n ) = ∑ H d (k )e 2π j kn N n= , i =0 (N − 1) − ( N t − 1) ,K, t 2 2 per la simmetria della risposta in frequenza: N −1 2 2π hd (n ) = H d (0 ) + ∑ H d (k ) cos kn , N i =0 41 n= − ( N t − 1) (N − 1) ,K, t 2 2 • Passo 4 : Si converte la risposta all’impulso non causale nella realizzabile risposta causale semplicemente spostandola di ( N t − 1) / 2 campioni. Le seguenti funzioni scritte per l’ambiente MATLAB permettono di calcolare automaticamente i coefficienti del filtro radice di coseno rialzato. % SqRCFilter – disegna un filtro SQRC con I parametri fissati. function [h] = SqRCFilter(N,Alpha,Tb,Fs) H(1) = sqrt(RaisedCosineResponse(0,Alpha,Tb)); for k = 1:(N-1)/2, H(k+1) = sqrt(RaisedCosineResponse(k*Fs/N,Alpha,Tb)); H(N-k+1) = H(k+1); end for n = -(N-1)/2:(N-1)/2 h(n+((N-1)/2)+1) = H(0+1); for m = 1:(N-1)/2, h(n+((N-1)/2)+1) = h(n+((N-1)/2)+1) + 2*H(m+1)*cos(2*pi*m*n/N); end end % RaisedCosineResponse – Genera una risposta a coseno rialzato function [y] = RaisedCosineResponse(f,Alpha,T) if (abs(f) > ((1+Alpha)/(2*T))), y = 0; elseif (abs(f) > ((1-Alpha)/(2*T))), y = (T/2)*(1+cos((pi*T/Alpha)*(abs(f)-(1-Alpha)/(2*T)))); else y = T; end Nella realizzazione pratica dei due filtri SRRC, per la necessità di simulare il funzionamento dei vari blocchi prima dell’implementazione finale, si è scelto di impiegare il software di calcolo Filter Design Toolbox 2.1 fornito con l’ambiente di calcolo Matlab che ha permesso la progettazione direttamente dagli schemi di simulazione dei progetti modulatore e demodulatore. Tale tool di calcolo integra nell’ambiente grafico del Simulink tutte le funzioni presenti a livello di libreria per la progettazione di filtri digitali, fornendo un’interessante visualizzazione grafica dei risultati e la possibilità di generare direttamente un header file contenente i risultati del calcolo del filtro. Un'altra importante funzione è la possibilità di scegliere direttamente il formato numerico nel quale saranno rappresentati 42 i coefficienti del filtro, molto utile per valutare gli effetti di eventuali arrotondamenti. Attualmente tale possibilità non è stata sfruttata in quanto si sono impiegati valori di tipo float ma rappresenta una attraente possibilità a livello di sperimentazione per una modifica futura. La struttura dei filtri FIR impiegati è quella classica della prima forma diretta, anche se si sarebbe potuta adottare una realizzazione più compatta sfruttando la simmetria dei coefficienti. Si è comunque osservato che il miglioramento avrebbe portato a un minore impiego di memoria ma non a un incremento di prestazioni. x (n ) 1 /Z h (0) 1 /Z h (1) 1 /Z h (2) 1 /Z h (M ) y (n ) Σ Figura 18 : I Forma diretta di un filtro trasversale L’operazione di filtraggio comporta l’esecuzione di N moltiplicazioni e N-1 somme secondo la classica espressione: y (n ) = ∑k =0 h(k )x(n − k ) M dove M è l’ordine del filtro e h(k ) sono gli M+1 coefficienti simmetrici rispetto a h(M / 2) per avere risposta all’ impulso reale. Nel trasmettitore dove i simboli in ingresso al filtro sono degli impulsi, si sarebbe potuto ottimizzare l’algoritmo implementando un filtro polifase ed evitando così molte moltiplicazioni per zero. Tale scelta non è però stata fatta per mantenere una più alta modificabilità del codice nell’ottica di permettere configurazioni diverse tra simboli e tipo di filtro. 43 Caratteristiche filtri realizzati Nei due progetti si sono impiegati due filtri con le stesse proprietà, in modo da ottenere la massima corrispondenza. I filtri presentano le seguenti caratteristiche comuni: Modello: FIR I forma diretta Tipo: SRRC Frequenza di campionamento: 2500Hz Frequenza di cut-off (-3dB) : 250Hz Roll-off: 0.5 Ordine del filtro 30 (31 Tappi). La frequenza di campionamento è stata una scelta obbligata perché l’unica possibile comune a modulatore e demodulatore. Il fattore di roll-off invece ha dovuto rappresentare un compromesso tra banda occupata e facilità nel recupero del sincronismo di simbolo; si è osservato infatti che con roll-off bassi diventava molto più instabile l’aggancio. La scelta finale è stata quella di utilizzare 0.5 per il migliore funzionamento del sistema. Il numero di tappi è stato selezionato dispari per facilitare il sincronizzatore Early Late, data la presenza di un picco nella risposta all’impulso all’esatto istante di campionamento del simbolo. Figura 19 : Risposta frequenziale in scala lineare del filtro SRRC 44 La lunghezza del filtro è stata scelta di 31 tappi ed è risultata decisamente elevata poichè ha permesso di ottenere una attenuazione superiore ai 30 dB per i lobi secondari. Si è scelto un valore così alto per compensare il discreto sovracampionamento dovuto alla scelta obbligata della Fs, e perché almeno inizialmente si pensava di operare con fattori di roll-off inferiori. Figura 20 : Risposta in frequenza in scala logaritmica del filtro SRRC Per raggiungere le stesse prestazioni sarebbe stato possibile usare un filtro più corto con frequenza di campionamento minore e operare in seguito un’interpolazione con successivo filtraggio per aumentare la sample rate. Tale implementazione non avrebbe comunque portato a un notevole vantaggio nel ridurre il tempo di esecuzione e quindi non è stata presa in considerazione. Figura 21 : Risposta all'impulso del filtro SRRC 45 4.2 Demodulatore coerente Metodi per generare una forma d’onda periodica La prima necessità che si pone nella realizzazione di un algoritmo di modulazione o demodulazione è rappresentata dalla generazione di forme d’onda sinusoidali. Per generare dei campioni appartenenti a una sinusoide il sistema più banale consiste nell’impiegare la funzione sin(). Anche se apparentemente non sembrano esserci controindicazioni, basta osservare come le librerie trigonometriche vengano implementate per capire quanto possa essere inefficiente tale scelta. Spesso i compilatori realizzano la funzione sin() per mezzo di polinomi razionali o sviluppi in serie che richiedono molto tempo per essere elaborati; questa limitazione ne rende sconsigliabile e antieconomico l’impiego. La soluzione del problema consiste nell’usare una tabella pre-compilata (Lookup Table LUT) contenente un periodo completo della forma d’onda periodica. Con tale artificio è possibile generare una sinusoide, controllandone frequenza e fase mantenendo la massima velocità permessa dal processore impiegato. Per prima cosa conviene definire una frequenza normalizzata: f Normalizzata = f f Campionamento dove f è la frequenza che si vuole generare e ovviamente fNormalizzata potrà assumere valori compresi tra 0 e 0.5, non potendo rappresentare sinusoidi con frequenza superiore a metà di quella di Nyquist. In questo modo si è reso la rappresentazione indipendente dallo specifico problema considerato. Se ora consideriamo l’inverso della frequenza normalizzata, otteniamo il numero di campioni per periodo necessari per generare la sinusoide alla frequenza f desiderata. Per prelevare i campioni dalla tabella si utilizza un puntatore Index che memorizza il punto attuale, e viene incrementato ogni volta con cadenza pari a fCampionamento di un valore pari a: Step = f Normalizzata ∗ Lunghezza _ Tabella 46 Il puntatore deve essere riportato a inizio tabella raggiunta la fine. A tale scopo è molto utile scegliere il numero di campioni per periodo pari a una potenza di 2, riducendo così l’operazione di confronto a un semplice AND binario. Index = Index & (Lunghezza _ Tabella − 1) Figura 22 : Tabella con i campioni per generare la funzione sin(). Gli errori introdotti da questo metodo interessano la frequenza e l’ampiezza della sinusoide generata e dipendono dal numero di campioni scelti per rappresentare un periodo completo della sinusoide. Sia il puntatore utilizzato che lo Step sono valori interi e permettono di generare solo un insieme discreto di frequenze. Per ridurre il problema una possibile soluzione consiste nell’impiegare (se si usano numeri interi) per le variabili Index e Step una rappresentazione con un numero di bit maggiore. Ad esempio con una tabella lunga 1024 (10 bit) si possono impiegare variabili a 20 bit e per prelevare un valore considerare solo i 10 bit più significativi. In pratica si opera come se si possedesse una tabella virtuale lunga 1048576 elementi(20 bit). 47 L’errore introdotto nell’ampiezza dipende dalla intrinseca discretizzazione dei campioni, e presenta il problema che per una fissata forma d’onda, viene generato un errore predicibile, non modellabile come rumore bianco. Fortunatamente tale rumore di discretizzazione può essere facilmente controllato. Figura 23 : Errore di ampiezza L’errore massimo di ampiezza dipende dalla distanza tra i punti della tabella e nel caso della sinusoide dalla massima pendenza della curva. Per la funzione sin() il massimo si ha nel passaggio per lo zero con pendenza quasi unitaria si può quindi affermare che l’errore massimo è circa metà della distanza tra due valori della tabella. Per una tabella lunga 1024 come quella impiegata nel demodulatore si osserva che questo rumore di discretizzazione ha un’ampiezza di –60dB rispetto al picco della sinusoide generata e scende di –6dB per ogni bit aggiunto nella lunghezza della tabella. Nel ricevitore si è fatto uso di tale metodo per rigenerare la portante: il principale problema da risolvere non risiedeva tanto nell’errore di ampiezza ma nell’accumulare correttamente la fase istantanea nella variabile Index per ridurre l’errore di frequenza. La soluzione migliore è stata quella di utilizzare una variabile di tipo float per accumulare in modo molto preciso la fase, mentre il puntatore Index viene ottenuto scalando la fase alla lunghezza della tabella e prendendone la parte intera troncata. 48 Realizzazione digitale di un PLL Un anello ad aggancio di fase è tipicamente composto da tre componenti fondamentali: 1) un rivelatore di fase, modellato nello schema come un moltiplicatore; 2) un filtro; 3) un VCO. Un PLL può essere realizzato sia con circuiti analogici che digitali e trova notevole utilizzo nell’ambito delle telecomunicazioni soprattutto per il recupero della portante. Figura 24 : Schema di un circuito PLL Si consideri il caso in cui s(t) sia il segnale di ingresso: s (t ) = cos(ω c + ϑ ) dove ω c è la frequenza in radianti della portante e ϑ è un fase arbitraria. Il segnale v(t) generato dall’oscillatore di riferimento locale sarà del tipo: ( v(t ) = − sin ω c t + ϑˆ ) Possiamo assumere senza perdita di generalità che la frequenza del segnale di ingresso e quella generata dal VCO siano identiche, perché ϑ̂ lo consideriamo una stima di ϑ , che è una variabile dipendente dal tempo. L’ uscita del rilevatore di fase produrrà il segnale di errore dato da: ( ) ( ) ( 1 1 e(t ) = s (t ) ⋅ v(t ) = − cos(ω c + ϑ ) ⋅ sin ω c t + ϑˆ = − sin 2ω c t + ϑ + ϑˆ + sin ϑ − ϑˆ 2 2 49 ) In pratica il termine al doppio della frequenza rappresenta un disturbo nel segnale di controllo che và eliminato con un filtro. Se si assume che il filtro di anello sia un passa basso e elimini completamente il termine a 2 ω c , il segnale di errore resta: e(t ) = ( 1 sin ϑ − ϑˆ 2 ) Nell’ipotesi che il sistema converga dopo un certo periodo l’errore sarà piccolo e potendo confondere la funzione seno con il suo argomento potremo scrivere e(t) come: e(t ) ≈ ϑ − ϑ̂ 2 Ossia l’oscillatore locale viene pilotato con un segnale di errore che tende ad annullare la differenza di fase. L’ipotesi di avere un piccolo errore permette di linearizzare il problema, è allora possibile applicare la trasformata di Laplace per esprimere la funzione di trasferimento { } ˆ (s ) = L ϑ̂ (t ) del sistema. Se chiamiamo Θ(s ) = L{ϑ (t )} , Θ e per l’errore di fase Φ(s ) = L{φ (t )}, si può scrivere la f.d.t. ad anello chiuso intesa come rapporto tra la fase di ingresso e la fase di uscita stimata. H (s ) = ˆ (s ) K d K o F (s ) Θ = Θ (s ) s + K d K o F (s ) dove il VCO è stato modellato come un perfetto integratore con guadagno K0. Figura 25 : Modello linearizzato nel dominio della frequenza di un PLL 50 L’ordine di un PLL viene definito come il numero di perfetti integratori presenti nell’anello di retroazione, dove per integratori perfetti si intendono degli oggetti caratterizzati da una f.d.t. del tipo 1/s che posiziona un polo a s=0 ossia in continua. Poiché il VCO possiede già un polo il filtro d’anello che ha funzione di trasferimento F(s) possiederà n-1 poli se n è l’ordine del PLL. Un PLL del primo ordine è in grado di agganciarsi a un segnale in ingresso variando la fase dell’oscillatore locale fino ad annullare l’errore di fase, non è però in grado di modificare la frequenza e può quindi portarsi in condizione di aggancio con un errore di frequenza costante. Il filtro è un semplice guadagno che fissa la dinamica del sistema. Il PLL del secondo ordine è sicuramente il più impiegato ed è in grado di variare sia la sua frequenza che la sua fase annullando i due errori a regime. La tipica funzione di trasferimento del filtro è: F (s ) = sτ 2 + 1 sτ 1 ponendo: τ1 = Kd K0 ω 2 n e τ2 = 2ζ ωn si ottiene: H (s ) = 2ζω n + ω n2 s 2 + 2ζω n s + ω n2 dove ω n e ζ sono i ben noti parametri della frequenza naturale in [rad/s] e il fattore di smorzamento. Tipicamente il fattore di smorzamento viene scelto pari a la massima rapidità di aggancio senza overshoot della frequenza. 51 1 2 per avere L’ultimo PLL che vale la pena di menzionare è quello del terzo ordine che trova impiego in apparecchiature che risentono dell’effetto Doppler, come ad esempio aerei o satelliti nei quali l’elevata velocità relativa rispetto al trasmettitore obbliga per un efficiente recupero della portante di dover annullare l’errore di accelerazione della fase istantanea. E’ possibile ottenere direttamente (nell’ipotesi che i poli di H (s ) siano a pulsazione molto bassa) tramite la trasformazione bilineare 2 1 − z −1 s= ⋅ T 1 + z −1 la funzione di trasferimento del sistema tempo discreto dall’equivalente tempo continuo, e in seguito dimensionare i parametri per le prestazioni desiderate. Qui invece si proporrà una trattazione alternativa molto più semplificata particolarmente adatta per una implementazione software, che sintetizza il PLL direttamente come un sistema tempo discreto. In una implementazione digitale il VCO è sostituito da un dispositivo denominato NCO (Numerically controlled oscillator) e costruito sfruttando una LUT come indicato nel paragrafo precedente. Nella realizzazione dell’NCO si è scelto di compattare il più possibile il PLL integrando direttamente il filtro di anello nelle equazioni che regolano il prelevamento dei campioni dalla LUT. Torniamo ora per un attimo ad analizzare il funzionamento della LUT per proporre alcuni cambiamenti di notazione che saranno utili in seguito. Consideriamo la LUT di lunghezza fissata e riempita con i campioni di un periodo completo della funzione sin(). Chiamiamo con ϑ (n ) la fase istantanea attuale ossia l’indice che punta al valore appena prelevato dalla tabella. Definiamo invece ϑ (n + 1) come la fase successiva ossia il valore che assumerà l’indice una volta trascorso un periodo di campionamento del sistema. 52 Chiamiamo infine con f (n ) l’equivalente della variabile Step precedentemente usata, ossia l’incremento inteso come numero di posizioni della LUT da saltare ad ogni esecuzione, relativo alla frequenza che si desidera generare. L’equazione alle differenze finite che esprime come vengono estratti i campioni dalla LUT diventa allora la seguente: ϑ (n + 1) = ϑ (n ) + f (n ) E’ così possibile generare la sinusoide alla frequenza desiderata. Vediamo ora come sia possibile variarne frequenza e fase in base a un segnale di errore in ingresso. Figura 26 : Schema PLL digitale primo ordine Un PLL del primo ordine è in grado di variare unicamente la sua fase allora l’equazione che gestisce la LUT conterrà un nuovo termine che permetterà di variare la fase istantanea in base al segnale di errore: ϑ (n + 1) = ϑ (n ) + α ⋅ e(n ) + f dove e(n) è l’errore retroazionato φ (n ) − ϑ (n ) . In questo caso f non dipende dal tempo perché per definizione un PLL del primo ordine non è in grado di variare la sua frequenza. Lo schema mostrato in figura 10 utilizza il valore di α per controllare la quantità di retroazione da fornire all’oscillatore. 53 Se tralasciamo il termine f è possibile ricavare come operi il PLL. Impiegando la Ztrasformata si può riscrivere l’espressione precedente come: Θ ( z ) ⋅ z = Θ ( z ) + α Ε ( z ) = Θ ( z ) + α (Φ ( z ) − Θ ( z )) Θ( z )( z − 1 − α ) = αΦ( z ) Θ( z ) α = Φ(z ) z − 1 + α Osservando tale equazione si nota che la relazione che intercorre tra la fase della forma d’onda ricevuta e quella generata è quella di un filtro ricorsivo passabasso con un polo collocato sull’asse reale. Il parametro α controlla la posizione del polo e quindi la banda del filtro. Se α < 1 il sistema è stabile, più si avvicina all’unità più la banda del filtro si riduce e il PLL impiega più tempo per stabilizzarsi. Passiamo ora a un PLL del secondo ordine; si utilizzano due equazioni che aggiornano la fase e la frequenza istantanea. Il segnale di errore interviene in entrambe le espressioni e modifica ad ogni esecuzione, sia la frequenza che non è più costante, che la fase. Le due equazioni seguenti riportano come vengano modificati ad ogni istante di campionamento la frequenza e la fase. ϑ (n + 1) = ϑ (n ) + α ⋅ e(n ) + f (n ) f (n + 1) = f (n ) + β ⋅ e(n ) La prima fornisce l’indice ϑ (n + 1) per accedere alla LUT e prelevare il campione corrente, mentre la seconda tiene unicamente memoria della frequenza attuale. Passando analogamente al caso precedente alla Z-trasformata: F (z ) = βE (z ) z −1 Θ( z )z = Θ( z ) + F ( z ) + αE ( z ) = Θ( z ) + αE ( z ) + 54 βE (z ) z −1 Θ( z ) α ⋅ z + β −α = 2 Φ( z ) z + (α − 2 )z + 1 + β − α L’ultima espressione mostra come il sistema sia equivalente a un filtro con due poli, per posizionare i poli è possibile agire sui due parametri α e β . Poiché i coefficienti sono reali è possibile ottenere tre distinti casi; i poli possono essere reali e uguali, reali ma diversi e complessi coniugati. Nel caso in cui siano complessi coniugati il sistema si mette a oscillare e va quindi evitato; per ottenere un filtro passabasso con il minimo tempo di stabilizzazione del PLL i poli devono essere reali e uguali (equivalente alla condizione di smorzamento critico del caso analogico). In tale caso si annulla il determinante del denominatore e si ricava: β= α2 4 con tale espressione è possibile ricavare la posizione dei due poli: P1, 2 = 2 −α 2 per avere un sistema stabile i poli devono essere contenuti nel cerchio di raggio unitario allora deve essere: 0<α < 4 mentre l’unico zero è posizionato in: 4 −α 4 Per progettare il PLL è sufficiente scegliere il valore di α . Tipicamente è consigliabile impiegare valori minori di 0.01, più α è grande più è veloce il sistema a stabilizzarsi ma è anche più sensibile al rumore, e può accadere che non riesca a agganciare perfettamente la portante del segnale ricevuto. 55 Una trattazione più completa può essere ottenuta in [10] dove viene affrontato in modo più rigoroso sia la parte analogica che la sintesi diretta tempo discreta affrontando in particolar modo i criteri di stabilità Il Costas Loop Il Costas loop rappresenta un sistema di recupero della portante che integra direttamente la demodulazione dei simboli ricevuti. Vengono impiegati due anelli di retroazione che operano sullo stesso NCO: il primo lavora come in un PLL normale e viene chiamato anello in fase, il secondo invece opera con uno sfasamento di 90° prendendo il nome di anello in quadratura. Tale metodo di demodulazione presenta il grosso vantaggio di poter operare correttamente con segnali a portante soppressa e sopporta una efficiente implementazione software. Per analizzare il funzionamento consideriamo il caso più semplice in cui in ingresso sia presente una semplice sinusoide del tipo v(t ) = sin (ω c t + φ ) . i(t) X i1(t) LPF cos IF e(t) NCO v(t) X -sin LPF X q(t) q1(t) Figura 27 : Schema di un Costas loop Assumiamo che il segnale v(t) sia ad una frequenza vicina a quella dell’NCO. Dai due mixer (moltiplicatori) si ottengono i segnali i(t) e q(t) che saranno composti da un termine a bassa frequenza e uno circa al doppio della frequenza ricevuta. 56 i (t ) = sin(ω c t + φ ) cos(ω c t + ϑ ) = 1 [sin (2ω c t + φ + ϑ ) + sin (φ − ϑ )] 2 q (t ) = sin(ω c t + φ )(− sin(ω c t + ϑ ) ) = 1 [cos(2ω c t + φ + ϑ ) − cos(φ − ϑ )] 2 L’operazione di filtraggio effettuata permette di ottenere i due termini in quadratura i1(t) e q1(t) da impiegare per stabilizzare l’anello attenuando sufficientemente il ripple a alta frequenza presente. Per semplicità supponiamo che i due LPF siano ideali con attenuazione infinita per i termini di disturbo. i1(t ) = 1 sin (φ − ϑ ) 2 1 q1(t ) = − cos(φ − ϑ ) 2 In una realizzazione digitale bisogna porre molta attenzione alla frequenza di campionamento del sistema che deve risultare sufficientemente alta per non avere aliasing delle componenti a 2ω c . Il moltiplicatore che opera sui due segnali in quadratura si comporta come un rilevatore di fase e genera il segnale di errore: 1 1 e(t ) = − sin (φ − ϑ ) cos(φ − ϑ ) = − [sin (2(φ − ϑ )) + sin (0 )] 4 4 che è proporzionale e opposto per piccoli valori dell’argomento all’errore di fase permettendo all’NCO del secondo ordine precedentemente descritto di agganciare in fase e frequenza la portante in ingresso. Una particolare osservazione và effettuata sui due filtri passa basso. Il circuito richiede per un corretto funzionamento due filtri perfettamente identici perché una eventuale asimmetria porterebbe inevitabilmente a degli offset nella fase della portante rigenerata, con notevole degradazione dei segnali demodulati. In una implementazione analogica risulta particolarmente complesso costruire due filtri perfettamente identici e per questo 57 motivo tale schema non è molto usato. Una realizzazione digitale invece non risente di tale problematica e ne permette la costruzione in modo semplice ed economico. In un ambiente rumoroso assume particolare importanza la banda dei due filtri LPF impiegati; essa deve essere la più ridotta possibile per limitare i disturbi che entrano nell’anello di retroazione, ma sufficientemente ampia per lasciare passare i simboli che modulano il segnale ricevuto. E’ possibile impiegare sia filtri FIR che IIR ma il modo migliore, almeno nella applicazione considerata consiste nell’utilizzare un filtro IIR con un solo polo a guadagno unitario noto anche come mediatore ricorsivo. L’equazione nel domino del tempo di tale filtro è: Uscita = Uscita ⋅ (1 − α f ) + Ingresso ⋅ α f applicando la Z-trasformata e calcolando la f.d.t. si ottiene: H (z ) = αf 1 − (1 − α f )z dove 0 < α f < 1 . Si ricava che la frequenza di taglio a –3dB del filtro risulta: 1 + (1 − α f )2 − 2α f 2 1 −1 cos θ= 2π 2(1 − α f ) dove θ è la frequenza normalizzata. 58 αf 0,00125 0,0025 0,005 0,01 0,015 0,02 0,025 0,03 0,035 0,04 0,045 0,05 θ 0,000199 0,000398 0,000798 0,001600 0,002405 0,003215 0,004030 0,004848 0,005671 0,006498 0,007329 0,008165 Figura 28 : Bande a -3dB per un filtro IIR a un polo al variare di αf Il rivelatore di fase rappresenta il punto fondamentale per demodulare correttamente il segnale ricevuto. Per modulazioni con ampiezza variabile è necessario implementare sistemi di controllo automatico del guadagno o sostituire il moltiplicatore con un blocco che valuta funzioni tipo la tanh-1() per ricavare il segnale di errore. L’operazione di calcolo di una funzione inversa del genere, è molto onerosa se effettuata direttamente, spesso si realizza con algoritmi di tipo CORDIC, in grado di approssimare utilizzando somme e moltiplicazioni successive tutte le funzioni trigonometriche. Il problema risiede nel PLL che richiede per la sua stabilità un ampiezza del segnale di ingresso costante. E’ comunque possibile riducendo la rapidità di aggancio con il sistema attuale arrivare a discreti risultati anche con modulazioni multilivello ma non in quadratura. L’introduzione di un ulteriore anello di reazione non è stata impiegata e si è preferito utilizzare un rivelatore di fase che fosse il più possibile rapido nell’esecuzione dell’algoritmo di calcolo. Lo schema scelto per realizzare il demodulatore 4-QASK differisce leggermente da quello analizzato e riprende un modello molto utilizzato di Costas loop per ricevere segnali a inviluppo complesso di tipo QPSK. Per ricavare un segnale che rappresenti il vero errore di fase è necessario impiegare una coppia ulteriore di moltiplicatori e due limitatori settati all’ampiezza dei simboli ricevuti. Tale variante prende il nome di Costas loop a 4 fasi o “hard-limited” o ancora “polarity loop”. Vediamo ora come sia possibile ricavare un segnale proporzionale all’angolo di errore partendo da un segnale modulato in quadratura a inviluppo costante come un QPSK. 59 I1(t) X I2(t) LPF X I3(t) cos + IF e(t) NCO Xc(t) Σ - sin LPF X Q1(t) X Q2(t) Q3(t) Figura 29 : Costas Loop 4 fasi Supponiamo il segnale di ingresso del tipo: X c (t ) = a k cos(ω c t ) + bk sin (ω c t ) dove a k e bk sono i valori delle ampiezze dei simboli assunti +1 o –1, e ω c è la pulsazione della frequenza portante in radianti per secondo. Il segnale generato dall’NCO è cos(ω c t + φ ) e sin (ω c t + φ ) dove φ rappresenta la differenza di fase tra la portante del trasmettitore e quella generata localmente che deve essere annullata. Con riferimento alla figura è possibile scrivere per le due vie: I 1 (t ) = cos(ω c t + φ )x(c ) = cos(ω c t + φ )(a k cos(ω c t ) + bk sin (ω c t )) = 1 [a k cos(2ωc t + φ ) + ak cos(φ ) + bk cos(2ωc t + φ ) − bk sin(φ )] 2 dopo il LPF che rimuove la componente al doppio della frequenza si ottiene: I 2 (t ) = 1 [a k cos(φ ) − bk sin (φ )] 2 60 Per la via in quadratura si ricavano le espressioni: Q1 (t ) = sin (ω c t + φ )x(c ) = sin (ω c t + φ )(a k cos(ω c t ) + bk sin (ω c t )) = 1 [− ak cos(2ωc t + φ ) + a k cos(φ ) − bk cos(2ωc t + φ ) + bk sin(φ )] 2 analogamente dopo il filtraggio: Q2 (t ) = 1 [a k cos(φ ) + bk sin (φ )] 2 Dalle moltiplicazioni incrociate si ottengono I3(t) e Q3(t): I 3 (t ) = bk ⋅ I 2 (t ) = ( ) 1 a k bk cos (φ ) − bk2 sin (φ ) 2 1 Q3 (t ) = a k ⋅ Q2 (t ) = ak2 sin (φ ) + a k bk cos (φ ) 2 ( ) il segnale di errore e(t) sarà allora: ( ) I 3 (t ) − Q3 (t ) = − a k2 + bk2 sin (φ ) se le ampiezze dei simboli sono prossime all’unità e(t) risulta adatto per correggere l’errore di fase del NCO. Per un corretto funzionamento è bene che i due limitatori operino con un segnale superiore alla soglia altrimenti dalle moltiplicazioni incrociate non si generano i segnali di errore che rendono possibile l’aggancio. 61 Implementazione nel demodulatore Per la stesura del software che realizza la demodulazione si è impiegato lo schema di figura 29. Il progetto ha richiesto il dimensionamento dei due filtri e dei coefficienti dell’NCO per avere stabilità e la velocità di aggancio desiderate. Data l’elevata frequenza di campionamento impiegata (circa 200Khz) è stato conveniente integrare nella procedura di demodulazione una decimazione dei campioni per permettere al filtro adattato che segue di lavorare con una frequenza ridotta e molto più prossima alla sua frequenza di taglio. I due filtri nell’ anello di retroazione svolgono la doppia funzione di eliminare la componente a 2ω c e di operare come filtro antialiasing per la decimazione successiva. Figura 30 : Risposta dei filtri ricorsivi dimensionati per fS=200Khz e fc=1000Hz Se ci si pone in condizione di PLL stabilizzato il primo disturbo rilevante che risulta presente è quello posizionato a 75 Khz. Dalla risposta del filtro si legge un’attenuazione di circa 45dB più che sufficiente se comparata con le prestazioni dei due filtri FIR impiegati. La frequenza di taglio è stata scelta superiore a quella del filtro adattato per degradare il meno possibile la fase del segnale che sarà poi filtrato dal filtro FIR, ma sufficientemente bassa per limitare i termini di disturbo che entrano nel rilevatore di fase. 62 αf IN + OUT 1-αf 1/Z Figura 31 : Scema filtro ricorsivo impiegato con αf=0.0015 Per dimensionare i parametri di funzionamento del PLL integrati nell’NCO si è dovuto rinunciare a una rapida stabilizzazione per ottenere un minore rumore di fase dell’oscillatore controllato numericamente. Scelto un parametro α=0.002 per avere un sufficientemente veloce tempo di assestamento si è calcolato β per stabilire il valore limite al di sopra del quale i poli della funzione di trasferimento del PLL diventano complessi coniugati. Si è ottenuto: α2 0.002 2 β= = = 1E − 6 4 4 Da osservazioni sul sistema realizzato è stato conveniente operare una scelta conservativa e impiegare come valore di β = 1E − 7 . In tal modo l’oscillatore NCO risulta molto più stabile e insensibile ai disturbi garantendo un errore di fase a regime di circa 1/100 di Hz. E’ quindi possibile immaginare che questo PLL possa trovare proficuo impiego anche in modulazioni multilivello con costellazioni ben più ampie di quella sperimentata. Figura 32 : Risposta a un gradino di 10Hz del PLL implementato 63 Nel demodulatore per motivi di precisione la fase e la frequenza istantanee sono state accumulate in due variabili di tipo float. E’ però necessario precisare che per mantenere una implementazione coerente con la trattazione effettuata si è dovuto far ricorso ad una pulsazione normalizzata in sostituzione della frequenza. Per prelevare un campione dalla tabella, l’NCO scala la fase espressa in radianti rispetto alla lunghezza della tabella e calcola un intero corrispondente all’indice del valore da prelevare. Per la cosinusoide invece l’indice viene valutato incrementando semplicemente quello calcolato per il seno di ¼ della lunghezza della tavola, si ottiene così lo sfasamento di π /4 desiderato. 4.3 Recupero sincronismo di simbolo Sincronizzatore Early - Late Il blocco di recupero del sincronismo di simbolo al pari del demodulatore coerente rappresenta uno dei punti più critici nella progettazione dell’intero sistema. La necessità di operare una precisa decisione sull’istante di campionamento è tanto più sentita quando si impiegano come in questo caso dei sistemi per limitare la banda del segnale trasmesso. Al diminuire del fattore di roll-off della caratteristica a coseno rialzato con la quale è stato progettato il collegamento, aumenta il valore dell’interferenza intersimbolo provocata dall’implementazione numerica. Se si sbaglia a stimare l’istante esatto le prestazioni del collegamento degradano molto rapidamente. Lo schema impiegato nella procedura Symbol_Clock_Recovery_and_Sample è del tipo Early – Late e basa il suo funzionamento sull’osservazione che in corrispondenza dei picchi del segnale demodulato si trovano i valori da campionare. 64 I x2 LPF I(t-T 1) I(t) T1 rappresenta l’intervallo di campionamento Q I(t+T 1) D e c i s o r e ( )² Σ LPF + ( )² Buffer_Simboli x2 LPF Figura 33 : Schema del rigeneratore del sincronismo di simbolo Nello schema sono riportati oltre al blocco decisore che integra la logica necessaria al corretto rilevamento dei massimi del segnale in ingresso anche i due interpolatori usati per incrementare la frequenza di campionamento dei segnali. L’uso dei due interpolatori è stato necessario per permettere al filtro SRRC di operare in condizioni ottimali senza eccessivo sovracampionamento. D’ altra parte per ottenere una buona sincronizzazione del ricevitore 5 campioni per periodo di simbolo risultavano essere troppo pochi e si è ritenuto necessario raddoppiare la sample rate per il decisore Early – Late. Ogni campione in ingresso viene replicato due volte e filtrato con un filtro ricorsivo passabasso calcolato per una frequenza di taglio pari alla banda del segnale a coseno rialzato, si eliminano così le immagini generate dalla operazione di interpolazione. Nella applicazione pratica si è utilizzato un valore di α f = 0.3 a cui corrisponde una banda passante di circa 250Hz. Come già anticipato l’informazione per ottenere la sincronizzazione viene prelevata unicamente dal canale I per permettere di gestire modulazioni su un singolo canale, anche se le prestazioni globali vengono leggermente ridotte. Il segnale interpolato viene caricato su due linee di ritardo a tre elementi che memorizzano il campione attuale e i due precedenti. Nel software si sono usate delle 65 variabili con i suffissi Precedente, Attuale e Successivo per meglio identificare le operazioni che si effettuano. Supposto noto il numero di campioni per periodo di simbolo il decisore opera come un contatore che raggiunto il valore fissato nella variabile Campioni_per_Simbolo si azzera e preleva il campione attuale dai due canali spostandolo nel buffer di uscita. A ogni campionamento il decisore verifica inoltre di trovarsi in un massimo del segnale e calcola un errore dato dalla differenza tra i quadrati del campione precedente (Early) e successivo(Late). L’elevazione al quadrato permette di rendere positivi i minimi negativi risolvendo così un incertezza di segno nella generazione dell’errore. Figura 34 : Generazione del segnale di errore Si può osservare tale problema nella figura precedente; nel caso A se si campiona in corrispondenza del punto 2 l’errore risulta: I (1) − I (3) < 0 ossia è necessario avanzare di un unità l’istante di campionamento. Se il punto attuale è il 4 l’errore risulta positivo ed è necessario ritardare. Nel caso B invece se il punto attuale è il 2 il segnale di errore sarà positivo ed erroneamente porterebbe il decisore a ritardare ulteriormente la finestra di campionamento. Il segnale di errore così calcolato viene filtrato da un filtro passabasso e inviato al decisore che opera in questo modo in un sistema ad anello chiuso dove il filtro permette di stabilire la banda di lavoro. Per stabilizzare il funzionamento bisogna introdurre una soglia minima al di sotto della quale si considera l’errore non sufficiente per variare l’istante di campionamento. Se la soglia viene superata si effettua una variazione al valore di azzeramento del contatore 66 ponendolo a –1 (si allunga di un unità il periodo di simbolo corrente) se l’errore è positivo e a +1 nel caso contrario. La scelta della soglia e della banda del filtro sono i punti più importanti e che stabiliscono un corretto e stabile funzionamento. Per quanto riguarda il filtro bisogna osservare che operando all’interno del decisore lavora a una frequenza di circa 1/10 rispetto alla sample rate in ingresso ossia a circa 500Hz. La sua realizzazione ha impiegato un filtro ricorsivo il cui parametro caratteristico è stato scelto pari a α f = 0.2 per garantire una banda passante di circa 15Hz. Bande minori avrebbero impedito l’aggancio perché bisogna tener conto che oltre alla differenza tra le frequenze di clock dei due DSP il sincronizzatore deve anche assorbire il leggero scostamento della frequenza di campionamento del demodulatore dai 200Khz teorici utilizzati. Per quanto riguarda la soglia si è cercato di ricavare un valore per via analitica che permetta di ottimizzare le prestazioni di questo DLL (Digital Locked Loop). Se supponiamo che sia possibile pensare i simboli come archi di sinusoide si può ricavare il valore massimo che può assumere l’errore. Con riferimento alla figura 34 A se l’istante di campionamento è il 2 l’errore relativo fissa un massimo sotto al quale deve stare la soglia cercata. Nel caso di 10 campioni per periodo di simbolo e ampiezza dei simboli unitaria tale valore sarà: 2π 2π I (1) 2 − I (3) 2 = sin 2 ⋅ 0 − sin 2 ⋅ 2 = 1 − 0.905 = 0.095 10 10 nella applicazione pratica si è scelto il valore 0.1 che garantisce buone prestazioni complessive. Tale valore rispecchia abbastanza il valore calcolato, bisogna però tenere presente che non tutti i massimi rappresentano l’esatto istante di campionamento a causa del filtraggio a coseno rialzato; solo durante le sequenze di zeri e uni su uno stesso canale ciò si verifica mentre quando sono presenti più zeri o uni consecutivi l’errore diventa inconsistente. Fortunatamente in questo ultimo caso si verifica che la frequenza di variazione del segnale di errore è maggiore e il segnale di disturbo viene tagliato in parte dal filtro di anello. 67 Si sono sperimentati altri tipi di sincronizzatori come lo “zero-crossing” riportato anche nelle simulazioni ma non si è notato un grosso miglioramento rispetto al metodo appena descritto. Probabilmente per miglioramenti futuri bisognerà prendere in considerazione un aumento del fattore di interpolazione e adottare schemi che permettano di generare direttamente un segnale legato alla frequenza di simbolo come il “time-2 loop”. E’ necessario infine osservare che gli algoritmi sono molto legati alla modulazione che si implementa e non esiste un modello standard che possa funzionare egregiamente in tutte le situazioni; la scelta migliore deve essere quindi fatta caso per caso in base a ciò che si vuole effettivamente implementare. 68 Capitolo 5 Modulatore 5.1 Introduzione Il modulatore è stato realizzato prendendo come modello lo schema di un trasmettitore numerico passabanda di tipo QASK ed è in grado di generare un segnale modulato in quadratura con una costellazione quadrata. Il numero di punti della costellazione può essere cambiato modificando una costante del progetto, le ampiezze relative vengono calcolate automaticamente durante l’esecuzione del software. I bit da trasmettere sono generati da un generatore di sequenze di massima lunghezza, per permettere al ricevitore di valutare nota la sequenza la qualità del collegamento; un blocco codificatore si occupa di codificare opportunamente i bit da trasmettere nei simboli della costellazione. Si sono inoltre previsti due filtri a coseno rialzato per limitare la banda dei segnali da inviare ai modulatori a prodotto e quindi del segnale in uscita. Due tabelle riempite all’avvio del software per ottimizzare il tempo di esecuzione e contenenti un periodo completo delle funzioni trigonometriche sin e cos, vengono impiegate per generare un periodo completo del segnale modulato. I campioni generati, opportunamente scalati per i 12 bit del convertitore D/A e posizionati in un buffer in memoria, vengono sequenzialmente trasferiti al convertitore in uscita. La presenza di alcuni Dip-Switch sulla piastra madre del DSP ha permesso inoltre di gestire il segnale in uscita dal modulatore. In base alla posizione degli interruttori è possibile attualmente osservare i simboli in uscita dal codificatore, la sequenza di simboli filtrata dal filtro SRRC (Square roor raised cosine) e ovviamente il segnale modulato in quadratura. La necessità di organizzare l’applicazione software in modo da essere facilmente modificabile nei suoi elementi fondamentali, è stata risolta utilizzando più procedure che eseguono in sequenza e che rappresentano i vari blocchi del sistema di trasmissione. 69 La temporizzazione principale dell’apparato viene derivata direttamente dalla porta seriale che gestisce i trasferimenti dei campioni elaborati in uscita, mentre le varie procedure eseguono con cadenze che sono sottomultipli di questa frequenza. Tale limitazione anche se da una parte potrebbe sembrare riduttiva, semplifica molto la struttura del programma e permette comunque una notevole flessibilità. Simbolo_I Bit_I Simbolo_Filtrato_I Filtro For matore SRRC Canale I Lookup Table Sin Generatore Sequenze Massima Lunghezza Σ Codif icatore Lookup Table Cos Filtro For matore SRRC Canale Q Bit_Q Simbolo_Filtrato_Q Simbolo_Q Figura 35 : Schema Modulatore QASK La gestione del trasferimento dei campioni verso il convertitore è stata la problematica che ha richiesto più tempo di ricerca in quanto si è cercato di ottenere il massimo delle prestazioni con il minimo utilizzo del processore. Dopo molte alternative vagliate si è scelto di utilizzare un canale dell’EDMA per effettuare lo spostamento dei campioni da due buffer impiegati alternativamente; tale metodologia ha permesso di svincolare il core del processore dal trasferimento dati, dando libertà così di utilizzare pienamente le prestazioni di calcolo del DSP nell’elaborazione dei segnali, e permettendo di generare un segnale modulato su una frequenza portante significativa. 5.2 Struttura del Progetto L’implementazione in software del modulatore è stata strutturata in più file al fine di permettere una più facile comprensione e modificabilità; in particolare si è separata la parte di gestione dell’ EDMA e di inizializzazione del convertitore dal main che contiene tutte le procedure per la realizzazione della modulazione e la gestione del trasmettitore. 70 Oltre a tali files si è utilizzata la possibilità fornita dall’ambiente di programmazione di gestire tramite il DSP/BIOS le procedure di interruzione, le procedure periodiche e i timer di sistema. Figura 36 : Struttura Progetto I file sorgente del progetto contenuti nella cartella ‘source’ gestiscono il funzionamento vero e proprio del modulatore mentre il file modulatore.cdb che nell’ambiente di sviluppo viene aperto per mezzo di un editor grafico, contiene la configurazione statica che verrà caricata nel DSP relativa ai vari dispositivi periferici integrati. I due file t56xx_ob.c e tidc_api.c unitamente all’header file dc_conf.h che contiene i parametri di configurazione della porta seriale e del convertitore vengono utilizzati per gestire l’inizializzazione della McBSP e del D/A. Tali files contengono una serie di procedure con nomi standardizzati da parte della Texas Instruments per la gestione dei propri convertitori. La generazione dei file avviene in automatico previa l’istallazione di un pacchetto aggiuntivo: il “Data Converter Plug-In” che permette una volta inseriti in una maschera i parametri di funzionamento del convertitore di ottenere i file sorgente. Le procedure contenute garantiscono la possibilità di spostare singoli campioni o blocchi di campioni, oltre alla più importante che inizializza il convertitore. Inizialmente si era pensato di sfruttare queste librerie per gestire il D/A ma alla prova dei fatti, già all’atto della compilazione, generavano numerosi errori ed inoltre, risolti 71 gli errori modificando a mano il codice, l’overhead dovuto alla chiamata delle procedure poneva seri problemi di sincronizzazione limitando molto la velocità massima di trasferimento dei campioni. Si è scelto allora di abbandonare tale strada e sfruttare unicamente la procedura dc_configure per configurare il D/A e la porta seriale all’avvio del modulatore, lasciando alla circuiteria hardware di DMA l’onere di garantire una sample rate costante in uscita. Il file Edma.c contiene i parametri per l’inizializzazione del canale di DMA impiegato per trasferire i campioni verso il convertitore in uscita. Come già accennato è possibile configurare le periferiche interne del DSP tramite un file .cdb nell’ambiente di sviluppo; tale configurazione è però statica e viene caricata assieme al file eseguibile nella memoria del DSP ogni volta si carica un programma. Teoricamente si sarebbe potuto gestire l’EDMA direttamente dall’ambiente di programmazione settando opportunamente i campi nella maschera di immissione dati per il DMA; tale scelta non è stata fatta per poter modificare a tempo di esecuzione la configurazione dell’EDMA. In particolare nel file Edma.c si è realizzata una tabella di configurazione in modo dinamico, ossia all’avvio del modulatore in base alle costanti presenti nel file Configurazione.h viene compilata una tabella contenente tutti i parametri relativi al tipo di trasferimento e alla sua lunghezza. In questo modo diviene molto più comprensibile il funzionamento dell’EDMA e inoltre risultano facilmente modificabili i parametri di gestione dei buffer di uscita, poichè si và a operare su costanti semplici invece che sulle parole esadecimali di controllo del dispositivo. Il file Edma_ISR.S62 è stato realizzato direttamente in assembler e si occupa di interfacciare il livello hardware del trasferimento dati con il software vero e proprio; gestisce le segnalazioni di fine buffer dell’EDMA e avvia l’interruzione software che realizza la modulazione. Il file main.c contiene tutte le procedure che realizzano il modulatore, e le routine scritte in C che implementano le interruzioni software, nella parte iniziale vengono incluse tutta una serie di librerie CSL (Chip Support Library) necessarie per poter sfruttare il DSP/BIOS e gestire le porte seriali, le interruzioni e l’EDMA. Nel main vengono inizializzati tutti i dispositivi e calcolati i parametri del progetto. 72 I coefficienti del filtro a coseno rialzato infine sono stati inseriti in un file separato RRC_Fir.h al fine di permetterne una facile sostituzione nell’ottica di sperimentare l’effetto di una variazione di tali valori. Figura 37 : Contenuto file Modulatore.cdb Nel file modulatore.cdb sono definiti l’oggetto SWI_Modula che opera con priorità 1 e richiama ogni volta viene schedulato la procedura SWI_Modulatore; mentre l’evento periodico Leggi_Dip_Switch è impostato per essere eseguito ogni due secondi e richiama la procedura Scegli_Uscita, entrambe le procedure sono definite nel main. 5.3 Strutture dati La gestione del flusso di dati dal generatore di sequenze di massima lunghezza verso l’uscita del modulatore ha dovuto necessariamente rappresentare un compromesso tra chiarezza del codice e rapidità di esecuzione; dopo aver sperimentato varie soluzioni si è arrivati alla conclusione che l’utilizzo delle strutture dati fornite a livello di DSP/BIOS nell’ambiente di sviluppo, pur garantendo una buona gestione, avrebbero reso il codice molto più complesso e cosa più importante limitato la velocità di esecuzione a causa dell’overhead introdotto nella chiamata delle procedure di gestione. Per tali motivi si è adottata la soluzione forse non molto elegante ma sicuramente molto funzionale di gestire il modulatore attraverso una serie di variabili globali nelle quali si spostano i dati 73 da trasmettere man mano che avanza l’elaborazione; ciò permette di risparmiare una discreta quantità di tempo perché non è più necessario passare parametri alle procedure. I dati sono strutturati in modo noto visibili all’intero progetto e per ogni procedura sono fissate la posizione in cui leggere i dati, quella in cui scrivere il risultato dell’elaborazione e il tipo di dati impiegati. DELAY_LINE_I Bit_I Simbolo_I 0 Delay_Lenght *Buffer 0 Puntatore_Read Simbolo_Filtrato_I Puntatore_Write Simbolo_Filtrato_Q Buffer_Lenght - 1 DELAY_LINE_Q Bit_Q Simbolo_Q 0 Delay_Lenght FIR_Coefficenti 0 Fir_Lenght Figura 38 : Percorso dati modulatore La figura mostra tutte le variabili globali e i buffer utilizzati nell’implementazione del modulatore, tralasciando la parte che gestisce i trasferimenti dal buffer di uscita al convertitore, che verrà dettagliatamente analizzata in seguito. Le variabili Bit_I e Bit_Q sono due variabili intere di 16 bit di lunghezza nelle quali vengono posizionati a partire dai meno significativi i bit da trasmettere in numero sufficiente per generare un simbolo. Simbolo_I e Simbolo_Q rappresentano i valori delle ampiezza dei simboli da trasmettere e sono variabili di tipo float. La scelta di operare con variabili float ha permesso di dimensionare il filtro in modo più semplice senza doversi preoccupare di eventuali problemi di troncamento nei coefficienti che con una realizzazione in virgola 74 fissa sarebbero sicuramente intervenuti. D’altra parte il DSP impiegato è un’unità floating point e avrebbe avuto poco senso non sfruttare questa possibilità. Non è comunque da escludersi che l’uso di variabili fixed point potessero permettere le stesse prestazioni anzi molto probabilmente in termini di velocità il software avrebbe potuto guadagnare, a discapito però di una complessità progettuale superiore. In futuro una modifica interessante potrebbe proprio essere quella di riscrivere il codice totalmente usando notazioni frazionarie, soprattutto alla luce del fatto che in implementazioni reali di modem, DSP del livello del TMS320C6711 sono troppo costosi e si preferisce utilizzare modelli fixed-point che hanno il vantaggio di consumare molto meno e per apparecchiature portatili diventano gli unici impiegabili. I valori di Simbolo_I e Simbolo_Q vengono inseriti nelle due linee di ritardo per essere filtrati dai filtri FIR; l’ implementazione dei filtri è stata realizzata in modo particolare e sensibilmente diverso rispetto al funzionamento classico in modo da ridurre al minimo il tempo di esecuzione del filtraggio. Le due delay line sono gestite in modo circolare ossia invece di spostare ogni volta che entra un nuovo dato nella linea di ritardo tutti i valori precedentemente inseriti, si utilizzano due puntatori che tengono memoria del punto di lettura e di scrittura dei campioni nei buffer, e vengono continuamente aggiornati in base alle operazioni effettuate sugli array. Usare tale tecnica porta a un notevole risparmio di tempo soprattutto se si impiegano filtri di ordine elevato, anche se sono necessarie delle ulteriori istruzioni per riportare i puntatori all’inizio dei buffer quando si raggiunge l’ultimo elemento. A riguardo si può osservare che se si impiegano linee di ritardo con lunghezze che sono potenze di due, l’istruzione IF che verifica il raggiungimento della fine dell’array non è più necessaria, e viene sostituita da una più semplice e veloce operazione di mascheratura dei bit meno significativi del puntatore. In generale l’istruzione eseguita è del tipo: Puntatore = Puntatore & Mask dove Mask vale nel caso di array di lunghezza N (potenza di 2): Mask = ( N − 1) Per le due delay line è stata scelta una lunghezza di 64 che garantisce la possibilità di implementare filtri con prestazioni sovrabbondanti all’applicazione realizzata, è inoltre molto interessante il vantaggio di poter realizzare filtri di lunghezze diverse senza dover riscrivere la routine di filtraggio, pagando come unico prezzo una maggiore latenza dei 75 campioni nelle due linee di ritardo, comunque insignificante ai fini del funzionamento del modulatore. Sarebbe stato possibile realizzare tale filtraggio direttamente in assembler per sfruttare il supporto in hardware del TMS320C6711 per i buffer circolari che il compilatore attuale non usa, ma data la limitazione a filtri molto corti e la poca comprensibilità del codice risultante è stata scelta l’implementazione in C che risulta sufficientemente rapida e ottimizzata per il sistema realizzato. A ogni operazione di filtraggio vengono generati due campioni posizionati nelle variabili Simbolo_Filtrato_I e Simbolo_Filtrato_Q sempre di tipo float; i valori vengono utilizzati per ottenere in uscita dal modulatore un periodo completo del segnale modulato che viene scalato e convertito in una parola a 16 bit nel formato richiesto dal convertitore D/A. I campioni pronti per essere inviati al D/A sono posizionati in memoria in un buffer puntato dalla variabile Buffer, e contenente un periodo completo del segnale, in attesa che l’EDMA li trasferisca. 5.4 Descrizione Procedure Procedura main Il software del modulatore dovendo operare in real-time non può essere strutturato come un normale programma, ma deve operare in risposta a stimoli esterni o a sincronizzazioni derivanti da timer o periferiche; per questo motivo il tempo di esecuzione della procedura main non corrisponde con il tempo di funzionamento del modulatore bensì, appena il main termina, è l’EDMA temporizzato dall’interfaccia seriale a mandare in escuzione le sezioni di codice che si occupano di implementare il modulatore. Dovrebbe quindi essere chiaro il motivo per cui nel main si calcolano unicamente le costanti per il progetto, si inizializzano le periferiche, si cancellano i buffer e al termine di tutto si abilitano le interruzioni, cadendo in un ciclo di Idle in attesa di qualche evento esterno. 76 Tra le varie costanti calcolate importante è Fattore_di_Scala che massimizza il segnale di uscita in modo da utilizzare tutta la dinamica fornita dai 12 bit del convertitore D/A utilizzato. Valori_Ampiezza[] è un vettore che in base al n° di punti della costellazione contiene le ampiezze del segnale di uscita; è significativo solo per modulazioni di tipo ASK o QASK. Per una costellazione con 16 punti ad esempio assume i valori [-3 –1 +1 +3]. Dopo aver calcolato tali parametri vengono inizializzati i vari buffer e generate le due Lookup Table contenenti i valori di seno e coseno usate per la modulazione. Il numero di campioni per periodo e quindi la lunghezza di tali tabelle è fissato nel file Configurazione.h. Infine si inizializzano la periferica seriale e il convertitore D/A, si setta l’EDMA per trasferire i due buffer e si abilitano le interruzioni; a questo punto il main termina e tutto viene gestito a interruzioni. Procedure Gen_Tab_sen e Gen_Tab_cos Riempiono le due Lookup Table Tab_sen e Tab_cos con il numero di campioni per periodo fissati Procedura Cancella_Buffer Cancella i due buffer di transito MEM_SRC_PING e MEM_SRC_PONG per non avere valori casuali alla partenza del modulatore. Procedura set_interrupts_edma Abilita l’interruzione hardware numero 14 assegnata alle richieste dati da parte dell’interfaccia seriale e l’interruzione numero 8 gestita dall’EDMA. 77 Procedura SWI_Modulatore Tale procedura è la procedura principale nel funzionamento del modulatore, viene chiamata ogni volta che Edma_ISR.s62 termina l’esecuzione (in risposta a INT 8), e si occupa oltre a settare il buffer da usare per la scrittura dei campioni, anche di chiamare in sequenza tutte le procedure che realizzano il modulatore. In particolare: Ogni 5 volte (ossia si utilizzano 5 campioni per periodo di simbolo) viene chiamata la procedura Genera_Bit. Chiama poi la procedura Codifica_Simboli che si occupa di mappare i simboli da trasmettere nelle relative ampiezze in uscita. Chiama la procedura Matched_Filter che gestisce il filtraggio a coseno rialzato dei simboli in trasmissione. Genera con i due valori Simbolo_Filtrato_I e Simbolo_Filtrato_Q posizionati in due variabili globali un periodo del segnale di uscita modulato scrivendolo nel buffer puntato da Buffer. Procedura Genera_Bit Genera in base ai punti della costellazione, utilizzando la procedura PN_Generator, due valori Bit_I e Bit_Q posizionati in due variabili globali del programma che rappresentano i bit da trasmettere nei due canali in quadratura. Eventualmente volendo utilizzare modulazioni con un solo canale basta disabilitare la parte di codice che genera i bit per il canale Q e fare lo stesso nel ricevitore. Procedura Codifica_Bit Codifica Bit_I e Bit_Q generati precedentemente. In tale procedura è possibile inserire codifiche più elaborate rispetto a quella di Gray implementata. Si è inoltre prevista la possibilità di usare simboli di tipo RZ o NRZ utilizzando il parametro N_Campione per decidere quando modificare il valore di 78 ampiezza del simbolo corrente. Attualmente per ottenere la minima occupazione di banda, i simboli sono degli impulsi di larghezza pari al periodo di campionamento che vengono poi sagomati dal filtro a radice di coseno rialzato che segue. Tabella di Codifica Bit_I Bit_Q 0 0 1 1 0 1 0 1 akbk 00 +1 10 Simbolo -1 -1 1 1 1 -1 1 -1 -1 01 +1 -1 11 Figura 39 : Costellazione usata per il 4-QASK La procedura prima di terminare inserisce il valore dei simboli Simbolo_I e Simbolo_Q nelle due linee di ritardo del filtro FIR DELAY_LINE_I e DELAY_LINE_Q e aggiorna il puntatore di scrittura Puntatore_Write per gestire i buffer circolari. Campioni +1 -1 Figura 40 : Esempio di valori caricati in Simbolo_I e Simbolo_Q Procedura Matched_Filter Calcola due campioni filtrati con i coefficenti del filtro FIR a 31 elementi usando le due delay line e scrive i valori calcolati in due variabili globali Simbolo_Filtrato_I e Simbolo_Filtrato_Q. 79 Procedura Cancella_Delay_Lines Riempie di zeri le due linee di ritardo. Procedura Scegli_Uscita Tale procedura non è essenziale per il funzionamento del modulatore, ma è stata inserita per poter osservare in uscita le sequenze di campioni prima del filtro SRRC, e dopo il filtraggio; ciò viene ottenuto agendo sui dip switch presenti nella piastra madre del DSP. In base alla posizione di tali switch si vanno a settare opportunamente i coefficenti del filtro, o i valori delle tabelle di seno o/e coseno, in modo da avere in uscita i campioni desiderati. La chiamata di Scegli_Uscita avviene ogni due secondi ed è gestita da un evento periodico definito nell’ambiente di programmazione del DSP, a ogni attivazione viene verificata la posizione degli switch e solo se è cambiata si modificano di conseguenza le tabelle. Attualmente le posizioni utilizzate sono: Tutti gli switch OFF : L’Uscita è il segnale modulato e il led 1 è acceso. Switch 1 ON : L’Uscita è il segnale I dopo il filtro SRRC. Switch 2 ON : L’Uscita è il segnale I prima del filtro SRRC. Procedura PN_Generator Realizza un generatore di sequenze di massima lunghezza; ogni volta che viene invocata restituisce un intero che può assumere valori 0 o 1 rappresentante il bit della sequenza da trasmettere. La sequenza attualmente implementata è di lunghezza 1024 e usa il polinomio generatore x10 + x 3 + 1 . 80 5.5 Funzionamento complessivo Ping Pong Buffer Come già accennato il trasferimento dei campioni elaborati verso il convertitore D/A in uscita è stato realizzato sfruttando interamente i dispositivi periferici del DSP, svincolando in questo modo il software dalla gestione dell’hardware sottostante. Tale scelta ha inoltre permesso di ottenere in modo relativamente semplice il segnale di sincronizzazione, che garantisce una cadenza costante al flusso dei campioni verso il convertitore D/A. MEM_SRC_PING 0 D A T A SWI Modula EDMA CH 14 Segnale Analogico Buffer_Lenght - 1 XINT1 MEM_SRC_PONG Buffer_in_use B U S 0 McBSP1 HWI TLV 5636 D/A EDMA_ISR Buffer_Lenght - 1 EDMA INT (8) Figura 41 : Percorso dati in uscita Per meglio comprendere come i campioni vengano portati dalla memoria verso il convertitore D/A in uscita, conviene iniziare a descrivere il funzionamento della periferica McBSP1 che rappresenta in questa applicazione il nucleo centrale al quale sono asserviti tutti gli altri dispositivi. Il McBSP1 è un dispositivo integrato nel chip del DSP che permette di gestire trasmissioni seriali ad alta velocità con dispositivi compatibili; in questo caso vi era la necessità di connettere il convertitore D/A TLV5636. 81 L’interfaccia seriale contiene una grande quantità di registri che opportunamente programmati permettono una notevole flessibilità nelle applicazioni; in particolar modo si è sfruttata la possibilità di generare il clock per il convertitore di uscita come divisione del clock principale del DSP; tale divisione viene impostata con due parametri contenuti nel file dc_conf.h del quale viene riportato qui di seguito un frammento. /* CSL device build option */ #define CHIP_6711 (1) #define DSP_FREQ (150) /* in MHz */ /* McBSPs parameter data */ #define MCBSP1_FPER_VALUE (24) /* 37.5Khz con 16 punti per sinusoide */ #define MCBSP1_CLKGDV_VALUE (4) #define MCBSP1_FSGM_MODE (0) #endif /* DC_CONF_H */ I valori significativi per settare tale divisione sono MCBSP1_FPER_VALUE, che imposta la durata in cicli di clock di un frame (è essenziale che tale durata sia superiore alla lunghezza in bit del dato da trasmettere); e MCBSP1_CLKGDV_VALUE che stabilisce il fattore di divisione tra DSP_FREQ/2 e il clock dell’interfaccia seriale. I valori da inserire in tali campi devono essere diminuiti di una unità rispetto a quelli impiegati per effettuare il calcolo della frequenza risultante. Volendo esprimere tutto con una formula si può scrivere l’espressione seguente: SAMPLE _ RATE = DSP _ FREQ / 2 (MCBSP1 _ FPER _ VALUE + 1)(MCBSP1 _ CLKGDV _ VALUE + 1) dove SAMPLE_RATE rappresenta il numero di campioni per secondo che vengono forniti al convertitore D/A. Vale la pena osservare che esistono due limitazioni fondamentali: la prima riguarda le frequenze portanti generabili in uscita che risultano ristrette a un insieme discreto e notevolmente ridotto; la seconda invece è legata alle caratteristiche elettriche del convertitore che può lavorare correttamente con frequenze di clock massime di 20Mhz, 82 va quindi posta attenzione nel caso si desiderino modificare tali valori a non eccedere il limite definito dal costruttore. Tutti i registri del McBSP1 vengono inizializzati nel file main.c dal software che implementa il modulatore richiamando la procedura dc_configure, al termine di tale inizializzazione, con la frequenza vista precedentemente il McBSP1 inizia a inviare campioni al convertitore D/A e non appena termina di trasferirne uno ne domanda subito un altro segnalando tale richiesta con la interruzione hardware XINT1 (associata al canale 14 del EDMA); l’uso di un terzo registro di transito permette di mantenere una frequenza costante evitando l’attesa di un nuovo campione per iniziare la trasmissione. Sincronizzato con queste richieste opera l’EDMA che si occupa di fornire i campioni da trasmettere prelevandoli da due buffer di transito posizionati in memoria; tale tecnica prende il nome di PING PONG Buffer, e in una struttura di memoria dotata di cache come quella del TMS320C6711 risulta particolarmente efficiente. Il problema da risolvere è quello di evitare il più possibile conflitti in accesi simultanei alla memoria. Per meglio comprendere consideriamo il caso ipotetico in cui si utilizzi un solo buffer per i campioni di uscita. Durante il normale funzionamento esiste un alta probabilità che mentre una parte del software sta accedendo un dato, arrivi la richiesta più prioritaria dal McBSP1 di un nuovo campione da trasmettere. In tale condizione si deve attendere il termine dell’operazione prima di poter leggere il campione da inviare alla porta seriale. Con due buffer invece si sfrutta la presenza della cache; mentre il buffer da cui si leggono i campioni è stato aggiornato in memoria principale, il buffer in cui si scrivono è presente in cache; poiché le due memorie sono collegate con bus separati al DSP, che produce i dati, e all’EDMA che li utilizza, non vi è mai pericolo di accessi simultanei. L’unico momento critico è quando si passa da un buffer all’altro, in tale istante è necessario copiare le righe di cache che contengono i dati appena elaborati nella memoria principale; l’operazione di copiatura è però molto più rapida dell’accesso a una singola locazione di memoria in quanto si trasferiscono in cicli burst intere righe di cache ossia 256 bit contemporaneamente, rendendo minime le possibili interferenze e il traffico sul bus. 83 Ritornando all’EDMA per poter correttamente funzionare deve essere programmato sia per il tipo di trasferimento da effettuare, che per la dimensione dei buffer da spostare. Tutte queste impostazioni devono venire codificate e depositate in memoria a alcuni indirizzi fissati; di tale operazione si occupa il file Edma.c nel quale vengono compilate le tabelle relative ai trasferimenti dai due buffer. Si sfrutta inoltre una interessante possibilità data dalla presenza di un campo link che permette una volta terminata l’esecuzione di una tabella di avviarne una successiva il cui indirizzo in memoria è proprio rappresentato dal valore di link. Grazie a tale artificio si è potuto programmare l’EDMA per gestire alternativamente il trasferimento dati da i due buffer in modo continuo. Figura 42 : Tabella di configurazione per un canale di EDMA Nel progetto del modulatore avendo come modello la realizzazione di un modulatore QASK si è cercato di ottimizzare il più possibile il trasferimento dei dati in uscita. Per prima cosa si è osservato che in una modulazione passabanda il segnale modulante varia molto lentamente rispetto alla portante; si è quindi pensato che dimensionando i due buffer di uscita in modo da contenere un periodo esatto della portante, sarebbe stato sufficiente replicare lo stesso buffer in uscita più volte, senza ricalcolare di continuo campioni identici sprecando inutilmente potenza di calcolo. Alla luce di tali considerazioni si è programmato L’EDMA in modo che trasferisse per un certo numero di volte un buffer per poi passare all’altro; tali settagli sono contenuti nel file Configurazione.h del quale viene riportato qui di seguito il frammento significativo. 84 /* Parametri EDMA */ #define Buffer_Lenght 16 /* N° campioni x periodo */ #define Ripetizioni 15 /*N° di volte che l'EDMA replica il Buffer in uscita*/ La costante Buffer_Lenght è la dimensione dei due buffer di transito; considerando che la sample rate è di 600KHz con 16 campioni per periodo, si riesce a generare una portante a 37.5KHz. La costante Ripetizioni rappresenta il numero di volte che un singolo buffer viene replicato in uscita. Eventualmente se si volessero realizzare modulazioni particolari, con l’implementazione di un oscillatore NCO (Numerically Controlled Oscillator) come presente nel demodulatore, è sempre possibile ingrandire le dimensioni dei due buffer e portare il numero di ripetizioni a 1 (Nessuna Ripetizione!). Bisognerà però verificare se il DSP possiede una sufficiente capacità di calcolo per eseguire l’applicazione. L’EDMA opera sincronamente con una variabile globale Buffer_in_use che tiene memoria di quale dei due buffer (MEM_SRC_PING o MEM_SRC_PONG) deve essere utilizzato per scrivere i campioni calcolati dalla procedura di modulazione; inizialmente assume il valore 1, indicando al SWI_modula che dovrà scrivere in MEM_SRC_PONG. Ogni volta che McBSP1 termina la trasmissione seriale di un campione attiva il segnale di interruzione numero 14 per informare il DMA che deve fornirne un altro, l’EDMA in risposta sposta un nuovo campione nel suo registro di trasmissione. Quando si termina il trasferimento di un buffer automaticamente l’EDMA, si sposta sull’altro e inizia a trasferire i nuovi campioni; durante tale transizione il passaggio viene segnalato con l’interruzione hardware EDMA_INT (la numero 8) e settando un falg nel registro CIPR (Channel Interrupt Pending Register). Tutto il modulatore è sincronizzato con tale transizione; quando si verifica un interruzione numero 8 viene richiamata una piccola routine di gestione che, per motivi di velocità, è stata resa il più piccola possibile e scritta direttamente in Assembler. Per prima cosa viene cambiato il valore della variabile Buffer_in_use in modo tale da settare il nuovo buffer da utilizzare, il flag nel registro CIPR viene portato a 1 (è in logica 85 negata) per permettere al DMA di continuare con la nuova tabella; viene chiamata l’interruzione software SWI_Modula che genera un nuovo periodo per il segnale modulato riempiendo un intero buffer. La scelta di utilizzare un’interruzione software anche se non strettamente necessaria è stata fatta per tenere la priorità di esecuzione di tutto il programma a un livello inferiore rispetto a future interruzioni che potrebbero essere aggiunte per gestire processi critici in termini di tempo di latenza. Il SWI_Modula prima di scrivere in uno dei due buffer aggiorna la variabile Buffer con il valore del puntatore al buffer da utilizzare per scrivere i campioni, e gestisce la coerenza dei dati contenuti nella cache interna al DSP con la SDRAM esterna sulla quale opera l’EDMA. Per tale motivo è necessario eseguire un’istruzione di CACHE_Flush ossia si copia il buffer appena scritto dalla cache alla memoria esterna in modo che il DMA lavori su campioni consistenti. Tutta la gestione dell’hardware avviene mostrando al programma una sola variabile Buffer che assume di volta in volta il valore del buffer (MEM_SRC_PING o MEM_SRC_PONG) da utilizzare; basta quindi inserire nella routine di gestione del SWI_Modula il programma che implementa il modulatore, il quale ogni volta che viene chiamato, dovrà avviare tutte le procedure in sequenza e riempire il buffer puntato dalla variabile Buffer con i campioni opportuni. La realizzazione della routine in assembler se da una parte ha permesso di velocizzare lo scambio tra i due buffer, dall’altra ha mostrato durante la sua realizzazione, come risulti complessa la programmazione direttamente in assembler su architetture vliw. Per la semplice assegnazione di un valore a una variabile è stato necessario utilizzare una istruzione nop per tener conto che il dato caricato non poteva essere disponibile prima di un certo numero di cicli di clock per l’elaborazione successiva. Tale problema dovuto al tempo di latenza nelle pipeline del processore, ha richiesto un notevole impegno per essere individuato, e ha indicato come sia necessaria una profonda conoscenza dell’hardware per poter efficacemente programmare a basso livello su tali dispositivi. 86 Generazione della modulazione Le operazioni di elaborazione dei bit da trasmettere sono effettuate in sequenza ogni volta che viene richiamato il SWI_Modula e comprendono il filtraggio e modulazione completa di un campione attraverso i due filtri SRRC. La prima azione effettuata consiste nel verificare la variabile Sample_Corrente che viene impiegata per dividere la frequenza di campionamento del filtro, e ottenere la chiamata alla procedura Genera_Bit con una cadenza pari alla simbol rate del trasmettitore. In pratica a ogni esecuzione Sample_Corrente viene incrementato, e quando raggiunge il valore fissato da Samples_T vengono generati i bit per due nuovi simboli posizionati nelle variabili Bit_I e Bit_Q. Viene poi richiamata la procedura Codifica_Simboli passandogli come parametro il valore della variabile Sample_Corrente; in questo modo è possibile generare impulsi con caratteristiche diverse dal tipo implementato, valutando i campioni trascorsi dall’inizio del simbolo e codificandoli in modo opportuno. I simboli codificati, filtrati dalla procedura Matched_Filter presenti nelle due variabili Simbolo_Filtrato_I e Simbolo_Filtrato_Q, vengono poi modulati a prodotto con le due tabelle sin e cos, generate valutando le omologhe funzioni trigonometriche, e sommati. I campioni risultanti sono scalati in modo da essere adattati ai 4096 livelli del convertitore tenendo conto della massima ampiezza calcolata in fase di inizializzazione per la costellazione scelta. Dopo tale operazione al segnale limitato tra –2048 e 2047 viene sommato un offset e convertito in un intero a 16 bit per ottenere un range massimo da 0 a 4095 per i codici di uscita. E’ necessario inoltre inserire nei 4 bit più significativi il codice binario 0x0100b, essenziale perché il convertitore interpreti il dato come un valore da convertire e non come una parola di controllo. 87 1000Hz 500Hz 2.5Khz 37.5Khz 600Khz *Buffer 0 SWI_Modula Genera_Bit PN_Generator 0101000... Bit_I Bit_Q Codifica_Simboli TLV 5636 D/A Matched_Filter Buffer_Lenght - 1 x 2·Bit_per_Canale ÷ Samples_T ÷ N_Ripetizioni ÷ Buffer_Lenght Figura 43 : Frequenze di funzionamento dei blocchi del modulatore (4 QASK) 88 Capitolo 6 Demodulatore 6.1 Introduzione Il demodulatore rappresenta la parte sicuramente più complessa e più onerosa dal punto di vista computazionale; la necessità di una sufficiente sovracampionatura del segnale in ingresso unita all’impiego di uno schema PLL per realizzare un demodulatore coerente ha portato a operare ai limiti delle capacità di calcolo del DSP. Segnale Analogico Conteggio errori e visualizzazione Filtro Adattato SRRC Canale I Sincronismo Simbolo (Early - Late) Demodulatore coerente (Costas Loop) Decisione Simboli e Decodifica Correlatore e verifica aggancio sequenza Filtro Adattato SRRC Canale Q Generatore Sequenze Massima Lunghezza Figura 44 : Schema di massima del ricevitore Lo schema utilizzato impiega un demodulatore coerente basato su un Costas Loop a quattro fasi che ha permesso di operare correttamente con segnali di tipo 4-QASK. La scelta di tale algoritmo, dovuta alla sua ridotta complessità computazionale e alle ottime prestazioni fornite, ha permesso di ottenere un notevole risparmio nel tempo di elaborazione rispetto a altri metodi come lo “Squaring loop” o il “Fourth Power loop” che avrebbero richiesto per isolare le componenti a 2ω c o a 4ω c filtri passa banda di ordine elevato per ottenere una sufficiente selettività. In ogni caso comunque sarebbe 89 stato necessario implementare un PLL per dividere per 2 o 4 tali frequenze incrementando ulteriormente la pesantezza dell’algoritmo. Due filtri SRRC filtrano i due segnali demodulati. Tali filtri sono esattamente identici a quelli implementati nel trasmettitore in modo da ottenere in uscita il massimo SNR. Il sincronismo di simbolo è rigenerato usando un algoritmo “non data aided”del tipo Early–Late. La scelta di tale metodo è stata effettuata nell’ottica di separare il blocco di campionamento e aggancio della frequenza di simbolo da quello di decisione e decodifica, per poter operare facilmente delle sostituzioni. I campioni prelevati negli istanti opportuni sono elaborati dal blocco di decisione che in base alle soglie fissate stabilisce il simbolo ricevuto e lo decodifica nei relativi bit. Infine un blocco correla lo stream di bit ricevuti con quelli generati da un generatore di sequenze di massima lunghezza identico a quello impiegato nel trasmettitore, verifica la sincronizzazione delle due sequenze, e valuta gli errori presenti nel collegamento. I led presenti sulla piastra madre del DSP sono impiegati per visualizzare la qualità del collegamento e si spengono proporzionalmente secondo delle soglie fissate all’aumentare del tasso di errore. Tutto il progetto a differenza del modulatore è stato strutturato facendo uso di buffer abbastanza lunghi per memorizzare i campioni sui quali lavorano le varie procedure, per sfruttare meglio il DSP e le sue capacità di parallelizzazione nei calcoli matematici. Nella realizzazione del demodulatore si sono sperimentate varie soluzioni alternative per cercare di demodulare segnali con costellazioni di ordine superiore, ma l’instabilità dell’oscillatore locale implementato come un NCO, ha sempre impedito un aggancio della portante con errore di fase accettabile. Manca inoltre rispetto al caso reale un ulteriore anello di retroazione che stabilizzi il guadagno (AGC) indispensabile se si volesse realizzare un collegamento radio per avere un’ampiezza consistente in ingresso del PLL. 6.2 Struttura del Progetto Il software che realizza il demodulatore mantiene una struttura molto simile al modulatore, pur variando completamente le modalità di gestione dell’hardware e la sincronizzazione dei vari blocchi costituenti il progetto. 90 Figura 45 : Struttura Progetto I file tidc_api.c e t1206_ob.c unitamente al file dc_conf.h contengono le procedure e i parametri di gestione per il convertitore A/D THS1206; la loro generazione è stata automatica e ha richiesto l’inserimento di tutte le parole di controllo per settare il modo di funzionamento del convertitore. Si è però scelto di non utilizzare le procedure di trasferimento dati ivi presenti, ad eccezione di quella di inizializzazione dell’A/D, e di sfruttare lo stesso schema di buffer alternati già proficuamente impiegati nel trasmettitore. I due file Edma.c e Edma_ISR.s62 svolgono la stessa funzione, ma sono stati modificati per adattarli al nuovo tipo di trasferimento che deve realizzare l’EDMA, e ai nuovi segnali di interruzione che regolano le sincronizzazioni in questo progetto. Il main.c contiene tutte le strutture dati e le procedure per gestire il demodulatore e opera nello stesso modo, inizializzando tutte le periferiche, calcolando le costanti, e terminando in attesa delle interruzioni richieste dal convertitore. Il file RRC_Fir.h contiene i coefficienti del filtro SRRC calcolati per la frequenza di campionamento presente nel ricevitore dopo la decimazione, mentre il file Configurazione.h contiene alcune costanti per l’intero progetto tra le quali la dimensione dei buffer di ingresso. Molto più articolata è invece la gestione dei parametri di configurazione per i dispositivi di supporto al corretto funzionamento del THS1206, realizzata staticamente all’interno del file demodulatore.cdb. 91 Figura 46 : Contenuto del file demodulatore.cdb Si sono impiegate due interruzioni software: la prima SWI_ALTA_Priorita possiede priorità maggiore e chiama la procedura di gestione SWI_Alta_Priorità ogni volta che è disponibile un buffer da demodulare; la seconda esegue invece con priorità inferiore quando sono disponibili un certo numero di campioni del segnale demodulato, lanciando la procedura SWI_Bassa_Priorità. La scelta di utilizzare una sezione di codice che possiede una precedenza rispetto al resto del progetto, è stata fatta per non perdere dei dati quando il processore è molto carico, la cosa sarà comunque chiarificata in seguito. Il processo periodico Cambia_fase_PLL eseguito ogni 5 secondi chiama la procedura Cambia_Fase_PLL, che si occupa di garantire l’aggancio nella corretta fase del PLL. Per generare la frequenza di campionamento utilizzata dal convertitore si è dovuto programmare il Timer0 con una tabella di configurazione denominata Clock_AD, nella quale è stata fissata la modalità di generazione del clock, il fattore di divisione rispetto 92 alla temporizzazione principale, e si è abilitata l’uscita TOUT0 per instradare il segnale verso la daughterboard THS1206EVM. Figura 47 : Configurazione del Timer per una fc di 200KHz circa 93 6.3 Strutture dati Nel demodulatore si è scelto di supportare lo scambio dati tra le varie procedure attraverso una serie di buffer, per permettere un migliore utilizzo del tempo di elaborazione del DSP. elementi_inseriti_nel_buffer Buffer_OUT_Filter 0 Buffer_OUT *Buffer_IN I Q I Q I I Q I Q I 64 I I Q I 128 192 Q I Q I 0 1 1 63 I I 0 Q Q Q 1 I 1 127 Q I Q Q I 191 Q Q Q I I 0 Q Q 0 I 1 Q 1 Buffer_Lenght - 1 I 0 Buffer_Bit Q Q 0 0 I Buffer_Simboli 256 63 Simboli_Elaborati 0 80 1 Puntatore_IN Bit_Elaborati 256 0 Figura 48 : Percorso dati demodulatore La dimensione del buffer di ingresso gestito dall’EDMA è stato oggetto di sperimentazione e ha dovuto rappresentare un compromesso: grandi dimensioni ottimizzano le prestazioni aritmetiche ma aumentano considerevolmente il tempo per trasferire i buffer dalla memoria. La scelta finale è stata di utilizzare una lunghezza di 1024 campioni, durata più che sufficiente per analizzare eventualmente con un algoritmo di DFT lo spettro del segnale acquisito al demodulatore. Il Buffer_IN che viene passato per indirizzo alla procedura di recupero della portante, contiene 1024 valori di tipo intero a 16 bit dei quali solo i 12 meno significativi rappresentano i valori campionati del segnale modulato. 94 Il seguente Buffer_OUT è invece impiegato in modo più complesso per evitare la perdita di pezzi di buffer durante l’esecuzione. Virtualmente pur essendo definito come un vettore di lunghezza 256 di tipo float, è stato pensato come diviso in quattro parti identiche. Il completamento di uno dei 4 frame permette l’inizio dell’elaborazione da parte delle procedure successive. Per memorizzare i campioni dei due canali in quadratura demodulati, si è scelto usare una modalità alternata, ossia per ogni istante di campionamento nel buffer sono presenti due campioni, il primo relativo al canale I e il secondo al canale Q; le due variabili che contengono il punto di lettura e scrittura sono rispettivamente Puntatore_IN e elementi_inseriti_nel_buffer, entrambe locali alle due procedure che generano e producono i campioni. Buffer_OUT_Filter gestisce dati dello stesso tipo di Buffer_OUT ma ha una lunghezza minore, e contiene i campioni dei segnali filtrati dal filtro SRRC. Dopo il recupero del sincronismo di simbolo i valori campionati all’istante opportuno vengono inseriti sempre in modo alternato in Buffer_Simboli, mentre una variabile Simboli_elaborati tiene memoria di quanti simboli sono presenti nel buffer e disponibili per il blocco di decisione e decodifica successivo. Questa variabile viene inoltre impiegata come contatore per avviare la procedura di decodifica quando sono presenti un numero sufficiente di campioni; attualmente il limite è settato a 64 ovvero 32 simboli per canale. Buffer_Bit raccoglie il flusso di bit decodificati pronto per essere correlato con la sequenza generata al ricevitore; anche in questo caso una variabile Bit_Elaborati conta il numero di bit presenti nel buffer, e segnala alla procedura di verifica degli errori su quanti bit deve operare. La dimensione è stata volutamente presa maggiore di quella strettamente necessaria, e va comunque rivista con costellazioni di ordine superiore, poiché dall’ elaborazione di 64 simboli potrebbero scaturire più di 256 bit decodificati. Si sono dovute impiegare due ulteriori variabili globali: Locked e Cambia_Fase che vengono utilizzate per gestire il corretto aggancio del PLL, e risolvere l’incertezza nella fase del Costas Loop. 95 6.4 Descrizione Procedure Procedura main Il main si occupa di calcolare le costanti del sistema di demodulazione; vengono poi cancellati i buffer in modo tale che il sistema si avvii con dei valori nulli, per prevenire possibili situazioni di instabilità nel PLL, del rigeneratore della portante. La tabella del seno necessaria per l’NCO viene compilata e si inizializzano il convertitore e l’EDMA. Si deve inoltre configurare la EMIF per adattare le tempistiche di accesso del DSP alle specifiche del THS1206, poiché i settaggi di default non funzionano correttamente. Vengono infine abilitati gli interrupt e il sistema resta in attesa di ricevere le interruzioni del DMA. Procedura Cancella_Buffer Tale Procedura si occupa di cancellare all’avvio i due buffer MEM_DST_PING e MEM_DST_PONG in modo che contengano tutti valori nulli. Le istruzioni Cache_flush sono istruzioni di libreria che gestiscono la cache di secondo livello del DSP e permettono di copiare nella SDRAM esterna, una certa zona di memoria della cache L2. E’ importante osservare che il DSP non gestisce la coerenza in hardware dei dati presenti nella cache con quelli presenti nella memoria esterna; ciò porta a dover utilizzare questi comandi per aggiornare i buffer in modo che contengano valori consistenti. Usando la tecnica del PING PONG buffering i dati vengono trasferiti dall’EDMA senza che il core del DSP ne tenga traccia. Al termine del riempimento di un buffer viene richiamata un’interruzione che cambia il flag indicante il buffer da utilizzare; a questo punto abbiamo in memoria SDRAM i valori campionati, ma il DSP non sapendo che sono variati continua ad accedere ai valori presenti in cache L2 che non sono significativi. Si deve allora prevedere di invalidare le righe di cache appena il SWI_alta_Priorità ha demodulato un buffer, costringendo cosi il core del DSP, la 96 prossima volta che si accederà a tale buffer, a leggere i dati presenti nella memoria esterna che rappresentano i veri campioni da utilizzare. Procedura set_interrupts_edma Abilita nei registri interni del DSP l’interruzione hardware numero 4 proveniente dalla daughterboard del convertitore THS1206 per la sincronizzazione dell’EDMA, e l’interruzione numero 8 che segnala il riempimento completo di un buffer. Va osservato che la documentazione della Texas Instruments a riguardo presenta un’imprecisione, in quanto negli schemi viene erroneamente riportata l’interruzione numero 7. Procedura Gen_Tab_sen Genera una Lookup Table contenente un periodo della funzione sin, valutando la omologa funzione trigonometrica; la lunghezza è stata fissata a 1024, in modo da garantire un ottimo compromesso tra uso della memoria e accuratezza della generazione. La procedura viene chiamata una sola volta nel main prima che il programma inizi a demodulare il segnale, per evitare ritardi nell’elaborazione. Procedura SWI_Alta_Priorità Gestisce le sezioni di codice che devono operare a frequenza maggiore e che quindi sono più critiche per quanto riguarda il tempo di esecuzione e per priorità; indicativamente nell’implementazione attuale tale interruzione occupa il processore per più del 40% del tempo medio di ciclo. Viene inizialmente selezionato il buffer da utilizzare per l’elaborazione e invalidato con un’istruzione Cache_clean l’altro buffer. Viene poi chiamata la procedura Carrier_Recovery_and_Demodulator passandogli l’indirizzo del buffer da usare. 97 Procedura SWI_Bassa_Priorità Gestisce il codice con necessità meno stringenti in termini di utilizzo del processore. Inizialmente verifica quante volte è stata chiamata l’interruzione SWI_bassa_Priorità, in quanto potrebbe accadere che il SWI più prioritario esegua più volte prima che il SWI_bassa_Priorità riesca a ottenere tempo per operare; si ripete poi l’esecuzione del codice di questa procedura per Numero_Ripetizioni volte. In sequenza si richiamano le procedure Matched_Filter, che filtra con un filtro SRRC il segnale demodulato e Symbol_Clock_Recovery_and_Sample, che si aggancia al sincronismo di simbolo e fornisce nel buffer di uscita il valore all’istante di campionamento. Tale procedura aggiorna inoltre una variabile globale Simboli_Elaborati, contenente il numero di simboli presenti nel buffer Buffer_Simboli. Quando sono presenti 64 simboli si chiamano le procedure che decidono e decodificano nei relativi bit, e verificano gli errori del collegamento. Procedura Carrier_Recovery_and_Demodulator Si aggancia alla portante con un Costas Loop a 4 fasi e demodula il segnale nei due canali in quadratura. In ingresso accetta un puntatore al buffer da utilizzare mentre in uscita salva i campioni demodulati in Buffer_OUT. Buffer_OUT è gestito in modo circolare; la variabile elementi_inseriti_nel_buffer tiene conto della posizione di scrittura, mentre la variabile Numero_Campione permette di effettuare una decimazione sui campioni demodulati. Il PLL implementato è un PLL del secondo ordine che permette quindi di annullare sia l’errore di frequenza che quello di fase. Per generare la sinusoide si è utilizzato un NCO sfruttando la tabella del sin precedentemente calcolata e una variabile index_sen che accumula la fase istantanea; il filtro di anello è stato direttamente realizzato usando un registro anche per la pulsazione istantanea, e calcolando opportunamente i due coefficienti Beta_NCO e Alfa_NCO per la stabilità, e una rapida velocità di aggancio. Ogni Decimazione campioni ne vengono spostati due in uscita; uno per il canale I e uno per il canale Q; quando sono presenti in Buffer_OUT 64 campioni (32 per canale) viene chiamato il SWI a bassa priorità che si occupa di elaborarli. 98 Al termine della procedura si verifica il flag Cambia_Fase che viene usato, se necessario, per cambiare di 90° la fase di aggancio del PLL. Tale artificio si è reso necessario per non essere costretti ad usare codifiche differenziali, che avrebbero reso meno modulare il sistema. Figura 49 : Costas Loop 4 fasi (realizzazione analogica) Procedura Matched_Filter Realizza un filtro SRRC con una struttura FIR di ordine 30 roll-off 0.5; la frequenza di campionamento del segnale da filtrare deve essere di 2.5KHz. Per tale motivo si deve aggiustare il parametro Decimazione in modo opportuno se viene variata la sample rate del convertitore A/D. Rispetto al modulatore l’algoritmo di filtraggio è stato interamente riscritto per trattare in parallelo i campioni dei due canali senza l’impiego di ulteriori linee di ritardo, che avrebbero inutilmente appesantito l’elaborazione. In questa procedura assume importanza fondamentale la variabile Puntatore_IN, che rappresenta il punto di lettura nel buffer Buffer_OUT; il valore di inizializzazione è scelto in modo che i dati vengano letti correttamente dopo che sono stati inseriti da SWI_alta_Priorità. La procedura opera su 32 campioni per canale. Ogni volta che viene chiamata filtra un frame completo di Buffer_OUT, e deposita il risultato dell’elaborazione in Buffer_OUT_Filter. 99 Procedura Symbol_Clock_Recovery_and_Sample Si occupa di agganciarsi al sincronismo di simbolo e di campionare il segnale demodulato nell’istante opportuno. Legge i valori presenti in Buffer_OUT_Filter e salva i campioni in Buffer_Simboli, incrementa inoltre la variabile globale Simboli_Elaborati, ogni volta ne viene inserito uno nel buffer di uscita. Al fine di ottenere una migliore decisione sull’istante esatto di campionamento si è utilizzato un interpolatore di ordine 2, seguito da un filtro anti-immagine ottenendo così dieci campioni per ogni simbolo in ingresso. Per rigenerare il sincronismo di simbolo si è impiegato un Early-Late Syncronizer. Assunto noto il periodo di simbolo settato dalla costante Campioni_per_Simbolo, si sposta la finestra di campionamento in base all’errore, valutato come differenza tra i quadrati dei campioni successivo e precedente; una soglia permette di ridurre le oscillazioni attorno ai punti di massimo dei simboli elaborati. Quando si raggiunge l’istante di campionamento, i valori correnti delle due vie vengono copiati in Buffer_Simboli, inserendo prima il canale I e poi il Q. Il clock di simbolo è agganciato unicamente sul canale I per permettere di operare con modulazioni che non utilizzano due vie in quadratura. Il Buffer_Simboli ha una lunghezza superiore a 64 in quanto potrebbe capitare di avere con 62 simboli inseriti, più di due periodi di simbolo da elaborare provenienti da Buffer_OUT_Filter, che andrebbero altrimenti persi. Procedura Decision_and_Decode Decide con i valori disponibili il simbolo ricevuto e lo decodifica nei relativi bit. Legge Simboli_Elaborati campioni, presenti in Buffer_Simboli e scrive in uscita in Buffer_Bit i bit decodificati; aggiorna inoltre la variabile globale Bit_Elaborati. In base alla costellazione usata, confronta con le soglie fissate, i campioni presenti in Buffer_Simboli, e decide i simboli ricevuti che vengono in seguito decodificati nei relativi bit e posizionati in Buffer_Bit. Incrementa inoltre la variabile globale Bit_Elaborati, coerentemente con i bit inseriti nel buffer di uscita. 100 Procedura Error_Block Gestisce la sincronizzazione con la sequenza di massima lunghezza del trasmettitore, valuta il tasso di errore del collegamento e visualizza tale valore. Legge Bit_Elaborati bit da Buffer_Bit e accende i led in base al tasso di errore. Per verificare l’aggancio delle due sequenze di massima lunghezza vengono impiegati due buffer, rappresentati da due variabili intere (32 bit) Buffer_bit_Generati e Buffer_bit_Ricevuti. Sono inoltre fissate alcune soglie che stabiliscono il numero massimo di errori su 32 bit per poter dichiarare la sequenza agganciata; una variabile globale Locked infine segnala all’intero progetto lo stato del ricevitore (agganciato o meno). Inizialmente il ricevitore cerca una sequenza nota nei bit ricevuti; tenendo fisso Buffer_bit_generati che è inizializzato con 32 bit appartenenti alla sequenza, shifta a sinistra di una posizione Buffer_bit_Ricevuti caricando nel LSB un bit prelevato da Buffer_Bit. Viene effettuata una correlazione tra i buffer dei bit generati e ricevuti, semplicemente contando i bit differenti tra le due variabili: se tale differenza risulta minore di Soglia_corr si considera la sequenza agganciata e la variabile Locked viene portata a 1. Quando la sequenza è agganciata oltre ad aggiornare per ogni bit, Buffer_bit_Ricevuti, si genera un bit con il generatore PN e si inserisce in Buffer_bit_Generati; in tal modo i due buffer vengono spostati parallelamente, e si verifica unicamente se i bit meno significativi appena inseriti sono diversi, in tal caso si incrementa la variabile Errori. Se Errori supera Soglia_Locked_loss la sequenza viene considerata non più agganciata, si azzera la variabile Locked, e si riprende a ricercare nello stream di dati demodulati la sequenza Buffer_bit_Generati presente all’istante della perdita di sincronizzazione con i bit ricevuti. Il tasso di errore del collegamento viene valutata attraverso le variabili Errori_Totali e Bit_Ricevuti che conteggiano, mentre le sequenze sono agganciate, gli errori che si verificano e i bit ricevuti. In base al rapporto tra le due variabili si calcola il tasso cercato, e si accendono i led relativi per visualizzare le prestazioni del collegamento. Nell’implementazione attuale ai led sono associate i seguenti tassi di errore: Led 1 acceso : Sequenza agganciata ma Te >10-4 Led 2 acceso : Sequenza agganciata ma 10-4 > Te > 10-5 Led 3 acceso : Sequenza agganciata e Te < 10-5 101 Sono state scelte tali soglie in quanto con una bit rate di trasmissione di 1Kbps il tempo per valutare Te inferiori sarebbe risultato troppo elevato, e comunque sarebbe stato poco significativo. Procedura PN_Generator Genera una sequenza di massima lunghezza di 1023 elementi. Restituisce ad ogni chiamata un intero che può assumere valori 1 o 0; viene utilizzato il polinomio generatore x10 + x 3 + 1 , mentre la parola di stato del generatore è mantenuta in una variabile intera di 32 bit, nella quale solo i 10 bit meno significativi sono usati. La sequenza è stata scelta con una lunghezza così ridotta per permettere al ricevitore di agganciarsi in tempi brevi, dell’ordine di qualche secondo, semplicemente analizzando sequenzialmente i bit ricevuti. Sequenze più brevi potrebbero portare a righe spettrali significative nel segnale modulato, rendendo necessario da una parte un aumento dei bit del generatore PN, e dall’altro un incremento della complessità del software che effettua la correlazione, per mantenere il tempo di aggancio della sequenza, entro valori accettabili di alcuni secondi. Procedura Cambia_Fase_PLL Gestisce l’incertezza di aggancio del PLL; la procedura esegue periodicamente in risposta a un processo che la invoca ogni 5 secondi. Viene verificato se il ricevitore è agganciato, in caso contrario si setta la variabile globale Cambia_Fase che alla prossima esecuzione di Carrier_Recovery_and_Demodulator incrementa la fase del NCO di 90°. Questo artificio permette di scandire in sequenza le possibili fasi di aggancio del PLL in modo da trovare la posizione in cui le due vie I e Q corrispondono con quelle del modulatore. 102 6.5 Funzionamento complessivo Ping Pong Buffer Anche il demodulatore gestisce l’acquisizione dei campioni lavorando su due buffer alternati con la tecnica di PING-PONG buffer già menzionata, variando però il metodo di sincronizzazione tra i vari dispositivi. MEM_DST_PING 0 Segnale Analogico D A T A THS 1206 A/D INT 4 Buffer_Lenght - 1 SWI EDMA Alta_Priorità CH 4 MEM_DST_PONG B U S 0 Buffer_in_use TOUT0 (CLK) HWI Buffer_Lenght - 1 EDMA INT (8) EDMA_ISR Figura 50 : Percorso dati demodulatore Il convertitore A/D presenta la caratteristica di integrare una memoria FIFO lunga 14 campioni; tale scelta progettuale tipica di convertitori ad alte prestazioni permette di acquisire in tempo reale blocchi di campioni nel modo più efficiente possibile. A livello di inizializzazione il convertitore viene settato per richiedere lo svuotamento della sua memoria raggiunta la soglia di 8 valori in modo da lasciare alcune locazioni libere per continuare a depositare dati, mentre si attende l’azione del processore. La segnalazione avviene attraverso una interruzione hardware (la numero 4) che viene gestita direttamente dall’EDMA; i campioni generati dal convertitore A/D vengono copiati dalla FIFO in uno dei due buffer MEM_DST_PING o MEM_DST_PONG. Quando un buffer è terminato l’EDMA avvisa il DSP con il segnale di interruzione (il 103 numero 8) che sono disponibili dei campioni per l’elaborazione, in risposta a tale interruzione in modo assolutamente analogo a quanto avviene nel modulatore, viene eseguita una procedura di gestione dell’interruzione scritta in codice assembler, che cambia il valore della variabile Buffer_in_use, setta a 1 il bit nel registro CIPR relativo all’interruzione numero 4 e richiama il codice SWI_Alta_Priorità per la demodulazione della portante. Al termine di tutto, al programma sono disponibili i due buffer MEM_DST_PING e MEM_DST_PONG, nei quali vengono alternativamente copiati i campioni acquisiti. Il clock di conversione viene fornito dal Timer0 attraverso l’uscita TOUT0, per la generazione viene sfruttata la temporizzazione principale del DSP opportunamente divisa. Se si volesse operare una modifica a tale parametro è necessario variare il registro PRD della periferica secondo la formula: PRD _ DEC = CLK _ DSP / 4 CLK _ AD * 2 dove CLK_DSP è la frequenza del clock principale 150MHz, CLK_AD è la frequenza di campionamento desiderata, e PRD_DEC rappresenta il valore da inserire nel registro PRD dopo averne presa la parte intera e convertito in esadecimale; per l’operazione di troncamento appena effettuata la vera frequenza di campionamento differirà leggermente dal valore iniziale anche se la differenza risulta trascurabile per l’applicazione. Gestione della demodulazione Nel Demodulatore si è scelto di spezzare il progetto in due blocchi principali per poter gestire in modo ottimale lo sfruttamento del processore. Un primo blocco realizzato con l’interruzione software SWI_alta_Priorità esegue a frequenza molto elevata la demodulazione e il recupero della portante, mentre il secondo SWI_bassa_Priorità si occupa di filtrare il segnale demodulato e di recuperare i bit ricevuti. Tale struttura porta un vantaggio in termini di risparmio del tempo di esecuzione ma soprattutto permette di dare una priorità crescente alla rigenerazione della portante rispetto al resto del codice; ciò è tanto più necessario quanto più il processore è caricato. 104 Potrebbe infatti accadere che saltuariamente per l’esecuzione di task più prioritari relativi alla gestione del DSP dal parte del software di sviluppo, o a future modifiche, non ci sia sufficiente tempo in un ciclo per mantenere il real-time; in tale condizione se si eseguissero sequenzialmente le varie procedure, potrebbe accadere di perdere dei campioni per lo scambio prematuro dei buffer di ingresso. Ponendo a una priorità più alta la rigenerazione della portante (e utilizzando un buffer dei campioni demodulati più lungo del necessario) ogni volta che il Buffer_IN cambia, anche se per qualche motivo si sta ancora eseguendo la parte di codice meno prioritaria, ne viene sospesa l’esecuzione, viene demodulato il segnale e i campioni elaborati scritti in Buffer_OUT. Non esiste così il pericolo di perdere valori per fluttuazioni temporanee del tempo di esecuzione. Una simile gestione presenta comunque un limite dovuto alla lunghezza di Buffer_OUT; con i parametri attuali, SWI_alta_Priorità può eseguire al massimo 4 volte prima che si vadano a sovrascrivere dei campioni ancora da elaborare; tale valore è in ogni caso molto elevato. Sperimentalmente anche con processore molto caricato rare volte si è arrivati a 2. Riassumendo tutto il software che implementa il ricevitore opera nel modo seguente: La procedura di recupero portante e demodulazione agganciata all’interruzione software più prioritaria, scala il segnale di ingresso (Buffer_IN) in modo da ottenere un guadagno circa unitario del canale di trasmissione. Il segnale viene demodulato coerentemente da SWI_Alta_Priorità e decimato per raggiungere una sample rate pari a quella del filtro SRRC che segue. I campioni dei due canali così trattati vengono infine depositati in Buffer_OUT; viene altresì schedulato il SWI_bassa_Priorità un numero di volte pari ai frame completati. Quando entra in esecuzione SWI_Bassa_Priorità filtra i segnali con la procedura Matched_Filter e li campiona all’istante opportuno con Simbolo_Clock_Recovery_and_Sample. Raggiunta la sogli fissata di simboli campionati posizionati in Buffer_Simboli, viene chiamata Decision_and_Decode che decodifica i campioni nei bit relativi e avviata Error_Block che valuta gli errori introdotti dal sistema di trasmissione. 105 200KHz 195Hz 78Hz 15,1Hz SWI_Bassa_Priorità 15,1Hz SWI_Bassa_Priorità SWI_Bassa_Priorità Decision_and_ Decode Error_ Block 0.5Ksps 1Kbps SWI_Alta_Priorità Matched_Filter THS 1206 A/D Carrier_Recovery_ and_Demodulator 200Ksps ÷ Buffer_Lenght 2.5Ksps Symbol_Clock_ Recovery_and_Sample 2.5Ksps - 5Ksps ÷5 ÷ (Decimazione/32) Figura 51 : Frequenze di escuzione dei blocchi del demodulatore. 106 Capitolo 7 Simulazioni 7.1 Introduzione Nella realizzazione pratica del sistema di trasmissione presentato è stata molto sentita la necessità di verificare su un simulatore l’effettivo e corretto funzionamento degli algoritmi prima della stesura finale del codice in C per il DSP. In particolar modo nel demodulatore ciò ha permesso di studiare più agevolmente l’effetto delle variazioni nei coefficienti, soprattutto per quanto riguarda il sincronizzatore Early – Late, nel quale la soglia rappresenta un parametro molto critico. Valori troppo alti impediscono al DLL di stabilizzarsi nel punto esatto, mentre valori troppo bassi creano una eccessiva oscillazione attorno al punto di massimo cercato e destabilizzano l’anello di retroazione. Il software impiegato è stato l’ambiente Matlab 6.1 del quale si sono sfruttate le capacità di simulazione introdotte nel “Simulink” con il “DSP Blockset”. Gli schemi rispecchiano in modo abbastanza fedele quello che si è realizzato. In particolare il modulatore permette con leggere modifiche di generare modulazioni multilivello in quadratura. Nel demodulatore i due PLL sono stati studiati a fondo considerando più alternative per la realizzazione finale e cercando di demodulare correttamente costellazioni di ordine superiore. Si sono sperimentati oltre al “Costas loop” un “Fourth-power loop”, mentre per il sincronizzatore di simbolo è stata scritta una procedura che sfrutta lo “zero-crossing” per decidere l’istante di campionamento. Non essendo disponibili i blocchi NCO e DLL si sono scritte direttamente in C le due “S-Function” per non complicare inutilmente lo schema. Tale modo di operare ha permesso di verificare in modo immediato il funzionamento del codice che è stato poi copiato con leggere modifiche nelle procedure del demodulatore. Non si è implementata la parte di verifica per il tasso di errore in quanto si è ritenuta inutile ai fini della simulazione. Tutta la simulazione è stata fatta imponendo ai vari blocchi una discretizzazione temporale pari alla frequenza di campionamento dei due sistemi. 107 7.2 Modulatore Nel modulatore il generatore di sequenze di massima lunghezza è accoppiato a una serie di moltiplicatori per permettere di separare la sequenza di bit in due canali e generare due segnali compresi tra 0 e N − 1 dove N sono i livelli necessari per una delle due vie in quadratura. Lo schema riportato era stato inizialmente pensato per un 16-QASK ma attualmente è settato per generare una modulazione QPSK (Il vettore Ampiezze Simboli1 contiene i valori [–1 –1 +1 +1]; per avere 16 punti nella costellazione bisogna cambiarlo in [-3 –1 +1 +3] e variare opportunamente la sample rate del generatore PN. Non è stata prevista nessuna particolare codifica perché lo scopo era quello di verificare l’aggancio dei PLL al ricevitore. I simboli codificati dai prodotti matriciali Codifica_Simboli assumono ora i valori bipolari contenuti in Ampiezze Simboli1 e presentano una sample rate di 500Hz. I due blocchi di “upsample” incrementano la frequenza di campionamento e inseriscono 4 campioni nulli per ogni campione prelevato dall’ingresso. La moltiplicazione viene impiegata per ottenere dopo il filtro un segnale prossimo all’ampiezza unitaria; nel DSP si è evitata tale moltiplicazione e si è rimandata alla scalatura finale del segnale di uscita. I due filtri a radice di coseno rialzato realizzati con l’FDA tool operano a una sample rate di 2500Hz e presentano le specifiche riportate nel capitolo 4. Vengono infine generate la sinusoide e cosinusoide a frequenza opportuna con il numero di campioni per periodo fissato, simulando le “lookup table” presenti nella realizzazione fisica. I segnali così ottenuti sono modulati a prodotto, sommati e al termine scalati opportunamente. Nello schema si sono inoltre impiegati dei blocchi che realizzano un ritardo unitario che a prima vista non sembrano trovare alcuna utilità. La loro presenza è richiesta dall’ambiente di simulazione che ogni volta si verifica una variazione della frequenza di campionamento ne richiede l’inserimento. 108 109 Nelle figure seguenti sono visibili i simboli generati per il canale I e il risultato del filtraggio con il filtro SRRC. Agli impulsi in ingresso è stato applicato un ritardo pari a quello introdotto dal filtro FIR per avere la corrispondenza riportata. Figura 53 : Simboli filtrati Il segnale modulato in uscita dal trasmettitore è visibile nella figura seguente; si possono notare le variazioni di ampiezza dovute al filtraggio a radice di coseno rialzato. Figura 54 : Segnale modulato all'uscita del trasmettitore Figura 55 : Inviluppo del segnale modulato 110 Si è infine cercato di ottenere una stima dello spettro del segnale QPSK generato, ma non potendo ingrandire la zona attorno al picco massimo risulta difficile valutare la larghezza di banda occupata. Il grafico mette comunque in evidenza un’attenuazione di circa 25 dB per i lobi secondari. Figura 56 : Spettro del segnale modulato 111 7.3 Demodulatore La simulazione del demodulatore realizza lo schema del Costas Loop a 4 fasi e integra tutta la gestione del recupero del sincronismo di simbolo. Si è prevista la possibilità di osservare come opera il campionatore Early – Late e il diagramma di scatter relativo. I filtri SRRC sono stati creati nello stesso modo del trasmettitore, mentre tutti gli altri sono semplici filtri IIR a un polo implementati in sottosistemi separati dalla simulazione principale. Figura 57 : Sottosistema filtro IIR I due blocchi NCO e DLL sono realizzati come procedure all’interno del componente generico “S-Function”. Secondo le regole fissate in Matlab per la stesura di tali routine. Una volta selezionati il numero di ingressi e uscite, si sono scritti due listati in C che regolano l’aggiornamento dello stato del blocco e delle uscite a ogni esecuzione. Pur dovendo operare con variabili fissate è stato possibile realizzare una buona corrispondenza con quello che si è poi implementato nel DSP garantendo così una minima differenza tra il comportamento del simulatore e il sistema reale. Nel blocco NCO si è realizzato il PLL implementando la stessa lookup table del demodulatore. Tutto il Costas Loop opera a 200KHz mentre i due decimatori riducono la sample rate a 2.5 KHz per i filtri SRRC. Principalmente si è verificata la stabilità al variare dei parametri caratteristici e l’effetto di un incremento della frequenza di campionamento sulla stabilità del sistema. E’ risultato inoltre necessario al fine di un buon funzionamento ridurre la soglia dei due limitatori rispetto a 1 per ottenere un segnale di errore accettabile con impulsi sagomati a coseno rialzato. Il DLL contiene l’algoritmo Early – Late; accetta nei suoi due ingressi i campioni filtrati e interpolati e fornisce in uscita i valori per un eventuale decisore. 112 113 Oltre a tale realizzazione si è simulato il comportamento di un “Fourth-power loop” per il recupero della portante. Tutto il sistema si basa sulla applicazione di una non-linearità per estrarre dal segnale di ingresso un componente frequenziale significativa a 4 ω c . Il segnale RF viene elevato alla quarta potenza e filtrato con un filtro passabanda in grado di isolare la riga spettrale desiderata. 114 L’NCO per motivi di velocità opera alla stessa frequenza della portante da generare e la sinusoide prodotta subisce lo stesso trattamento del segnale da demodulare. Un mixer ricava un segnale proporzionale all’errore di fase che viene poi filtrato passabasso e decimato per portarlo alla stessa sample rate dell’NCO. La simulazione è stata effettuata innalzando la frequenza di campionamento a 400KHz ma ha dato risultati alquanto scadenti per la sua bassa stabilità e una notevole sensibilità alla variazione di ampiezza dei segnali di ingresso. Per questi motivi non è stata impiegata nella implementazione finale. Il DLL è stato realizzato in due versioni oltre all’Early–Late usato si è utilizzato anche un algoritmo di tipo zero–crossing che genera un segnale di errore osservando gli attraversamenti del segnale per lo zero, ma non si sono notate differenze significative nel recupero del sincronismo di simbolo. In seguito verrà comunque riportato un diagramma di scatter ottenuto con tale metodo. Le figure seguenti mostrano alcuni segnali significativi per il funzionamento del sistema; volutamente è stata tralasciata l’analisi del comportamento dinamico dell’NCO perché già sufficentemente documentato in precedenza. Figura 60 : Segnale di errore in ingresso all'NCO Dalla figura si può vedere che l’errore di fase non tende mai ad annullarsi; ciò non deve essere inteso come un malfunzionamento perché il filtro di anello è stato integrato nella gestione della lookup table, e non è possibile visualizzare il classico andamento del segnale filtrato che a stabilizzazione avvenuta si azzera quasi totalmente. 115 Figura 61 : Segnale demodulato prima della decimazione In figura è possibile osservare come prima del filtro adattato a radice di coseno rialzato, il segnale non presenti la caratteristica di annullare l’ISI a intervalli regolari pari al periodo di simbolo. Figura 62 : Simboli in uscita dal filtro adattato Dopo il filtro adattato agli istanti di campionamento il segnale assume valori prossimi all’unità. Si nota comunque in figura 62 una leggera differenza dovuta probabilmente a distorsioni introdotte dal sistema di recupero della portante. Nelle due figure che seguono sono riportati due diagrammi di scatter ottenuti con i sincronizzatori menzionati; le prestazioni come già anticipato sono simili anche se si nota una “nuvola” più estesa nel caso dello zero–crossing. La presenza di più punti attorno ai valori ideali è dovuta a molti fattori: variazioni della frequenza portante, instabilità dell’NCO, e non ultimo l’impiego di un numero così 116 limitato di campioni per simbolo che rende molto grande l’errore commesso anche se si sbaglia di una sola unità l’istante di campionamento. Bisogna comunque considerare che un aumento del fattore di interpolazione aumenterebbe anche la richiesta di tempo per eseguire l’elaborazione e probabilmente con gli algoritmi considerati non si sarebbe in grado di raggiungere prestazioni molto superiori. Figura 63 : Diagramma di scatter per il sincronizzatore Early – Late Figura 64 : Diagramma di scatter per il sincronizzatore Zero–Crossing 117 Capitolo 8 Misure 8.1 Metodo di misura La ridotta frequenza portante unita a una banda molto stretta del segnale modulato hanno posto un grosso problema nella misura dello spettro generato. Dopo aver analizzato varie possibilità ci si è resi conto che gli strumenti disponibili in laboratorio non avrebbero permesso di analizzare span così ridotti a frequenze così basse, si è cercato così di ovviare al problema per via software utilizzando i campioni acquisiti dal demodulatore e applicando un algoritmo di FFT. Poiché l’ambiente di sviluppo fornisce la possibilità di effettuare elaborazioni di tale genere si è sfruttata questa opportunità ottenendo dei risultati alquanto coerenti con il dimensionamento precedentemente effettuato anche se le misure risultano limitate dal ridotto numero di campioni presi in considerazione. Per ottenere la più alta precisione possibile si è creato un buffer con una dimensione pari a quella massima utilizzabile (2048 campioni), si è poi modificato il codice per riempirlo continuamente con i valori desiderati operando come in una memoria FIFO. Una volta mandato in esecuzione il programma e stabilizzato il sistema, si è bloccata l’esecuzione e si è passato l’indirizzo di tale buffer alla finestra di visualizzazione per la successiva elaborazione. Tale tecnica ha consentito di indagare le caratteristiche spettrali dei segnali dopo i vari blocchi del demodulatore, permettendone l’osservazione nei punti caratteristici del sistema. Oltre a ciò si è riportata una serie di misurazioni effettuate sui campioni del demodulatore tra le quali: il diagramma ad occhio, di scatter e alcuni grafici sui segnali presenti nel ricevitore. 119 8.2 Spettri del segnale elaborato Tutti gli spettri proposti sono stati calcolati utilizzando una FFT di ordine 17 operante su frame di lunghezza 512 con finestratura di Hanning, ad eccezione del seguente nel quale per ottenere la massima risoluzione si è allargata la finestra a tutti i 2048 campioni del buffer. In ascissa è riportata la frequenza normalizzata mentre in ordinata è espressa l’ampiezza in dB. Nella figura seguente è rappresentato un ingrandimento del segnale di ingresso acquisito al demodulatore, l’ampiezza del picco centrale non può essere considerata significativa perché utilizzando la dimensione della finestra pari a quella del buffer lo spettro risultante è relativo a un particolare istante temporale e non a un valore medio come sarebbe accaduto con finestre più piccole. In ogni caso lo scopo di questa misura è rilevare l’occupazione di banda del segnale e quindi più che l’attenuazione dei lobi secondari, interessa avere una buona risoluzione in frequenza per misurare correttamente la larghezza del lobo principale. La frequenza centrale normalizzata è pari a circa 0.188 mentre la larghezza di banda si può stimare in circa 0.0038 corrispondente approssimativamente a 760Hz. Avendo utilizzato filtri a coseno rialzato con fattore di roll-off pari a 0.5 in banda traslata l’occupazione spettrale sarà: B = (1 + α )Rs = (1 + 0.5) ⋅ 500 = 750 Hz Il risultato ottenuto è quindi molto vicino a quanto stabilisce la trattazione teorica. Figura 65 : Ingrandimento spettro segnale di ingresso(finestra di Hamming) 120 Per quanto riguarda l’attenuazione dei lobi secondari si è rinunciato ad avere un ingrandimento nella zona desiderata e si è ridotta la finestra per permettere all’algoritmo di calcolo di mediare più spettri al fine di ottenere un valore significativo. Figura 66 : Spettro segnale di ingresso(finestra di Hamming) Il grafico ottenuto permette anche se approssimativamente di apprezzare quanto sia l’effettiva attenuazione lasciando intravedere valori prossimi ai 20dB. In realtà il risultato ottenuto è leggermente inferiore alle aspettative dovute alla grande lunghezza dei filtri FIR impiegati. E’ interessante notare il disturbo presente in continua che potrebbe facilmente derivare dall’offset del convertitore A/D in ingresso. Figura 67 : Spettro della portante generata Nella figura si può vedere come l’NCO generi una sinusoide priva di armoniche significative. 121 Figura 68 : Spettro del segnale all'uscita di uno dei due mixer Sono ben visibili la componente posizionata a bassa frequenza e quella circa al doppio della portante generata, che deve essere attenuata dal filtro ricorsivo inserito nell’anello di retroazione. Figura 69 : Spettro del segnale dopo il filtro IIR Prima della decimazione si osserva come alla frequenza di 250Hz il segnale presenti una attenuazione di circa 25 dB rispetto al massimo. La componente a circa 75KHz invece, viene ridotta a livelli trascurabili, rendendo possibile la decimazione seguente. 122 8.3 Segnali generati I segnali riportati sono stati rilevati sul sistema reale acquisendo un certo numero di campioni consecutivi e visualizzando graficamente i risultati. Nella seguente figura è possibile osservare i campioni che entrano nel filtro a radice di coseno rialzato nel modulatore; si vedono distintamente gli impulsi generati ogni 5 periodi di campionamento. Figura 70 : Impulsi codificati generati nel modulatore Figura 71 : Simboli demodulati al ricevitore prima del filtro SRRC Figura 72 : Simboli dopo il filtro adattato Nelle due figure precedenti è possibile invece verificare la differenza tra il segnale ottenuto prima e dopo il filtro SRRC. Si può notare come i due grafici rispecchino molto bene quanto ottenuto dalle simulazioni. 123 8.4 Diagrammi ad occhio e di scatter Per valutare la qualità del collegamento pur nella condizione ideale in cui non sia presente rumore additivo si sono misurati, come nelle simulazioni effettuate, il diagramma di scatter e quello ad occhio. Figura 73 : Diagramma scatter roll-off=0,5 Come si osserva nella figura precedente i quattro punti della costellazione risultano ben distinti pur presentando una notevole “nuvola” attorno ai valori nominali, ciò è dovuto probabilmente al sincronizzatore di simbolo che non operando perfettamente si trova spesso a campionare in punti affetti da interferenza intersimbolo degradando sensibilmente l’immunità al rumore del sistema. Nella figura seguente è invece rappresentato il relativo diagramma ad occhio. Figura 74 : Diagramma ad occhio roll-off =0,5 124 Come termine di paragone si presentano in seguito altre due figure che mostrano il comportamento di un sistema con maggiore occupazione di banda nel quale i due filtri di trasmissione e ricezione hanno una banda passante pari alla frequenza di simbolo. Gli algoritmi di modulazione e demodulazione restano gli stessi. Figura 75 : Diagramma di scatter ottenuto con filtri a fc=500Hz Figura 76 : Eye diagram 16 campioni per periodo di simbolo e filtri a fc=500Hz Come si può notare il diagramma di scatter migliora molto come anche il diagramma ad occhio per il minore problema di interferenza tra simboli. Nel diagramma ad occhio in particolare sono visibili le correzioni che compie il sincronizzatore oscillando tra due valori prossimi al massimo del segnale in ingresso, creando un leggero jitter. 125 Per ricavare la curva relativa al BER del sistema sono possibili due metodi: Generare esternamente in hardware del rumore bianco e inserirlo nel buffer di interfaccia. Inserire nel software del modulatore una routine che produca una sequenza pseudo casuale e permetta di variarne l’ampiezza. In entrambi i casi bisogna effettuare un filtraggio per limitare la banda del rumore a quella del segnale modulato. Un soluzione migliore potrebbe essere quella di implementare un filtro passabanda in ingresso al demodulatore direttamente in software, che attualmente non è presente. Nel sistema presentato non si è effettuata tale misura, ma ci si è limitati ad osservare che una volta messi i dispositivi in funzione senza rumore sovrapposto non si registra alcun errore al ricevitore anche dopo ore di lavoro. Va comunque notato che con una bit rate di 1Kbps in tempi ragionevoli di osservazione, diventa difficile apprezzare tassi di errore inferiori a 10-6; comunque più che sufficienti per ricavare un grafico significativo. Figura 77 : Curva BER teorica per modulazione QPSK 126 Capitolo 9 Conclusioni 9.1 Considerazioni finali Il sistema progettato ha mostrato le potenzialità di una realizzazione interamente in software per un collegamento numerico passabanda. La grossa capacità di calcolo del DSP unita a una efficiente implementazione delle procedure di gestione nel sistema, hanno consentito di raggiungere una notevole modularità e modificabilità del software. La struttura hardware sottostante ha richiesto un notevole impegno per ottenere un funzionamento il più possibile rapido, obbligando a uno studio molto particolareggiato sulle modalità di interfacciamento dei convertitori esterni, e sul funzionamento dei dispositivi periferici interni al DSP. La documentazione a tale riguardo fornita dalla Texas Instruments non si è sempre rivelata sufficientemente esaustiva ed è stato necessario operare numerose ricerche in rete e in gruppi di discussione a livello internazionale, per cercare di comprendere e risolvere numerosi malfunzionamenti che si sono verificati durante la progettazione del software che gestisce l’hardware impiegato. Il dimensionamento del sistema di trasmissione pur nel suo scopo dimostrativo ha dovuto tener conto della richiesta computazionale dei vari algoritmi, e soprattutto nel ricevitore si è evidenziata una limitazione alla massima frequenza di campionamento impiegabile, introdotta dalla notevole pesantezza elaborativa del blocco di recupero della portante. I filtri a radice di coseno rialzato impiegati hanno mostrato abbondanti caratteristiche di attenuazione, anche se lo spettro rilevato all’uscita non indica una riduzione così elevata dei lobi secondari. Tale problema andrà indagato in futuro; significativi miglioramenti potrebbero venire da un aumento del numero di campioni per periodo di simbolo impiegati nel modulatore, e nell’inserimento di un filtro predistorsore che compensi gli effetti dello zero order hold a monte della conversione D/A. Dal lato ricevitore si sono implementati in modo molto compatto ed efficiente due sistemi PLL che hanno mostrato buone caratteristiche di stabilità. 127 L’NCO ha dimostrato un ottimo funzionamento, e inserito in un anello di demodulazione come il Costas loop, può permettere la corretta demodulazione di una grande varietà di segnali, con modifiche minime al rilevatore di fase. Il punto più critico, e se vogliamo debole della catena, è il rigeneratore del sincronismo di simbolo che non si è rilevato all’altezza di tutto il resto del demodulatore. Sono stati provati due algoritmi ma hanno mostrato entrambi una limitata stabilità nel campionare esattamente in assenza di ISI i simboli ricevuti. In ogni caso il funzionamento globale è risultato buono, e in condizioni normali al ricevitore non vengono rilevati errori durante la trasmissione. Si è infine cercato di aumentare la costellazione demodulabile ma per problemi di instabilità nel sistema di recupero della portante non è stato possibile ottenere proficui risultati. La realizzazione implementata rappresenta infine un buon punto di partenza integrando un sistema completo di rice-trasmissione in grado di verificare la qualità del collegamento, e che permetterà in futuro di supportare notevoli aggiunte e ulteriori ottimizzazioni. 128 Bibliografia [1] Steven W.Smith, ‘Digital Signal Processing’, California Technical Publishing 1999. [2] Oppenheim Shafer Buck, ‘Discrete time signal processing’, Prentice Hall 1998. [3] A.Bateman I.Paterson-Stephens, ‘The DSP Handbook’, Prantice Hall 2001. [4] L.Litwin, ’Matched filtering & timing recovery in digital receivers’, rfdesign. [5] J.Steber, ‘PSK Demodulation’ WJ Communication. [6] J. Webber N. Dahnoun, ’Implementing a π /4 Shift D-QPSK Baseband Modem Using the TMS320C50’, Texas Instruments. [7] SPRA013, ’Theory and Implementation of a Splitband Modem Using the TMS32010’, Texas Instruments. [8] K.Miyauchi T.Nagai M.Kato, ’Phase Jitter of carrier Recovery Using Fourth-Power Multiplier for QPSK and QAM Trasmission’, IEICE Trans. Commun. [9] ‘TDA8046H Qam Reciver Data Sheet’,Philips Semiconductors. [10] SLYT015, ’Introduction to phase-locked loop system modeling’, Texas Instruments. [11] SPRA522, ’How to Begin Development with the TMS320C6711 DSP’, Texas Instruments. [12] SPRU401, ’TMS320C6000 Chip Support Libray API Reference Guide’, Texas Instruments. 129 [13] SPRU432A, ’TMS320C6000 DSK Board Support Library API User’s Guide’, Texas Instruments. [14] SPRU190, ’TMS320C6000 Peripherals Reference Guide’, Texas Instruments. [15] SPRA636, ’Application Using TMS6x EDMA’, Texas Instruments. [16] SPRA488A, ’TMS320C6000 McBSP Inizializzation’, Texas Instruments. [17] SLAA094,’Designing With the THS1206 High Speed Data Converter’, Texas Instruments. [18] SLAS287A,’THS1206 12-Bit 4 Channel 6Msps With Internal FIFO’, Texas Instruments. [19] SLAS223,’TLV5636 Low Power 12-Bit D/A Converter With Internal Reference and Power Down’, Texas Instruments. [20] ‘AD711 Precision Low Cost High Speed BiFET Op Amp Datasheet’, Analog Device. [21] ‘AD845 Precision 16MHz CBFET Op Amp Datasheet’, Analog Device. [22] ‘TL081 Wide Bandwidth JFET Input Op Amp Datasheet’, Texas Instruments. [23] SPRU328B, ‘Code Composer Studio User Guide’ , Texas Instruments. [24] SPRA711, ‘TMS320 Cross-Platform Daughtercard Specification Revision 1.0’ , Texas Instruments. 130 Appendice Listati software modulatore main.c /****************************************************************/ /* Scritto da Raffaele Rugin */ /* modificato il 01/10/2002 */ /* Main realizza un modulatore QASK */ /****************************************************************/ /* File di supporto convertitore D/A TLV5636 */ #include "dc_conf.h" #include "t56xx_fn.h" /* File di configurazione Generale */ #include "Configurazione.h" /* File dei coefficenti del filtro FIR */ #include "RRC_Fir.h" /* Librerie */ #include <stdlib.h> #include <std.h> #include <hwi.h> #include <swi.h> #include <log.h> /* DSP/BIOS includes */ #include <csl.h> #include <csl_edma.h> #include <csl_mcbsp.h> #include <csl_irq.h> #include <csl_cache.h> /* CSL includes */ /* Libreria Matematica */ #define _TI_ENHANCED_MATH_H 1 #include <math.h> /* Definizioni */ #define LED1_on #define LED2_on #define LED3_on #define Spegni_Led *(int *)0x90080000 = 0x0E000000 *(int *)0x90080000 = 0x0D000000 *(int *)0x90080000 = 0x0B000000 *(int *)0x90080000 = 0x07000000 131 #define Get_Switches ((*(int *)0x90080000>>24) & 0x07) #define CS_DA_Multiconverter *(int *)0x01980000 = 0x00000004 //Setta pin XF #define pi 3.1415927 //Definisce il valore di P-Greco /*Variabili Globali*/ #pragma DATA_ALIGN (MEM_SRC_PING , Buffer_Lenght*sizeof(Uint16)); Uint16 MEM_SRC_PING[Buffer_Lenght]; #pragma DATA_ALIGN (MEM_SRC_PONG , Buffer_Lenght*sizeof(Uint16)); Uint16 MEM_SRC_PONG[Buffer_Lenght]; #pragma DATA_ALIGN (DELAY_LINE_I,Delay_Lenght*sizeof(float)); float DELAY_LINE_I[Delay_Lenght]; #pragma DATA_ALIGN (DELAY_LINE_Q,Delay_Lenght*sizeof(float)); float DELAY_LINE_Q[Delay_Lenght]; float FIR_Coefficenti[Fir_Lenght]; short Puntatore_Read=0; short Puntatore_Write=(Fir_Lenght-1); Uint32 Buffer_in_use=1; float Tabella_sen[Buffer_Lenght]; float Tabella_cos[Buffer_Lenght]; Uint16 Bit_per_Canale; Uint16 Punti_Canale; Uint16 Max_Ampiezza; Uint16 Zero_DA; Uint16 Data_DA=0x4000; /* Buffer in uso per la scrittura*/ /* Bit per simbolo per canale */ /* valori dell'ampiezza per 1 canale */ /* Max ampiezza segnale modulante */ /* Offset dello 0 del D/A rispetto a 0x000 */ /* Codice 0x4000 per dati */ Uint16 maschera=(Delay_Lenght-1); /* Maschera per il buffer circolare */ float Fattore_di_Scala; /* Coefficente di scala per il D/A */ float Simbolo_Filtrato_I; float Simbolo_Filtrato_Q; float Simbolo_I; float Simbolo_Q; short Bit_I=0; short Bit_Q=0; float *Valori_Ampiezza; /* Valori possibili ampiezza */ /* Prototipi funzioni */ void Gen_Tab_sen(void); void Gen_Tab_cos(void); void Cancella_Buffer(void); void Cancella_Delay_Lines(void); void set_interrupts_edma(void); int PN_Generator(void); void SWI_modulatore(void); 132 void Codifica_Simboli(short N_Campione); void Genera_Bit(void); void Matched_Filter(void); extern Int32 cfg_edma(EDMA_Handle *hEdma_ch14); void Scegli_Uscita(void); /* main */ void main() { Uint32 error=0; EDMA_Handle hEdma_ch14; Uint16 loop; Int16 temp; /* initialize the CSL library */ CSL_init(); /* Calcola le costanti del Modulatore */ Punti_Canale=(short)sqrt(Punti_Costellazione); Bit_per_Canale=(short)log2f(Punti_Canale); Max_Ampiezza=Punti_Canale-1; Zero_DA=(1<<(Bit_DA-1))-1; Fattore_di_Scala=(float)(Zero_DA)/((float)(Max_Ampiezza)*0.4); /* Alloca memoria per il vettore valori Ampiezza */ Valori_Ampiezza=malloc(Punti_Canale*sizeof(float)); /* Genera i valori delle ampiezze per i 2 canali */ for (loop=0,temp=Max_Ampiezza;loop<Punti_Canale;loop++) { Valori_Ampiezza[loop]=(float)temp; temp-=2; } /* Carica i coefficenti del Filtro FIR */ for (loop=0;loop<Fir_Lenght;loop++) FIR_Coefficenti[loop]=Coefficenti_Fir[loop]; /* Genera la tabella del sin e cos */ Gen_Tab_sen(); Gen_Tab_cos(); /* Cancella i Buffer */ Cancella_Buffer(); /* Cancella le Delay Line */ Cancella_Delay_Lines(); /* Configura il dispositivo di EDMA */ error=cfg_edma(&hEdma_ch14); 133 if (!error) { /* Abilita il Chip Select del convertitore D/A */ CS_DA_Multiconverter; /* Inizializza McBSP1 e il convertitore D/A */ dc_configure(&TLV5636_1); /* Abilita il canale 14 dell' EDMA */ EDMA_enableChannel(hEdma_ch14); /* setta gli interupt per il DMA */ set_interrupts_edma(); /* Cade nel BIOS idle loop */ return; } } /* Fine main */ /*Procedura Gen_Tab_sen()*/ void Gen_Tab_sen() { Uint16 loop; double coefficente; coefficente=(2*pi/(Buffer_Lenght)); for (loop=0;loop<Buffer_Lenght;loop++) { Tabella_sen[loop]=sin(coefficente*loop); //Calcola il valore del sin } } /* Fine Gen_tab_sen */ /*Procedura Gen_Tab_cos()*/ void Gen_Tab_cos() { Uint16 loop; Uint16 phase; phase=(Buffer_Lenght >> 2); for (loop=0;loop<Buffer_Lenght-phase;loop++) { Tabella_cos[loop]=Tabella_sen[loop+phase]; } for (loop=0;loop<phase;loop++) 134 //Calcola il valore del cos { Tabella_cos[Buffer_Lenght-phase+loop]=Tabella_sen[loop]; } } /* Fine Gen_tab_cos */ /* Procedura Cancella_Buffer */ void Cancella_Buffer() { unsigned short *pingval; unsigned short *pongval; unsigned short i=0; pingval=(unsigned short *)MEM_SRC_PING; pongval=(unsigned short *)MEM_SRC_PONG; /* Azzera i 2 Buffer */ for (i=0;i<Buffer_Lenght;i++) { *pingval++=0; *pongval++=0; } CACHE_flush(CACHE_L2,(void*)MEM_SRC_PING,Buffer_Lenght >> 1); CACHE_flush(CACHE_L2,(void*)MEM_SRC_PONG,Buffer_Lenght >> 1); } /* Fine Cancella_Buffer */ /* set_interrupts_edma() */ void set_interrupts_edma(void) { IRQ_nmiEnable(); IRQ_globalEnable(); IRQ_reset(IRQ_EVT_EDMAINT); IRQ_disable(IRQ_EVT_EDMAINT); EDMA_intDisable(14); /* ch 14 for McBSP transmit event XEVT1 */ IRQ_clear(IRQ_EVT_EDMAINT); EDMA_intClear(14); IRQ_enable(IRQ_EVT_EDMAINT); EDMA_intEnable(14); return; } /* Fine set_interrupts_edma() */ /* Software Interrupt */ 135 void SWI_Modulatore() { short loop; float risultato; unsigned short *Buffer; unsigned short *Temp; static short Sample_Corrente=0; if (Sample_Corrente == Samples_T) { /* Chiama la procedura Genera_Bit che genera i Bit per i */ /* simboli da trasmettere */ Genera_Bit(); /* Ripristina il valore di Sample_Corrente */ Sample_Corrente=0; } /* Incrementa il valore di Sample_Corrente */ Sample_Corrente++; /* Chiama la procedura Codifica_Simboli che codifica i Bit */ /* Generati e li converte nei simboli da Trasmettere */ Codifica_Simboli(Sample_Corrente); /* Chiama la procedura Matched_Filter che filtra la sequenza*/ /* dei simboli da trasmettere */ Matched_Filter(); /* Modula i simboli da trasmettere */ /* Seleziona il buffer da utilizzare */ if (Buffer_in_use) { Buffer=(unsigned short *)MEM_SRC_PONG; } else { Buffer=(unsigned short *)MEM_SRC_PING; } /* Blocco che effettua la modulazione */ Temp=Buffer; for (loop=0;loop <Buffer_Lenght;loop++) { risultato=Simbolo_Filtrato_I * Tabella_sen[loop]; risultato+=Simbolo_Filtrato_Q * Tabella_cos[loop]; risultato*=Fattore_di_Scala; *Temp++=(((short)risultato+Zero_DA) & 0x0FFF)+ Data_DA; }; CACHE_flush(CACHE_L2,(void*)Buffer,Buffer_Lenght >> 1); }/* Fine SWI_Modulatore */ /* Procedura Genera_Bit() */ 136 void Genera_Bit() { short loop; short bit; /* Azzera il valore di Bit_I */ Bit_I=0; /* Genera i bit per il canale I */ for (loop=0;loop < Bit_per_Canale;loop++) { bit=PN_Generator(); Bit_I=(Bit_I << 1) | bit; } /* Azzera il valore di Bit_Q */ Bit_Q=0; /* Genera i bit per il canale Q */ for (loop=0;loop < Bit_per_Canale;loop++) { bit=PN_Generator(); Bit_Q=(Bit_Q << 1) | bit; } } /* Fine Genera_Bit */ /* Procedura Codifica_Simboli() */ void Codifica_Simboli(short N_Campione) { /* Azzera i valori contenuti nei simboli */ Simbolo_I=0; Simbolo_Q=0; if (N_Campione==Samples_T) { /* Codifica i bit nei simboli da tx */ /* con codice gray */ Simbolo_I=-Valori_Ampiezza[Bit_I]; Simbolo_Q=Valori_Ampiezza[Bit_Q]; } /* Inserisce i simboli nelle Delay Line */ DELAY_LINE_I[Puntatore_Write]=Simbolo_I; DELAY_LINE_Q[Puntatore_Write]=Simbolo_Q; /* Aggiorna il valore del puntatore di scrittura */ Puntatore_Write++; Puntatore_Write&=maschera; } /* Fine Codifica_Simboli */ /* Procedura Matched_Filter() */ 137 void Matched_Filter() { short loop; short index; float coefficente; /* Calcola 1 campione per i 2 canali I e Q */ Simbolo_Filtrato_I=0,Simbolo_Filtrato_Q=0; index=Puntatore_Read; for (loop=0;loop < Fir_Lenght;loop++) { coefficente=FIR_Coefficenti[loop]; Simbolo_Filtrato_I+=DELAY_LINE_I[index]*coefficente; Simbolo_Filtrato_Q+=DELAY_LINE_Q[index]*coefficente; index++; index&=maschera; } /* Incrementa il puntatore di lettura nella delay line */ Puntatore_Read++; Puntatore_Read&=maschera; } /* Fine Matched_Filter() */ /* Procedura Cancella_Delay_Lines() */ void Cancella_Delay_Lines() { short loop; for (loop=0;loop<Delay_Lenght;loop++) { DELAY_LINE_I[loop]=0; DELAY_LINE_Q[loop]=0; } } /* Fine Cancella_Delay_Lines() */ /* Procedura Scegli_Uscita() */ void Scegli_Uscita(void) { static Uint8 Posizione_Dip=1; Uint8 temp_Dip; Uint8 loop; temp_Dip=Get_Switches; 138 if (Posizione_Dip != temp_Dip) { Spegni_Led; /* Decide cosa fare */ switch (temp_Dip) { case 0: { /* Funzionamento Normale l'Uscita è il segnale modulato */ LED1_on; /* Ripristina la tabella del sin e cos */ Gen_Tab_sen(); Gen_Tab_cos(); /* Ricarica i coefficenti del Filtro FIR */ for (loop=0;loop<Fir_Lenght;loop++) FIR_Coefficenti[loop]=Coefficenti_Fir[loop]; break; } case 1: { /* L'Uscita è il Segnale modulante del canale I dopo il FIR*/ /* Azzera la tabella del coseno e riempie di tutti */ /* 1 quella del seno */ for (loop=0;loop<Buffer_Lenght;loop ++) { Tabella_cos[loop]=0; Tabella_sen[loop]=1; } /* Ricarica i coefficenti del Filtro FIR */ for (loop=0;loop<Fir_Lenght;loop++) FIR_Coefficenti[loop]=Coefficenti_Fir[loop]; break; } case 2: { /* L'Uscita è la sequenza di simboli del canale I prima */ /* del filtro FIR */ /* Azzera la tabella del coseno e riempie di tutti */ /* 1 quella del seno */ for (loop=0;loop<Buffer_Lenght;loop ++) { Tabella_cos[loop]=0; Tabella_sen[loop]=1; } /* Carica i coefficenti opportuni nel Filtro FIR */ for (loop=0;loop<Fir_Lenght-1;loop++) FIR_Coefficenti[loop]=0; for (;loop<Fir_Lenght;loop++) FIR_Coefficenti[loop]=1; break; } 139 } /* Aggiorna il valore di Posizione_Dip */ Posizione_Dip=temp_Dip; }; } /* Fine Scegli_Uscita() */ /* PN_Generator */ int PN_Generator() /* Ritorna un Bit generato con una sequenza PN di lunghezza 1023 */ { #define IB1 0x0001 #define IB3 0x0004 #define IB10 0x0200 #define MASK (IB3) /* seme di partenza */ /* in PN i 10 LSB sono significativi */ static short PN=0x0001; if (PN & IB10) { /*Cambia tutti i bit mascherati Shifta e mette 1 nel bit 1 */ PN=((PN ^ MASK) << 1) | IB1; return 1; } else { /*Shifta e mette 0 nel bit 1 */ PN <<= 1; return 0; } }/* Fine PN_Generator */ Configurazione.h /****************************************************************/ /* Scritto da Raffaele Rugin */ /* il 11/02/2002 */ /* Configurazione.h contiene tutti i parametri globali del */ /* modulatore */ /****************************************************************/ /* Parametri EDMA */ #define Buffer_Lenght 16 /* N° campioni x periodo USARE solo multipli di 4!!!*/ #define Ripetizioni 15 /*N° di volte che l'EDMA replica il Buffer in uscita*/ /* Parametri D/A */ #define Bit_DA 12 /* N° di bit del convertitore D/A */ 140 /* Parametri Modulatore */ #define Punti_Costellazione 4 /* N° di punti della Costellazione */ #define Delay_Lenght 64 /* Lunghezza in campioni della linea */ /* di ritardo deve essere una potenza di 2 */ #define Samples_T 5 /* Numero di campioni per ogni periodo */ /* di simbolo */ dc_conf.h #ifndef DC_CONF_H #define DC_CONF_H /* DAC 1 parameter data */ #define DAC1_TYPE TLV5636 #define DAC1_CONTROL (0x4000) #define DAC1_REFSET (0xD000) /* Riga modificata setta 1uS e Ext Ref */ #define DAC1_SERPORT (1) /* DSP parameter data */ #define TMS320C6711 /* CSL device build option */ #define CHIP_6711 (1) #define DSP_FREQ (150) /* in MHz */ /* McBSPs parameter data */ #define MCBSP1_FPER_VALUE (24) /* 37.5Khz con 16 punti per sinusoide */ #define MCBSP1_CLKGDV_VALUE (4) #define MCBSP1_FSGM_MODE (0) #endif /* DC_CONF_H */ edma.c /****************************************************************/ /* Scritto da Raffaele Rugin */ /* il 08/02/2002 */ /* Edma.c Usa il canale N° 14 dell' EDMA riservato */ /* per gestire il dispositivo McBSP1 usando il segnale XEVT1 */ /* per sincronizzare il trasferimento dati. */ /* Il canale 14 dell'EDMA è programmato in modo tale da */ /* trasferire in modo continuo e indipendente dalla CPU i */ /* campioni elaborati e depositati in una coppia di buffer */ /* Una opportuna ISR seleziona alternativamente uno dei 2 buffer*/ /* come sorgente del trasferimento al fine di permettere alla */ /* CPU di scrivere i campioni calcolati senza interferire con */ 141 /* il dispositivo di EDMA. */ /****************************************************************/ /* Definizione CHIP in uso */ #define CHIP_6711 1 /* Librerie */ #include <csl.h> #include <csl_edma.h> #include <csl_mcbsp.h> #include "Configurazione.h" /* Parametri globali del modulatore */ /* Definizioni */ /* Prototipi */ Int32 cfg_edma(EDMA_Handle *hEdma_ch14); /**************************cfg_edma******************************/ /* Programma il canale 14 per servire il trasferimento verso */ /* McBSP1. */ /****************************************************************/ Int32 cfg_edma(EDMA_Handle *hEdma_ch14) { extern far Uint16 MEM_SRC_PING[]; extern far Uint16 MEM_SRC_PONG[]; Uint32 Collegamento_Ping_Tx; Uint32 Collegamento_Pong_Tx; Int16 Frame_Index; Uint16 Element_Index; EDMA_Config Configurazione; EDMA_Handle hEdma_Ping_Tx; EDMA_Handle hEdma_Pong_Tx; if(!EDMA_allocTableEx(1,&hEdma_Ping_Tx)) return(-1); Collegamento_Ping_Tx=EDMA_getTableAddress(hEdma_Ping_Tx); if(!EDMA_allocTableEx(1,&hEdma_Pong_Tx)) return(-1); Collegamento_Pong_Tx=EDMA_getTableAddress(hEdma_Pong_Tx); /*Calcola i valori di Frame_Index e Element_Index*/ Frame_Index=-((Int16)((Buffer_Lenght-1)*2)); // 2 è il N° di Byte per Element_Index=2; // ogni campione 142 *hEdma_ch14=EDMA_open(14,EDMA_OPEN_RESET); /*Configura il canale di trasmissione (14)*/ Configurazione.opt = (Uint32) ((EDMA_OPT_PRI_HIGH << _EDMA_OPT_PRI_SHIFT ) | (EDMA_OPT_ESIZE_16BIT << _EDMA_OPT_ESIZE_SHIFT ) | (EDMA_OPT_2DS_NO << _EDMA_OPT_2DS_SHIFT ) | (EDMA_OPT_SUM_IDX << _EDMA_OPT_SUM_SHIFT ) | (EDMA_OPT_2DD_NO << _EDMA_OPT_2DD_SHIFT ) | (EDMA_OPT_DUM_NONE << _EDMA_OPT_DUM_SHIFT ) | (EDMA_OPT_TCINT_YES << _EDMA_OPT_TCINT_SHIFT ) | (EDMA_OPT_TCC_OF(14) << _EDMA_OPT_TCC_SHIFT ) | (EDMA_OPT_LINK_YES << _EDMA_OPT_LINK_SHIFT ) | (EDMA_OPT_FS_NO << _EDMA_OPT_FS_SHIFT )); Configurazione.src = (Uint32)MEM_SRC_PING; // Ind. Sorg. PING EDMA Configurazione.cnt = (Uint32) ((EDMA_CNT_FRMCNT_OF(Ripetizioni-1) << _EDMA_CNT_FRMCNT_SHIFT) | (EDMA_CNT_ELECNT_OF(Buffer_Lenght) << _EDMA_CNT_ELECNT_SHIFT)); Configurazione.dst = (Uint32)_MCBSP_DXR1_ADDR; // Ind. Dest. EDMA Configurazione.idx = (Uint32) ((EDMA_IDX_FRMIDX_OF(Frame_Index) << _EDMA_IDX_FRMIDX_SHIFT) | (EDMA_IDX_ELEIDX_OF(Element_Index) << _EDMA_IDX_ELEIDX_SHIFT)); Configurazione.rld = (Uint32) ((EDMA_RLD_ELERLD_OF(Buffer_Lenght) << _EDMA_RLD_ELERLD_SHIFT) | (EDMA_RLD_LINK_OF(Collegamento_Pong_Tx & 0xffff) << _EDMA_RLD_LINK_SHIFT)); EDMA_config(*hEdma_ch14,&Configurazione); EDMA_config(hEdma_Ping_Tx,&Configurazione); Configurazione.src = (Uint32)MEM_SRC_PONG; //Ind. Sorg. PONG EDMA Configurazione.rld = (Uint32) ((EDMA_RLD_ELERLD_OF(Buffer_Lenght) << _EDMA_RLD_ELERLD_SHIFT) | (EDMA_RLD_LINK_OF(Collegamento_Ping_Tx & 0xffff) << _EDMA_RLD_LINK_SHIFT)); EDMA_config(hEdma_Pong_Tx,&Configurazione); return(0); } /* fine cfg_edma */ 143 edma_ISR.s62 ; Scritto da Raffaele Rugin ; 14/02/2002 ; ======== Edma_ISR.s62 ======== ; .include "hwi.h62" ; macro header file .include "c62.h62" .include "swi.h62" IEMASK .set 0xFFFF CCMASK .set C62_PCC_ENABLE CIPR_ADDR .set 0x01A0FFE4 ;indirizzo per il registro CIPR CIPR_SET .set 0x00004000 ;Reset per il ch 14 dell CIPR .text ; ; ======== EDMA ISR ======== ; .global _Edma_ISR,_Buffer_in_use,_SWI_Modula,fine _Edma_ISR: HWI_enter C62_ABTEMPS,0, IEMASK, CCMASK ;Setta la variabile Buffer_in_use per il nuovo buffer da utilizzare mvkl _Buffer_in_use,b0 ;carica l'indirizzo della variabile buffer mvkh _Buffer_in_use,b0 ldw *b0,b1 ;carica la variabile buffer nop 4 ;attende che il dato sia disponibile xor b1,1,b1 ;setta il nuovo buffer da usare stw b1,*b0 ;scrive la variabile buffer in memoria ;Resetta il Channel Interrupt Pending Register del canale 14 ;dell edma mvkl CIPR_ADDR,a0 ;carica l'indirizzo del CIPR mvkh CIPR_ADDR,a0 mvkl CIPR_SET,a1 ;carica il valore di CIPR_SET mvkh CIPR_SET,a1 ldw *a0,a2 ;carica il valore del registro CIPR xor a2,a1,a2 ;aggiunge CIPR_SET stw a2,*a0 ;scrive il valore calcolato nel registro CIPR ;Schedula il SWI che si occupa di riempire il buffer scelto con ;i nuovi valori calcolati mvkl _SWI_Modula,a4 ;carica l'indirizzo del SWI_Modula mvkh _SWI_Modula,a4 SWI_post ;Schedula l'interrupt Software mvkl fine,b3 ;carica l'indirizzo di fine 144 Modula mvkh fine,b3 nop 3 fine: HWI_exit C62_ABTEMPS,0, IEMASK, CCMASK .end Listati software demodulatore main.c /*****************************************************************/ /* Scritto da Raffaele Rugin */ /* modificato il 01/10/2002 */ /* Main realizza un demodulatore 4-QASK */ /*****************************************************************/ /* File di supporto convertitore A/D THS1206 */ #include "dc_conf.h" #include "t1206_fn.h" /* File di configurazione Generale */ #include "Configurazione.h" /* Include i coefficenti del filtro FIR */ #include "RRC_Fir.h" /* Librerie */ #include <stdlib.h> #include <std.h> #include <hwi.h> #include <swi.h> #include <log.h> #include <trc.h> #include <csl.h> #include <csl_edma.h> #include <csl_irq.h> #include <csl_cache.h> #include <csl_emif.h> /* DSP/BIOS includes */ /* CSL includes */ /* Libreria Matematica */ #define _TI_ENHANCED_MATH_H 1 #include <math.h> 145 /* Definizioni */ #define LED1_on #define LED2_on #define LED3_on #define Spegni_Led *(int *)0x90080000 = 0x0E000000 *(int *)0x90080000 = 0x0D000000 *(int *)0x90080000 = 0x0B000000 *(int *)0x90080000 = 0x07000000 /*Variabili Globali*/ #pragma DATA_ALIGN (MEM_DST_PING , 32); Uint16 MEM_DST_PING[Buffer_Lenght]; #pragma DATA_ALIGN (MEM_DST_PONG , 32); Uint16 MEM_DST_PONG[Buffer_Lenght]; float Buffer_OUT[Buffer_OUT_Lenght];/* Buffer Uscita Demodulatore */ float Buffer_OUT_Filter[64]; /* Buffer Uscita Filtro FIR */ float Buffer_Simboli[80]; /* Buffer Simboli Campionati */ short Simboli_Elaborati=0; /* Simboli nel Buffer */ short Buffer_Bit[256]; /* Buffer sequenza Bit ricevuti */ short Bit_Elaborati=0; /* Modificare in base ai bit per Simbolo*/ short Locked=0; /* Flag di aggancio della sequenza */ short Cambia_Fase=0; float Tabella_sen[1024]; Uint32 Buffer_in_use=1; /* Flag per il cambio di fase del PLL */ /* Buffer in uso per la lettura*/ float Due_pi; float Pi_mezzi; Uint16 Bit_per_Canale; /* Bit per simbolo per canale */ Uint16 Punti_Canale; /* valori dell'ampiezza per 1 canale */ Uint16 Max_Ampiezza; /* Max ampiezza segnale Ricevuto */ float *Valori_Ampiezza; /* Valori possibili ampiezza */ EMIF_Config emifadconfig; extern far SWI_Obj SWI_BASSA_Priorita; extern far LOG_Obj trace; /* Prototipi funzioni */ void Gen_Tab_sen(void); void Cancella_Buffer(void); void set_interrupts_edma(void); void SWI_Alta_Priorita(void); void SWI_Bassa_Priorita(void); void Carrier_Recovery_and_Demodulator(short *Buffer_Ingresso); void Matched_Filter(void); void Symbol_Clock_Recovery_and_Sample(void); void Decision_and_Decode(void); 146 void Error_Block(void); void Cambia_Fase_PLL(void); int PN_Generator(void); extern Int32 cfg_edma(EDMA_Handle *hEdma_ch4); /* main */ void main() { Uint32 error=0; EDMA_Handle hEdma_ch4; short loop; float temp; /* initialize the CSL library */ CSL_init(); /* Calcola le costanti del Demodulatore */ Due_pi=8*atanf(1); Pi_mezzi=Due_pi/4; Punti_Canale=(short)sqrt(Punti_Costellazione); Bit_per_Canale=(short)log2f(Punti_Canale); Max_Ampiezza=Punti_Canale-1; /* Alloca memoria per il vettore valori Ampiezza */ Valori_Ampiezza=malloc(Punti_Canale*sizeof(float)); /* Genera i valori delle ampiezze per i 2 canali */ for (loop=0,temp=Max_Ampiezza;loop<Punti_Canale;loop++) { Valori_Ampiezza[loop]=(float)temp; temp-=2; } /* Cancella i Buffer */ Cancella_Buffer(); /* Genera la tabella del sin */ Gen_Tab_sen(); /* Setta la EMIF per le tempistiche del D/A */ /* legge i parametri correnti */ EMIF_getConfig(&emifadconfig); 147 /* Setta i parametri per lo spazio di indirizzamento di CE#2 */ emifadconfig.cectl2=0x21E1C423; /* Setta il registro della emif */ EMIF_config(&emifadconfig); /* Configura il dispositivo di EDMA */ error=cfg_edma(&hEdma_ch4); if (!error) { /* Inizializza il convertitore A/D */ dc_configure(&Ths1206_1); /* Abilita il canale 4 dell' EDMA */ EDMA_enableChannel(hEdma_ch4); /* setta gli interupt per il DMA */ set_interrupts_edma(); /* Cade nel BIOS idle loop */ return; } } /* Fine main */ /* Procedura Cancella_Buffer */ void Cancella_Buffer() { unsigned short *pingval; unsigned short *pongval; unsigned short i=0; pingval=(unsigned short *)MEM_DST_PING; pongval=(unsigned short *)MEM_DST_PONG; /* Azzera i 2 Buffer */ for (i=0;i<Buffer_Lenght;i++) { *pingval++=0; *pongval++=0; } CACHE_flush(CACHE_L2,(void*)MEM_DST_PING,Buffer_Lenght >> 1); CACHE_flush(CACHE_L2,(void*)MEM_DST_PONG,Buffer_Lenght >> 1); } /* Fine Cancella_Buffer */ /* set_interrupts_edma() */ void set_interrupts_edma(void) { 148 IRQ_nmiEnable(); IRQ_globalEnable(); IRQ_reset(IRQ_EVT_EDMAINT); IRQ_disable(IRQ_EVT_EDMAINT); EDMA_intDisable(4); /* ch 4 for EXT_INT4 event */ IRQ_clear(IRQ_EVT_EDMAINT); EDMA_intClear(4); IRQ_enable(IRQ_EVT_EDMAINT); EDMA_intEnable(4); return; } /* Fine set_interrupts_edma() */ /*Procedura Gen_Tab_sen()*/ void Gen_Tab_sen() /* Genera una LOOKUP TABLE per la funzione SIN */ /* La lunghezza è fissata a 1024 */ { const int Lunghezza=1024; short loop; double coefficente; coefficente=(Due_pi/(Lunghezza)); for (loop=0;loop<Lunghezza;loop++) { Tabella_sen[loop]=2*sin(coefficente*loop); //Calcola il valore di 2*sin } } /* Fine Gen_tab_sen */ /* SWI_Alta_Priorita */ void SWI_Alta_Priorita() /* Esegue i blocchi che devono operare */ /* a elevata frequenza */ { short *Buffer_IN; short *Buffer_Next; /* Carica il buffer da utilizzare */ if (Buffer_in_use) { Buffer_IN=(short *)MEM_DST_PONG; Buffer_Next=(short *)MEM_DST_PING; } 149 else { Buffer_IN=(short *)MEM_DST_PING; Buffer_Next=(short *)MEM_DST_PONG; } CACHE_clean(CACHE_L2,(void*)Buffer_Next,Buffer_Lenght >> 1); /* Chiama la procedura che si aggancia alla portante */ /* del segnale ricevuto e lo demodula */ Carrier_Recovery_and_Demodulator(Buffer_IN); }/* Fine SWI_Alta_Priorita */ /* SWI_Bassa_Priorita */ void SWI_Bassa_Priorita() /* Esegue i blocchi che devono operare */ /* a bassa frequenza */ { short Numero_Ripetizioni; short loop; /* Legge quante volte è stato chiamato il SWI */ Numero_Ripetizioni=SWI_getmbox(); for(loop=0;loop < Numero_Ripetizioni;loop ++) { /* Filtra I Segnali Decimati */ Matched_Filter(); /* Rigenera il Clock di Simbolo e campiona in tale istante */ Symbol_Clock_Recovery_and_Sample(); /*Verifica se il Buffer_Simboli è pieno */ /* e eventualmente chiama Decision_and_Decode() */ if (Simboli_Elaborati >= 64) { /* Decide i simboli ricevuti e li decodifica */ Decision_and_Decode(); /* Azzera il Buffer */ Simboli_Elaborati=0; /* Sincronizza il TX e l' RX correlando le 2 sequenze PN */ /* Valuta i simboli ricevuti Errati */ Error_Block(); /* Azzera il Buffer */ Bit_Elaborati=0; 150 } } }/* Fine SWI_Bassa_Priorita */ /* Carrier_Recovery_and_Demodulator() */ void Carrier_Recovery_and_Demodulator(short *Buffer_Ingresso) /* Costas Loop */ { const float Alfa_NCO=0.002; const float Beta_NCO=1e-7; const float Alfa_Filtro=0.015; const float Uno_meno_Alfa_Filtro=0.985; const int Decimazione=80; const float Coefficente_Scala=0.0012; int loop; int index_sen; int index_cos; static int elementi_inseriti_nel_buffer=0; static int Numero_Campione=0; float Segnale_Ingresso; float Uscita_Mixer_I; float Uscita_Mixer_Q; float Uscita_I_Lim; float Uscita_Q_Lim; static float Uscita_I=0; static float Uscita_Q=0; static float errore=0; static float fase_NCO=0; static float frequenza_NCO=1.181238838; static float coefficente; coefficente=1024/Due_pi; #pragma MUST_ITERATE(Buffer_Lenght,Buffer_Lenght); for(loop=0;loop < Buffer_Lenght;loop++) { /* Numeric Controlled Oscillator */ /* Calcola i valori di sin e cos per i Mixer */ fase_NCO+=errore*Alfa_NCO; 151 fase_NCO+=frequenza_NCO; frequenza_NCO+=errore*Beta_NCO; if (fase_NCO >= Due_pi) fase_NCO-=Due_pi; index_sen=(int)(fase_NCO*coefficente); index_cos=(index_sen+256)&1023; /* Scala il segnale di ingresso tra -1 e +1 */ Segnale_Ingresso=(float)((Buffer_Ingresso[loop]& 0xFFF)2047)*Coefficente_Scala; /* Mixer I */ Uscita_Mixer_I=Segnale_Ingresso*Tabella_sen[index_cos]; /* Filtro Ricorsivo I */ Uscita_I=Uscita_Mixer_I*Alfa_Filtro+Uscita_I*Uno_meno_Alfa_Filtro; /* Mixer Q */ Uscita_Mixer_Q=Segnale_Ingresso*Tabella_sen[index_sen]; /* Filtro Ricorsivo Q */ Uscita_Q=Uscita_Mixer_Q*Alfa_Filtro+Uscita_Q*Uno_meno_Alfa_Filtro; /* Calcola segnale errore */ Uscita_Q_Lim=Uscita_Q; Uscita_I_Lim=Uscita_I; if (Uscita_Q > 0.2) Uscita_Q_Lim=0.2; if (Uscita_I > 0.2) Uscita_I_Lim=0.2; if (Uscita_Q < -0.2) Uscita_Q_Lim=-0.2; if (Uscita_I < -0.2) Uscita_I_Lim=-0.2; errore=Uscita_I*Uscita_Q_Lim-Uscita_Q*Uscita_I_Lim; /* Ogni Decimazione Elementi ne sposta */ /* uno in uscita */ Numero_Campione++; if (Numero_Campione == Decimazione) { Numero_Campione=0; Buffer_OUT[elementi_inseriti_nel_buffer++]=Uscita_I; Buffer_OUT[elementi_inseriti_nel_buffer++]=-Uscita_Q; if ((elementi_inseriti_nel_buffer % 64)==0) { /* Chiama il SWI_BASSA_Priorita */ SWI_inc(&SWI_BASSA_Priorita); } /* Raggiunta la fine del Buffer si riporta all' inizio */ if (elementi_inseriti_nel_buffer == Buffer_OUT_Lenght) { elementi_inseriti_nel_buffer = 0; /* Verifica se deve cambiare la Fase */ if (Cambia_Fase) { fase_NCO+=Pi_mezzi; /* Azzera il Flag Cambia_Fase */ Cambia_Fase=0; } } 152 } } } /* Fine Carrier_Recovery_and_Demodulator() */ /* Matched Filter */ void Matched_Filter() /* Root Rised Cosine FIR Order 30 Fs=2500Hz Fc=250Hz */ { /* I coefficenti del filtro sono nel file RRC_Fir.h */ float Uscita_I_Filtro=0; float Uscita_Q_Filtro=0; static short Puntatore_IN=(Buffer_OUT_Lenght-((Fir_Lenght-1)*2)); short loop,loop1,inizio,indice; /* Elabora 32 Campioni Prelevati da Buffer_OUT */ /* Puntatore_IN corrisponde al punto in cui leggere*/ /* da Buffer_OUT */ for (loop=0;loop <32;loop++) { inizio=Puntatore_IN; #pragma UNROLL(Fir_Lenght); #pragma MUST_ITERATE(Fir_Lenght,Fir_Lenght); for (loop1=0;loop1 <Fir_Lenght;loop1++) { Uscita_I_Filtro+=Buffer_OUT[inizio++]*Coefficenti_Fir[loop1]; Uscita_Q_Filtro+=Buffer_OUT[inizio++]*Coefficenti_Fir[loop1]; inizio&=(Buffer_OUT_Lenght-1); } /* Scrive i valori calcolati nel buffer di uscita */ /* Buffer_OUT_Filter di 64 Elementi */ indice = loop << 1; /* moltiplica per 2 */ Buffer_OUT_Filter[indice++]=Uscita_I_Filtro; Buffer_OUT_Filter[indice]=Uscita_Q_Filtro; /* Azzera Uscita_I e Uscita_Q */ Uscita_I_Filtro=0; Uscita_Q_Filtro=0; /* Aggiorna il Puntatore a Buffer_OUT */ Puntatore_IN+=2; Puntatore_IN&=(Buffer_OUT_Lenght-1); } } /* Fine Matched_Filter() */ 153 /* Symbol_Clock_Recovery_and_Sample() */ void Symbol_Clock_Recovery_and_Sample() /* Early Late Synchronizer */ { #define Fattore_Interpolazione 2 const float Soglia=0.1; const float Alfa_Filter=0.2; const float Alfa_Interpolatore=0.3; const short Campioni_per_Simbolo=Fattore_Interpolazione*5; static short Campioni_Trascorsi=0; static float Campione_Precedente_I=0; static float Campione_Attuale_I=0; static float Campione_Successivo_I=0; static float Campione_Precedente_Q=0; static float Campione_Attuale_Q=0; static float Campione_Successivo_Q=0; static float Errore; float Errore_Istantaneo=0; float Campione_I=0; float Campione_Q=0; static float Campione_I_Filtrato=0; static float Campione_Q_Filtrato=0; short loop; short loop1; short index; /* Puntatore al campione in Buffer_OUT_Filter */ for (loop=0;loop < 32; loop++) { index=loop << 1; /*moltiplica per 2 */ for (loop1=0;loop1<Fattore_Interpolazione;loop1++) { if (loop1==0) { Campione_I=Buffer_OUT_Filter[index++]; Campione_Q=Buffer_OUT_Filter[index]; } /* filtro anti immagine */ Campione_I_Filtrato=Campione_I*Alfa_Interpolatore+ Campione_I_Filtrato*(1-Alfa_Interpolatore); Campione_Q_Filtrato=Campione_Q*Alfa_Interpolatore+ Campione_Q_Filtrato*(1-Alfa_Interpolatore); /* Aggiorna la linea di ritardo per il canale I */ 154 Campione_Successivo_I=Campione_Attuale_I; Campione_Attuale_I=Campione_Precedente_I; Campione_Precedente_I=Campione_I_Filtrato; /* Aggiorna il campione per il canale Q */ Campione_Successivo_Q=Campione_Attuale_Q; Campione_Attuale_Q=Campione_Precedente_Q; Campione_Precedente_Q=Campione_Q_Filtrato; /* Incrementa il numero dei campioni trascorsi */ Campioni_Trascorsi++; /* Verifica se è trascorso il Periodo di Simbolo */ if (Campioni_Trascorsi==Campioni_per_Simbolo) { Campioni_Trascorsi=0; /* Valuta l'errore */ Errore_Istantaneo=Campione_Successivo_I*Campione_Successivo_I -Campione_Precedente_I*Campione_Precedente_I; Errore=Errore_Istantaneo*Alfa_Filter+Errore*(1-Alfa_Filter); /* Decide se variare l'istante di campionamento */ if (Errore > Soglia) Campioni_Trascorsi=1; if (Errore < -Soglia) Campioni_Trascorsi=-1; /* Scrive i valori Campionati nel Buffer di Uscita */ Buffer_Simboli[Simboli_Elaborati++]=Campione_Attuale_I; Buffer_Simboli[Simboli_Elaborati++]=Campione_Attuale_Q; } } } } /* Fine Symbol_Clock_Recovery_and_Sample() */ /* Decision_and_Decode() */ void Decision_and_Decode() /* Decide il punto della costellazione */ /* Decodifica i simboli */ { float Campione_simbolo_I; float Campione_simbolo_Q; short loop; short index; short Simbolo_I; short Simbolo_Q; 155 for (loop=0 ;loop < (Simboli_Elaborati >> 1);loop++) { index=loop << 1; /* moltiplica per 2 */ Campione_simbolo_I=Buffer_Simboli[index++]; Campione_simbolo_Q=Buffer_Simboli[index]; /* Decide il simbolo ricevuto in base alla costellazione */ if (Campione_simbolo_I < 0) Simbolo_I =-1; else Simbolo_I =1; if (Campione_simbolo_Q < 0) Simbolo_Q =-1; else Simbolo_Q =1; /* Decodifica i simboli in codice Gray*/ /* Scrive in buffer Bit i bit calcolati */ if (Simbolo_I==-1) Buffer_Bit[Bit_Elaborati++]= 0; else Buffer_Bit[Bit_Elaborati++]= 1; if (Simbolo_Q==-1) Buffer_Bit[Bit_Elaborati++]= 1; else Buffer_Bit[Bit_Elaborati++]= 0; } }/* Fine Decision_and_Decode() */ /* Error_Block() */ void Error_Block() /* Genera una sequenza PN uguale a quella del TX */ /* Correla La Sequenza ricevuta con quella generata */ /* Se si aggancia accende il Led 1 */ /* Led 2 Te < 1e-4 Led 3 Te < 1e-5 */ { const short Soglia_corr=1; /*Soglia massima di errori su 32 bit per cons.*/ const short Soglia_Locked_loss=3; /*la sequenza agganciata */ const float Soglia_2=1e-4; const float Soglia_1=1e-5; short PN_bit; short RX_bit; short loop; 156 short loop_Principale; static short Led_1_acceso=0; static short Led_2_acceso=0; static short Led_3_acceso=0; short Errori_corr; /* bit errati tra i due buffer */ short Errori=0; /* errori nell' ultimo Buffer_Bit */ static Uint32 Buffer_bit_Generati=0xD6592401;/* Deve appartenere alla sequenza */ static Uint32 Buffer_bit_Ricevuti=0; static unsigned short Errori_Totali=0; /* errori totali sui bit ricevuti */ static unsigned int Bit_Ricevuti=0; /* bit totali ricevuti */ float Probabilita_errore=0; Uint32 Correlazione; /* Entra nel loop che verifica gli errori e si aggancia alla sequenza */ for (loop_Principale=0;loop_Principale <Bit_Elaborati;loop_Principale ++) { /* Carica un bit da Buffer_Bit */ RX_bit=Buffer_Bit[loop_Principale]; /* Aggiorna il buffer dei bit ricevuti */ Buffer_bit_Ricevuti=(Buffer_bit_Ricevuti << 1) | RX_bit; if(Locked) { /* Genera un bit della sequenza */ PN_bit=PN_Generator(); /* Aggiorna il buffer dei bit generati */ Buffer_bit_Generati=(Buffer_bit_Generati << 1) | PN_bit; /* Verifica se c'è stato un errore */ if (RX_bit ^ PN_bit) { Errori++; Errori_Totali++; } /* Incrementa il numero dei bit ricevuti */ Bit_Ricevuti++; /* Accende i LED i base al Tasso di errore */ Probabilita_errore=(float)Errori_Totali/(float)Bit_Ricevuti; if ((Probabilita_errore <= Soglia_1) && (Led_3_acceso==0)) { LED3_on; Led_3_acceso=1; Led_1_acceso=0; Led_2_acceso=0; } if ((Probabilita_errore <= Soglia_2) && (Led_2_acceso==0)&& (Probabilita_errore > Soglia_1)) { 157 LED2_on; Led_2_acceso=1; Led_1_acceso=0; Led_3_acceso=0; }; if ((Led_1_acceso==0)&&(Led_2_acceso==0)&&(Led_3_acceso==0)) { LED1_on; Led_1_acceso=1; Led_2_acceso=0; Led_3_acceso=0; } /* Verifica se si è superata la soglia degli errori */ if (Errori >= Soglia_Locked_loss) { LOG_printf(&trace,"Bit Errati:%d su Bit Ricevuti:%d",Errori_Totali,Bit_Ricevuti); Locked=0; Spegni_Led; Bit_Ricevuti=0; Errori_Totali=0; Errori=0; Led_1_acceso=0; Led_2_acceso=0; Led_3_acceso=0; } } else { /* Effettua una correlazione parziale su 32 Bit di Sequenza */ Correlazione=Buffer_bit_Generati ^ Buffer_bit_Ricevuti; /* Calcola quanti Bit errati ci sono nella sequenza */ Errori_corr=0; for (loop=0;loop <32;loop ++) { if (Correlazione & 1) Errori_corr++; Correlazione>>= 1; } /* Verifica se la sequenza è agganciata */ if (Errori_corr < Soglia_corr) { Locked=1; } } } }/* Fine Error_Block */ 158 /* PN_Generator */ int PN_Generator() /* Ritorna un Bit generato con una sequenza PN di lunghezza 1023 */ { #define IB1 0x0001 #define IB3 0x0004 #define IB10 0x0200 #define MASK (IB3) /* seme di partenza */ /* in PN i 10 LSB sono significativi */ static short PN=0x0409; if (PN & IB10) { /*Cambia tutti i bit mascherati shifta e mette 1 nel bit 1 */ PN=((PN ^ MASK) << 1) | IB1; return 1; } else { /*Shifta e mette 0 nel bit 1 */ PN <<= 1; return 0; } }/* Fine PN_Generator */ /* Cambia_Fase_PLL() */ void Cambia_Fase_PLL() /* Cambia di 90° la fase del PLL */ { if (!Locked) Cambia_Fase=1; }/* Fine Cambia_Fase_PLL */ Configurazione.h /****************************************************************/ /* Scritto da Raffaele Rugin */ /* il 23/02/2002 */ /* Configurazione.h contiene tutti i parametri globali del */ /* demodulatore */ /****************************************************************/ /* Parametri EDMA */ #define Buffer_Lenght 1024 */ /* N° campioni buffer 159 #define Ripetizioni 128 /* N° di letture dall 'A/D per riempire */ /* il buffer */ /* Parametri A/D */ #define Bit_AD 12 /* N° di bit del convertitore A/D */ /* Parametri Demodulatore */ #define Punti_Costellazione 4 /* N° di punti della Costellazione*/ #define Buffer_OUT_Lenght 256 /* Lunghezza buffer campioni demodulati */ dc_conf.h #ifndef DC_CONF_H #define DC_CONF_H /* ADC 1 parameter data */ #define ADC1_TYPE THS1206 #define ADC1_CR0_VALUE (0x00) #define ADC1_CR1_VALUE (0xB8) #define ADC1_TRIGGER_LEVEL (8) #define ADC1_NR_CHANNEL (1) #define ADC1_SAMPLE_FREQ (200) #define ADC1_SHIFT (0) #define ADC1_INTNUM (4) #define ADC1_BUS_NONE /* EMIF Interface parameters */ #define ADC1_ADDRESS (0xA0000000) #define ADC1_RDSETUP (1) /* read */ #define ADC1_RDSTRB (4) #define ADC1_RDHLD (1) #define ADC1_WRSETUP (4) /* write */ #define ADC1_WRHLD (6) #define ADC1_WRSTRB (3) #define ADC1_TIM_PERIOD (0x005D) /* DSP parameter data */ #define TMS320C6711 /* CSL device build option */ #define CHIP_6711 (1) #define DSP_FREQ (150) /* in MHz */ /* McBSPs parameter data #endif /* DC_CONF_H */ */ 160 edma.c /*****************************************************************/ /* Scritto da Raffaele Rugin */ /* il 23/02/2002 */ /* Edma.c Usa il canale N° 4 dell' EDMA riservato */ /* per gestire il dispositivo THS1206 usando il segnale EXT_INT4 */ /* per sincronizzare il trasferimento dati. */ /* Il canale 4 dell'EDMA è programmato in modo tale da */ /* trasferire in modo continuo e indipendente dalla CPU i */ /* campioni ricevuti e depositati in una coppia di buffer */ /* Una opportuna ISR seleziona alternativamente uno dei 2 buffer */ /* come destinazione del trasferimento al fine di permettere alla*/ /* CPU di leggere i campioni ricevuti senza interferire con */ /* il dispositivo di EDMA. */ /*****************************************************************/ /* Librerie */ #include "Configurazione.h" #include "dc_conf.h" #include <csl.h> #include <csl_edma.h> /* Parametri globali del modulatore */ /* Definizioni */ /* Prototipi */ Int32 cfg_edma(EDMA_Handle *hEdma_ch4); /**************************cfg_edma******************************/ /* Programma il canale 4 per servire il trasferimento dall' A/D */ /****************************************************************/ Int32 cfg_edma(EDMA_Handle *hEdma_ch4) { extern far Uint16 MEM_DST_PING[]; extern far Uint16 MEM_DST_PONG[]; Uint32 Collegamento_Ping_Rx; Uint32 Collegamento_Pong_Rx; EDMA_Config Configurazione; EDMA_Handle hEdma_Ping_Rx; EDMA_Handle hEdma_Pong_Rx; if(!EDMA_allocTableEx(1,&hEdma_Ping_Rx)) return(-1); Collegamento_Ping_Rx=EDMA_getTableAddress(hEdma_Ping_Rx); 161 if(!EDMA_allocTableEx(1,&hEdma_Pong_Rx)) return(-1); Collegamento_Pong_Rx=EDMA_getTableAddress(hEdma_Pong_Rx); *hEdma_ch4=EDMA_open(4,EDMA_OPEN_RESET); /*Configura il canale di Ricezione (4)*/ Configurazione.opt = (Uint32) (( EDMA_OPT_PRI_HIGH << _EDMA_OPT_PRI_SHIFT ) | (EDMA_OPT_ESIZE_16BIT << _EDMA_OPT_ESIZE_SHIFT ) | (EDMA_OPT_2DS_NO << _EDMA_OPT_2DS_SHIFT ) | (EDMA_OPT_SUM_NONE << _EDMA_OPT_SUM_SHIFT ) | (EDMA_OPT_2DD_NO << _EDMA_OPT_2DD_SHIFT ) | (EDMA_OPT_DUM_INC << _EDMA_OPT_DUM_SHIFT ) | (EDMA_OPT_TCINT_YES << _EDMA_OPT_TCINT_SHIFT ) | (EDMA_OPT_TCC_OF(4) << _EDMA_OPT_TCC_SHIFT ) | (EDMA_OPT_LINK_YES << _EDMA_OPT_LINK_SHIFT ) | (EDMA_OPT_FS_YES << _EDMA_OPT_FS_SHIFT )); Configurazione.src = (Uint32)ADC1_ADDRESS; // Ind. Sorg. PING EDMA Configurazione.cnt = (Uint32) ((EDMA_CNT_FRMCNT_OF(Ripetizioni-1) << _EDMA_CNT_FRMCNT_SHIFT) | (EDMA_CNT_ELECNT_OF(ADC1_TRIGGER_LEVEL)<< _EDMA_CNT_ELECNT_SHIFT)); Configurazione.dst = (Uint32)MEM_DST_PING; // Ind. Dest. EDMA Configurazione.idx = (Uint32)0x0000; Configurazione.rld = (Uint32)((EDMA_RLD_LINK_OF(Collegamento_Pong_Rx & 0xffff) << _EDMA_RLD_LINK_SHIFT)); EDMA_config(*hEdma_ch4,&Configurazione); EDMA_config(hEdma_Ping_Rx,&Configurazione); Configurazione.dst = (Uint32)MEM_DST_PONG; //Ind. Dest. PONG EDMA Configurazione.rld = (Uint32) ((EDMA_RLD_LINK_OF(Collegamento_Ping_Rx & 0xffff) << _EDMA_RLD_LINK_SHIFT)); EDMA_config(hEdma_Pong_Rx,&Configurazione); return(0); } /* fine cfg_edma */ Edma_ISR.s62 ; Scritto da Raffaele Rugin ; 24/02/2002 ; ======== Edma_ISR.s62 ======== ; .include "hwi.h62" ; macro header file .include "c62.h62" .include "swi.h62" 162 IEMASK .set 0xFFFF CCMASK .set C62_PCC_ENABLE CIPR_ADDR .set 0x01A0FFE4 ;indirizzo per il registro CIPR CIPR_SET .set 0x0000010 ;Reset per il ch 4 dell CIPR .text ; ; ======== EDMA ISR ======== ; .global _Edma_ISR,_Buffer_in_use,_SWI_ALTA_Priorita,fine _Edma_ISR: HWI_enter C62_ABTEMPS,0, IEMASK, CCMASK ;Setta la variabile Buffer_in_use per il nuovo buffer da utilizzare mvkl _Buffer_in_use,b0 ;carica l'indirizzo della variabile buffer mvkh _Buffer_in_use,b0 ldw *b0,b1 ;carica la variabile buffer nop 4 ;attende che il dato sia disponibile xor b1,1,b1 ;setta il nuovo buffer da usare stw b1,*b0 ;scrive la variabile buffer in memoria ;Resetta il Channel Interrupt Pending Register del canale 4 ;dell edma mvkl CIPR_ADDR,a0 ;carica l'indirizzo del CIPR mvkh CIPR_ADDR,a0 mvkl CIPR_SET,a1 ;carica il valore di CIPR_SET mvkh CIPR_SET,a1 ldw *a0,a2 ;carica il valore del registro CIPR xor a2,a1,a2 ;aggiunge CIPR_SET stw a2,*a0 ;scrive il valore calcolato nel registro CIPR ;Schedula il SWI che si occupa di riempire il buffer scelto con ;i nuovi valori calcolati mvkl _SWI_ALTA_Priorita,a4 ;carica l'indirizzo del SWI_Alta_Priorita mvkh _SWI_ALTA_Priorita,a4 SWI_post ;Schedula l'interrupt Software Demodula mvkl fine,b3 ;carica l'indirizzo di fine mvkh fine,b3 nop 3 fine: HWI_exit C62_ABTEMPS,0, IEMASK, CCMASK .end 163 Procedura di zero crossing per il recupero del sincronismo di simbolo /* Symbol_Clock_Recovery_and_Sample() */ void Symbol_Clock_Recovery_and_Sample() /* Zero Cross Synchronizer */ { #define Delay_Lenght 6 const float Soglia=0.15; const float Alfa_PLL=0.05; const float Alfa_Interpolatore=0.3; const short Campioni_per_Simbolo=10; static short Campioni_Trascorsi=0; static float Delay_Line_I[Delay_Lenght]; static float Delay_Line_Q[Delay_Lenght]; static float Errore_Filtrato=0; static float Campione_Filtrato_I=0; static float Campione_Filtrato_Q=0; float Campione_I; float Campione_Q; float Errore_Istantaneo; float Successivo_I; float Attuale_I; float Precedente_I; short Errore_Usato=0; short loop; short loop1; short loop2; short index; /* Puntatore al campione in Buffer_OUT_Filter */ for (loop=0;loop < 32; loop++) { index=loop << 1; /* moltiplica per 2 */ /* Interpola per 2 i campioni in ingresso */ for (loop2=0;loop2 <2;loop2++) { if (loop2==0) { Campione_I=Buffer_OUT_Filter[index++]; Campione_Q=Buffer_OUT_Filter[index]; } /* Interpola i segnali */ Campione_Filtrato_I=Campione_I*Alfa_Interpolatore+ Campione_Filtrato_I*(1-Alfa_Interpolatore); 164 Campione_Filtrato_Q=Campione_Q*Alfa_Interpolatore+ Campione_Filtrato_Q*(1-Alfa_Interpolatore); /* Aggiorna la linea di ritardo per il canale I e Q */ for (loop1=Delay_Lenght-1;loop1>0;loop1--) { Delay_Line_I[loop1]=Delay_Line_I[loop1-1]; Delay_Line_Q[loop1]=Delay_Line_Q[loop1-1]; } /* Carica due nuovi valori */ Delay_Line_I[0]=Campione_Filtrato_I; Delay_Line_Q[0]=Campione_Filtrato_Q; /* Incrementa il numero dei campioni trascorsi */ Campioni_Trascorsi++; /* 0 Campione successivo */ Successivo_I=Delay_Line_I[0]; /* 1 Campione attuale */ Attuale_I=Delay_Line_I[1]; /* 2 Campione precedente */ Precedente_I=Delay_Line_I[2]; /* Verifica di essere in un passaggio per lo zero */ if (((Successivo_I>0)&&(Precedente_I<0)) || ((Successivo_I<0)&&(Precedente_I>0))) { Errore_Istantaneo=Attuale_I; /* Filtra l'errore */ Errore_Filtrato= Errore_Istantaneo*Alfa_PLL+Errore_Filtrato*(1-Alfa_PLL); Errore_Usato=0; } /* Verifica se è trascorso il Periodo di Simbolo */ if (Campioni_Trascorsi==Campioni_per_Simbolo) { Campioni_Trascorsi=0; /* Decide se variare l'istante di campionamento */ if (Errore_Usato==0) { if (Errore_Filtrato > Soglia) Campioni_Trascorsi=1; if (Errore_Filtrato < -Soglia) Campioni_Trascorsi=-1; Errore_Usato=1; } /* Scrive i valori Campionati nel Buffer di Uscita */ Buffer_Simboli[Simboli_Elaborati++]=Delay_Line_I[Delay_Lenght-1]; Buffer_Simboli[Simboli_Elaborati++]=Delay_Line_Q[Delay_Lenght-1]; } } } } /* Fine Symbol_Clock_Recovery_and_Sample() */ 165 RRC_Fir.h /* Raffaele Rugin 18/04/2002 */ /* Coefficenti del filtro FIR TX Root Rised Cosine 2.5KHz Fs 250Hz Fc 31 Taps*/ #define Fir_Lenght 31 /* Numero di coefficenti del filtro FIR const float Coefficenti_Fir[Fir_Lenght] = { 0.0006063045585, -0.002680619946, -0.003889523447, -0.001077757566, 0.004563248716, 0.008488263935, 0.005343637429, -0.006789231207, -0.02308195643, -0.03223999217, -0.02122065984, 0.0175157506, 0.08012024313, 0.1505657285, 0.2061932236, 0.2273239493, 0.2061932236, 0.1505657285, 0.08012024313, 0.0175157506, -0.02122065984, -0.03223999217, -0.02308195643, -0.006789231207, 0.005343637429, 0.008488263935, 0.004563248716, -0.001077757566, -0.003889523447, -0.002680619946, 0.0006063045585}; 166 */
Documenti analoghi
Documenti_Sistemi a microprocessore - Parte I
In linea di principio entrambe le memorie possono essere considerate come un insieme di “contenitori” in ognuno dei quali viene registrata, in forma binaria, una informazione; questi contenitori
ve...