• Non ci sono risultati.

CAPITOLO III Simulatore del Sistema MC-CDMA con Generatore di Traffico

N/A
N/A
Protected

Academic year: 2021

Condividi "CAPITOLO III Simulatore del Sistema MC-CDMA con Generatore di Traffico"

Copied!
35
0
0

Testo completo

(1)

Simulatore del Sistema

MC-CDMA con Generatore di Traffico

III.1 Introduzione

In questo capitolo sarà descritto il cuore del funzionamento del simulatore del sistema MC-CDMA integrato con il generatore di traffico. Il simulatore completo ha una struttura abbastanza complicata: insieme al programma principale (simulatorepred.cpp) interagiscono diverse altre funzioni; prima tra tutte, la gentraf.h che implementa il generatore di traffico: tuttavia tale funzione non rappresenta nessuno dei due programmi descritti nel Capitolo II (la versione base e la sua variante) che erano comunque programmi indipendenti, questa terza versione è stata adeguatamente adattata per cooperare con il simulatore MC-CDMA, come una sua funzione che viene richiamata ad ogni ciclo. Sono da considerare poi altre due importanti funzioni che provvedono al corretto funzionamento e monitoraggio del programma: sono la funzione “PowerAnalysis” e la “Predistorsore”: la prima si occupa del calcolo della potenza d’ingresso all’HPA e della potenza all’uscita, inoltre implementa il calcolo del Back-Off; la seconda invece realizza l’algoritmo adattativo del sistema di predistorsione.

In questo terzo capitolo si analizzerà in maniera esaustiva il funzionamento del simulatore in ogni sua parte e componente, vedremo dei diagrammi a blocchi che consentiranno di capire come le varie funzioni cooperino tra di loro per restituire dei valori finali significativi come la BER (Bit Error Rate) o dei file di uscita che visualizzano i diagrammi IQ dei simboli ricevuti o dei baricentri acquisiti (si spiegherà a

(2)

breve che cosa si intenda per baricentro). Pertanto il presente capitolo è prettamente descrittivo, i risultati delle simulazioni vengono momentaneamente omessi poiché saranno trattati in maniera esaustiva nel capitolo finale.

III.2 Cicli del Simulatore MC-CDMA

Il simulatore del sistema MC-CDMA inizia con la lettura del file d’ingresso “MC-CDMA Input.txt” dove sono contenuti tutti i dati essenziali alla definizione delle varie caratteristiche del simulatore stesso; vediamo un esempio di tale file in Fig. III.1:

****************************** ***Impostazioni Calcolo BER*** ******************************

Eb/N0 [dB] ( Starting, Step, Number of points ): 10,2,1

Massimo numero di blocchi da trasmettere: 9000000

Massimo numero di bit errati: 9000000

************************** ***Impostazioni Sistema*** ************************** Tipo di modulazione (P = Psk, Q = Qam): Q

Punti costellazione: 16

Numero di sottoblocchi di simboli d'informazione (Ns): 1

Dimensione dei sottoblocchi (L)(min L=16, max L=256): 256

Lunghezza prefisso ciclico: 64

Numero di campioni per intervallo di chip (NcIc): 8

Durata del filtro di trasmissione in intervalli si segnalazione (Dur): 20

Roll Off (RO): 0.125

Intervallo di Segnalazione (nsec): 50 ************************* ***Impostazioni Utenti*** ************************* Numero utenti: 256

Seme per l'allocazione degli utenti: 11478

