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
*/