Matematiikkaa mikrokontollerille

Seuraa 
Viestejä45973
Liittynyt3.9.2015

Nyt alkaa pää hajoomaan ku ei keksi mitään laskukaavaa. Homma siis menee niin että C-kielellä väännän koodia kontrolleriin. x-muuttujan arvo muuttu yhden pykälän verran (kun potentiometriä kääntää, kyseessä lineaarinen potentiometri). Tämä x on arvo välillä 0 - 1024 (10-bittisen AD-muunnoksen tulos).

Tuossa liitteenä tekstitiedosto jossa havainnollistetaan mitä pitäis saada aikaseksi.

x-sarakkeessa on x:n arvo ja y-sarakkeessa arvo joka tarttis jollain laskukaavalla saada aikaseksi arvosta x. Tuon muunnoksen ei tartte olla ihan tarkka, mutta sen pitäis noudattaa sitä linjaa että isoilla x:n arvoilla, yhden x:n pykälän tiputus muuttais y:n arvoa selkeästi pienemmäksi kuin pienillä x:n arvoilla. Toisessa ääripäässä taas x:n pieneneminen ei enää vaikuta kovinkaan merkitsevästi y:n arvoon.

Kaikenmaailman potenssien käyttö ei kai oo ihan järkevää ku ^-merkki ei saa aikaan C-kielessä potenssiin korotusta. Eli tarttis päästä mahdollisimman yksinkertaisilla +-/* -laskuilla eteenpäin.

Tässä tekstitiedosto

Sivut

Kommentit (27)

Neutroni
Seuraa 
Viestejä26898
Liittynyt16.3.2005

Miten nuo tiedoston luvut on saatu? Onko se jokin matemaattinen funktio vai empiirinen mittuastulos? Kuinka nopea muunnoksen pitää olla?

Näytti aika jyrkältä tuo, jyrkemmältä kuin eksponenttifunktio.

Miten tuttua interpolointi on? Siinä jaat tuon funktion pätkiksi, joiden väliä approksimoit polynomilla. Yksinkertaisin on lineaarinen interpolaatio, jolloin pisteiden välit ovat suoria. Kuutiollinen interpolaatio on samalla pistemäärällä tarkempi, mutta vaatii enemmän koodia ja laskenta-aikaa.

Interpolaatiopolynomin asteen ja pistemäärän valitseminen riippuu sitten siitä, mitä haluat tehdä. Korkea aste (älä mene yli kolmen, jos et tiedä mitä teet) maksaa kellojaksoissa ja suuri määrä pisteitä muistissa. Jos maltat raottaa salaisuuden verhoa sen päältä, mitä olet tekemässä (ainakin tarkkuus- ja nopeusvaatimukset) ja millä kalustolla (prosessori, taajuus), voin antaa tarkempia neuvoja.

Vierailija

Interpolointi hä? Interpolaatiopolynomi tä? Siis mä olen ihan yläastetasoinen matematiikassa... Siis toi 0-1024 arvo on tietenkin se AD-muunnoksesta saatava arvo. Se luetaan ja jos vaikkapa AD-arvo on 923, niin tarttis y:n arvo olla jotakuinkin 2066. Tämä y, tässä tapauksessa 2066 sijoitetaan viivefunktioon. Se perustuu 16-bit timerin käyttöön. Tuo 2066 ei sitten tarkoita mitään eksaktia ms tai us-viivettä vaan prescalerin (kahdeksan) läpi ajettuja kellojaksoja. Eli kun timeri on laskenut arvokseen 2066, jatketaan ohjelmassa eteenpäin. Atmega16 käytössä ja tällä hetkellä 4MHz sisäinen kello, sen voi nostaa 8MHz:iin jos on tarvetta.

Neutroni
Seuraa 
Viestejä26898
Liittynyt16.3.2005
Kuramalli
Atmega16 käytössä ja tällä hetkellä 4MHz sisäinen kello, sen voi nostaa 8MHz:iin jos on tarvetta.

Sinulla on varmaan pari kilotavua ylimääräistä ohjelmamuistia tuossa projektissa. Pane tuo taulukko sellaisenaan muistiin ja lue LPM-käskyillä oikeasta kohtaa.

Tyyliin:
[code:2cwhs12y]
in r30,ADCL
in r31,ADCH
lsl r30
rol r31
subi r30,low(-2*taulukko)
sbci r31,high(-2*taulukko)
lpm r16,Z+
lpm r17,Z
out OCR1AH,r17 ;timer 1:n output compare
out OCR1AL,r16
...

taulukko:
.dw 239,240,240,240,240,241,241
...
.dw 10870,11364,11905
[/code:2cwhs12y]

Luulen että nuo IO-reksiterit pitää osoittaa lds ja sts -käskyillä ATmega 16:ssa. Datalehdestä se selviää. 10 bitin AD-muunnin antaa arvot 0-1023, tuota 1024:ää vastaavaa lukua ei milloinkaan lueta, joten jätin sen pois.

CE-hyväksytty
Seuraa 
Viestejä29006
Liittynyt30.4.2005
Neutroni
Kuramalli
Atmega16 käytössä ja tällä hetkellä 4MHz sisäinen kello, sen voi nostaa 8MHz:iin jos on tarvetta.



Sinulla on varmaan pari kilotavua ylimääräistä ohjelmamuistia tuossa projektissa. Pane tuo taulukko sellaisenaan muistiin ja lue LPM-käskyillä oikeasta kohtaa.

Tyyliin:
[code]
inr30,ADCL

Mutta miten? Käytännössä...?

Vierailija
Neutroni

Miten tuttua interpolointi on? Siinä jaat tuon funktion pätkiksi, joiden väliä approksimoit polynomilla. Yksinkertaisin on lineaarinen interpolaatio, jolloin pisteiden välit ovat suoria. Kuutiollinen interpolaatio on samalla pistemäärällä tarkempi, mutta vaatii enemmän koodia ja laskenta-aikaa.

Jassoo, no jos lähdetään ongelmaa ratkomaan myös tällä tapaa, niin saa esittää käytännönläheisempää esimerkkiä.

En tiä nimittäin kuinka paljon toi taulukko vie tilaa, joten jatkossa kun taulukkoja tulisi lisää, niin sitte alkanee tulla ahdasta muistissa(?). Joten jos kattois likimäärästä ratkasua tältä kannalta myös polynomilaatioilla.

mattile71
Seuraa 
Viestejä198
Liittynyt6.9.2006
Kuramalli

Tuossa liitteenä tekstitiedosto jossa havainnollistetaan mitä pitäis saada aikaseksi.

Tässä tekstitiedosto

Tuo näyttäisi olevan parabolin näköinen funktio.Ratkaise tuosta
funktio y = ax^2+bx+c laittamalla y:n ja x: n arvoiksi ensimmäinen
arvo, viimeinen arvo ja arvo keskeltä.

Tai sitten tee taulukko Neutronin neuvojen mukaan.Hidastaa ohjelmankehitystä, tho.

Neutroni
Seuraa 
Viestejä26898
Liittynyt16.3.2005
Kuramalli

Jassoo, no jos lähdetään ongelmaa ratkomaan myös tällä tapaa, niin saa esittää käytännönläheisempää esimerkkiä.



En löytänyt yläastetasoista esitystä aiheesta. Niillä taidoilla kyseeseen tulee lähinnä lineaarinen interpolaatio. Siinä jaetaan tarkasteltava väli tasaisiin välein (tässä, epätasaiset välit tekevät hommasta hankalampaa). Otetaan vaikka esimerkki niin, että jaetaan tuo väli 64:ään osaan, eli otetaan taulukosta joka kuudestoista arvo. Kahden kilotavun taulukko supistuu siten 128 tavuun.

Ohjelmassa sitten lasketaan välipisteet olettamalla funktio perättäisten mittapisteiden välillä suoraksi. Esimerkiksi oletetaan, että saadaan AD-muuntimelta arvo x, joka on välillä 0-1023. Oikean pisteen löytämiseksi jaetaan a 16:lla, ja otetan talteen jakojäännös. Yleensä kannattaa käyttää jakajina ja taulukoiden pituuksina kahden kerrannaisia, niin nuo saadaan loogisilla operaatioilla.

[code:19ppjl58]
in r30,ADCL ;luetaan arvo
in r31,ADCH
mov r16,r30
andi r16,0x0F ;tässä on nyt jakojäännös, se on välillä 0-15

lsr r31 ;jaetaan luku 16:lla bittiä vierittämällä
ror r30
lsr r31
ror r30
lsr r31
ror r30
lsr r31
ror r30

lsl r30 ;kerrotaan kahdella, koska taulukossa on wordeja
rol r31 ;tämä on selvyyden vuoksi, muuten ei kannata yllä jakaa
;ja sitten kertoa, vaan hoitaa homma "and r30,0xFE" :lla

subi r30,low(-2*taulukko) ;taulukon osoite, kakkonen pitää olla
sbci r31,high(-2*taulukko) ;kääntäjän ominaisuuksien takia

lpm r18,Z+ ;luetaan taulukosta arvo interpolaatiopisteen vasemmalta puolelta
lpm r19,Z+
lpm r20,Z+ ;ja oikealta
lpm r21,Z
[/code:19ppjl58]

Nyt meillä on taulukkoarvo interpolointivälin vasemmalta (r19:r18) ja oikealta (r21:r20) puolelta, sekä tieto siitä kuinka kaukana interpolointipiste on vasemmanpuoleisesta taulukkoarvosta (r16). Interpolointitulos saadaan painotettuna keskiarvona edellisistä siten, että oikeanpuoleista pistettä painotetaan r16:lla ja vasemmanpuoleista 16-r16:lla. Nyt taulukkoon vaaditaan myös maksimi-indeksiä seuraava arvo (vastaten muunnostulosta 1024), koska sitä tarvitaan interpoloinnissa. Painotetut arvot summataan, ja jaetaan 16:lla. Saatkohan itse aikaan koodin.

En tiä nimittäin kuinka paljon toi taulukko vie tilaa, joten jatkossa kun taulukkoja tulisi lisää, niin sitte alkanee tulla ahdasta muistissa(?).

Taulukko vie tilaa 1024 * 2 tavua, kaksi kilotavua siis. Kontrollerissa on ohjelmamuistia 16 kilotavua, joten ei sinne kovinkaan montaa tuollaista taulukkoa mahdu. Koodilla kuudentoista kilotavun täyttäminen vaatii jo isoa ohjelmaa.

Tässäs vähän lisätietoa matematiikasta:
http://solmu.math.helsinki.fi/2004/3/apiola.pdf

Neutroni
Seuraa 
Viestejä26898
Liittynyt16.3.2005
mattile71

Tuo näyttäisi olevan parabolin näköinen funktio.Ratkaise tuosta
funktio y = ax^2+bx+c laittamalla y:n ja x: n arvoiksi ensimmäinen
arvo, viimeinen arvo ja arvo keskeltä.

Se on hirvittävästi paraabeliä (ja myös eksponenttifunktiota) jyrkempi.

Sellainen juttu tuli mieleen, että halutaanko tässä lineaarisesti AD-muunnostulokseen verrannollinen taajuus? Jos, niin sitten melkeinpä kannattaa laskea taajuudelle kaava (tulee jotain muotoa f=1/(a+b*x)), ja siitä haluttu viive x=(1-a*f)/(b*f). 16 bittinen jakolasku haukkaa jotain pari-kolmesataa kelloa, ellen väärin muista.

Neutroni
Seuraa 
Viestejä26898
Liittynyt16.3.2005

No niin, tuo funktio on muotoa t=250000/(1044-x), jossa x on AD-muunnostulos. Miksei sitä voinut sanoa, niin olisi voinut saman tien laskea suoraan. Tosin jos on kova kiire, tuo interpolaatio on nopeampi.

Tarvitset tuohon 24 bittisen jakolaskun. Voin katsoa, minulla pitäisi olla sille koodi, joskin löydät Atmelin Application note 200:sta 16 bittisen jakolaskun, joka on helppo modifioida 24 bitin versioksi.

Vierailija
Neutroni
Miten nuo tiedoston luvut on saatu? Onko se jokin matemaattinen funktio vai empiirinen mittuastulos? Kuinka nopea muunnoksen pitää olla?

Näytti aika jyrkältä tuo, jyrkemmältä kuin eksponenttifunktio.

Miten tuttua interpolointi on? Siinä jaat tuon funktion pätkiksi, joiden väliä approksimoit polynomilla. Yksinkertaisin on lineaarinen interpolaatio, jolloin pisteiden välit ovat suoria. Kuutiollinen interpolaatio on samalla pistemäärällä tarkempi, mutta vaatii enemmän koodia ja laskenta-aikaa.

Interpolaatiopolynomin asteen ja pistemäärän valitseminen riippuu sitten siitä, mitä haluat tehdä. Korkea aste (älä mene yli kolmen, jos et tiedä mitä teet) maksaa kellojaksoissa ja suuri määrä pisteitä muistissa. Jos maltat raottaa salaisuuden verhoa sen päältä, mitä olet tekemässä (ainakin tarkkuus- ja nopeusvaatimukset) ja millä kalustolla (prosessori, taajuus), voin antaa tarkempia neuvoja.

Suosittelisin toisenasteen interpolaatiota lineaarisen sijaan. Sen lisäksi vakioaskelien sijaan suosittelisin välien valinnan optimointia interpolointi virheen minimoimiseksi ja pienemmän muistin kulutuksen saavuttamiseksi.

Itse olen vastaavanlaisen virityksen joutunut tekemään nelisen vuotta sitten ja silloin toisenasteen interpolaatio yhdessä optimoiduilla väleillä antoi parhaan tuloksen pienemmällä määrällä pisteitä.

Sivut

Uusimmat

Suosituimmat