Plne digitálny VU-meter s DSPic

Borsányi Tamás, UREL, FEEC, VUT Brno
xborsa00stud.feec.vutbr.cz,

Obsah:

  1. Úvod
  2. Realizácia
  3. Záver
  4. Literatúra

Úvod:

Tento projekt slúži ako doplnenie mojej bakalárskej práce "Nízkofrekvenční výkonový zesilovač ve třídě D s integorvaným DSP" [1]. Cieľom tohto projektu je vytvorenie merača vybudenia audio signálu, tzv. VU-meter. Prístroj má indikovať silu signálu pomocou LED stĺpca. VU-meter má mať digitálny vstup I2S, a má byť priamo pripojiteľný k audio A/D prevodníku použitého v zosilňovači (PCM1850 [3]).


Riadiaci mikrokontrolér má zvládať dekódovať I2S signál s vzorkovaním 48 kHz a bitovou šírkou aspoň 16b (pravý aj ľavý kanál). Ďalej do kontroléru majú byť naimplementované funkcie na spracovanie signálu, a má zvládať vytvárať dátový tok pre LED stĺpec. Vhodným riešením bol 16 bitový mikrokontrolér DSPic 33FJ12GP202 [2], výrobcom zvaný ako Digital Signal Controller, ktorý obsahuje rozšírenú inštrukčnú sadu DSP operácií a špeciálne registre a bloky pre tieto účely.

Complete_pict
Obr. 1: Hotový pristroj.

Realizácia:

1. Trocha teórie z analógových obvodov

Aby bolo možné signál spracovať, je potreba ho trosku upraviť. Poprvé je potreba audio signál usmerniť. Pri spracovaní nieje potreba mať signál oboch polarít, postačí len pozitívna polovina prípadne signál je možné usmerniť plným mostom, akoby vyrobiť absolútnu hodnotu signálu. Tento signál však ešte je potreba vyhladiť aby LED stĺpec neskákal na frekvenciu signálu, ale na tempo hudby (priemer sily signálu). U nízkych tónov by bolo možno vidieť samotný priebeh usmerneného sínusového signálu, ako blikanie celého LED stĺpca (veľmi rýchly priebeh od max k min). Kebyže boli LED stĺpce ešte aj multiplexované situácia by sa opakovala aj pri rôznych kombináciách frekvencie audio signálu a frekvencie multiplexu po celom počuteľnom pásme(typicky príklad nesprávne navrhnutého digi VU-metra). Tým pádom by bol prístroj len ťažko použiteľný, na profesionálne použitie potom vôbec. Teda je potreba pridať RC článok.
Aby LED stĺpec bol použiteľný na audio techniku je treba mať inú RC konštantu tau na zväčšujúci sa signál a na zmenšujúci sa signál. Čo znamená že LED stĺpec rýchlejšie bude reagovať na zväčšujúci sa signál a pomalejšie na zmenšujúci. U tohto konkrétneho prípadu je časová konštanta na zväčšujúci sa signál nulová, na padajúci signál potom desiatky až stovky ms (nastaviteľná). Tým pádom je vytvorený akýsi kvázi špičkový detektor. Celu časť je možné predstaviť v analógovej podobe takto:

Progress_bar
Obr. 2: Idealizovaný model


Kde rect(ifier) je diódový usmerňovač (plný či polovičný most), RC článok na vyhladenie signálu a dióda na okamžitú reakciu na rastúci signál.
Zapojenie však zďaleka nekryje skutočné zapojenie. U audio signálov sa predpokladá pomerne malá amplitúda, linkový výstup okolo 1 Vpp. Avšak v tomto prípade dióda u usmerňovačov a u RC článku sa neotvorí, alebo sa otvorí len veľmi málo, a tým značne skreslí výstup. Existuje viac možností, jeden z možných reálnych riešení môže vypadať takto:

Progress_bar
Obr. 3: Kompletný analógový model.


Takýto rozsiahli blok s idealizovanými usmerňovačmi a diódou potom už je vhodný na spracovanie audio signálu. Takýto blok je však oveľa jednoduchší implementovať softwarovo v mikrokontroléru. Má viacero výhod oproti analógu, ako: nulové miesto na plošnom spoji, celý blok je implementovaný kódom, bez pridania jedinej súčiastky, ideálne parametre bloku, netreba uvažovať otváracie napätie diód, limity operačných zosilňovačov, teplotná stálosť systému atd.

