Hangsugárzók valós effektív terhelésének mérése mikrovezérlővel 2.

Az előző részben röviden átfutottuk a készülék célját és a jelfeldolgozás elvi alapjait. Most azt fogjuk megvizsgálni, hogy gyakorlati szempontból gépi közeli szemléletben (Assembly nyelven) hogyan lehetne mindezt megvalósítani.

Funkcionális időzítések

Azt már az elején látjuk, hogy az ADC mintavételezésnek folyamatosan, adott mintavételi frekvencián, lehetőleg jitter mentesen kell ketyegnie. Minden mintavételezést le kell reagálnia egy kódnak, mely beolvassa a mintát, négyzetre emeli, és működteti az 1. szűrőt, mely az átlagoló előszűrő. Emlékeztetőül a kétlépcsős szűrő blokkdiagramja:

Teljes digitális megvalósítás kétlépcsős digitális szűréssel

Tehát az 1. szűrő a magas mintavételi frekvenciát átlagolással lekvantálja néhány 10Hz-re, és ezen a frekvencián szintén szigorúan ütemezetten (minden eseményt elkapva) kell működnie a 2. szűrőnek, mely az RC aluláteresztő karakterisztikájú szűrést valósítja meg egy IIR rekurzív szűrővel, valamint működtetni kell még a kijelzési és egyéb funciókat. Mit jelent ez egy mikrovezérlő szemszögéből? Először is, az ADC mintavételezése free running (néhol auto triggerednek mondva) módban folyamatosan kell mennie, és minden elkészült (lekonvertált) mintavételezésre le kell futnia egy rutinnak. Ezt eseményvezérelt megszakítással fogjuk megoldani, ahol a megszakítási eseményt az ADC konverter váltja ki, amikor elkészült egy konverzióval. Ebbe a rutinba lesz benne a mintavételezésen túl az előszűrő (1. szűrő) algoritmusa is, és ennek a rutinnak kell majd “trigger jelet adnia” a 2. szűrőnek. Ezt úgy fogjuk elérni, hogy a 2. szűrő a main programba lesz beleírva, és a státusz regiszter T bitjét fogjuk jelzésadásra felhasználni, egyfajta szoftveres triggerelést valósítunk így meg. A megszakítási rutin számolja, hogy éppen hányadjára fut (hány beérkezett mintát összegzett eddig) és amikor elérjünk az összegzés végét, megvan a szükséges mintaszám (pl. 10000db), akkor bebillenti a T bitet. A főprogramban pedig egy önmagára ugró brtc utasítás fogja várni a triggert; addig pörög egymagában, amíg a T alacsony aktuális értéke magasba nem billen. (Nem új ez a megoldás, a spektrumanalizátornál is ezt használtam) Amikor a brtc utasításról le tud jönni a vezérlés, ráfut a 2. szűrőre, majd onnan tovább a kijelzés és egyéb vezérlési funkciókra, majd a main program végén visszaugrunk annak elejére, ahol ismét megáll a brtc utasításon, és csak a következő szoftveres triggerre tud egy újabb kört futni. Ebből következően a funkciók működtetése és a kijelzések is ezzel az alacsony frekvenciával ismétlődnek, ezen majd a későbbiekben változtatni kell, a kijelzőfrissítés frekvenciáját célszerű 2-4Hz-re levinni, hogy olvasható legyen a kijelző akkor is, ha futnak rajta a számok.

