• Non ci sono risultati.

Capitolo 2: Il Software Defined Radio

N/A
N/A
Protected

Academic year: 2021

Condividi "Capitolo 2: Il Software Defined Radio"

Copied!
30
0
0

Testo completo

(1)

Capitolo 2:

Il Software Defined Radio

Nel capitolo introduttivo si è fatto cenno al concetto di Software Radio, tecnologia con cui si cercherà di creare un ricetrasmettitore VHF-DSC multicanale che rispetti le specifiche di modulazione viste nel capitolo 1. In questo capitolo si vedrà, un po’ più approfonditamente, che cosa si intende per Software Radio, entrando più nel dettaglio per l’analisi di quella che sembra essere il progetto SDR più significativo in circolazione, anche e soprattutto per l’approccio open source seguito: GNU Radio.

2.1 Cos’è il Software Defined Radio

Per Software Defined Radio (o più brevemente Software Radio) si intende un sistema di comunicazioni radio in cui le componenti di solito implementate da hardware specifico (modulatori, filtri, mixer, etc.) sono realizzate via software. Nonostante dal punto di vista concettuale l’SDR non sia una novità, la rapida evoluzione delle tecnologie elettroniche ad alta velocità atte alla manipolazione digitale dei segnali l’ha resa attuale e di interesse non più solo teorico [1]. L’SDR Forum [2] definisce come requisiti minimi per poter definire un apparato come “Software Radio”1:

1

In realtà non esiste una vera e propria definizione universale di Software Radio, non esistendo uno standard specifico al riguardo.

(2)

1. la capacità di processare (senza modifiche dell’hardware, ma con semplici cambi di software) segnali appartenenti ad un range frequenziale molto esteso (ad esempio da 2 a 500 MHz o da 1 a 2 GHz);

2. la capacità di conservare in memoria un gran numero di forme d’onda differenti e la possibilità da parte di un utente di aggiungerne di nuove;

3. la possibilità di applicare aggiornamenti o correzioni di singoli moduli senza dover ricaricare l’intera dotazione del software.

Nella sua accezione più generica, una Software Radio è costituita da un front end a radiofrequenza e da hardware DSP, microprocessori e circuiti integrati, oltre che da un opportuno pacchetto software al fine di applicare determinate modulazioni, codifiche o protocolli. Dal punto di vista teorico, in assenza di limitazioni tecniche alla velocità delle componenti hardware, si potrebbe campionare il segnale direttamente a radiofrequenza, per poi procedere ad una elaborazione digitale. All’atto pratico però la velocità degli ADC è limitata – e comunque tanto più essa è elevata, tanto più sarà difficile o costoso realizzarli: si preferisce quindi (a) convertire tutto il segnale in banda base tramite un ricevitore analogico (ad esempio un supereterodina), per poi campionarlo e demodularlo, oppure (b) abbassare la frequenza di interesse ad una certa frequenza intermedia fIF, campionarlo con ADC ad alta velocità, ed infine portarlo in banda base tramite DDC (Digital Down Converter) per l’elaborazione DSP [3]. In figura 2.1 si ha un esempio esplicativo.

(3)

L’utilizzo di tali metodi digitali di conversione di frequenza del segnale risultano in particolar modo interessanti: infatti i campioni numerici I e Q dell’inviluppo complesso ricevuto (magari corrispondente a un numero elevato di canali) possono essere elaborati con opportuni filtri digitali, permettendo la definizione filtri equivalenti eccellenti, caratterizzati da fianchi ripidi e perciò da un’ottima reiezione dei canali adiacenti. Ciò risparmia, tra l’altro, il compito spesso gravoso (dal punto di vista economico e di ingombro) di utilizzare filtri analogici particolarmente selettivi a frequenza intermedia.

2.1.1 Architettura generica

La tipica architettura di un ricevitore Software Radio è costituita dai seguenti blocchi fondamentali [4]:

1. antenna;

2. front end a radiofrequenza;

3. convertitore analogico-digitale (campionamento più quantizzazione);

4. hardware per il processing di segnali digitali, controllato e configurato via software.

Dualmente, un trasmettitore è costituito dalla seguente catena:

1. hardware per il DSP controllato via software; 2. convertitore digitale-analogico;

3. front end a radiofrequenza; 4. antenna.

Si faccia ora riferimento alla catena di ricezione.

L’antenna viene assimilata in molte pubblicazioni al front end. Il suo dimensionamento avviene in base al range frequenziale di funzionamento del dispositivo; si avranno così, a seconda dei casi, antenne filari, yagi-uda, una vasta gamma di antenne a circuito stampato, etc.

Il front end a radiofrequenza si rende necessario per abbassare la frequenza portante del segnale che si vuole campionare senza incorrere in fenomeni di aliasing; come già accennato, questo passo è indispensabile perché non esistono ADC abbastanza veloci per

(4)

campionare direttamente un segnale a radiofrequenza rispettando nel contempo il teorema di Nyquist; è composto essenzialmente da:

• un amplificatore a bassa cifra di rumore (LNA, Low Noise Amplifier), posto all’inizio della catena per tenere bassa la cifra di rumore complessiva della catena di ricezione (formula di Friis);

• un filtro passa basso a banda piuttosto larga (fattore di qualità basso), con scopi essenzialmente di filtraggio del rumore ed eliminazione della frequenza immagine;

• un mixer;

• un oscillatore locale (nel caso più semplice un VCO), utilizzato per generare una sinusoide a frequenza fOL tale che fOL = fRFfIF, essendo fRF la frequenza che si vuole

selezionare ed fIF la frequenza intermedia (fissa);

un filtro passa basso per eliminare il termine indesiderato a frequenza 2fRF - fIF.

Il convertitore analogico-digitale campiona il segnale ad un certo sampling rate, con un certo numero di bit per campione (valori tipici sono 8 e 16 bit, corrispondenti rispettivamente a 256 e 65536 livelli distinti), entro un certo dynamic range (differenza tra il valore massimo ed il valore minimo del segnale distinguibili); il passo di quantizzazione è dato dal rapporto tra il range ed il numero di livelli [5]. In molte applicazioni tale quantità non è uniforme, ma viene infittita in corrispondenza dei valori più frequenti statisticamente.

Infine, l’hardware per l’elaborazione del segnale digitalizzato: tale hardware può essere completamente general purpose, costituito da DSP (Digital Signal Processor), oppure consistere in FPGA (Field Programmable Gate Array) ed ASIC (Application Specific Integrated Circuit). Essendo allo stato attuale i DSP general purpose non ancora sufficientemente veloci per le specifiche SDR e gli ASIC non programmabili e quindi non flessibili, lo stato dell’arte è costituito da FPGA, occasionalmente integrati con un certo numero di ASIC per implementare le operazioni più complesse. Per approfondimenti, si rimanda alla bibliografia specializzata ([6], [7]).

Per quanto riguarda il software, non esistono ad oggi delle limitazioni stringenti e vincolanti. L’SDR forum ha però sviluppato un modello di architettura software (DOCSRA - Distributed Object Computing Software Radio Architecture), che adotta le metodologie descrittive raccomandate dall’IEEE (astrazione a strati). È ragionevole supporre che questo

(5)

modello possa essere un buon candidato ad una futura standardizzazione ufficiale. L’esposizione dei principi di architettura software esula dai propositi di questa tesi, quindi si rimanda il lettore interessato all’apposita bibliografia ([8]).

Fig. 2.2: architettura generica di un sistema SDR

2.1.2 Perché SDR?

La scelta da parte della comunità degli sviluppatori e di molte imprese di telecomunicazioni di muoversi in maniera decisa nella direzione del Software Radio è causata da tre sostanziali vantaggi che tale concezione lascia intravedere [9].

Il primo beneficio è in termini di flessibilità e affidabilità: l’SDR permette operazioni simultaneamente su più canali e comunicazioni tra organizzazioni diverse; da sempre aree geograficamente distinte, ma anche organi diversi dello stesso Stato, hanno sviluppato ed adottato protocolli e canoni radio differenti, impedendo la comunicazione reciproca; cosicché esistono problemi di compatibilità tra apparati europei e americani, ad esempio, ma anche tra i vari corpi di Pubblico Soccorso della stessa nazione, o tra differenti corpi armati. La capacità del Software Radio di generare e ricevere innumerevoli tipi di segnale risolve tale problema, convertendo una questione hardware insolubile in un semplice cambio di parametri via software.

Il secondo beneficio consiste in una maggiore sicurezza: una Software Radio può essere dotata di un meccanismo di crittografia dei dati, il cui algoritmo può essere mutato in caso di compromissione dei meccanismi di riservatezza; si possono inoltre programmare

(6)

meccanismi di interferenza o di protezione da essa, nonché frequency hopping, espansione dello spettro, etc.

Fig. 2.3: comunicazioni tra mezzi di Soccorso Pubblico o militari

Terzo ed ultimo punto, la facilità di aggiornamento: di giorno in giorno vi sono miglioramenti o modifiche nelle tecniche di codifica e modulazione dei mezzi di telecomunicazione; una Software Radio può essere aggiornata in maniera rapida ed efficiente, perfino “over-the-air”, secondo un principio già adottato per l’aggiornamento software degli odierni Personal Computer. Le modifiche possono essere apportate anche “al volo”, cioè durante il normale funzionamento.

Allo stato attuale, lo sviluppo del Software Radio si sta indirizzando verso la creazione di radio “intelligenti”, in grado di osservare l’utilizzazione dello spettro elettromagnetico e di “autosettarsi” per raggiungere performance ottimali; la ricerca è insomma rivolta alla creazione di dispositivi di radiocomunicazione universali.

2.2 Il progetto GNU Radio

In circolazione esistono diversi progetti di Software Defined Radio; tra gli altri, si citano Flex Radio System2, SoftRock Radio3, KGKSDR4. Tra le varie proposte, GNU Radio è

2

(7)

quella che sembra essere la più rilevante per diffusione, applicabilità ad un’ampissima gamma di utilizzi, disponibilità di codice sorgente e supporto nella sua analisi e modifica.

GNU Radio ([10], [11]) è un progetto open source fondato da Eric Blossom, un ingegnere informatico di Berkeley. Consta di una collezione di software sottoposti a licenza GPL (GNU General Public License5) liberamente scaricabili, consultabili e modificabili, che combinati con un hardware minimo permettono la costruzione di un sistema software radio basato su piattaforma PC. A tale pacchetto software è associata anche una piattaforma hardware ben definita ed interfacciata, sviluppata dalla Ettus Research LLC6, in alternativa alla quale si può fare uso della scheda audio del PC.

All’interno del software distribuito sono disponibili inoltre innumerevoli applicativi pronti all’uso, il cui (parziale) elenco verrà visto nel paragrafo 2.2.2. In figura 2.4 si può vedere, rappresentata schematicamente, l’architettura di GNU Radio, i cui singoli elementi verranno visti più avanti.