2. Trocha teórie z digitálneho spracovania signálu

Aby bolo možné signál spracovať digitálne je treba matematicky popísať predošlé zapojenie. Predpokladom je teraz, že už signál je digitalizovaný a nachádza sa niekde v pamäti mikrokontroléra (WREG6). Predpokladajme tiež že originálna hodnota bola znamienková s 16b šírkou v kódovaní dvojkový komplement. Potom absolútna hodnota (usmernenie) nieje nič viac ako test najvyššieho bitu (znamienka). Keď je znamienko nastavené, čiže je = 1 hodnota sa vynásobí -1 a pripočíta sa k nemu +1. Ako výsledok potom zostane 15b široká neznamienková absolútna hodnota.
Kód vytvárajúci absolútnu hodnotu (vstup aj výstup WREG6):

      if (WREG6 & 0x8000) WREG6 = ~WREG6 + 1;

Ďalej je potreba matematicky vyjadriť funkciu RC článku. RC článok sa vybíja exponenciálne a pracuje ako spriemerujúci filter. Existuje priamo typ filtra ktorý túto úlohu zvláda, nazýva sa exponenciálny kĺzavý priemer [4] ang.: exponential moving average [5]. Je možno ho predstaviť si takto:

Progress_bar
Obr. 4: Bloková schéma filtra s exponenciálnym kĺzavým priemerom


Kde xk(n) je vstupujúca hodnota, t je orezanie (truncation) vstupu, aby na výstupu boli hodnoty z intervalu akú na vstupu, yk(n) je výstup filtra, z-1 je oneskorenie (delay) o jednu vzorku, q je koeficient filtra, ktorým sa oneskorená hodnota vynásobí. Jeho hodnota musí byt medzi (0 - 1), čím bližšie je hodnota k 1 tým viac sa "spomaľuje" reakcia filtra (staršie vzorky strácajú prioritu pomalejšie).

Takýto filter nieje komplikovaným na zápis, keď je použitá reprezentácia čísel s plávajúcou desatinnou čiarkou. Avšak dnešné mikrokontroléry nemajú hardwarovo implementované FPU, dokážu pracovať floating pointom len softwarovo. Tým pádom by výpočet bol veľmi náročný. Avšak takýto filter sa dá implementovať aj celočíselne za cenu trocha komplikácie. Ako už bolo písané filter musí mat koeficient medzi (0-1). Ako spraviť násobenie 0,85 s celočíselnou hodnotou ? Riešenie je v použitý škálovania čísiel. Násobenie 0,85 je možno vytvoriť x⋅85/100. Ale aj delenie (ľubovoľným číslom) je dosť náročnou úlohou. Preto je dobre deliť číslom 2n, kde n je celé pozitívne číslo. Potom 0,85 je možno vytvoriť napr. x⋅870/1024 (0,849609) alebo aj x⋅3481/4096 (0,849854) atd. Je vidieť, že čím presnejšie chceme mať koeficient tým väčšie škálovanie je treba spraviť, ktoré môže viesť k limitom, alebo nepresnostiam. Riešením je mikrokontrolér so širokými akumulátormi, a MAC (multiply accumulate) inštrukciou, niektorý mikrokontrolér z rady DSPic33xxx.

3. DSP engine

Mikrokontroléry rady DSPic sú 16 bitové mikrokontroléry, a obsahujú takzvaný DSP engine, ktorý obsahuje 40 bitové akumulátory, 16b x 16b násobičku, 32 / 16 deličku, 40b + 40b sčítačku, 40b barell shifter a ďalšie užitočné hardwarovo implementované bloky. Pomocou takýchto hardwaovích pomôcok je potom možno inštrukciu ako MAC (multiply accumulate) vykonať za jediný takt hodinového signálu. Treba pridať že mikrokontroléry tejto rodiny dokážu pracovať na 40MHz s rýchlosťou 40 MIPS (teoreticky 40M MAC/s).
Pomocou 40b akumulátorov je potom možné signál vynásobiť veľmi presne. Aby bolo zrejmé o akú presnosť ide, uvediem príklad. Predpokladajme, že signál vstupujúci má 15b, takže ho bez problémov sa dá vynásobiť 216 (65535). Výsledok bude mať 31b, teda bohate sa zmestí do akumulátora. Potom krok je 1/65536 = 15,2588⋅10-6 a je možné násobiť hodnotami, ako:
x⋅65472/65536 = x⋅0,9990234
x⋅65473/65536 = x⋅0,9990387


Prečo počítať s až takou presnosťou ?
Po málo počítaní bude zrejmé že je to nevyhnutné pre bezchybnú funkciu systému. Vzorkovacia frekvencia vstupného signálu je 48 kHz. Povedzme že potrebujeme aby výstupná hodnota filtra z 100% klesla na hodnotu 36,8% za 341,3334 ms. (Vychádzajúcej z analógie RC článkov, čas vybitia z 100% na 36,8% sa nazýva tau). Potrebný čas prepočítame na počet vzorkou audiosignálu:

48000 ⋅ 341,3334⋅10-3 = 16384

Teraz sme zistili, že hodnota má klesnúť z 100% na 36,8% za 16384 vzorkov. Povedzme že filter obsahuje hodnotu 10000, teda otázka znie: o akú hodnotu musíme vynásobiť hodnotu vo filtru 16384 krát za sebou, aby zostala v registru hodnota 3680 ? Matematicky:

10000⋅x16384 = 3680
úpravou získame:

x = 10 ( log10(0,368) / 16384 )
x = 0,9999389867

hodnota sa dá vyjadriť potom ako 16383/16384 = 65532/65536 = 0,9999389648
Kvôli univerzálnosti sa použije ale formát 65532/65536. Delenie zostane napevno 216 a koeficient q sa nastaví násobením (čitateľom).
Chyba požadovanej hodnoty a hodnoty ktorú reálne použijeme je potom 0,9999389867 - 0,9999389648 = 21,86⋅10-9

Výpočet času sa dá overiť potom simuláciou (ktorá je súčasťou zip súboru projektu: tools/exp_time_VUmeter_16b.m).


Bitmap
Obr. 5: Meranie času tau matlabom.


Parametre simulácie: koeficient 65532/65536 = 0.9999389648
Filter sa vybíja z hodnoty 10000 na 0
Na hodnotu 3680 (36,8%) sa vybije za 16384 vzorkou, ktorá činí 1/48000⋅16384 = 341,334 ms (pri 48 kHz vzorkovaní).

Keby počítanie nebolo presné na toľko desatinných miest, mohla by nastať situácia, keď chyby sa začnú zhromažďovať v akumulátoru (akumulátor sa nikdy nevynuluje úplne). Toto by sa prejavovalo nesprávnou reakciou filtra, hodnota by neklesla inou konštantou (v závislosti na konkrétnych číslach). S presnosťou 21,86⋅10-9 však je isté že chyba sa neprejaví.


Bitmap
Obr. 6: Prirovnanie presností pomocou matlabu.


Na obrázku je vidieť prirovnanie priebehov, keď filter pracuje s 16b škálovaním (červene) a s 13b škálovaním (modro).
Filter klesá z hodnoty 4000, na vstupu neustále prichádza hodnota 970 (práve preto neklesne výstup na nulu).
Zdrojový kód tejto simulácie je súčasťou zip súboru projektu: tools/exp_time_VUmeter_16b_presnost.m.
Zaujímavé môže potom byť graf chýb hodnôt, ktoré boli počítané floating pointom a hodnoty ktoré boli počítané škálovaním.


Bitmap
Obr. 7: Výpočet chyby pomocou matlabu.


Na obrázku 7 je vidieť potom absolútnu chybu z hodnôt výstupu filtra, ktoré boli počítané floating pointom (predpokladá sa za presnú hodnotu) a ktoré boli počítané 16b škálovaním.

4. Softwarová implementácia

Časť kódu ktorý tvorí samotný filter je napísaný v inline assembleru (kus kódu ASM v C kóde), aby bolo možno dosiahnuť maximálnu rýchlosť.
Parametre:
tau na rastúci signál = 0
vybíjaci čas = 341.334ms (vzorkovanie 48kHz)
kód potom vyzerá nasledovne:

          if (WREG6 > R_out)  // WREG6 obsahuje hodnotu ADC_L
                {
                R_out = WREG6;

		asm volatile ("NOP"); //kompenzacia casu
                asm volatile ("NOP");
		asm volatile ("NOP");
		asm volatile ("NOP");
		asm volatile ("NOP");
		asm volatile ("NOP");
		asm volatile ("NOP");
		asm volatile ("NOP"); //kompenzacia casu
		}

          else
                {
		WREG5 = R_out;

                //vynulovanie celej časti bufferu pomocou registru
		asm volatile ("clr w7");
		//tým pádom zostane v ňom len zbytek z predošlého cyklu
		asm volatile ("mov w7,0x2A");

                //kompenzacny koeficient aj s truncation vstupneho signalu
		asm volatile ("mov #4,w7");
		//vynásobím vstupný signál koeficientom aby filter pracoval s celou 32b šírkou
		asm volatile ("mac w6*w7,B");

                // koeficient času
		asm volatile ("mov #65532,w7");
		// vynásobím predošlú hodnotu a pridám zbytek z predošlého cyklu
		asm volatile ("mac w5*w7,B");
                // výsledok uložím (len msb 16b)
		asm volatile ("sac B,w5");

		R_out = WREG5;
		}

Do tejto časti už vstupuje absolútna hodnota z predchádzajúcich krokov. Keď vstupujúci signál je väčší ako hodnota prítomná vo filtru, tak hneď sa zmení na väčšiu (nulové tau). Keď však signál je menší ako hodnota prítomná vo filtru, tak hodnota prejde filtrom.

V akumulátore je uložená hodnota z predošlej iterácie. Táto hodnota obsahuje celú časť aj desatinnú časť (škálovanie). Na začiatku sa vynuluje celá časť, zostane v buffru len zvyšok po predošlej iterácií. Do ďalšieho registra sa nahraje kompenzačný koeficient t (viď. obrázok 4), ktorým je potreba vynásobiť vstupný signál aby pri násobení koeficientom q filtra nedošlo k počítaní s číslami s iným škálovaním. Následne touto hodnotou sa vynásobí aj vstupný signál a MAC operáciou sa pridá do akumulátoru (akumulátor A slúži na pravý kanál, akumulátor B potom na ľavý kanál). Výsledok tejto operácie sa vynásobí ešte q = 0,9999389 spôsobom 65532/65536.

Delenie preto nieje vidieť v kóde, pretože z akumulátora sa dá uložiť z ľubovoľného miesta 16b široká hodnota do pracovného registra. (hodnota v akumulátoru sa oreže presne o 16b).

Bitmap
Obr. 8: Škálovanie z akumulátora do pracovného registra.

Bitmap
Obr. 9: Škálovanie z akumulátora do pracovného registra.


Na obrázku 9 je potom vidieť reakciu filtra na signál. Modre je vstupný signál, červene je potom výstupný signál. Je vidieť že filter pracuje podľa predpoklad a exponenciálne vyhladzuje vstupný signál. Zdrojový kód tejto simulácie je tiež súčasťou zip súboru projektu: tools/exp_times_realinput.m).

5. Pár slov k priloženým programom

V adresári projektu okrem firmwaru do mikrokontroléra, schémat a plošných spojov je aj adresár Tools. V tomto adresári sú všetky pomocné programy ktoré boli použité behom práce na tomto projektu.
Budú popísané v poradí ako boli použité.

Prvý krok je vygenerovanie prahových hodnôt, na akú úroveň majú jednotlivé ledky zareagovať. Na to slúži prvá časť excelovskej tabuľky "generovanie krivky", podľa ktorej potom LED stĺpec funguje. Krivka môže byť napr. exponenciálneho, lineárneho alebo logaritmického charakteru s rôznymi koeficientmi krivosti. Prvá časť obsahuje hneď 3 krivky aby bolo zrejmé ako sa má postupovať. Po vytvorení logaritmickej krivky však výsledky ani z ďaleka niesú v rozsahu ktoré je možno použiť do mikrokontroléra. Preto je treba ich normovať (koeficienty A a B nad tabuľkami). Na normovanie slúži okno vedľa prvého grafu. Je treba zadať prvú (minimálnu) a poslednú (maximálnu) hodnotu z vygenerovanej krivky, a napísať požadovanú minimálnu a maximálnu hodnotu (z rozsahu 0-32768). Koeficienty A a B stačí prekopírovať na dané miesto nad tabuľkami príslušných kriviek.

Druhým krokom je program v adresári "VU meter levels gen 8bit to TXT", ktorý vygeneruje podľa daných prahových hodnôt Look Up Table (ďalej len LUT). Prahové hodnoty je treba skopírovať z excelu do zdrojového kódu generátora LUT a znova preložiť (z časových dôvodov som to nedotiahol do univerzálnejšej podoby, ale myslím si že programátor s tým poradí). Výstup programu je potom textový súbor "coeffs.txt", ktorý obsahuje 2x LUT a údaje o presnosti. Tabuľky stačí prekopírovať do zdrojového kódu mikrokontroleru, preložiť, a nahrať. Kontrolér potom hneď funguje podľa nových hodnôt.
Údaje o presnosti sa dajú potom využiť v ďalšej časti už zmieneného excelovského súboru v časti "skúška presnosti". Do tabuliek treba uviesť originálne prahové hodnoty a hodnoty ktoré vrátil program generátoru LUT (hodnoty by mali byt rozsahu 0-128). Potom je možno vidieť chybu absolútnu, chybu relatívnu v % a nakoniec porovnanie optimálnej a reálnej krivky graficky.

Kde sa vzala chyba ?
Chyba nastáva pri generovaní tabuľky LUT. Pretože vstupná hodnota má 16b, bolo by potreba 216 kombinácií na každý kanál (128kB na kanál). Toto je veľmi veľké množstvo dát, ktoré by sa nezmestili do mikrokontroléra. Riešením je použiť len msb 8b. Potom potrebné miesto je počet výstupných hodnôt * šírka výstupných dať (16b = 2B) 28⋅2 = 512B na kanál. Takéto množstvo dát sa už bez problémov zmestí do pamäte mikrokontroléra. Takéto orezanie však nevadí, pretože prahy sú dosť "ďaleko" od seba, a na 12 stavov (a optický výstup) ajtak nieje potreba veľkú presnosť. Ako je z grafikonu potom vidieť prahové hodnoty sa líšia len minimálne, opticky sa ani nedali pozorovať zmeny.

Prečo použiť LUT ?
Použitím Look Up Table celý proces výpočtu výstupu na LED stĺpec (ktorá ma svietiť a ktorá nie) sa značne urýchli a čo je ešte dôležitejšie, výpočtový čas nezávislí od toho aká je vstupná hodnota.
Pri použitý zložených IF príkazov je čas výpočtu tým väčší čím je IF komplikovanejší (čím má IF viac vetví). Pri výstupu na 12 LED môže trvať výpočet potom 1 až 12 násobok čašu výpočtu vzatého na výpočet jednej IF inštrukcie. U tohto projektu avšak bolo kritické časovanie (kvôli synchronizácie na I2S signál z ADC), keď sa vetví program, aby každá vetva mala stejný počet inštrukcií (aby trvalo každá vetva toľko času).

6. Hardware

Hardware sa skladá z dvoch plošných spojov. Jedna je riadiaca doska s mikrokontrolérom, druhá je samotná doska s LED diódami a drivermi pre ne. Ako už bolo zmienené prípravok bol vyvinutý pre konkrétny prevodník, ktorý je súčasťou už existujúceho zosilňovača [1]. Avšak pripojením I2S signálu s vzorkovacím kmitočtom 48 kHz a napájacieho napätia 3,3 V bude prístroj bezchybne fungovať.
Na riadiacej doske pracuje mikrokontrolér DSPIC33FJ12GP202. Doska je pripojená k AD prevodníku aj k LED stĺpci MLW konektorom. Napájanie dostáva z konektoru od AD prevodníku. Cez tento konektor je privedený aj samotný diditalizovaný audio signál vo formáte I2S 24b 48 kHz. Druhy MLW konektor slúži na pripojenie LED stĺpca. Mikrokontrolér posiela dáta na LED stĺpec pomocou protokolu SPI, vždy po 3x8 bitoch (12 LED na kanál) 100x za sekundu s rýchlosťou 9,216Mb/s (36,864/4). Na výstupný konektor je tiež privedené napájacie napätie 3,3V. LED stĺpec ale potrebuje napájacie napätie 5V. Toto napätie je možno vyrobiť buď spínaním meničom 3.3V → 5V, alebo potom napájanie z riadiacej dosky nevyužiť, a pripojiť k LED stĺpci napájanie zvlášť.