A működés időzítése ezzel tehát tisztázva. Ami még fontos, hogy mind a két rutin a maga időszeletében képes legyen teljesen lefutni, ne csússzon át a következő időszeletre. Ez főleg a megszakítási rutinra érvényes; pl. egy 48kHz-es audio mintavétel esetén 20.8μs idő alatt minden körülmény közöt be kell fejeznie egy ciklust, el kell érnie a reti utasítást, sőt végre is kell hajtania! A főprogramnak lényegesen több ideje van a 10-30Hz működési ütemezés miatt. Persze ezalatt akár többször lefuthat a megszakítási rutin is, de ez a működésben természetesen nem okozhat zavart. Azonban a megszakítási rutin mintegy a PC-khez hasonlóan százalékosan mérhetően elveszi a processzoridőt a main programtól. Ha pl 10.4us a futásideje, akkor 50%-ban ő birtokolja a cpu-t. Kb olyan 80-90%-ig nincs ebből gond, 10-20% cpu kapacitás kell, hogy maradjon a főprogramnak is, de ezt a konkrét megvalósításnál le lehet majd mérni. (Amúgy erről is volt már szó a spektrumanalizátornál, sőt ott számszerűen 208 órajelben volt meghatározva a mintavételező megszakítási rutin hossza, és erre mondtuk, hogy kb 160-180 óránál ne legyen több.)

A digitális szűrő

A szűrő első fokozata látszólag nem bonyolult: Mintavételezünk, négyzetre emelünk (szorzással) és összegzőgyűjtést csinálunk. Csupán azt kell kiszámolni, hogy mennyi a bitigénye a művelet un akkumulátor regiszterének (vagy munkaregiszterének ahogy tetszik). A szorzási eredmény bitigénye a két szorzandó szám bithosszának összege, ami itt a szám bithosszának kétszerese lesz, mivel önmagával szorzunk. Pl. 8 bites szám szorzása esetén 16 biten jön létre az eredmény. De úgy is eljárhatunk, hogy kiszámoljuk, mekkora a legnagyobb érték amit még ábrázolnunk kell, és megnézzük hány számjegyes kettes számrendszerbeli számmal írható le. (Ezt kettes alapú logaritmus függvénnyel tudjuk kiszámolni, ahol az értéket fel kell kerekíteni, ha van törtrésze) Szerencsére semmit nem kell kézzel számolgatni, készítettem erre számoló táblázatot, ami egy konkrét valós beállítással így fest:

HF terhelésanalizátor számoló