Fig. 2.4: architettura di GNU Radio

3 http://www.softrockradio.org/ 4 http://www.m0kgk.co.uk/sdr/index.php 5

Disponibile per consultazione all’URL http://www.gnu.org/licenses/gpl.html.

6

(8)

Le caratteristiche salienti di GNU Radio sono:

• sistema operativo per cui il software è dimensionato: Linux;

• disponibili drivers per pilotare l’hardware (USRP e scheda audio – ALSA)

• esistenza di un’interfaccia grafica e possibilità di costruire un vero e proprio grafo i cui blocchi corrispondono alle varie fasi del signal processing, mentre le connessioni che li uniscono rappresentano il flusso dei dati;

• possibilità di rappresentare gli ingressi e le uscite dei blocchi come delle porte (in ogni blocco almeno una, ma anche più di due);

• i parametri dei blocchi e la topologia del grafo possono essere cambiati in ogni momento, anche in fase di funzionamento;

• possibilità di variare il rate dei dati in ingresso ed uscita, anche dinamicamente;

• possibilità di costruire una GUI (Graphical User Interface) per gli applicativi;

• disponibilità di una vastissima gamma di ingressi e uscite già pronti: per e da file, schede audio, etc.

2.2.1 Struttura hardware

La componente hardware fondamentale attorno a cui ruota la struttura di GNU Radio è la USRP (Universal Software Radio Peripheral), prodotta dalla Ettus Research LLC. A tale motherboard, che implementa funzionalità generiche, possono poi essere collegate fino a quattro daughterboard create specificatamente per l’utilizzo in trasmissione o ricezione in differenti range frequenziali.

In figura 2.5 è si può osservare la motherboard senza altre periferiche collegate, mentre in figura 2.6 è fotografata collegata a quattro differenti daughterboards.

Si nota di primo acchito che i componenti principali della motherboard USRP sono i convertitori ADC, quelli DAC, un FPGA (dedicato al pre-processing del segnale) ed alcuni stadi di front end a RF.

Come si può vedere, l’approccio tenuto nel dimensionamento dell’hardware è modulare, specularmene a come succede nell’architettura software (che si vedrà dopo), con lo

(9)

scopo dichiarato di mantenere semplice e flessibile la configurazione del sistema radio da implementare.

Fig. 2.5: la motherboard USRP

Si vedranno ora un po’ più nel dettaglio i componenti succitati [12]:

1. Convertitori ADC e DAC

La scheda è dotata di quattro ADC ad alta velocità e a 12 bit; il rate è pari a 64 milioni di campioni al secondo (MS/s), corrispondenti, in linea di principio, ad una banda massima campionabile di 32 MHz. Altre caratteristiche sono:

(10)

• massima potenza di ingresso 40 mW (16 dBm);

• presenza di un PGA (Programmable Gain Amplifier) per amplificare il segnale di ingresso in modo da coprire tutta la dinamica (massima amplificazione 20 dB);

• possibilità di utilizzare frequenze di campionamento pari a sottomultipli di 128 MS/s (64, 42.66, 32, 25.6, 21.33 MS/s).

In dotazione vi sono anche quattro DAC ad alta velocità, le cui caratteristiche sono:

• ingresso a 14 bit;

• velocità di clock pari a 128 MHz (frequenza di Nyquist 64 MHz, ma è consigliato stare sotto i 50 MHz);

• tensione di picco in uscita pari a 1 V con carico di 50 Ω;

• massima potenza 10 mW (10 dBm);

• presenza di un PGA con amplificazione massima di 20 dB.

In linea di principio, la presenza di 4 ADC permetterebbe la presenza di 4 canali di ingresso; in realtà il campionamento è complesso, avviene cioè separatamente sui canali I e Q, permettendo l’ingresso di 2 canali complessi. Altrettanto si ha nella catena di uscita.

(11)

2. FPGA

Ha principalmente due scopi: svolgere operazioni matematiche ad alta velocità e ridurre il flusso di dati per poterli trasmettere tramite USB2 (lo standard USB 2.0 supporta un massimo di 60 MB/s), cui è collegata tramite apposito chip (Cypress FX2).

Nella sua configurazione standard include DDC (Digital Down Converter), aventi come ingressi (in ricezione) i campioni I e Q provenienti dagli ADC (figura 2.7); tali dispositivi sono costituiti da NCO (Numerically Controlled oscillator) e filtri CIC, filtri ad elevate prestazioni costituiti da semplici sommatori e ritardi. In trasmissione invece i DUC (Digital Up Converter) sono contenuti in chip separati e non nella FPGA.

Mentre i data rate di lato TX e lato RX possono essere differenti, in caso di ricezione (o trasmissione) di più canali le singole linee di RX devono essere percorsi da flussi di campioni aventi la stessa velocità.

In uscita si avrà in definitiva un segnale complesso in banda base, corrispondente all’inviluppo complesso della porzione di spettro che intendiamo demodulare (operazione che verrà compiuta dal processore del PC a cui l’USRP è collegata).

(12)

Fig. 2.8: struttura dei Digital Down Converter

3. Le daughterboards

Sulla motherboard USRP sono disposti 4 slots atti alla connessione di fino a due daughterboards per la ricezione e due per la trasmissione; tali schede contengono semplicemente il front end per interfacciarsi a RF.

(13)

Ogni scheda è quindi dimensionata in maniera differente, e rappresenta la parte “analogica” della USRP. Le schede attualmente disponibili sul mercato sono:

• BasicRX, 0.1-300 MHz receiver • BasicTX, 0.1-200 MHz transmitter • LFRX, DC-30 MHz receiver • LFTX, DC-30 MHz transmitter • TVRX, 50-860 MHz receiver • DBSRX, 800-2400 MHz receiver • RFX900, 800-1000 MHz Transceiver • RFX1200, 1150-1400 MHz Transceiver • RFX1800, 1500-2100 MHz Transceiver • RFX2400, 2250-2900 MHz Transceiver

A breve saranno disponibili un transceiver per banda 50 MHz-1 GHz ed un transceiver per la banda UNII/ISM a 5 GHz.

(14)

2.2.2 Struttura software

Essendo GNU Radio un sistema SDR, il “nucleo” è costituito ovviamente dal software. La caratteristica primaria è l’aspetto modulare della programmazione: la costruzione via software di un ricevitore/trasmettitore avviene, in analogia con la visione “tradizionale” di un sistema di telecomunicazioni, tramite la formazione di una catena di blocchi che processano un flusso di dati: le funzioni dei singoli blocchi di signal processing sono implementate in C++, mentre il linguaggio di programmazione utilizzato per definire la forma della catena di ricezione (o trasmissione) e le connessioni tra i singoli blocchi è il Python. Il motivo di tale approccio ibrido è presto detto: il C++, grazie la sua efficienza, viene usato per ottimizzare la velocità di elaborazione; il Python, essendo un linguaggio di scripting interpretato dal calcolatore al momento dell’avvio del programma e non compilato, ha performance peggiori del C++ in termini di efficienza (ed infatti non è consigliato, in generale, il suo utilizzo per il calcolo matematico a causa dei tempi di elaborazione troppo lunghi [13]), ma è estremamente più flessibile e facilmente riconfigurabile: di qui la scelta di utilizzarlo per definire la costruzione, la gestione e le decisioni ad “alto livello”. GNU Radio prevede anche la presenza opzionale di GUI, per rendere il sistema più “user friendly”: la costruzione di interfacce grafiche è affidata ad un toolkit basato su Python, studiato appositamente per facilitare la portabilità (wxPython).

Per poter interfacciare tra di loro i due differenti linguaggi di programmazione è stato infine inserito un ulteriore layer software, invocato soltanto in fase di inizializzazione dell’applicazione: lo SWIG (Simplified Wrapper and Interface Generator)7.

Il software GNU Radio è a sua volta organizzato in maniera modulare: accanto ad alcuni pacchetti base necessari è stata sviluppata dalla comunità dei programmatori e degli utenti (in conformità al principio del software open source) una vasta gamma di pacchetti software opzionali, che implementano i blocchi necessari a diversi tipi di applicazioni.

I pacchetti base sono [14]:

gnuradio-core: la libreria principale, contenente il sistema sottostante i blocchi di processing, indipendenti dal particolare hardware utilizzato;

gr-wxgui: framework grafico GUI;

7

(15)

gr-audio-alsa: supporto per i driver ALSA;

gr-audio-oss: supporto per i driver OSS;

usrp: librerie specifiche per il controllo della scheda USRP con il firmware FPGA;

gr-usrp: integrazione dei driver USRP nel framework di GNU Radio.

All’interno della libreria gnuradio-core sono contenute le funzioni di base disponibili, comprendenti [15]:

• un set di operatori matematici, comprendenti tra gli altri: o sommatore di sequenza costante

o sommatore di differenti flussi di campioni o moltiplicatore per una sequenza costante o moltiplicatore per differenti flussi di campioni o divisore

o funzione logaritmi

• diversi tipi di sorgente (reale e complessa), tra cui: o campioni nulli

o funzioni trigonometriche (seno e coseno) o sorgenti di rumore

o ingresso da vettore

• diversi tipi di destinazione: o file o scheda audio o vettori o oscilloscopio o analizzatore di spettro • filtraggio

o diversi filtri FIR implementati o funzione per il filtraggio IIR e FIR

o definizione di filtri IIR semplici (a singolo polo)

• conversioni di tipo

(16)

Tra i pacchetti opzionali si hanno invece:

gnuradio-examples: contiene alcuni semplici esempi per provare le funzioni primitive;

gr-gsm-fr-vocoder: encoder/decoder vocale per il sistema GSM a 13 kbit/sec;

gr-howto-write-a-block: documentazione ed esempi su come scrivere un blocco di signal processing.

Altri applicativi implementati dalla comunità di sviluppatori sono:

• ricevitore e trasmettitore per FM commerciale

• ricevitore per trasmissioni AM commerciali

• ricetrasmettitori amatoriali

• access point e host interface per reti WLAN 802.11

• ricevitori e trasmettitori GSM

• ricevitori e trasmettitori HDTV non real time per standard ATSC (Advanced Television Systems Committee, organizzazione americana)

Sono infine in fase di definizione e studio innumerevoli ulteriori applicativi, tra cui: sistemi di radioastronomia, sistemi MIMO, GPS, reti di sensori, reti ad hoc, sistemi radar passivi, etc.

2.2.3 Convenzioni

Si vedrà di seguito, accennato per sommi capi, il procedimento da seguire per scrivere un nuovo blocco di signal processing in GNU Radio; l’attenzione sarà focalizzata su aspetti formali quali la nomenclatura e le convenzioni da rispettare: la maggior parte dei passaggi, seppur fortemente consigliata dal creatore di GNU Radio Eric Blossom, non è obbligata [16]. Non si entrerà nello specifico degli aspetti di programmazione, rimandando piuttosto all’appendice 2.A a titolo di esempio e nel contempo raccomandando la bibliografia apposita ([16] - [20]).

Il primo passo a cui prestare attenzione è la costruzione di un albero di sviluppo, che deve possibilmente rispettare la struttura mostrata in tabella 2.1.

(17)

File/Dir Name Comment

topdir/Makefile.am Makefile.am

topdir/Makefile.common

Frammenti comuni inclusi nei vari Makefile delle sottodirectory

topdir/bootstrap Esegue autoconf, automake, libtool la prima volta

topdir/config Directory di macros usate da configure.ac

topdir/configure.ac Input per autoconf

topdir/src

topdir/src/lib Cartella in cui inserire il codice C++

topdir/src/lib/Makefile.am

topdir/src/python Cartella in cui inserire il codice Python

topdir/src/python/Makefile.am

topdir/src/python/run_tests Script per eseguire test nell’albero di sviluppo

Tabella 2.1: impostazione delle directory

Creare un nuovo blocco di signal processing implica la scrittura di tre file distinti: un file .h ed uno .cc, che definiscono una nuova classe, ed un file .i the dica allo SWIG come deve essere interfacciata tale classe in Python. A questi tre file si può aggiungere un file .py, in cui viene definito e descritto il grafo che rappresenta il flusso dei dati all’interno del sistema radio e cioè il suo schema a blocchi. Quest’ultimo file, scritto in Python, non rientra in senso stretto nella costruzione di un singolo blocco, ma anche in esso è opportuno fare attenzione alla nomenclatura.

Riguardo alle convenzioni sui nomi di file, cartelle e variabili, valgono le seguenti regole:

• non sono ammessi spazi;

• tutti gli identificatori devono essere scritti in minuscolo, escluse macro e costanti, che devono essere interamente maiuscole;

• se il nome è formato da più parole, queste vanno separate con il carattere “_”;

• le variabili globali devono essere precedute da un prefisso identificativo; attualmente esistono i seguenti prefissi:

(18)

o gr_ o gri_ o atsc_ o usrp_ o qa_

• all’interno delle definizioni delle classi, tutti le variabili di istanza devono avere il prefisso d_, mentre i membri statici devono avere prefisso s_;

• il nome della classe deve comparire anche come nome dei corrispondenti file .h e .cc;

• a seconda di cosa si stia definendo (in sostanza del tipo di dati che il blocco tratta), si devono utilizzare anche i seguenti suffissi, che indicano il tipo di dato in ingresso ed il tipo di dato in uscita:

o _f (float)

o _c (complex float) o _s (short int a 16 bit) o _i (int a 32 bit)

• tali suffissi devono essere scritti:

o una sola volta per sorgenti (source) e destinazioni (sink); es: end_f o due volte per tutti i blocchi intermedi; es: end_ff

o tre volte per i filtri FIR (indicano tipo di input, output e coefficienti); es:

end_fff

• un ulteriore suffisso è la lettera “v”, da applicare per blocchi che accettano come ingressi e/o come uscite vettori; es: gr_fft_vcc

(19)

Appendici

2.A Esempi di codice GNU Radio

Si propongono ora alcuni listati molto semplici, tratti dal pacchetto software GNU Radio, per mostrare un esempio pratico di costruzione di un blocco (2.A.1, file howto_square_ff.h; 2.A.2, file howto_square_ff.cc; 2.A.3, file howto.i; 2.A.4, file Makefile.am) e di un grafo (2.A.5, file usrp_wfm_rcv.py).

2.A.1 howto_square_ff.h

~/gnuradio/gr-howto-write-a-block/src/lib/howto_square_ff.h /* -*- c++ -*- */ #ifndef INCLUDED_HOWTO_SQUARE_FF_H #define INCLUDED_HOWTO_SQUARE_FF_H #include <gr_block.h> class howto_square_ff; /*

* We use boost::shared_ptr's instead of raw pointers for all access * to gr_blocks (and many other data structures). The shared_ptr gets * us transparent reference counting, which greatly simplifies storage * management issues. This is especially helpful in our hybrid

* C++ / Python system. *

* See http://www.boost.org/libs/smart_ptr/smart_ptr.htm *

* As a convention, the _sptr suffix indicates a boost::shared_ptr */

typedef boost::shared_ptr<howto_square_ff> howto_square_ff_sptr; /*!

* \brief Return a shared_ptr to a new instance of howto_square_ff. *

* To avoid accidental use of raw pointers, howto_square_ff's * constructor is private. howto_make_square_ff is the public * interface for creating new instances.

*/

howto_square_ff_sptr howto_make_square_ff (); /*!

* \brief square a stream of floats. * \ingroup block

*

* \sa howto_square2_ff for a version that subclasses gr_sync_block. */

(20)

class howto_square_ff : public gr_block {

private:

// The friend declaration allows howto_make_square_ff to // access the private constructor.

friend howto_square_ff_sptr howto_make_square_ff (); howto_square_ff (); // private constructor

public:

~howto_square_ff (); // public destructor // Where all the action really happens int general_work (int noutput_items,

gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); }; #endif /* INCLUDED_HOWTO_SQUARE_FF_H */

2.A.2 howto_square_ff.cc

~/gnuradio/gr-howto-write-a-block/src/lib/howto_square_ff.cc /* -*- c++ -*- */ /*

* config.h is generated by configure. It contains the results * of probing for features, options etc. It should be the first * file included in your .cc file.

*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <howto_square_ff.h> #include <gr_io_signature.h> /*

* Create a new instance of howto_square_ff and return

* a boost shared_ptr. This is effectively the public constructor. */

howto_square_ff_sptr howto_make_square_ff () {

return howto_square_ff_sptr (new howto_square_ff ()); }

/*

* Specify constraints on number of input and output streams. * This info is used to construct the input and output signatures * (2nd & 3rd args to gr_block's constructor). The input and * output signatures are used by the runtime system to

* check that a valid number and type of inputs and outputs * are connected to this block. In this case, we accept

(21)

* only 1 input and 1 output. */

static const int MIN_IN = 1; // mininum number of input streams static const int MAX_IN = 1; // maximum number of input streams static const int MIN_OUT = 1; // minimum number of output streams static const int MAX_OUT = 1; // maximum number of output streams /*

* The private constructor */

howto_square_ff::howto_square_ff () : gr_block ("square_ff",

gr_make_io_signature (MIN_IN, MAX_IN, sizeof (float)), gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (float))) {

// nothing else required in this example }

/*

* Our virtual destructor. */

howto_square_ff::~howto_square_ff () {

// nothing else required in this example }

int

howto_square_ff::general_work (int noutput_items, gr_vector_int &ninput_items,

gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) {

const float *in = (const float *) input_items[0]; float *out = (float *) output_items[0];

for (int i = 0; i < noutput_items; i++){ out[i] = in[i] * in[i];

}

// Tell runtime system how many input items we consumed on // each input stream.

consume_each (noutput_items);

// Tell runtime system how many output items we produced. return noutput_items;

}

2.A.3 howto.i

~/gnuradio/gr-howto-write-a-block/src/lib/howto.i

/* -*- c++ -*- */

%feature("autodoc", "1"); // generate python docstrings %include "exception.i"

(22)

%import "gnuradio.i" // the common stuff %{

#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix #include "howto_square_ff.h" #include "howto_square2_ff.h" #include <stdexcept> %} // --- /*

* First arg is the package prefix.

* Second arg is the name of the class minus the prefix. *

* This does some behind-the-scenes magic so we can * access howto_square_ff from python as howto.square_ff */

GR_SWIG_BLOCK_MAGIC(howto,square_ff);

howto_square_ff_sptr howto_make_square_ff (); class howto_square_ff : public gr_block

{ private: howto_square_ff (); }; // --- GR_SWIG_BLOCK_MAGIC(howto,square2_ff); howto_square2_ff_sptr howto_make_square2_ff (); class howto_square2_ff : public gr_sync_block { private: howto_square2_ff (); };

2.A.4 Makefile.am

~/gnuradio/gr-howto-write-a-block/src/lib/Makefile.am include $(top_srcdir)/Makefile.common

# Install this stuff so that it ends up as the gnuradio.howto module # This usually ends up at:

# ${prefix}/lib/python${python_version}/site-packages/gnuradio ourpythondir = $(grpythondir)

ourlibdir = $(grpyexecdir)

AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)

(23)

$(WITH_INCLUDES) ALL_IFILES = \ $(LOCAL_IFILES) \ $(NON_LOCAL_IFILES) NON_LOCAL_IFILES = \ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i LOCAL_IFILES = \ $(top_srcdir)/src/lib/howto.i

# These files are built by SWIG. The first is the C++ glue.

# The second is the python wrapper that loads the _howto shared library # and knows how to call our extensions.

BUILT_SOURCES = \

howto.cc \

howto.py

# This gets howto.py installed in the right place

ourpython_PYTHON = \

howto.py

ourlib_LTLIBRARIES = _howto.la

# These are the source files that go into the shared library

_howto_la_SOURCES = \

howto.cc \

howto_square_ff.cc \ howto_square2_ff.cc

# magic flags

_howto_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version

# link the library against some comon swig runtime code and the # c++ standard library

_howto_la_LIBADD = \

$(PYTHON_LDFLAGS) \ -lstdc++

howto.cc howto.py: $(LOCAL_IFILES) $(ALL_IFILES)

$(SWIG) $(SWIGPYTHONARGS) -module howto -o howto.cc $(LOCAL_IFILES) # These headers get installed in ${prefix}/include/gnuradio

grinclude_HEADERS = \

howto_square_ff.h \ howto_square2_ff.h

# These swig headers get installed in ${prefix}/include/gnuradio/swig swiginclude_HEADERS = \

$(LOCAL_IFILES)

MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc # Don't distribute output of swig

(24)

@for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done

2.A.5 usrp_wfm_rcv.py

~/gnuradio/gnuradio-examples/python/usrp/usrp_wfm_rcv.py

#!/usr/bin/env python #

# Copyright 2005,2006,2007 Free Software Foundation, Inc. from gnuradio import gr, gru, eng_notation, optfir

from gnuradio import audio from gnuradio import usrp from gnuradio import blks2

from gnuradio.eng_option import eng_option from gnuradio.wxgui import slider, powermate

from gnuradio.wxgui import stdgui2, fftsink2, form from optparse import OptionParser

from usrpm import usrp_dbid import sys

import math import wx

def pick_subdevice(u): """

The user didn't specify a subdevice on the command line.

Try for one of these, in order: TV_RX, BASIC_RX, whatever is on side A. @return a subdev_spec

"""

return usrp.pick_subdev(u ,(usrp_dbid.TV_RX,

usrp_dbid.TV_RX_REV_2, usrp_dbid.TV_RX_REV_3, usrp_dbid.BASIC_RX))

class wfm_rx_block (stdgui2.std_top_block): def __init__(self,frame,panel,vbox,argv):

stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv) parser=OptionParser(option_class=eng_option)

parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,

help="select USRP Rx side A or B (default=A)") parser.add_option("-f", "--freq", type="eng_float", default=100.1e6, help="set frequency to FREQ", metavar="FREQ") parser.add_option("-g", "--gain", type="eng_float", default=40, help="set gain in dB (default is midpoint)") parser.add_option("-V", "--volume", type="eng_float", default=None, help="set volume (default is midpoint)")

parser.add_option("-O", "--audio-output", type="string", default="", help="pcm device name. E.g., hw:0,0 or surround51

or /dev/dsp")

(options, args) = parser.parse_args() if len(args) != 0:

(25)

parser.print_help() sys.exit(1) self.frame = frame self.panel = panel self.vol = 0 self.state = "FREQ" self.freq = 0 # build graph

self.u = usrp.source_c() # usrp is data source adc_rate = self.u.adc_rate() # 64 MS/s

usrp_decim = 200

self.u.set_decim_rate(usrp_decim)

usrp_rate = adc_rate / usrp_decim # 320 kS/s chanfilt_decim = 1

demod_rate = usrp_rate / chanfilt_decim audio_decimation = 10

audio_rate = demod_rate / audio_decimation # 32 kHz if options.rx_subdev_spec is None:

options.rx_subdev_spec = pick_subdevice(self.u) self.u.set_mux(usrp.determine_rx_mux_value(self.u,

options.rx_subdev_spec)) self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) print "Using RX d'board %s" % (self.subdev.side_and_name(),)

chan_filt_coeffs = optfir.low_pass (1, # gain

usrp_rate, # sampling rate 80e3, # passband cutoff 115e3, # stopband cutoff 0.1, # passband ripple 60) # stopband attenuation #print len(chan_filt_coeffs)

chan_filt = gr.fir_filter_ccf (chanfilt_decim, chan_filt_coeffs) self.guts = blks2.wfm_rcv (demod_rate, audio_decimation)

self.volume_control = gr.multiply_const_ff(self.vol) # sound card as final sink

audio_sink = audio.sink (int (audio_rate), options.audio_output, False) # ok_to_block

# now wire it all together

self.connect (self.u, chan_filt, self.guts, self.volume_control, audio_sink)

self._build_gui(vbox, usrp_rate, demod_rate, audio_rate) if options.gain is None:

# if no gain was specified, use the mid-point in dB g = self.subdev.gain_range()

(26)

if options.volume is None: g = self.volume_range() options.volume = float(g[0]+g[1])/2 if abs(options.freq) < 1e6: options.freq *= 1e6 # set initial values

self.set_gain(options.gain) self.set_vol(options.volume)

if not(self.set_freq(options.freq)):

self._set_status_msg("Failed to set initial frequency")

def _set_status_msg(self, msg, which=0):

self.frame.GetStatusBar().SetStatusText(msg, which)

def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate): def _form_set_freq(kv):

return self.set_freq(kv['freq'])

if 1:

self.src_fft = fftsink2.fft_sink_c(self.panel,

title="Data from USRP", fft_size=512,

sample_rate=usrp_rate) self.connect (self.u, self.src_fft)

vbox.Add (self.src_fft.win, 4, wx.EXPAND) if 1: post_filt_fft = fftsink2.fft_sink_f(self.panel, title="Post Demod", fft_size=1024, sample_rate=usrp_rate, y_per_div=10, ref_level=0) self.connect (self.guts.fm_demod, post_filt_fft) vbox.Add (post_filt_fft.win, 4, wx.EXPAND)

if 0: post_deemph_fft = fftsink2.fft_sink_f(self.panel, title="Post Deemph", fft_size=512, sample_rate=audio_rate, y_per_div=10, ref_level=-20) self.connect (self.guts.deemph, post_deemph_fft) vbox.Add (post_deemph_fft.win, 4, wx.EXPAND)

# control area form at bottom self.myform = myform = form.form() hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add((5,0), 0)

(27)

myform['freq'] = form.float_field(

parent=self.panel, sizer=hbox, label="Freq", weight=1, callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) hbox.Add((5,0), 0) myform['freq_slider'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,

range=(87.9e6, 108.1e6, 0.1e6), callback=self.set_freq) hbox.Add((5,0), 0) vbox.Add(hbox, 0, wx.EXPAND) hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add((5,0), 0) myform['volume'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume", weight=3, range=self.volume_range(), callback=self.set_vol) hbox.Add((5,0), 1) myform['gain'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain", weight=3, range=self.subdev.gain_range(), callback=self.set_gain) hbox.Add((5,0), 0) vbox.Add(hbox, 0, wx.EXPAND) try: self.knob = powermate.powermate(self.frame) self.rot = 0

powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate) powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button) except:

print "FYI: No Powermate or Contour Knob found" def on_rotate (self, event):

self.rot += event.delta if (self.state == "FREQ"): if self.rot >= 3: self.set_freq(self.freq + .1e6) self.rot -= 3 elif self.rot <=-3: self.set_freq(self.freq - .1e6) self.rot += 3 else: step = self.volume_range()[2] if self.rot >= 3: self.set_vol(self.vol + step) self.rot -= 3 elif self.rot <=-3: self.set_vol(self.vol - step) self.rot += 3

(28)

def on_button (self, event):

if event.value == 0: # button up return self.rot = 0 if self.state == "FREQ": self.state = "VOL" else: self.state = "FREQ" self.update_status_bar () def set_vol (self, vol):

g = self.volume_range()

self.vol = max(g[0], min(g[1], vol))

self.volume_control.set_k(10**(self.vol/10)) self.myform['volume'].set_value(self.vol) self.update_status_bar ()

def set_freq(self, target_freq):

"""

Set the center frequency we're interested in. @param target_freq: frequency in Hz

@rypte: bool

Tuning is a two step process. First we ask the front-end to tune as close to the desired frequency as it can. Then we use the result of that operation and our target_frequency to

determine the value for the digital down converter. """

r = usrp.tune(self.u, 0, self.subdev, target_freq) if r: self.freq = target_freq self.myform['freq'].set_value(target_freq) self.myform['freq_slider'].set_value(target_freq) self.update_status_bar() self._set_status_msg("OK", 0) return True self._set_status_msg("Failed", 0) return False

def set_gain(self, gain):

self.myform['gain'].set_value(gain) # update displayed value self.subdev.set_gain(gain)

def update_status_bar (self):

msg = "Volume:%r Setting:%s" % (self.vol, self.state) self._set_status_msg(msg, 1) self.src_fft.set_baseband_freq(self.freq) def volume_range(self): return (-20.0, 0.0, 0.5) if __name__ == '__main__':

app = stdgui2.stdapp (wfm_rx_block, "USRP WFM RX") app.MainLoop ()

(29)

Riferimenti Bibliografici

[1] http://en.wikipedia.org/wiki/Software-defined_radio.

[2] http://www.sdrforum.org.

[3] Leon W. Couch II, “Fondamenti di telecomunicazioni”, Apogeo, 2002.

[4] Dawei Shen, “Tutorial 3: Entering the World of GNU Software Radio”, 2005.

http://www.nd.edu/~jnl/sdr/docs/tutorials/.

[5] Aldo N. D’Andrea, “Comunicazioni Elettriche”, ETS, 2002.

[6] Joseph Mitola III, “Software Radio Architecture Object Oriented Approaches to Wireless Systems Engineering”, John Wiley & Sons Inc, 2000.

[7] Walter Tuttlebee, “Software Defined Radio Enabling Technologies”, John Wiley & Sons Inc, 2002.

[8] Paul Burns, “Software Defined Radio for 3G”, Artech House, 2003.

[9] Ahmed Eltawil, “Realizing the power of Software Defined Radio”,

http://newport.eecs.uci.edu/~aeltawil/.

[10] http://www.gnuradio.org/trac.

[11] http://www.gnu.org/software/gnuradio/.

[12] Dawei Shen, “Tutorial 4: The USRP Board”, 2005.

http://www.nd.edu/~jnl/sdr/docs/tutorials/.

(30)

[14] Alessandro Di Nepi, “GNU Radio: A primer”.

http://www.comlab.uniroma3.it/.

[15] http://gnuradio.org/doc/doxygen/modules.html.

[16] Eric Blossom, “How to Write a Signal Processing Block”, 2006.

http://www.gnu.org/software/gnuradio/doc/.

[17] Eric Blossom, “GNU Radio: Tools for Exploring the Radio Frequency Spectrum”, 2004. http://www.linuxjournal.com/article/7319.

[18] Dawei Shen, “Tutorial 5: Getting Prepared for Python in GNU Radio by Reading the FM Receiver Code Line by Line”, 2005. http://www.nd.edu/~jnl/sdr/docs/tutorials/.

[19] Dawei Shen, “Tutorial 6: Graph, Blocks & Connecting”, 2005.

http://www.nd.edu/~jnl/sdr/docs/tutorials/.

[20] Dawei Shen, “Tutorial 10: Writing A Signal Processing Block for GNU Radio”, 2005.

Figura

Fig. 2.1: esempio di ricetrasmettitore I-Q con elaborazione numerica in banda base
Fig. 2.2: architettura generica di un sistema SDR
Fig. 2.3: comunicazioni tra mezzi di Soccorso Pubblico o militari
Fig. 2.4: architettura di GNU Radio
+7

Riferimenti

Documenti correlati

Our exploration method is based on Ant Colony Optimization (ACO) [ 13 ] and efficiently solves the combined problem: it refines the target architecture (i.e., it selects both

Abl = ablative, Acc = accusative, AmongP = among construction, BareP = bare partitives, CanonP = canonical partitives, CovertP = covert partitives, DegP =

Si può quindi concludere che gli effetti sugli agenti attivi dovuti a un diverso termine massimo di incarcerazione e ad un aumento delle forze dell’ordine in presenza di

Se sin dall’inizio i brand stranieri di alta moda rappresentavano l’intero mercato, grazie alla loro indiscussa identità culturale e approvata sapienza nel

© The Author(s). European University Institute. Available Open Access on Cadmus, European University Institute Research Repository... EU Citizenship as the

Questo penalizza in particolar modo il colore verde, che non è mai ottenuto come miscela di blu e giallo, non solo per via di tabù religiosi, ma anche a causa della

Da queste poche informazioni, associate a quelle fornite dallo studioso Miotti si sono sviluppate le campagne di scavo dell’Università Cà Foscari che, oltre a

Available Open Access on Cadmus, European University Institute Research Repository... Charles Tilly thinks the Europeanization of conflict may already