Matematika v robotice 9. Trojčlenka 2.

11. července 2013 v 5:36 | Petr |  Roboti a Matematika
Mám nepříjemný pocit, že jediný rozdíl mezi mým blogem a školou spočívá v tom, že ve škole je matematika častěji než jednou za týden, ale jelikož jsem 2/3 své bastlířské kariéry používal celočíselné algoritmy v assembleru - tak toho mám tolik na jazyku, že si mě raději vyhoďte ze záložek, protože nemám v úmyslu jen tak přestat.

Mimochodem jak byste spočetli 2/3 * A což takhle 22 / 33 * A neboli 22 / 32 * A neboli ( 22 * A ) >> 5 neboli - jak dále všechno převést na sčítání a bitový posun ?

Už minule jsme měli násobit 39,2 a vykašlali jsme se na to a násobili jsme místo toho 39. V tomto blogu popis mých potíží s měřením napětí pokračuje. TAkže minule jsme použili dělič 1 : 16 a AD převodník, který měří maxímálně do 2,56 V abychom změřili napětí až do 30 voltů.
Vše jsem si početl jako minule, naprogramoval a - ono to nefungovalo - tak jsem přeměřil hodnotu napěťové reference v procesoru (je vyvedená na pin AREF) a zjistil jsem, že napěťová reference není 2,56, ale 2,73 V což je ještě v normě, neboť Atmel pripouští, že referenční napětí se může pohybovat "od Šumavy k Tatrám"

Všechno je zapájeno, naroutováno, tak co teď - pokusíme se počítat napětí v milivoltech z hodnoty AD převodníku úplně přesně.
Takže máme napětí 2,73 a dělič 1: 16 - maximální napětí které odpovídá hodnotě 1024 10 bitového AD převodníku tedy je 2,73 * 16 = 43,68 V převedeno na milivolty 43680 mV.

Kdybychom postupovali jako minule tak bychom uvažovali čím budeme hodnotu AD převoníku násobit a došli bychom k hodnotě 43680 / 1024 = 42,65 - což bychom mohli zaokrouhlit na 43.
Řekl jsem ale, že spočteme napětí úplně přesně pokud tedy hodnotě ADC = 1024 má odpovídat hodnota NAPETI = 43680 což takhle na to jít stylem
NAPETI = 43680 * ADC / 1024
Ano - takhle je to správně, ale chce to ještě učesat.
1. násobit 40 000 a pak dělit 1000 to zavání přetečením mezivýsledku, takže nejprve všechno vykrátíme na nejvyšším společným dělitelem - hodnotu 32.
NAPETI = 1365 * ADC / 32
Pak doplníme všecno zaokrouhlování, bitové posuny a tak
NAPETI = ( 1365 * ADC + 16) >> 5
A máme to spočteno maximálně přesně, stejně přesně jako kdybychom počítali s reálnými čísly a skutečným dělením.
Následuje obvyklá kapitola poznámek - kde má celý postup čertovo kopýtko ? Především v tom, že násobíme 1024 * 1365 - přetečení 16 bitového mezivýsledku tedy není možnost, ale jistota. Musíme tedy použít 32 bitový mezivýpočet - proměnnou typu uint32_t.
Tím je jasné, že nemá smyslu ani násobit pomocí bitových posunů jeden bitový posun 32 bitového čísla je kompilátorem přeložen jako 4 bitové posuny 8 bitové hodnoty, takže (aleposň u AVR) je rychlejší rovnou násobit. pokusím se napsat vzorovou proceduru

uint16_t Convert (uint32_t ADC) {
return ( 1365 * ADC +16 ) >> 5 ;
}
Znalcí jazyka C asi křičí - kde je přetypování mezivýsledku na 32 bitů ? Není potřeba (doufám), protože už vstupní hodnotu ADC jsem deklaroval jako 32 bitovou, ačkoliv hodnota z AD převodníku bude mít jen 10 "platných" bitů . Upřímně jako bývalý programátor v Pascalu se přetypovávání smrtelně bojím - a v C, kde číslo přetypujete na pointer a zpět - dvojnásob.
Předpokládám, že právě si říkáte - měsíc žvanění a výsledkem je procedura na tři řádky - s lehkou ironií vám odpovídám - na tři řádky, ale jak sofistikovaná ;-)).

Zbývá už jenom oblíbená rada paní Kubáčové pro novomanželky : pokud máte manžela, co neumí do pětí napočítat a slibujete si od toho, že vám to nespočítá - nemylte se - právě tyhle typy vám to bez slitování spočtou do posledního zrnka.
 

1 člověk ohodnotil tento článek.

Komentáře

1 Petr G. Petr G. | 12. července 2013 v 23:57

Geniální, jen na ZŠ i VŠ bych se podobného zaokrouhlování bál ... to by bylo za 5! i bez faktoriálu.

Komentáře jsou uzavřeny.


Aktuální články

Reklama