Allocazione codici di Walsh-Hadamard (0=Guidata / 1=Dall'ultima linea a salire / 2=Random): 2

****************************** ***Impostazioni Nonlinerità*** ****************************** Accensione Nonlinearità (0 Off / 1 On) 1

Tipo di amplificatore: R

(3)

Fig. III.1 - “MC-CDMA Input.txt” Back-Off di ingresso (IBO):

3

Numero di blocchi per il calcolo delle potenze medie: 2000

Valore di partenza della costante di normalizzazione della potenza media (Kappa): 0.5 Passo di Kappa: 0.01 ************************* ***Impostazioni Canale*** *************************

Accensione generatore di rumore (0 spento, 1 acceso): 1

Seme del rumore: 773710487

***************************** ***Impostazioni Generatore*** ***************************** Lunghezza Tblocco (secondi): 0.000016

Tempo Medio di permanenza del Real Time (secondi): 180

Tempo Medio di permanenza dello Streaming (secondi): 180

Tempo Medio di permanenza dei Dati (secondi): 60

Tasso di Arrivo di un Utente Real Time (arrivi/secondo): 0.1009

Tasso di Arrivo di un Utente Streaming (arrivi/secondo): 0.053

Tasso di Arrivo di un Utente Dati (arrivi/secondo): 0.1816

Numero di Portanti Totali: 256

Numero di Sottoportanti (inutile per MC-CDMA): 16

Tipo di allocazione codice (0=Random, 1=Ordinata da File): 1

************************** ***Impostazioni Monitor*** ************************** Interruttore su Monitor1 (0=off 1=on): 0

Interruttore su Monitor2 (0=off 1=on): 0

Interruttore su Monitor3 (0=off 1=on): 0

Interruttore su Monitor4 (0=off 1=on): 0

******************************** ***Impostazioni Predistorsore*** ******************************** Interruttore sul Predistorsore (0=off 1=on): 1

Numero di cicli effettuati del predistorsore: 100

Step size del predistorsore: 0.5

Soglia del predistorsore: 0.1

Quantizzazione costellazione Interferenti (primo,secondo,terzo): 1,1,1

Monitoraggio Potenza-BackOff (0 off/1 on) 0

Monitoraggio Warping-Clustering Predistorsore - Stampa Costellazione Predistorta(0 off/1 on) 0

Stampa evoluzione DiagrammaIQ-Baricentri per un utente (0 off/1 on, numero utente) 0,0

Monitoraggio BER (0 off/1 on, intervallo di controllo in secondi) 0,3600

(4)

Come si vede dalla figura, il file fornisce informazioni innanzitutto per quanto riguarda la

BER (Bit Error Rate) pertanto indicherà il valore del rapporto segnale-rumore a cui il

sistema dovrà lavorare, quanti blocchi OFDM dovrà inviare, quanti errori saranno tollerati; ci sono poi informazioni più specifiche per il trattamento dei simboli: il tipo di modulazione prevista (16 QAM), la grandezza della costellazione, il numero di punti della costellazione, la lunghezza del prefisso ciclico che serve per controllare l’ISI (Interferenza Inter-Simbolica), il fattore di Spreading (L=256) del sistema, le caratteristiche dei filtri, la sagomatura (RRCR), il valore del roll-off, la durata di un simbolo (o intervallo di segnalazione=50nsec); seguono informazioni riguardanti gli

utenti: il numero di utenti massimo previsto dal sistema (Nu=L), il tipo di allocazione

seguita dagli utenti (guidata o random); impostazioni sulla non-linearità: un tasto per accendere e spegnere la non-linearità stessa, il tipo di amplificatore usato, il Back-Off d’ingresso (IBO); impostazioni di canale: se il rumore c’è oppure no; impostazioni sul

generatore di traffico: questa parte ricalca in maniera abbastanza coerente le grandezze

d’ingresso per il generatore così come visto nel Capitolo II, pertanto contiene il valore di Tblocco, i tassi di arrivo, i tempi medi di servizio, il tipo di allocazione, il numero di portanti (che coincide anche questo con L); ci sono inoltre dei valori che consentono di attivare o meno tutta una serie di monitor che implementano una sorta di debug nei punti più critici di tutto il sistema; infine ci sono le informazioni riguardanti il predistorsore: un tasto per accenderlo e spegnerlo, il numero di cicli necessari per acquisire i baricentri, lo step-size del predistorsore, la soglia di tolleranza del predistorsore, la complessità del predistorsore. I vari termini saranno più chiari una volta preso in esame ogni singolo blocco del sistema.

Il programma legge il file d’ingresso e per ciascun termine associa una memoria corrispondente al valore indicato.

Finita la prima fase di lettura dei dati, si passa all’inizializzazione delle memorie dinamiche: i primi elementi che vengono inizializzati, al di fuori di ogni ciclo del sistema, sono quelli relativi al generatore di traffico:

(5)

for (i=0; i<Nu+1; i++) { UTENTI[i]=0; EXIT[i]=Nu; AUX[i]=0; DURATA[i]=0; UTILIZZOCODE[i]=0; }

pertanto si assume che il simulatore parta da una situazione iniziale in cui nessun utente è presente al suo interno: il vettore UTENTI è posto a zero, dunque nessun codice è assegnato ( EXIT[i]=Nu ), nessun codice è occupato ( AUX[i]=0 ), non sono assegnati i valori di DURATA del servizio e pure il vettore che conta l’utilizzo dei codici nel tempo è azzerato; si ricordi che abbiamo definito Nu=L e si noti che la dimensione di questi vettori è pari a L+1, questo perché EXIT[i] talvolta rappresenterà l’argomento di altri vettori ad esempio:

UTENTI[EXIT[i]]

Se EXIT[i]=Nu=256 e se la dimensione di UTENTI fosse Nu, si verificherebbe un memory fault, ossia si andrebbe a cercare un valore che non esiste, in quanto gli indici del vettore UTENTI[Nu] andrebbero da 0 a Nu-1 (da 0 a 255), pertanto la dimensione viene settata a Nu+1. In seguito verranno usati i valori L e Nu in maniera interscambiabile: anche se rappresentano parametri distinti (rispettivamente il fattore di Spreading e il numero di utenti massimo) il sistema è pensato perché ci sia una corrispondenza uno a uno, pertanto nel seguito si preferisce riferirci ad uno solo dei due, ricordando che rappresentano lo stesso valore.

Prima di entrare nel ciclo principale devono essere caricati altri valori: nella matrice

CrossMat vengono inseriti i valori di cross-correlazione dei codici ( è una matrice

quadrata di dimensione L), nel vettore AllocTree[L] risiedono i codici ordinati secondo il metodo di allocazione guidata. Le cross-correlazioni vengono calcolate come spiegato nel

(6)

Capitolo I, invece per definire l’ordine di allocazione ottima esiste un algoritmo la cui

descrizione esula dagli scopi della presente trattazione [], infine sulla matrice Valori vengono caricati i valori di fase e quadratura dei simboli in maniera coerente alla modulazione definita nel file d’ingresso.

A questo punto si entra nel primo ciclo del programma: il simulatore è costituito da una serie di cicli annidati che realizzano lo stesso tipo di operazioni al variare di una certa grandezza, si faccia riferimento alla Fig. III.2.

MAIN

Fig.III.2 – Schema del Simulatorepred.cpp

Ind=IBO

While (Ind<=IBO) CICLO IBO Cont_block[curr_point]=0

NerrCODE[codice][curr_point]=0 NerrfCODE[codice][curr_point]=0 NerrqCODE[codice][curr_point]=0

For (curr_point=0 ; curr_point<max_point ; curr_point++) CICLO Eb/N0

Ind++ Ind++

VettSomma[i][codice]=0 VettNum[i][codice]=0 Cont [codice]=0

While (cont_block[curr_point]<max_block) CICLO BLOCCHI

Cont_block[curr_point]++ Cont_block[curr_point]++ GENERATORE TRAFFICO PREDISTORSORE POWERANALYSIS CALCOLO INTERFERENTI CALCOLO BER

(7)

I cicli annidati sono principalmente tre: un ciclo sul valore dell’IBO (Input Back-Off), un ciclo sul valore di Eb/N0, e un ciclo sui Blocchi OFDM. Il primo è previsto nel caso in cui si voglia ripetere le simulazioni per molti valori di IBO, tipicamente si potrebbe voler partire da un valore iniziale di 1dB per arrivare ad un valore massimo di 6 dB: il Back-Off d’ingresso rappresenta la distanza che intercorre tra la potenza in ingresso all’HPA e la potenza di saturazione d’ingresso dell’HPA. Ovviamente più è grande tale valore più ci si trova nella zona di linearità dell’amplificatore; ora, poiché il predistorsore, e dunque il sistema MC-CDMA, deve operare in condizioni di linearità ma soprattutto in condizioni di non-linearità (IBO piccolo) si rende necessario analizzare il comportamento su un certo range di valori di IBO, per fare un confronto. Per questo il sistema è predisposto in modo tale che ad ogni nuovo valore di IBO a cui si voglia lavorare, le grandezze che dipendono da questo valore vengano azzerate e dunque:

for (i=0; i<max_point; i++) cont_block[i]=0;

for (codice=0; codice<L; codice++)

for (i=0; i<max_point; i++) {

NErrCODE[codice][i]=0; NErrfCODE[codice][i]=0; NErrqCODE[codice][i]=0; }

Il vettore cont_block[i] conta il numero di blocchi che sono stati trasmessi per l’attuale valore di IBO e per l’attuale valore di Eb/N0; coerentemente con il file d’ingresso di Fig.

III.1 verranno trasmessi 9 milioni di blocchi per ciascun valore di Eb/N0 e per ciascun

valore di IBO; ora in questo caso si è interessati ad unico valore di IBO=3dB e ad un unico valore di Eb/N0 pertanto i cicli su IBO e su Eb/N0 vengono iterati una sola volta ciascuno. Gli altri tre vettori contano il numero di errori che si verificano complessivamente, sul ramo in fase e sul ramo in quadratura: tali valori saranno utili per il calcolo delle BER alla fine della simulazione, ora poiché un valore di BER viene calcolato in corrispondenza di un certo IBO e di un certo valore di Eb/N0 è opportuno che tali vettori vengano riazzerati ogni volta in questa sede.

(8)

for (codice=0; codice<(2*num_utenti); codice+=2)

for (i=0; i<largecost; i++) {

Vettsomma[i][codice]=0; Vettsomma[i][codice+1]=0; VettNum[i][codice/2]=0; }

for (codice=0; codice<(2*num_utenti); codice+=2

for (i=0; i<cost; i++) {

VettsommaCluster[i][codice]=0; VettsommaCluster[i][codice+1]=0; VettNumCluster[i][codice/2]=0; }

for (codice=0; codice<L; codice++) cont[codice]=0;

Il vettore Vettsomma serve in sede di ricezione, in questa memoria verranno sommati i

simboli ricevuti separati secondo un certo ordine che sarà più chiaro nel paragrafo

successivo. VettNum esegue la stessa operazione ma sui simboli appena generati anziché su quelli ricevuti, il rapporto tra posizioni corrispondenti di due vettori fornirà il Baricentro necessario all’algoritmo di predistorsione. Ovviamente tali vettori devono essere riazzerati ogni volta che il predistorsore compie un’iterazione e fornisce il valore del Baricentro, dopodiché tali memorie possono essere ripulite: questo però avviene solo dopo che il predistorsore ha agito e pertanto all’interno del ciclo sui blocchi. In questa sede però è importante inizializzare tali memorie cosicché il primo ciclo del predistorsore di ogni nuovo valore di Eb/N0 non usi valori residui dei vettori VettNum e Vettsomma dell’ultimo ciclo dei blocchi provenienti dal valore di Eb/N0 precedente.

Infine esiste anche un contatore per ogni codice che viene usato, questo perché la prima volta che si usa un codice non sono disponibili i valori delle costellazioni predistorte, in tal caso l’aggiornamento della costellazione predistorta non può avvenire, allora si usano i valori della costellazione nominale.

Infine inizia il ciclo sui blocchi; all’interno del ciclo dei blocchi avviene la trasmissione vera e propria ed è qui che si trova la versione del sistema di rice-trasmissione così come è stato descritto nel Capitolo I. Per descrivere meglio il funzionamento di questa parte del programma ci si atterrà a quanto scritto nel file d’ingresso di Fig. III.1 e dunque

(9)

supporremo di lavorare con un solo ciclo di IBO ed un solo ciclo di Eb/N0 e con un solo sottoblocco (Ns=1). Prima di analizzare in maniera completa il sistema però, è necessario descrivere le funzioni che vengono impiegate al suo interno: Poweranalysis,

Predistorsore, Calcolo Interferenti e Calcolo BER.

III.3 Funzione Poweranalysis

La funzione Poweranalysis è in grado di lavorare in due modalità: una con predistorsore e una senza; entrambe le modalità risultano utili all’interno del simulatore poiché vengono richiamate in circostanze diverse. Per adesso ci si limiterà a descrivere le due modalità mentre si spiegherà piu avanti quando queste debbano essere usate. Agendo sul parametro pred2 si sceglie se usare la versione senza predistorsore (pred2=0) oppure quella con predistorsore (pred2=1). Per capire meglio quali sono le azioni compiute da questa funzione nei due casi, si considerino da principio i parametri che vengono passati di volta in volta; il primo parametro è il vettore Calc[] che ha dimensione 3 e contiene i seguenti valori: a partire dal valore attuale di IBO espresso in dB si passa al suo valore lineare mediante l’espressione:

IBOlin= 10 IBOdB

10

dopodiché si ricava dal valore di IBOlin il valore della costante di attenuazione, ossia considerando la potenza si saturazione d’ingresso normalizzata, la corrispondente potenza d’ingresso può essere così espressa:

IBOlin= Psat ,in

Pin in cui Psat ,in = 1 e Pin = 1! K

2

(10)

K = 1 IBOlin

a cui si assegna il valore di Calc[1]. Gli altri due valori di Calc[0] e Calc[2] rappresentano invece valori di uscita della funzione stessa: la potenza d’ingresso all’HPA e la potenza d’uscita.

Successivamente ci sono una serie di valori che servono per ottenere una replica esatta del sistema di trasmissione così come lo si trova nel main: dunque avremo informazoni sul tipo di modulazione, sul numero di utenti, sul prefisso ciclico, sul filtro di trasmissione e sul tipo di amplificatore di potenza. Poi ci saranno le informazioni riguardanti lo stato degli utenti che cambiano ad ogni ciclo a causa del generatore di traffico: quanti utenti sono attivi (su_attuale, PRIMA, DOPO) e soprattutto quali utenti sono attivi (vettore EXIT dei codici). Infine tutte le informazioni necessarie all’aggiornamento della costellazione con quella predistorta (che verranno realmente utilizzate solo nel caso pred2=1): il vettore degli interferenti (interf2), i valori della costellazione predistorta (b_fase e b_quad, calcolati dalla funzione Predistorsore, come si vedrà più avanti), la complessità a cui lavora il predistorsore (CostInterf20, CostInterf21, CostInterf22). I parametri che riguardano il predistorsore servono per far lavorare la funzione nella modalità con pred2=1 e ricreano pertanto l’aggiornamento della costellazione con quella predistorta: l’unica differenza tra le due modalità è rappresentata dal tipo di simboli su cui le potenze vengono calcolate, nel caso pred2=0 i risultati vengono calcolati sui simboli della costellazione, nel caso pred2=1 vengono calcolati sui simboli predistorti.

Dopo aver esaminato le grandezze in ingresso alla funzione si analizza il funzionamento facendo ricorso al diagramma in Fig. III.3:

(11)

Calc[1] Ciclo su cont Gen. Simboli B_fase B_quad Pred2=? Aggiornamento Con costellazione predistorta 1 0 SPREAD ING IFFT PREFIX Filtro TX 1 0 Calc[0] Cont=? Normal De-Normal HPA Calc[2] OBO

Fig. III.3 – Funzione Poweranalysis Trasm2

Trasm22

StrasmFase STrasmQuad

(12)

Lo schema compie due cicli di cont. Come prima cosa si provvede a creare i simboli d’ingresso, ora il generatore del main e quello della funzione sono inizializzati con lo stesso seed e lavorano in modo contemporaneo, pertanto i simboli del programma e della funzione coincidono (questo perché le sequenze che vengono create sono pseudo-casuali e non completamente random). I simboli (fase e quadratura) vengono memorizzati in due memorie distinte: Trasm2 e Trasm22; la prima copia del simbolo viene usata per essere trasmessa nel trasmettitore locale, dunque su di essa verranno eseguite le varie operazioni (spreading, IFFT, aggiunta del prefisso ciclico, sagomatura con filtro di trasmissione), la seconda copia invece, viene usata per memorizzare il valore originale assunto dal simbolo che sarà necessaria qualora si voglia aggiornare la costellazione con quella predistorta (questo perché b_fase e b_quad sono dei vettori che contengono i risultati del predistorsore ordinati secondo un criterio che dipende anche dal simbolo originale trasmesso).

Sia nel caso pred2=0 che nel caso pred2=1 si arriva ai simboli indicati con STrasmFase2 e STrasmQuad2 che rappresentano la parte in fase e in quadratura dei simboli dopo che sono passati attraverso il trasmettitore locale.

Durante il primo ciclo di cont, su questi simboli si calcola la potenza media che viene memorizzata in Calc[0]. A questo punto si esce dal ciclo principale e si ricomincia il ciclo da capo, non dopo aver incrementato il valore di cont a 1. A questo punto quando si arriva alla domanda sul valore di cont, anziché uscire dal ciclo, questa volta si procede e si ha la normalizzazione che esegue due importanti operazioni: la più ovvia, divide il valore dei simboli per la radice della potenza d’ingresso così da compiere la normalizzazione; contemporaneamente moltiplica per il valore della costante di attenuazione desiderato, così da portare il sistema nelle condizioni di Back-Off d’ingresso desiderate:

SAmpl[0]= Calc[1]! STrasmFase Calc[0] SAmpl[1]= Calc[1]! STrasmQuad

(13)

a questo punto può avvenire l’amplificazione vera e propria: sui simboli in uscita dall’HPA si calcola la potenza (Pout) e su di questa si realizza il calcolo del Back-Off

d’uscita (OBO): OBO= 10! log 1 Pout " #$ % &' ln10

a questo punto i simboli vengono de-normalizzati con l’operazione inversa alla precedente e si ottengono i valori su cui viene implementato il calcolo della potenza d’uscita de-normalizzata che viene memorizzata in Calc[2].

Pertanto la funzione Poweranalysis riceve in ingresso il valore della costante di attenuazione Calc[1] e fornisce come uscita il valore della potenza in ingresso all’HPA (Calc[0]) e in uscita (Calc[2]) ovviamente de-normalizzate, inoltre fornisce anche il valore dell’OBO; le operazioni compiute da questa funzione vengono riassunte dallo schema in Fig. III.4:

Fig. III.4 – Input e Output della Poweranalysis Calc[2] OBO Calc[0] IBO Calc[1] FUNZIONE POWERANALYSIS

(14)

III.4 Riempimento di VettNum e Vettsomma

Prima di procedere con l’analisi della funzione Predistorsore è utile analizzare che cosa sono e come vengono riempiti due vettori importanti per il calcolo della costellazione predistorta stessa: VettNum e Vettsomma.

Nel programma principale, subito dopo la generazione dei simboli e contemporaneamente all’aggiornamento della costellazione con quella predistorta, avviene il riempimento della memoria VettNum. Il riempimento avviene in questo modo:

for(codice=0; codice<(2*L); codice+=2)

for(i=0; i<Ns; i++) if (EXIT[codice/2]!=Nu) for (j=0; j<cost; j++) if(TrasmCODE[codice][i]==Valori[j][0]&& TrasmCODE[codice+1][i]==Valori[j][1]) for (k=0; k<cost; k++) if (TrasmCODE[2*interf3[EXIT[codice/2]][0]][i]==Valori[k][0]&& TrasmCODE[(2*interf3[EXIT[codice/2]][0])+1][i]==Valori[k][1]) for (x=0; x<cost; x++) if (TrasmCODE[2*interf3[EXIT[codice/2]][1]][i]==Valori[x][0] TrasmCODE[(2*interf3[EXIT[codice/2]][1])+1][i]==Valori[x][1]) for (z=0; z<cost; z++) if (TrasmCODE[2*interf3[EXIT[codice/2]][2]][i]==Valori[z][0] && TrasmCODE[(2*interf3[EXIT[codice/2]][2])+1][i]==Valori[z][1 ]) { RAMaddress1=((costInterf0*costInterf1*costInterf2)*j)+((costInter f1*costInterf2)*(k%costInterf0))+costInterf2*(x%costInterf1)+z%costInte rf2; VettNum[RAMaddress1][codice/2]++; VettNumCluster[j][codice/2]++;

(15)

Analizzando le righe del programma si vede che c’è inizialmente una serie di cicli annidati di for e if e solo in seguito l’indirizzamento della memoria RAM che va poi a riempire VettNum (e VettNumCluster che esegue le stesse operazioni di VettNum solo al livello di cluster anziché di simbolo).

Le operazioni vengono eseguite su ciascun codice che è attivo (questo è garantito dal for sul codice e su Ns e dall’if su EXIT), dopodiché per ogni codice attivo si va a cercare il simbolo di costellazione che è stato trasmesso: questo è garantito dal ciclo su j che scorre tutti i simboli possibili e dall’if su Valori che restringe il campo al solo simbolo effettivamente trasmesso (fase e quadratura).

A questo punto si va a cercare la combinazione tra il simbolo trasmesso e i simboli trasmessi dai tre maggiori interferenti col codice in esame; per fare questo si ha bisogno del vettore interf3 che fornisce per ciascun codice i tre maggiori interferenti (e che è dato dalla funzione Calcolo Interferenti).

La k scorre tutti i possibili simboli di costellazione e l’if sul primo interferente, che viene confrontato su tutti i Valori[k], fornisce la combinazione esatta simbolo utile e primo simbolo interferente.

Si replicano gli stessi passaggi anche per il secondo e terzo interferente: in questo modo si trova la combinazione dei quattro simboli (utile più i primi tre interferenti) che sono stati trasmessi all’istante attuale del ciclo. Noti questi si va a riempire in maniera ordinata la RAMaddress che andrà ad indirizzare la memoria VettNum.

Da un punto di vista implementativo la dimensione della matrice VettNum (e anche quella di Vettsomma) sarà definita non più dal numero di punti della costellazione M ma dal numero di punti della costellazione estesa ML contenuto nella variabile largecost definita e inizializzata all’inizio del main. La fase più delicata è rappresentata dall’ordine con cui vengono letti e scritti gli elementi dei vettori.

Supponiamo, per semplicità, di avere tre utenti (quindi due interferenti) e che x individui il simbolo trasmesso dall’utente utile, y il simbolo trasmesso dal primo interferente e k il simbolo trasmesso dal secondo interferente. La Fig. III.5 mostra come vengono immagazzinate le informazioni nel vettore VettNum (così come in Vettsomma) relative all’utente utile considerato.

(16)

Fig. III.5 - Immagazzinamento in memoria degli elementi relativi alla costellazione estesa

Per cui in lettura l’elemento relativo alla trasmissione dei simboli individuati da x,y,k si troverà nella locazione individuata dalla formula

(17)

2

( *cos ) ( *cos )

RAMaddress= x t + y t + k

con cost pari al numero di elementi della costellazione M.

Estendendo il ragionamento al caso con tre utenti e facendo le dovute corrispondenze delle notazioni si arriva ad interpretare l’espressione che indirizza il valore di

RAMaddress nel programma.

Per adesso si è parlato solo di indirizzamento della memoria e non di riempimento della stessa: questo perché l’indirizzamento, così come è stato appena spiegato, è il medesimo sia per VettNum che per Vettsomma e ciò non a caso: infatti dal confronto delle locazioni di queste memorie la funzione Predistorsore ricaverà i Baricentri delle costellazioni, come vedremo a breve.

La differenza tra VettNum e Vettsomma sta dunque nel riempimento: VettNum si trova in fase di trasmissione, subito dopo la generazione dei simboli: in questa sede si procede ad incrementare di uno la locazione corrispondente, ogni volta che per un determinato codice si realizza una determinata combinazione di “simbolo utile più tre interferenti” e questo si fa per ogni codice attivo e per tutte le combinazioni di simboli possibili che si sono verificate.

Vettsomma invece si trova in ricezione, subito dopo la decisione sui simboli ricevuti dal

ricevitore locale (quello senza la componente di rumore additivo gaussiano). In questa memoria viene accumulata la somma dei simboli ricevuti in corrispondenza dei simboli che sono stati effettivamente trasmessi: la corrispondenza è garantita dal modo in cui si indirizza la memoria stessa, che è uguale a quello di VettNum e che è garantito dalla presenza, nel ricevitore locale, di una copia del simbolo effettivamente trasmesso (TrasmoldCODE).

A questo punto è noto cosa è contenuto dentro i vettori VettNum e Vettsomma e come è stato calcolato: questi valori verranno passati come argomenti alla funzione Predistorsore e una volta passati le memorie VettNum e Vettsomma verranno riazzerate per ripartire al ciclo di blocco successivo con i conteggi.

Attenzione: siccome il predistorsore e il generatore di traffico lavorano in maniera reciproca, richiamandosi l’uno con l’altro e siccome il generatore di traffico parte da una condizione iniziale di zero utenti, è ovvio che ci saranno dai casi in cui gli interferenti

(18)

non ci saranno o saranno in numero inferiore a tre. Ebbene in queste circostanze è ovvio che l’indirizzamento della RAMaddress cambia di caso in caso ed è per questo che nel programma vero e proprio vengono considerati i vari casi separatamente, il fenomeno di diversa interpretazione delle memorie tuttavia non rappresenta un problema per il simulatore in quanto l’importante è che le due memorie vengano allocate nello stesso modo all’interno di uno stesso ciclo, e questo è garantito dalla reinizializzazione delle matrici all’inizio di ogni nuovo ciclo: infine avremo tre casi particolari (di un solo utente attivo, oppure solo due, oppure solo tre) e un caso generale (con quattro o più utenti attivi), il metodo di riempimento delle memorie è diverso di caso in caso, ma all’interno di ogni caso particolare è uguale per VettNum e Vettsomma.

III.5 Funzione Calcolo_Interferenti

La funzione Calcolo_Interferenti fornisce per ciascun utente attivo i tre utenti attivi che rappresentano le maggiori problematiche di interferenza inter-canale con il primo.

Questa funzione riceve come parametri d’ingresso dal main: il file CrossMat che contiene la matrice delle cross-correlazioni tra i codici, su_attuale che indica il numero di utenti attivi per il ciclo dei blocchi attuale, EXIT che indica quali codici sono attivi, il fattore di spreading L (che coincide con Nu), la matrice Interf3[L][3] che conterrà per ciascun codice i primi tre interferenti.

All’interno della funzione, per ciascun utente attivo si va alla ricerca della posizione della

CrossMat che corrisponde al valore di cross-correlazione maggiore con l’utente

considerato; ovviamente, trattandosi di cross-correlazione sarà escluso dai possibili interferenti il codice che è in esame (infatti la diagonale principale della matrice non può contenere termini di cross-correlazione, per questa ragione è stata riempita con zero). Trovato il valore massimo, si va a memorizzare il codice responsabile di tale valore nella posizione corrispondente del vettore Interf3.

(19)

Ad esempio supponiamo che i codici attivi siano 255 254 90 80 60 e supponiamo che la matrice CrossMat sia fatta così, Fig. III.6:

0 2 1 3 4 1 0 3 4 2 6 1 0 3 5 3 1 2 0 7 5 4 1 2 0

Fig. III.6 – CrossMat per i codici 255, 254, 90, 80 e 60

Ovviamente i valori delle cross-correlazioni sono simbolici e sono state riportate soltanto le righe e le colonne interessate dai codici attivi.

Supponiamo che si stia calcolando il primo interferente per il codice 255 che si trova sulla quinta riga. La funzione Calcolo_Interferenti inizia a scorrere la matrice a partire dalla quinta colonna: legge dunque il valore 4 e lo memorizza, poi scorre e legge il secondo elemento della colonna: è un 2 che è minore di 4 allora viene scartato; successivamente si trova un 5 che viene memorizzato e infine si trova un 7 che viene eletto come maggior interferente. Allora adesso si deve riportare l’evento sulla matrice di uscita della funzione, pertanto si scriverà Interf3[255][254] che significa che il primo interferente di 255 è 254. Il ciclo viene ripetuto altre due volte per trovare il secondo e terzo interferente, ovviamente nel confronto tra i vari valori di cross-correlazione, verrà escluso quello appena preso in considerazione dal primo interferente; alla fine nella matrice di uscita troveremo scritto: Interf3[255][254, 90, 60].

(20)

III.6 Funzione Predistorsore

La funzione Predistorsore implementa il calcolo del baricentro. Questa funzione riceve in ingresso alcune variabili importanti per il suo funzionamento: innanzi tutto il vettore

cont[L] che è il contatore dell’utilizzo di ciascun codice, poi vengono passati tutti i valori

necessari per coordinarsi con il simulatore dunque il fattore di spreading L, la durata del

prefisso ciclico, il numero di sottoportanti Ns, il numero attuale di utenti (su_attuale), su

quali utenti dovrà essere effettuato il calcolo del baricentro (ossia solo su quelli attivi, indicati da EXIT) , infine le memorie di conteggio VettNum e Vettsomma (e le reciproche VettNumCluster e VettsommaCluster).

Poi vengono passate anche tutte le informazioni necessarie al predistorsore e al corretto indirizzamento delle memorie sopracitate: la matrice Valori, che contiene la costellazione nominale, riferimento per la convergenza dell’algoritmo, cost che indica la grandezza della costellazione e poi ancora il vettore Interf3.

Infine grandezze che servono per definire la complessità e le caratteristiche dell’algoritmo stesso: lo step size rappresenta il passo con cui si aggiornano le correzioni nelle equazioni ricorsive del sistema, la soglia invece rappresenta la tolleranza sotto la quale si può affermare che le costellazioni sono state acquisite, infine il predistorsore può considerare diversi livelli di complessità per i tre interferenti massimi con l’utente attivo, tali complessità sono rappresentate dal numero di punti con cui si quantizzano le costellazioni degli interferenti; ad esempio in una 16QAM si può scegliere di quantizzare la costellazione su tutti e 16 i punti, oppure per quadranti (complessità 4) oppure si può scegliere la complessità minima (1, non quantizzata), per la 4QAM invece potremo scegliere tra 4 e 1 e cosi via… ovviamente gli interferenti maggiori dovranno essere presi a complessità maggiore o uguale rispetto agli interferenti inferiori: ha senso scegliere complessità 16,4,1 (notazione che indica complessità 16 per il primo interferente, 4 per il secondo e 1 per il terzo), o anche 16,16,1 mentre invece non ha senso scegliere 1,1,16. In base al prodotto tra le complessità si definisce largecost che indica la dimensione della costellazione allargata con i tre interferenti.

(21)

Per capire il procedimento seguito dall’algoritmo di predistorsione implementato in questo programma, si faccia riferimento alla Fig. III.7:

Fig. III.7 – Funzione Predistorsore

codice largecost B_fase B_quad B CALCOLO BARI CENTRO VettNum VettSomma SogliaINout=? 0 1 EQUAZIONI ITERATIVE ValoriC BaricentroC CORREZIONI ErrMod ErrFase AGGIORNAMENTO VERIFICA SOGLIA Erre Teta B_fase B_quad B

(22)

La funzione riceve in ingresso i valori di b_fase e b_quad che contengono i valori delle costellazioni predistorte al passo precedente (ovviamente se il ciclo avviene per la prima volta le costellazioni non sono state ancora predistorte, allora in tal caso i b_fase e

b_quad vengono inizializzati con i valori nominali della costellazione). Tali memorie

sono riempite con lo stesso criterio d’ordine illustrato per VettNum e Vettsomma e saranno allora delle matrici in cui ciascuna colonna rappresenta un codice che contiene un vettore lungo come largecost in cui sono scritti i valori della costellazione predistorta, calcolati dalla funzione Predistorsore al passo precedente nel modo che si enuncerà a breve.

Prima di entrare nel ciclo del predistorsore si inizializza un vettore SogliaINout[L] di dimensione L che informa, per ciascun codice, sul fatto se tale codice si trovi entro la soglia di tolleranza del predistorsore stesso (0) oppure no (1); ovviamente al primo ciclo nessun codice si trova entro soglia pertanto tale vettore viene inizializzato con tutti 1. A questo punto si entra nel ciclo principale che viene ripetuto per ogni codice attivo e per ogni punto della costellazione allargata (largecost): si entra nel blocco BARICENTRO che mediante l’uso delle informazioni contenute in VettNum e Vettsomma implementa il calcolo del Baricentro in questo modo:

BARICENTRO= VettNum Vettsomma

ovviamente per entrambe le componenti di fase e quadratura.

Adesso c’e il controllo sulla soglia: se il punto della costellazione dell’utente si trova entro soglia (cioè SogliaINout=0) non è necessario fare l’aquisizione della costellazione predistorta per cui i valori di b_fase e b-quad non devono essere aggiornati e si esce dal ciclo per passare a calcolare i baricentri di un altro punto; se invece il punto in questione è fuori soglia (SogliaINout=1), come ad esempio al primo ciclo, si procede con l’aquisizione della costellazione predistorta.

L’equazione iterativa conosce il valore di ValoriC e BaricentroC che sono semplicemente i corrispondenti valori complessi (parte reale e immaginaria) della costellazione nominale e del baricentro che è appena stato calcolato, e fornisce la

(23)

differenza che intercorre tra il simbolo che si dovrebbe avere e il simbolo che si ha in realtà (distorto dalla non-linearità dell’HPA). Il calcolo fornisce ErrMod e ErrFase ossia l’errore complessivo in termini di modulo e fase:

ErrMod= mod(ValoriC) ! mod(BaricentroC) ErrFase= fase(ValoriC) ! fase(BaricentroC)

a questo punto bisogna applicare la correzione, mediante l’errore appena calcolato, ai valori precedenti di b-fase e b-quad: b_fase e b_quad però rappresentano parte reale e parte immaginaria della costellazione predistorta (il valore di fase e quadratura), invece la correzione viene eseguita su modulo e fase, pertanto a questi si fa corrispondere i valori

Erre e Teta. La correzione viene eseguita ad ogni ciclo con un passo pari a step size: Erre= Erre + step _ size * ErrMod

Teta= Teta + step _ size * ErrFase

Adesso si può realizzare l’aggiornamento della costellazione e caricare nella tabella i nuovi valori: il blocco AGGIORNAMENTO esegue le seguenti operazioni:

b _ fase= Erre * cos(Teta) b _ quad = Erre *sin(Teta)

e i valori di b_fase e b_quad vengono aggiornati e passati al programma centrale per eseguire l’aggiornamento della costellazione con quella predistorta appena calcolata. Prima di uscire dalla funzione si calcola se i nuovi valori si trovano entro soglia o meno e si provvede ad aggiornare il valore corrispondente di SogliaINout; questa verifica realizza una sorta di interruttore sul predistorsore: è infatti inutile iterare l’algoritmo laddove sia stata raggiunta la soglia di tolleranza, rappresenterebbe uno spreco di tempo e di memoria insistere sulla correzione e non poterebbe comunque ad un miglioramento della BER.

(24)

III.7 Funzione show_BER

La funzione show_BER fornisce il file d’uscita dell’intero sistema MC-CDMA e contiene i valori su cui saranno basati i grafici dei risultati delle simulazioni.

Sinora abbiamo considerato un unico ciclo di IBO e un unico ciclo di Eb/N0 pertanto il file d’uscita sarà unico e relativo questi valori soltanto, ma il simulatore è in grado di fornire un file per ogni combinazione di questi parametri.

I parametri che vengono passati a questa funzione sono: il tipo di modulazione, che serve per applicare la corretta formula per il calcolo della BER, e le informazioni sul tipo di sistema in esame (L, num_utenti, IBO, Eb/N0, UTILIZZOCODE) e in particolare i vettori che contengono il numero di errori commessi sul ramo in fase (NErrfCODE), sul ramo in quadratura (NErrqCODE) e il numero di errori complessivi (NErrCODE). Questi vettori vengono conteggiati nel main e passati alla funzione che implementa il calcolo della BER.

Nel main si provvede a confrontare ciascun simbolo trasmesso (di cui si ha a disposizione una copia) con il corrispondente simbolo ricevuto (dopo la decisione), nel caso in cui questi differiscano si provvede a incrementare di uno il valore del vettore che conta gli errori.

Alla fine del ciclo su Eb/N0 questi vettori adeguatamente riempiti vengono passati alla

show_BER che restituisce il file dei risultati finali.

All’interno della funzione si procede al calcolo della BER in questo modo:

log ln 2 NerrCODE UTILIZZOCODE BER M Ns = !

il denominatore serve per passare dalla SER (symbol error rate) alla effettiva BER (bit error rate) per questo si divide per un coefficiente correttivo; in questo conto si è ipotizzato una codifica di Gray che impone che l’errore su un simbolo corrisponda ad un errore su un bit. Invece il numeratore realizza, per ciascun codice, la stima secondo il metodo Monte Carlo, ossia il numero di bit errati fratto il numero di bit trasmessi (che a

(25)

livello di codice è rappresentato proprio dal vettore UTILIZZOCODE, come si è già spiegato).

Attenzione che il metodo Monte Carlo fornisce risultati attendibili di BER solo con una durata delle simulazioni abbastanza elevata: per questo la funzione prevede un parametro di controllo che assegna un valore di BER pari a 1 nel caso non siano stati trasmessi almeno 10.000 simboli per codice o non siano stati errati almeno 60 simboli per codice. Il file d’uscita presenta una tabella che contiene il valore di Cicli, il valore di IBO, il valore di Eb/N0 e i valori di BER ordinati dal codice 0 al 255 (nel caso L=256).

III.8 Struttura generale del simulatore

Finora si sono descritte le varie componenti che realizzano il programma, abbiamo scomposto il simulatore e abbiamo analizzato i vari cicli annidati e le varie funzioni di cui il simulatore stesso si serve; lo scopo di questo paragrafo finale è quello di dare un significato complessivo a tutte queste funzioni e di esaminare pertanto il programma nella sua organicità con particolare attenzione al modo in cui queste funzioni collaborano tra di loro.

Per capire meglio come funziona il simulatore si faccia riferimento alla Fig. III.8:

(26)

RX LOCALE VettNum Trasm, Trasm3 Trasmold Dev Calc Interf3 EXIT DOPO PRIMA Generatore Traffico If cont[codice]≠L B_fase B_quad Valori If PRIMA≠DOPO CalcoloInterferenti Poweranalysis Calcolo Dev If EXIT≠L Generatore Simboli Aggiornamento Cost Predistorta Trasm3 B_fase B_quad SPREADING IFFT PREFIX FILTRO TX DESPREADING FFT REMOVEPREFIX FILTRO RX

RXRX

Calcolo Vettsomma PREDISTORSORE Poweranalysis If PRIMA=DOPO B_fase B_quad HPA

(27)

Fig. III.8b – Ricevitore MC-CDMA

La Fig. III.8a considera il caso di un unico valore di IBO e di Eb/N0 e rappresenta un unico ciclo sui blocchi: l’iterazione del ciclo realizza la trasmissione del sistema MC-CDMA nel suo evolversi temporale.

Il simulatore esamina come primo blocco il generatore di traffico: inizialmente non ci sono utenti attivi, pertanto non si trasmette neanche nessun simbolo ( PRIMA=0, EXIT=Nu ). Si attende finchè il generatore non informa che è entrato un utente, in tal caso si aggiorna il valore degli utenti attuali (DOPO) e si provvede ad assegnare un codice al canale (il valore di EXIT, in corrispondenza dell’utente entrato, assume un valore compreso tra 0 e 255).

A questo punto si deve inizializzate i valori delle tabelle che servono per l’aggiornamento dei simboli trasmessi con quelli predistorti ( ossia b_fase e b_quad ); siccome al primo

AWGN DESPREADING FILTRO RX REMOVEPREFIX FFT If Deciso≠Trasmold NErrCODE++ Show_BER

(28)

ciclo non è stata effettuata neanche una chiamata sul predistorsore, i valori delle costellazioni predistorte non sono disponibili: in tal caso si inizializzato ai valori della costellazione nominale (Valori).

Nel blocco successivo si entra solo nel caso che sia appena entrato un utente ( cioè solo quando PRIMA≠DOPO ): in tal caso è necessario aggiornare la tabella degli interferenti (Interf3), infatti ogni nuovo ingresso potrebbe cambiare l’interazione di alcuni tra i vari utenti attivi (a causa dei valori di cross-correlazione). Inoltre si richiama anche la funzione Poweranalysis che fornisce il valore aggiornato della potenza in ingresso e in uscita all’amplificatore di potenza. Il vettore Calc in uscita a Poweranalysis è importante per l’implementazione del calcolo della variabile Dev, che a sua volta è necessaria per il calcolo delle componenti di rumore gaussiano.

Calcolo della Dev

Nel programma di simulazione il canale trasmissivo è affetto da rumore additivo gaussiano bianco AWGN (Additive White Gaussian Noise), con densità spettrale di potenza nota e pari a No 2.

Il rumore si somma alle componenti di segnale in uscita dall’HPA (fase e quadratura); quindi il problema si riconduce a quello di dover generare delle componenti, fase e quadratura, di rumore.

Tali campioni di rumore devono rispondere a dei requisiti particolari, ovvero devono essere caratterizzate da una distribuzione di tipo gaussiano con valor medio nullo e deviazione standard σ.

La procedura che si occupa della generazione del rumore è:

void Noise(double* w,double dev,int& jseed)

alla quale si passano, oltre alla deviazione Dev, un vettore Rum di dimensione due (per riferimento) in cui verranno scritte le componenti del rumore ed un intero che dà il seme per la funzione random.

(29)

Si fissi l’attenzione sulla variabile Dev e quindi sulla calibrazione del generatore di rumore Gaussiano in modo da riprodurre un desiderato valore del rapporto segnale-rumore. Per semplicità, si limiti la trattazione al caso in cui si desideri generare un processo di rumore Gaussiano bianco reale w t

( )

con DSP bilatera:

Pw

( )

f = N0

Il processo w t( ) può rappresentare una delle due componenti di rumore in banda base ( )

c

n t o n t che sono presenti nel modello di simulazione tramite gli inviluppi s( ) complessi. Dal punto di vista teorico, il processo w t( ) dovrebbe avere potenza infinita, ma in pratica siamo in grado di generare solo una sequenza di variabili Gaussiane nk, a media nulla e varianza finita !n2. Si assume che tali variabili rappresentino una versione campionata a frequenza fsa =1/Tsa di un processo Gaussiano a tempo continuo n t( ), avente DSP bilatera costante, pari a N0 nell’intervallo frequenziale (!fsa / 2, fsa/ 2), espressa da

( )

0 rect n sa f f N f ! " = # $ % & ' P ( III.8.1 ) Definendo quindi:

( )

k sa n =!n kT

con le seguenti proprietà:

{ }

E nk = 0

{ }

2 2

(30)

93

( ) {

}

2 2 ,0 per 0 =E 0 per 0 n n k k m n m m R m n n m + !" = # = " #$ = % & '

La DSP del processo a tempo discreto n così definito è data da: k

( )

( )

e j2 sa k mT f n n sa m f " ! R m # $ T =#! =

&

% % P

dove il coefficiente Tsa serve per mantenere l’omogeneità delle unità di misura (in pratica si assimila la sommatoria della auto-correlazione discreta ad un integrale in dt della TCF della correlazione del processo a tempo continuo). Ricordando la funzione di auto-correlazione espressa prima, si trova:

( )

2 2 k n n n sa sa f T f ! = ! " = P

Uguagliando l’equazione precedente con la ( III.8.1 ), si ha, nell’intervallo

(

! fsa 2, fsa 2

)

, 2 0 n sa N f ! =

da cui si ottiene infine la relazione tra la varianza del generatore di variabili Gaussiane e la DSP del processo che si desidera simulare:

2 0

n N fsa

! = " ( III.8.2 )

(31)

( )

( )

( )

2 2 2 2 2 0 2 2 2 2 d d d d sa sa sa sa k sa sa sa sa f f f f w n n n f f f f f f f f f f N f ! ! ! ! = = = = "

#

P

#

P

#

P

#

e quindi la ( III.8.2 ) rappresenta anche la potenza del processo di rumore w t( ) valutata nell’intervallo di frequenza (!fsa/ 2, fsa/ 2), come illustrato in figura:

1 f fsa/2 -fsa/2 w(t) f N0 P w(f) H(f) kTsa n(t) f N0 P n(f) nk fsa/2 -fsa/2 -fsa -fsa/2 fsa/2 fsa f N0 σ2 n P n k(f)

Fig. 2.15 – Schema a blocchi concettuale della simulazione a tempo discreto di un processo di

rumore Gaussiano bianco

Per esprimere la varianza in funzione di E N si procede come segue: b/ 0

( ) 2 0 0 2 0 2 0 1 1 log log RF b b s s n sa sa sa sa b b b b E E E P T N f f f f E E N M E N M E N ! = " " = " = " " = " " "

(

)

( ) ( ) ( ) 2 2 0 2 0 2 0 1 1

log log log

RF RF RF s s s sa n sa b sa b b P T P P N f T M E N T M E N M E N ! = " " " = " " = "

Nelle simulazioni per sistemi MC-CDMA e con una modulazione M-QAM si può allora scrivere: ( ) ( 1) 3 RF S sa M L NcIc P "N = ! " "

(32)

Da cui si ricava la deviazione standard (Dev) da utilizzare nel programma: 2 0 ( 1) 3log b/ M L NcIc Dev M E N ! = "

Per una modulazione M-PSK facendo analoghe considerazioni si può concludere:

2 0 2log b/ L NcIc Dev M E N = !

Nella deviazione standard si deve tenere conto anche di un altro problema. Il segnale, passando nella non linearità, subisce un effetto di clipping, ovvero un taglio dei picchi di segnale. Per cui il segnale all’uscita del canale non lineare avrà una potenza inferiore rispetto al segnale in ingresso. Il livello di potenza su cui effettuo la calibrazione del rumore, per ottenere dei risultati corretti, deve essere riferito al ricevitore. Per cui la formula precedente per il calcolo della deviazione standard di rumore deve essere corretta inserendo un termine che tenga conto della perdita di potenza subita dal segnale nel passaggio attraverso la non linearità.

Per risolvere questo problema, nella simulazione, quando si va a calcolare la costante moltiplicativa che mi serve per ottenere un determinato back-off, si calcola anche la potenza in ingresso all’amplificatore e quella d’uscita a quel determinato back-off di uscita. Queste due quantità vengono memorizzate in Calc, rispettivamente in Calc[0] ed in Calc[2], la deviazione standard viene quindi modificata come segue:

2 0 ( 1) [2] 3log [0] b/ M L Calc NcIc Dev M Calc E N ! " = "

(33)

2 0 [2] 2log [0] b/ L Calc NcIc Dev M Calc E N ! = ! ! per modulazioni M-PSK

Rimane un ultimo problema da affrontare. Come gestire la calibrazione del rumore nel caso in cui la costellazione trasmessa sia stata predistorta?

Il problema si pone nella misura in cui la costellazione predistorta presenti una potenza media diversa dalla costellazione originaria. Infatti, se si lasciasse inalterata la formula per la calibrazione, poiché presumibilmente la costellazione predistorta avrà una potenza maggiore rispetto a quella nominale si otterrebbe una BER in funzione del rapporto segnale rumore sovrastimata rispetto alla realtà. In termini pratici le curve di BER risulterebbero traslate a sinistra rispetto a quelle reali. Inoltre va tenuto presente che ogni canale avrà una costellazione diversa dalle altre. Si è scelto di utilizzare per la calibrazione, la potenza media della costellazione predistorta, mediata fra tutti gli utenti attivi. In seguito si vedono le linee di programma relative a questo particolare punto:

Dove b_fase[i][utente] e b_quad[i][utente] rappresentano la parte in fase e in quadratura dei simboli della costellazione predistorta estesa e largecost3 è il numero di punti di quest’ultima.

Si ritorna a considerare lo schema di Fig. III.8a.

In base al numero di canali attivi si deve generare un corrispondente numero di simboli da trasmettere. Ciascun simbolo generato viene salvato in tre copie: Trasm3 viene

for (utente=0; utente<num_utenti; utente+=1) {

for (i=0; i<largecost3; i++)

potCP[utente]+=b_fase[i][utente]*b_fase[i][utente]+b_quad[i][utente]*b_quad[i][utente]; potCP[utente]=potCP[utente]/largecost3;

pmedCP = pmedCP + potCP[utente]; }

pmedCP = pmedCP / num_utenti;

Dev=sqrt((pmedCP*L*NcIc*Calc[2]/(2*Calc[0]*pow(10.0,(ebn0_min+curr_point*ebn0_ step)/10.0)*

(log(cost)/log(2)))));

(34)

utilizzata per la trasmissione vera e propria, Trasm viene utilizzata per memorizzare il valore effettivamente trasmesso (utile per indirizzare correttamente il calcolo di VettNum che avviene contemporaneamente all’aggiornamento della costellazione con quella predistorta), infine Trasmold che ricorda il valore del simbolo trasmesso al passo precedente (serve per indicizzare correttamente il calcolo di Vettsomma che avviene nel ricevitore locale e che pertanto si trova a lavorare con simboli del ciclo immediatamente precedente, serve anche per confrontare simbolo deciso e simbolo trasmesso).

I simboli trasmessi a questo punto vengono aggiornati mediante i b_fase e b_quad che contengono i valori forniti dal predistorsore sulla costellazione predistorta (al primo ciclo però coincidono con Valori); contemporaneamente si realizza il calcolo di VettNum (coerentemente con quanto spiegato in Par. III.4).

A questo punto i simboli sono stati predistorti e sono pronti per essere trasmessi: si realizza pertanto lo spreading dei simboli, la IFFT, l’aggiunta del prefisso ciclico e la sagomatura con il filro di trasmissione. Infine il campione, debitamente predistorto,

passa attraverso la non-linearità dell’HPA e, se la predistorsione è avvenuta nel corretto modo, l’effetto dei b_fase e b-quad si dovrebbe neutralizzare con la non-linearità stessa, dando luogo a dei campioni che, appropriatamente elaborati, dovrebbero fornire dei simboli ricevuti il più vicino possibile ai simboli nominali effettivamente trasmessi.

Prima di essere trasmesso, il campione viene duplicato: una copia andrà nel canale di trasmissione dove sarà distorta dall’AWGN che possiede le caratteristiche di varianza esposte in “Calcolo della Dev” e in seguito al ricevitore; l’altra copia, priva della distorsione dovuta al canale, realizza invece l’implementazione del RICEVITORE

LOCALE: in questa fase sul campione in uscita si eseguono tutte le operazioni di un

vero e proprio ricevitore (convoluzione con filtro adattato, rimozione del prefisso ciclico, FFT e despreading) e questo per ottenere i simboli ricevuti che vanno ad incrementare il valore assunto da Vettsomma (indirizzato con Trasmold). Adesso si hanno a disposizione tutti i valori necessari per aggiornare la funzione predistorsore che fornisce in uscita i nuovi b_fase e b_quad. In questa sede deve essere ripetuta la chiamata della funzione Poweranalysis per ottenere i valori di Calc nel caso non entrino utenti (la precedente chiamata di Poweranalysis realizzava la condizione complementare).

(35)

In questo modo i simboli predistorti vengono trasmessi e in ricezione ( Fig. III.8b ) si esegue la decisione sui campioni affetti da rumore: il confronto tra simbolo deciso e simbolo effettivamente trasmesso realizza la stima Monte Carlo e fornisce i valori del vettore NErrCODE che verrà passato alla funzione show_BER e determinerà il file d’uscita che contiene i valori di BER per ciascun canale ad un certo valore di IBO e di Eb/N0.

Figura

Fig. III.1 - “MC-CDMA Input.txt” Back-Off di ingresso (IBO):
Fig. III.3 – Funzione Poweranalysis Trasm2
Fig. III.4 – Input e Output della Poweranalysis  Calc[2] OBO Calc[0] IBO Calc[1] FUNZIONE  POWERANALYSIS
Fig. III.5 -  Immagazzinamento in memoria degli elementi relativi alla costellazione estesa
+4

Riferimenti

Documenti correlati

Si utilizza nelle rendite vitalizie, infatti una rendita vitalizia si può considerare come somma di capitali

Facendo sempre riferimento al collegamento mobile-base, supponendo che il controllo di potenza sia assente e che tutti i trasmettitori emettano una stessa potenza fissa, si calcoli la

Based on a liberal intergovernmental reading, four factors have been identified which explain the varying involvement of the EU23: first, the distribution of competences; second,

Come verrà illustrato più nel dettaglio, l’analisi dei dati raccolti tramite l’osservazione e le in- terviste ai professionisti mostra come esista una differenza nella

But, as with the case of Malta selling its citizenship for € 650,000, the policies adopted by Qatar and Bahrain are blatant in making explicit what was

nel secondo capitolo si forniranno informazioni riguardo al tipo di traffico che deve essere supportato dal sistema e descriveremo come è stato ottenuto un generatore di

• L’uso più antico documentato per separare la parte intera dai decimali, che prima erano scritti come frazione aggiunta alla parte intera, è dovuto a Nepero Nepero, che

Dal terzo-quarto decennio dell'800, come già detto, si può parlare di un “sistema adriatico” di strade rotabili in larga misura autonomo da quello tirrenico ed orientato su