Ami sárga/kék színű, azok bemenő adatok. Mindenekelőtt meg kell adni a mikrovezérlő (AVR ATmega) működési órajelét, ez most 20MHz (kvarcról), és az ADC konverternek az un. prescaler (órajelosztó) beállítását, ami most 32, azaz a 20MHz 32-ed része lesz az ADC órajele, ami 625kHz. Azonban az ADC free running üzemmódban 13 órajel alatt állít elő egy mintát, tehát ezt tovább kell osztani 13-al, ebből kapjuk a konverzió mintavételi frekvenciáját, ami kb 48kHz (vagy kS/s). Lehetnének az adatok másfélék is; pl. 10MHz-es kvarc esetén 16-os ADCclk osztással szintén 48kHz lesz a mintavételi frekvencia, vagy ha nincs külső kvarc, akkor 8MHz-es belső órajel esetén 16-os osztóval kb 38kHz mintavételi frekvencia érhető el. Az első előzetes verzióban pl. 10.7MHz-es kerámiarezonátor volt, amivel 51.44kHz-es audio mintavételi freki állítható be, és hát nem feltétlenül baj, hogy ezzel a legtöbb audio anyag mintavétele fölött dolgozunk (aliasing problémák). A következő sorban azt látjuk, hogy 9 bites mintával dolgozunk (hogy mért ennyi, arra a programkódnál visszatérünk) és hogy az abszolút értéke a mintának így 0-255 közé esik (igazából 0-256, mivel negatív tartományban van egy -256 értékünk, de erre szintén vissza fogunk térni) Ha a 255-öt négyzetre emeljünk, akkor 65025-öt kapunk, ez a legnagyobb négyzetes értékünk, ábrázolásához 16 bit szükséges. Ebből fogunk összeadni 2048-at az 1. szűrő szerint, ekkor 65025·2048=133171200 lesz a legnagyobb előforduló összegzett érték, mely 27 biten írható le. Alatta azt látjuk, hogy ez 4 bájton fér el (4 regiszter), de így 32-27=5 bit nincs kihasználva, vagyis a felső 5 bit mindig nulla lesz. Mivel az így kapott 27 bites értéket 16 bitre akarjuk csonkítani, ezért 5 bittel balra kell shiftelni és úgy kell kiolvasni a felső 16 bitet (vagy 3-al jobbra és a két középső regiszterből olvasni az eredmény, ami programozás szempontjából jobb megoldás) Lényegében ez helyettesíti majd az összegzés utáni osztást, az értéktartomány újra 0-65025 között lesz. A 2. szűrőnél megadjuk az RC aluláteresztő karakterisztikájú IIR szűrő időállandóját (10s), és alatta kiszámolódik a két IIR időállandó, ill. azok reciprokai. Mint a spektrumanalizátors cikkben is láttuk, reciprokot is érdemes nézni IIR időállandóban, mert az nem 0-1 tartományba eső tört, természetesen ekkor az együtthatóval nem szorzunk, hanem osztunk. Ez így rosszabb felállásnak tűnhet, de ha sikerül valamilyen kettő-hatvány számot kifaragni, akkor az osztás helyett shiftelést is lehet használni, ami roppant jól hangzik Assembly nyelvjárásban. És a fenti ábrán látjuk is, hogy az 1/a0 együttható nagyon rá akar állni a 256-os értékre, ami 28, ami duplán jó, mert még rotálni sem kell, csak egy regiszterrel odébb kell címezni! Lehet, hogy így az időállandó nem lesz hajszál pontosan 10s hanem mondjuk 11s körüli értéket vesz fel, de ez gyakorlatilag lényegtelen, különben sem véstük kőbe a 10 szekundumot. Ha pedig a dolog előnyét, megvalósíthatóságát nézzük, akkor főleg nem lehet kérdés. Szintén a spektrumanalizátoros történetből ismerős, hogy a két IIR együttható egymásba rendezhető, így csak egy marad meg belőlük. A rekurzív egyenlet szintén átrendezhető olyan alakra, amit a könnyebb leprogramozni. Az IIR szűrő egyenlete alaphangon így fest:

y = a0·x + b1·y

Átrendezve Assembly-barát verzióra és A0=1/a0 helyettesítéssel pedig így:

y = y - y/A0 + x/A0

vagy esetleg így:

y = y - ( y - x )/A0

Az első Assembly-barát verzióban kétszer kell rotálni (osztani), de nincs túlcsordulás veszély. A másodiknál csak egyszer kell osztani, de nehezen lekezelhető túlcsordulás léphet fel a zárójeles műveletben. A spektrumanalizátoros kódban az utóbbi (egy magas bit tartalékkal a túlcsordulás ellen), ebben a kódban az előbbi változat van leprogramozva. És mi a helyzet az IIR szűrő akkumulátorának bithosszával? Egyszerű: 16 bites értéket kap a bemenetére, látni fogjuk (ill láttunk hasonlót a spektrumanalizátorban) hogy ahány bitet jobbra kell rotálni, annyi bittel kell jobbra kiegészíteni, azaz a fenti példa szerint egy teljes bájttal. Ezzel 24 bites (3 bájtos) lesz az akksi. Valójában még ennyi se kellene, mert a kijelzés 0-200 közötti értékre lesz formálva, amit kettő-hatványra kerekítéssel inkább 0-204.8-ra veszek 0.1 felbontás mellett. Ez 0-2048 egészértéket jelent, adott fix helyre leszúrt tizedesponttal. Hossza 11 bit, és ehhez jönne a plusz 8 bit, így 19 bit a működéshez szükséges minimum, ez az a határ ami alatt nem dolgozna kielégítően az IIR algoritmus. Csakhát a 19 bit ugyanúgy 3 bájtos, mint a 24, így ezzel nem nyernénk semmit.

A következő részben megnézzük, hogyan dolgozhatjuk fel ill jelezhetjük ki az így nyert mérési adatokat.

Mellékletek

Számoló táblázat: HFterh_IIR_calc.ods