Obsah:

Průběžný průměr pro vaše projekty mikrokontroléru: 6 kroků
Průběžný průměr pro vaše projekty mikrokontroléru: 6 kroků

Video: Průběžný průměr pro vaše projekty mikrokontroléru: 6 kroků

Video: Průběžný průměr pro vaše projekty mikrokontroléru: 6 kroků
Video: Nejpokročilejší Megaprojekty Na Světě 2024, Listopad
Anonim
Průběžný průměr pro vaše projekty mikrokontroléru
Průběžný průměr pro vaše projekty mikrokontroléru

V tomto návodu vysvětlím, co je to běžný průměr a proč by vás to mělo zajímat, a také vám ukážu, jak by to mělo být implementováno pro maximální výpočetní efektivitu (nebojte se složitosti, je to velmi jednoduché na pochopení a já budu poskytněte snadno použitelnou knihovnu i pro vaše projekty arduino:)

Klouzavý průměr, také běžně označovaný jako klouzavý průměr, klouzavý průměr nebo klouzavý průměr, je termín používaný k popisu průměrné hodnoty posledních N hodnot v datových řadách. Lze jej vypočítat jako normální průměr nebo můžete použít trik, aby měl minimální dopad na výkon vašeho kódu.

Krok 1: Případ použití: Vyhlazení měření ADC

Případ použití: Vyhlazení měření ADC
Případ použití: Vyhlazení měření ADC

Arduino má slušný 10bitový ADC s velmi malým šumem. Při měření hodnoty na senzoru, jako je potenciometr, fotorezistor nebo jiné komponenty s vysokým šumem, je těžké uvěřit, že je měření správné.

Jedním z řešení je provést více měření pokaždé, když chcete přečíst senzor a zprůměrovat je. V některých případech je to schůdné řešení, ale ne vždy. Pokud byste chtěli přečíst ADC 1000krát za sekundu, museli byste 10 000, pokud byste provedli průměr 10 měření. Obrovská ztráta výpočetního času.

Moje navrhované řešení je provést měření 1000krát za sekundu, pokaždé aktualizovat běžný průměr a použít jej jako aktuální hodnotu. Tato metoda zavádí určitou latenci, ale snižuje výpočetní náročnost vaší aplikace, což vám dává mnohem více času na další zpracování.

Na obrázku výše jsem použil průměr za posledních 32 měření. Uvidíte, že tato metoda není 100% odolná proti selhání, ale výrazně zvyšuje přesnost (není to horší než průměrování pokaždé 32 vzorků). Pokud byste chtěli vypočítat průměrně 32 měření pokaždé, na Arduino UNO by to trvalo jen 0,25 ms pro samotné měření!

Krok 2: Pouzdro: Měření stejnosměrné složky signálu mikrofonu

Případ použití: Měření stejnosměrné složky signálu mikrofonu
Případ použití: Měření stejnosměrné složky signálu mikrofonu
Případ použití: Měření stejnosměrné složky signálu mikrofonu
Případ použití: Měření stejnosměrné složky signálu mikrofonu
Případ použití: Měření stejnosměrné složky signálu mikrofonu
Případ použití: Měření stejnosměrné složky signálu mikrofonu

Arduino může měřit napětí mezi 0 a Vcc (obvykle 5 V). Zvukový signál je zcela střídavý a pokud jej chcete měřit na mikrokontroléru, musíte jej předepnout kolem 1/2 Vcc. V projektu Arduino UNO by to znamenalo zhruba 2,5 V (DC) + zvukový signál (AC). Při použití 10bitového napájecího zdroje ADC a 5 V by se zkreslení 2,5 V mělo rovnat měření 512. Abyste získali AC hodnotu signálu, je třeba odečíst 512 od měření ADC a je to, že?

V ideálním světě by to byla pravda. Skutečný život je bohužel komplikovanější a naše předpojatost signálu má tendenci se unášet. Velmi častý je 50 Hz šum (60 Hz, pokud žijete v USA) z elektrické sítě. Obvykle to není příliš problematické, ale je dobré vědět, že to existuje. Problematičtější je lineární posun od zahřívání součástí. Pečlivě nastavíte DC offsetovou korekci na začátku a pomalu se unáší, jak je vaše aplikace spuštěna.

