Lo sviluppo delle tecnologie di memorizzazione e trattamento digitale dei segnali è stato possibile grazie anche alla diffusione di convertitori digitali sempre più prestanti e di tecniche di compressione del segnale sempre più raffinate. Comprimere segnali digitali significa risparmiare tempo e spazio. Si esamina una tecnica di compressione audio detta ADPCM ed una applicazione pratica della stessa per la riproduzione sonora in tale formato, mediante PICMicro®.
ADPCM: LA TEORIA
Formati di compressione
La possibilità di risparmiare spazio e tempo operando sulla forma d’onda è stata una scelta obbligata. Inizialmente si operava sul segnale analogico, attualmente invece con la diffusione capillare dei microcontrollori e dei DSP è stato possibile agire sul segnale digitale con i vantaggi che ne conseguono (maggiore immunità al rumore e capacità di architetture sempre più complesse). La Figura 1 riporta il tipico schema a blocchi di un convertitore analogico/digitale.
Come si può vedere, è necessario implementare due blocchi fondamentali:
- il campionatore, che preleva i campioni (s[n]) del segnale analogico (s(t)) ad istanti di tempo predefiniti. La velocità con cui avviene questo processo prende il nome di frequenza di campionamento;
- il quantizzatore, che trasforma il segnale analogico campionato (s[n]) in una parola digitale (c[n]) formata da un numero variabile di bit, per poter essere trattato dai circuiti digitali. In base alle modalità con cui viene effettuato questo processo (detto anche di codifica) è possibile comprimere il segnale e quindi risparmiare bit. Il passo di quantizzazione rappresenta la minima risoluzione del segnale convertito.
Dalla lunghezza della parola digitale dipende, in buona sostanza, la fedeltà e la qualità del campionamento. Un modo per valutare la bontà dell’audio in uscita è la cosiddetta scala MOS. La Tabella 1 riporta i diversi livelli di tale scala.
La scala MOS è una valutazione ottenuta in modo statistico ed empirico, da un campione di persone (uomini e donne) che ascoltano brevi pezzi di parlato. Uno degli standard di codifica maggiormente utilizzato per l’audio è il PCM (Pulse Code Modulation). Esso è impiegato principalmente per segnali di qualità telefonica. Poiché il segnale analogico telefonico (voce) è limitato alla banda 300÷3400Hz è sufficiente una frequenza di 8000Hz (1 campione ogni 125ms) per la sua conversione, in accordo con il teorema di Nyquist secondo il quale per la corretta ricostruzione di un segnale digitale, è necessaria una frequenza di campionamento almeno doppia rispetto alla banda del segnale analogico. Il numero di bit per ogni campione è pari ad 8. Questo comporta un bitrate di 64kbps. Esistono due tipi di codifica PCM, non uniforme ed uniforme, in base al passo di quantizzazione utilizzato. Nel primo caso si sfruttano le leggi di codifica dette µ-Law (in Nord America e Giappone) e A-Law (in Europa e nel resto del mondo), secondo quanto stabilito dallo standard ITU-T G.711. Si tratta in entrambi i casi di una codifica logaritmica. La legge di compressione nel caso di codifica A-Law è di seguito riportata:
dove A = 87.6, x il valore non compresso e y quello compresso. La Figura 2 riporta il grafico di tale funzione.
Nel caso di codifica µ-Law la funzione utilizzata ha, invece, la forma seguente:
dove µ = 255 e x,y hanno analogo significato. In entrambi i casi si effettua una compressione dei livelli sonori, privilegiando quelli più bassi dove si può dimostrare che l’errore di quantizzazione risulta superiore.
Ovviamente, in fase di decodifica sarà necessario effettuare un espansione del segnale. Tale processo di compressione e decompressione è spesso indicato con il termine inglese compension, contrazione di compression e expansion. Questa codifica ha qualità sonora MOS 4+. Esiste anche la codifica PCM uniforme in cui si utilizzano 16bit/campione ed una frequenza di campionamento pari a 44.1kHz (il cosiddetto audio di qualità CD). Il bitrate risultante è in questo caso pari a 705kbps per ogni canale. In questo caso il passo di quantizzazione risulta fisso. La qualità è MOS 5 (il massimo). Una sensibile riduzione del numero di bit utilizzati si può ottenere se si codifica la differenza tra un campione ed il precedente, anziché il valore assoluto del campione stesso. Si tratta delle cosiddette tecniche di compressione differenziale. Un esempio di queste codifiche è rappresenta da variate della PCM, conosciuta con il termine di DPCM (Differential PCM). Un caso particolare della DPCM è la cosiddetta codifica delta (e), in cui si aumenta la frequenza di campionamento per ottenere una maggiore correlazione tra i campioni. In questa maniera è possibile utilizzare un solo bit per la codifica. Il codificatore, in sostanza, dice se il campione è più grande (“1”) oppure più piccolo (“0”) del precedente. La Figura 3 chiarisce il senso di tale codifica.
Tra gli svantaggi delle codifiche differenziali vi è il cosiddetto fenomeno dello slope overload. Differenze elevate (e quindi frequenze elevate) non si possono rappresentare con un ridotto numero di bit. Gli errori introdotti si ripercuotono sulla qualità del segnale, distorcendolo. Per superare i limiti della DPCM o della codifica delta si è giunti all’introduzione della Adaptative Differential PCM (ADPCM), regolata dallo standard ITU-T G-726. Anche in questo caso viene codificata la differenza tra il campione e quello stimato. Esiste però la possibilità di modificare, in maniera adattativa appunto, l’ampiezza degli intervalli di quantizzazione in funzione del segnale di ingresso: si usa un passo più grande per codificare un segnale ad elevata frequenza ed uno più piccolo per variazioni più lente del segnale. La Figura 4 riporta un esempio in cui il passo di quantizzazione viene adeguato (incrementato) per seguire meglio le variazioni del segnale (aumento della frequenza).
La presenza di un quantizzatore adattativo elimina il problema dello slope overload e quindi della distorsione. Il bitrate minimo è pari a 16kbps, utilizzando 4bit/campione con una frequenza di 8000Hz. La qualità della codifica ADPCM è pari a MOS 4. L’algoritmo stabilito dalla specifica G.726 utilizza una aritmetica floating-point e funzioni logaritmiche implementabili abbastanza agevolmente su un DSP. Alcuni esempi sono la serie TMS320 di Texas Instruments oppure ADSP-2100 di Analog Device. La Tabella 2 riassume i principali tipi di codifica per la compressione audio regolati delle specifiche ITU-T ed elenca le corrispondenti caratteristiche.
ADPCM: LA PRATICA
La codifica
La Figura 5 riporta lo schema a blocchi dell’encoder ADPCM (secondo la specifica IMA). Per l’implementazione hardware di un codificatore/decodificatore ADPCM è possibile ricorrere ad un micro ad 8bit senza necessariamente utilizzare un DSP.
Nel corso dell’articolo si farà riferimento ad un PIC16C72. Il firmware per l’implementazione delle funzioni, messo a disposizione gratuitamente da Microchip, permette di ridurre drasticamente il tempo necessario a sviluppare progetti basati su tale tecnica di codifica. Il Listato 1 riporta l’intera procedura ADPCMEncoder() per effettuare la codifica.
/****Routine di codifica ADPCM***************** /* Tabella degli indici delle variazioni */ const int IndexTable[16] = { 0xff, 0xff, 0xff, 0xff, 2, 4, 6, 8, 0xff, 0xff, 0xff, 0xff, 2, 4, 6, 8 }; /* Look-up table dei passi di quantizzazione */ const long StepSizeTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; signed long diff; /* Differenza tra il campione e quello predetto */ long step; /* Passo di quantizzazione */ signed long predsample; /* Uscita del predittore ADPCM */ signed long diffq; /* Differenza in uscita al quantizzatore inverso */ int index; /* Indice della tabella dei passi di quantizzazione */ char ADPCMEncoder( signed long sample ){ int code; /* Valore codificato in ADPCM */ int tempstep; /* Passo di quantizzazione temporaneo */ predsample = state.prevsample; index = state.previndex; step = StepSizeTable[index]; /* Esegue la differenza tra il campione attuale e quello predetto */ diff = sample - predsample; if(diff >= 0) code = 0; else{ code = 8; diff = -diff; } /* Quantizza la differenza con 4bit usando il passo di quantizzazione adeguato */ tempstep = step; if( diff >= tempstep ){ code |= 4; diff -= tempstep; } tempstep >>= 1; if( diff >= tempstep ){ code |= 2; diff -= tempstep; } tempstep >>= 1; if( diff >= tempstep ) code |= 1; /* Quantizzazione inverse del valore codificato in ADPCM 4bit */ diffq = step >> 3; if( code & 4 ) diffq += step; if( code & 2 ) diffq += step >> 1; if( code & 1 ) diffq += step >> 2; /* Il predittore esegue il calcolo del nuovo campione predetto aggiungendo il vecchio valore alla differenza predetta */ if( code & 8 ) predsample -= diffq; else predsample += diffq; /* Verifica dell’overflow del nuovo campione predetto */ if( predsample > 32767 ) predsample = 32767; else if( predsample < -32768 ) predsample = -32768; /* Ricerca del nuovo passo di quantizzazione aggiungendo il vecchio indice alla look-up table */ index += IndexTable; if( index < 0 ) index = 0; if( index > 88 ) index = 88; /* Salva il campione predetto ed il passo di quantizzazione per la successive chiamata della routine */ state.prevsample = predsample; state.previndex = index; /* Return the new ADPCM code */ return ( code & 0x0f ); }
Listato 1 |
Essa ha come output un valore ad 8bit, di cui i 4 bit LSB rappresentano il valore del campione codificato in ADPCM, mentre i 4 bit MSB sono posti a zero. La funzione richiede 5 variabili a 16bit e 2 variabili ad 8bit. Il campione predetto, sp[n-1], e l’indice dei passi di quantizzazione sono memorizzati in una struttura apposita per le iterazioni successive. Inizialmente, questi valori sono impostati a zero. L’ingresso, s[n], alla routine di codifica deve essere un valore a 16bit ed in complemento a due. Perciò, il range di tutti i possibili valori varia da -32768 a +32767. Prima di essere quantizzato, al valore s[n] viene sottratto il valore predetto, sp[n-1]. Secondo la specifica G.726 il valore predetto è calcolato sulla base di una media pesata degli ultimi sei campioni. Nell’implementazione IMA, invece, si utilizza il valore precedente (sp[n-1]), riducendo in questo modo l’occupazione di memoria e il numero di istruzioni eseguite. La quantizzazione adattativa è effettuata, dunque, sulla differenza d[n], producendo una valore digitale a 4bit con segno (c[n]). Quest’ultimo valore viene retroazionato in ingresso, diventando il campione da sottrarre alla successiva iterazione. Per rendere adattativa la codifica si varia il passo di quantizzazione in base alla differenza quantizzata. Il valore dell’indice serve per ricavare quello del passo. Il passo viene deciso dal modificatore del passo di quantizzazione (Step-Size Adjuster, Figura 5), di cui è fornito uno schema a blocchi in Figura 6.
Ad esempio, se d[n] = x001 (La ‘x’ indica che il discorso vale sia per variazioni positive (x=0) che per quelle negative (x=1)) significa che il segnale sta variando di poco e quindi si può usare un passo di quantizzazione più piccolo; se d[n] = x110 significa che il segnale sta subendo grandi variazioni e perciò lo step-size adjuster deve aumentare il valore dell’indice e quindi del passo. Il valore dell’indice ha come limite inferiore 0 e come limite superiore 88. È previsto un apposito controllo software per evitare situazioni di overflow o underlow di tale valore (Tabella 3).
La decodifica
Lo schema a blocchi del decoder è mostrato in Figura 7.
La funzione ha come parametro di ingresso un valore ad 8bit, contenente nel nibble basso i 4bit della codifica ADPCM. Il range dei valori ammissibili è compreso tra 0 e 15, dove 7 = 0x07 e -7 = 0x0F. Il listato 2 riporta il codice della funzione ADPCMDecoder().
/******Routine di decodifica ADPCM***************** signed long ADPCMDecoder(char code ){ /* Ripristina il precedente valore del campione predetto e dell’indice del passo di quantizzazione */ predsample = state.prevsample; index = state.previndex; /* Ricerca il passo di quantizzazione entrando con l’indice */ step = StepSizeTable[index]; /* Quantizzazione inverse del codice ADPCM */ diffq = step >> 3; if( code & 4 ) diffq += step; if( code & 2 ) diffq += step >> 1; if( code & 1 ) diffq += step >> 2; /* Aggiunge la differenza al valore predetto */ if( code & 8 ) predsample -= diffq; else predsample += diffq; if( predsample > 32767 ) predsample = 32767; else if( predsample < -32768 ) predsample = -32768; /* Ricerca del nuovo passo di quantizzazione */ index += IndexTable; if( index < 0 ) index = 0; if( index > 88 ) index = 88; /* Salvataggio del valore predetto e del passo di quantizzazione per la successive iterazione */ state.prevsample = predsample; state.previndex = index; /* Restituzione del nuovo campione di voce per l’ascolto */ return( predsample ); }
Listato 2 |
Il procedimento seguito è inverso a quello di codifica: si somma la differenza quantizzata al valore predetto. Il valore restituito dalla routine è un campione a 16bit in complemento a 2.
Descrizione dell’applicazione: l’hardware
La scheda descritta di seguito permette di riprodurre audio (precedentemente memorizzato in EPROM) in formato ADPCM. Il progetto può essere la base per un’applicazione più complessa che prevede la trasmissione o la memorizzazione di audio compresso. Lo schema a blocchi dell’intera applicazione è riportato in Figura 8.
I valori dell’audio ADPCM saranno ottenuti a partire da un file audio non compresso, con il software pcspeech descritto nel paragrafo successivo. Come si nota la scheda utilizza un PIC16C72, con una quarzo a 20MHz. Per la memorizzazione dell’au- dio si sono sfruttate due EPROM Microchip (27C512A), in grado di contenere fino a 32768 secondi di dati in formato ADPCM. Ciascuna EPROM può contenere un massimo di 64kB (= 65536byte). Ogni byte contiene due campioni. Poiché 1 secondo di parlato richiede 8000 campioni ADPCM, ciascuna memoria può contenere (65536 x 2) / 8000 = 16384 secondi. Per l’estrazione dei dati dalle EPROM è stato usato un contatore a 16bit. Questo metodo risulta molto efficiente perché permette di usare solo 2 linee I/O per il controllo e 11 linee I/O per la lettura. Una volta avviato, il contatore genererà in sequenza tutti gli indirizzi delle locazioni di memoria della EPROM. La rigenerazione della voce è eseguita utilizzando il modulo CCP (Capture/Compare/PWM) del micro. Il modulo PWM è configurato per un periodo di 32kHz. Tale frequenza è stata scelta molto più grande di quella massima del segnale audio. Ciò con- sente una ricostruzione del segnale analogico, con una buona reiezione delle frequenze spurie dovute alla modulazione. Tale periodo è impostato scrivendo nel registro PR2 il valore ricavato dalla formula seguente:
Periodo PWM = [PR2 +1] · 4 · TOSC · (prescaler del TMR2)
Dove TOSC è la frequenza operativa. Nel caso in esame si avrà:
1 / 32 kHz = [PR2 + 1] · 4 · (1 / 20 MHz) · 1
31.25 ms = [PR2 + 1] · 4 · 50 ns · 1
156.25 = PR2 + 1
155.25 = PR2
Il modulo PWM ha la capacità di generare un duty-cycle con risoluzione fino a 10bit. Per il calcolo di tale valore è necessario far riferimento alla formula:
Duty-Cycle PWM = DC<10:0> · TOSC · (prescaler del TMR2)
Dove DC<10:0> = 2x. X è il numero di bit di risoluzione. In questo caso, i calcoli da effettuare sono:
1 / 32 kHz = 2x · (1 / 20 MHz) · 1
31.25 µs = 2x · 50ns * 1
625 = 2x
log(625) = log(2x)
log(625) = x * log(2)
9.3 = x
Quindi il duty cycle del PWM può essere impostato fino a 9bit di risoluzione. Ciò si traduce nell’utilizzare i primi 9bit (dei 16) del campione decodificato per impostare il duty cycle, nel modo seguente:
CCPR1L = campione <15:9> CCP1CON <5:4> = campione <8:7>
Questa configurazione produce sul pin CCP1 del PIC un’onda quadra con periodo fisso (32kHz) ed un duty cycle variabile, secondo il valore del campione. Ovviamente, non è possibile inviare direttamente tale segnale d’uscita allo speaker in quando è necessario eliminare le componenti spettrali indesiderate, dovute alla modulazione ed amplificare. Per questo motivo l’onda quadra è fatta passare attraverso un filtro passa basso la cui frequenza di taglio è 4kHz. Il tipo di filtro utilizzato è un Butterworth del IV ordine. L’implementazione di tale circuito è stata eseguita con filtri attivi del II ordine in cascata, utilizzando l’integrato LF442. La scelta di un filtro del IV ordine (pendenza -80dB/decade) è necessaria per avere una buona reiezione della frequenza a 32kHz e di tutte le armoniche superiori. Un approccio alternativo sareb- be quello di salire con la frequenza del PWM ed usare un filtro con ordine minore (quindi utilizzando un numero minore di componenti). Infine, il segnale analogico così ottenuto è amplificato con l’integrato LM386N della National Semiconductor. Ogni 125µs (8kHz) un codice ADPCM deve essere convertito in un campione vocale dal PWM. Con un quarzo di 20MHz, si possono eseguire in tale tempo:
125µs / [(1 / 20) · 4] = 625 istruzioni
Questo significa che la routine di decodifica, la lettura dalla EPROM e la scrittura nel registro del PWM devono essere eseguite con non più di 625 istruzioni. Tale tempo è sicuramente sufficiente ad eseguire tutte le operazioni sopra descritte.
Descrizione dell’applicazione: il firmware
All’indirizzo http://ww1.microchip.com/downlo- ads/en/AppNotes/00643.zip è possibile effettuare il download dei file relativi alle funzioni ADPCMEncoder() ed ADPCMDecoder(), denominati Adpcm.c e Adpcm.h. Tali file dovranno essere inclusi in qualsiasi progetto che utilizzi la codifica o decodifica dell’audio. Oltre a tali file, nello stesso pacchetto è disponibile il firmware completo per la gestione della scheda descritta precedentemente. Il relativo file è denominato speech.c. Il file può essere compilato con MPLAB. Per una più chiara visione del programma si riporta il suo flow-chart in Figura 9.
Infine, tra i file che si possono scaricare dal sito Microchip è presente Pcspeech.exe, che consente di codificare e decodificare un file da formato non compresso a formato compresso e viceversa. Tale applicazione viene utilizzata su PC per creare il file da scaricare sulla EPROM. Per fare questo è necessario registrare, con un qualunque programma di registrazione, un file in formato 16bit e campionato a 8kHz (non stereofonico). Si supponga di chiamare questo file noncompr.wav. A questo punto si apra la shell di DOS e posizionandosi nella directory in cui è presente il programma di conversione, si digiti:
pcspeech e c:\noncompr.wav c:\adpcm.wav
Se la conversione è stata effettuata con successo il file codificato si chiamerà adpcm.wav. Il software riporta la dimensione del file non convertito, quella del file con i valori ADPCM ed il rapporto di conversione. Quest’ultimo è pari ovviamente a 4 poiché i campioni a 16bit sono stati compressi in valori a 4bit. La lettera “e”, utilizzata nella sintassi, indica che il software deve eseguire una codifica (Encoder). Il file così ottenuto può essere scaricato nella EPROM. Nel pacchetto dei file che è possibile scaricare dal sito Microchip sono anche disponibili i file sorgenti del programma Pcspeech.exe (pcspeech.c, pcadpcm.h e pcadpcm.c).
Upgrade del sistema: la codifica
Per implementare la registrazione dell’audio è necessario apportare le seguenti modifiche alla parte hardware precedentemente descritta:
- Sostituzione delle due EPROM con una SRAM.
- Aggiunta un microfono con ingresso filtrato.
- Utilizzo del convertitore A/D del PICMicro ad 8bit per registrazioni di qualità medio-bassa (oppure utilizzo di un A/D esterno a 12bit/16bit per una registrazione di qualità elevata).
La Figura 10 riporta lo schema a blocchi che si dovrebbe adoperare per realizzare anche la funzione di codifica, insieme a quella di decodifica.
I blocchi aggiunti rispetto a quelli di Figura 8 sono stati evidenziati con un bordo rosso. Di seguito sono riportati i passi principali da eseguire nel firmware per la registrazione:
- Utilizzo del timer per scandire la conversione A/D.
- Iniziare un nuova conversione ogni volta che il timer va in overflow.
- Leggere il campione e passarlo alla funzione ADPCMEncoder().
- Memorizzare il risultato nel nibble alto di una variabile temporanea.
- Avviare una nuova conversione quanto il timer ritorna in overflow.
- Passare il valore convertito alla funzione ADPCMEncorder().
- Memorizzare il risultato nibble basso nella variabile di cui al passo 4.
- Scrivere la variabile temporanea nella SRAM.
- Ritornare al passo 1.
Il tempo di conversione tipico di un PIC16C72 è di 40µs. Assumendo di utilizzare una quarzo a 20MHz con una frequenza di campionamento di 8kHz, la routine di codifica impiega approssimativamente 45µs ( = 225 istruzioni · 200ns) per fornire il valore codificato. Questo significa che restano circa 40µs (oppure 200 istruzioni) per leggere il valore dall’A/D, scriverlo nella SRAM e completare i restanti task. Per incrementare quest’ultimo tempo è necessario utilizzare convertitori esterni più veloci.
Conclusioni
Con il presente articolo si è voluto dare una panoramica d’insieme su una particolare tecnica di compressione audio, la ADPCM. Sono state fornite le basi teoriche per comprendere l’algoritmo di codifica/decodifica e si è poi proceduto all’implementazione dell’hardware necessario alla riproduzione di audio in tale formato. Per questo è stato utilizzato il processore della Microchip, PIC16C72, del quale sono state impiegate le risorse riportate in tabella 4.
Bibliografia
- “Pulse Code Modulation (PCM) of Voice Frequencies” - ITU-T Reccomendation G.711
- “40, 32, 24, 16 kbit/s Adaptative Differential Pulse Code Modulation (ADPCM )” - ITU-T Reccomendation G.726
- “Adaptive Differential Pulse Code Modulation using PICmicro™ Microcontrollers” – AN643.
Complessivamente l’adpcm si basa sulla predizione del campione, valutando correttamente l’errore attraverso varie tecniche come la MEMQ. Trova spazio principalmente nell’optoelettronica ( fibra ottica). C’e qualcuno che ha avuto modo di approfondire questa tecnica ?