Riadiaca doska obsahuje kryštál s kmitočtom 24,576 MHz. Takýto kmitočet bol potrebný kvôli synchronizácie s AD prevodníkom. V procesoru potom táto frekvencia je ešte zvyšovaná pomocou PLL na 36,864 MHz (presne 3x frekvencia AD prevodníka). Na konektoru z prevodníka je privedený aj taktovací kmitočet prevodníka 12,288MHz, tým pádom bolo by možné kryštál úplne vynechať a pripojiť sa na tento hodinový signál (pomocou PLL by sa dalo tiež dosiahnuť 36,864 MHz). Avšak počas vývoja bolo jednoduchšie mat kryštál zvlášť aj na doske (pre overenie základných funkcií kontroléru, bez prevodníka). Keď bude niekedy ďalšia verzia hardwaru, už nebude obsahovať zvlášť kryštál, tiež by sa použil mikrokontrolér v SMD verzii.

Riadiaca doska obsahuje aj LED diódu, ktorá reaguje na hudbu silou svetla. Pôvodne LED dióda slúžila na debug programu a keď už to bolo na doske tak prečo ju nevyužiť. LED je riadený pomocou PWM signálu. Bolo by možné tento signál pripojiť na tranzistor a pridať väčšiu ledku, pripadne iný zdroj svetla.

Bitmap
Obr. 10: Riadiaca časť.



Obr. 11: LED stĺpec.


Schéma riadiacej časti vo forme obrázku je k nahliadnutí tu a schéma LED stĺpca tiež vo forme obrázku je k nahliadnutí tu. (.sch a .brd súbory sú dostupné zo zip súboru projektu: "Printed circuit boards").

Záver:

Tento projekt bol môj prvý projekt s mikrokontrolérom DSPic. Kto by našiel jednoduchšie riešenie, prípadne nájde niečo nevhodného v kóde, alebo len k tomu pridal koment, nech sa ozve (xborsa00stud.feec.vutbr.cz). Projekt je v štádiu plnej funkčnosti, čaká len na pridanie do zosilňovača.


   Video na youtube: ukážka 1: link, ukážka 2: link, a ukážka 3: link
    Ukážky je dobré si vypočuť zo slúchadlami, niektoré majú stereo efekty v hudbe, ktoré sú najlepšie práve slúchadlami.

Všetky zmienené programy, súbory, schémy, plošné spoje atd. sú dostupné na stiahnutie tu.

Literatúra:

[1] BORSÁNYI, T. Nízkofrekvenční výkonový zesilovač ve třídě D s integrovaným DSP. Brno: Vysoké učení technické v Brně, Fakulta elektrotechniky a komunikačních technologií, 2011. 62 s. Vedoucí bakalářské práce doc. Ing. Tomáš Kratochvíl, Ph.D. Dostupná z WWW: https://www.vutbr.cz/studium/zaverecne-prace?zp_id=39205
[2] Microchip Technology Inc. [online]. Datasheet dsPIC33FJ12GP202 [cit. 2012-04-02]. Dostupný z WWW: http://ww1.microchip.com/downloads/en/DeviceDoc/70264E.pdf
[3] Texas Instruments [online]. Datasheet PCM1850A - 24-BIT, 96-kHz STEREO A/D CONVERTER. Texas Instruments, Inc., 2005 - [cit. 02.04.2012]. Dostupné na www: http://focus.ti.com/lit/ds/symlink/pcm1850a.pdf
[4] KOLÁŘ, R. ČÍSLICOVÉ ZPRACOVÁNÍ SIGNÁLŮ (BCZA), prezentácie z prednášok, Vysoké učení technické v Brně, 2010.
[5] wikipedia.org [online]. Moving average [cit. 02.04.2012]. Dostupné na www: http://en.wikipedia.org/wiki/Moving_average