Tento problém ilustruji detektorem (hudby) úderů. Nastavíte odstranění předpětí a údery jsou jasné (obrázek 2). Po nějaké době se pohyby předpětí DC a údery mikrokontroléru sotva znají (obrázek 3). Algoritmus detekce úderů bude v budoucnu podrobně prozkoumán, protože překračuje rozsah tohoto článku.

Naštěstí existuje způsob, jak neustále počítat DC offset zvuku. Není žádným překvapením, že běžný průměr, téma tohoto pokynu, poskytuje řešení.

Víme, že průměrná hodnota jakéhokoli střídavého signálu je 0. Pomocí těchto znalostí můžeme odečíst, že průměrná hodnota signálu AC+DC je jeho předpětí DC. Abychom to odstranili, můžeme vzít běžný průměr posledních několika hodnot a odečíst jej od aktuálního čtení ADC. Všimněte si, že musíte použít dostatečně dlouhý průměr. U zvuku by měla stačit desetina sekundy (počet vzorků závisí na vaší vzorkovací frekvenci), ale vězte, že delší průměry fungují lépe. Na prvním obrázku vidíte příklad skutečného výpočtu předpětí DC s klouzavým průměrem se 64 prvky při vzorkovací frekvenci 1 kHz (méně, než jsem doporučil, ale stále to funguje).

Krok 3: Výpočet

Výpočet
Výpočet

Běžecký průměr si můžete představit jako průměrnou hmotnost lidí v čekárně u lékaře. Doktor dokončí vyšetření jednoho pacienta a současně do čekárny vstoupí nový.

Aby se zjistila průměrná hmotnost všech čekajících pacientů v čekárně, sestra se pak mohla každého pacienta zeptat na jeho váhu, sečíst tato čísla a vydělit počtem pacientů. Pokaždé, když lékař přijme nového pacienta, sestra celý proces zopakuje.

Možná si říkáte: „To nezní příliš efektivně … Musí existovat lepší způsob, jak to udělat.“A měl bys pravdu.

Pro optimalizaci tohoto procesu by sestra mohla vést záznam o celkové hmotnosti aktuální skupiny pacientů. Jakmile lékař zavolá nového pacienta, sestra se ho zeptá na jeho váhu, odečte jej od celkového počtu a nechá ho jít. Sestra by se pak zeptala pacienta, který právě vešel do čekárny, na jeho váhu a přičetla ji k celkové hmotnosti. Průměrná hmotnost pacientů po každé směně by byla součtem hmotností děleno počtem pacientů (ano, stejné jako dříve, ale nyní se sestra zeptala pouze dvou lidí na jejich hmotnost místo všech). Uvědomuji si, že tento odstavec mohl být trochu matoucí, takže pro větší srozumitelnost viz výše uvedený obrázek (nebo položte otázky v komentářích).

Ale i když vám poslední odstavec nepřišel matoucí, můžete mít otázky typu, co by mělo být na začátku v akumulátoru, jak mám do aktuálního C kódu vložit to, co jsem právě přečetl? To bude řešeno v dalším kroku, kde také získáte můj zdrojový kód.

Krok 4: Kód

Kód
Kód

Abyste mohli vypočítat průběžný průměr, potřebujete nejprve způsob, jak uložit posledních N hodnot. můžete mít pole s N prvky a přesunout celý obsah o jedno místo pokaždé, když přidáte prvek (nedělejte to), nebo můžete přepsat jeden starý prvek a upravit ukazatel na další prvek, který má být vyhozen (proveďte prosím toto:)

Akumulátor by měl začít inicializován na 0, totéž platí pro všechny prvky ve zpožďovací linii. V opačném případě bude váš průběžný průměr vždy špatný. Uvidíte, že delayLine_init se postará o inicializaci zpožďovací linky, o akumulátor byste se měli postarat sami.

přidání prvku do zpožďovacího řádku je stejně snadné jako snížení indexu nejnovějšího prvku o 1, přičemž se ujistěte, že neukazuje na stranu pole zpožďovacího řádku. po snížení indexu, když je 0, se bude smyčka pohybovat kolem 255 (protože je to 8bitové celé číslo bez znaménka). Operátor Modulo (%) s velikostí pole zpožďovacího řádku zajistí, že index bude ukazovat na platný prvek.

Výpočet průběžného průměru by měl být snadno pochopitelný, pokud jste v předchozím kroku postupovali podle mé analogie. Odečtěte nejstarší prvek z akumulátoru, přidejte nejnovější hodnotu do akumulátoru, zatlačte nejnovější hodnotu do zpožďovací linky, vráťte akumulátor dělený počtem prvků.

Snadné, že?

Neváhejte experimentovat s použitím přiloženého kódu, abyste lépe porozuměli tomu, jak to všechno funguje. V současné době čte arduino analogovou hodnotu na analogovém pinu A0 a tiskne „[hodnota ADC], [běžný průměr]“na sériový port rychlostí 115 200 baudů. Pokud otevřete arduino sériový plotter se správnou přenosovou rychlostí, uvidíte dva řádky: hodnota ADC (modrá) a vyhlazená hodnota (červená).

Krok 5: Doplňky

Doplňky
Doplňky

Existuje několik věcí, které nemusíte nutně vědět, abyste mohli ve svém projektu používat běžný průměr, neuškodí to vědět.

zpoždění: Začnu mluvit o ilustraci tohoto kroku. Všimnete si, že běžný průměr více prvků přináší větší zpoždění. Pokud je vaše doba odezvy na změnu hodnoty kritická, můžete použít kratší klouzavý průměr nebo zvýšit vzorkovací frekvenci (měřit častěji).

Posouvat se.

inicializace: Když jsem mluvil o inicializaci prvků akumulátoru a zpoždění, řekl jsem, že byste je měli všechny inicializovat na 0. Alternativně můžete inicializovat zpožďovací linku na cokoli, co se vám líbí, ale akumulátor by měl začínat jako součet nejnovějších N prvků ve zpožďovací linii (kde N je počet prvků ve vašem běžném průměru). Pokud akumulátor začíná s jakoukoli jinou hodnotou, vypočítaný průměr bude chybný - buď příliš nízký nebo příliš vysoký, vždy o stejnou částku (za předpokladu stejných počátečních podmínek). Navrhuji, abyste se pokusili zjistit, proč tomu tak je, pomocí nějaké „simulace pera a papíru“.

velikost akumulátoru: Měli byste si také uvědomit, že akumulátor by měl být dostatečně velký na uložení součtu všech prvků do zpožďovací linky, pokud jsou všechny kladné nebo záporné max. Prakticky to znamená, že akumulátor by měl být o jeden datový typ větší než prvky zpožďovacího řádku a podepsané, pokud jsou podepsány prvky zpožďovacího řádku.

trik: Dlouhé zpožďovací linky zabírají spoustu paměti. To se může rychle stát problémem. Pokud jste velmi omezeni pamětí a příliš se nestaráte o přesnost, můžete aproximovat běžící průměr úplným vynecháním zpoždění a místo toho: odečíst 1/N * akumulátor od akumulátoru a přidat novou hodnotu (na příkladu 8 dlouhého průběžného průměru: akumulátor = akumulátor * 7/8 + nováHodnota). Tato metoda poskytuje špatný výsledek, ale je to slušná metoda výpočtu klouzavého průměru, když vám dochází paměť.

lingvistika: „běžný průměr/průměr“se obvykle používá při odkazování na průměrování v reálném čase, zatímco „klouzavý průměr/průměr“obvykle znamená, že algoritmus běží na statické sadě dat, jako je například tabulka Excelu.

Krok 6: Závěr

Doufám, že tento návod byl dostatečně snadno pochopitelný a že vám pomůže ve vašich budoucích projektech. Pokud je něco nejasného, neváhejte posílat dotazy do komentářů níže.

Doporučuje: