Interpolationsknas på Arduino
Interpolationsknas på Arduino
Hade lite strul med en linjär interpolation.
V(x) = (A*x + B*(M-x))/M
V = Värdet jag vill ha. 8 bitar unsigned. Beräknas som long och trunkeras till bytestorlek.
A,B = Gränsvärden att interpolera mellan. 8 bitar unsigned.
M = Maxvärde för styrvariabeln x.
x = Går mellan 0 och M.
Fick det fungerande genom typecast med "unsigned long" på varje variabel och subuttryck. Jätteful kod, och det tog ganska mycket längre tid att göra beräkningen. Och jag kan inte riktigt inse hur teckenbit skulle påverka beräkningen. Alla värden och deluttryck ska bli positiva.
När det inte fungerade fick jag ett skumt skalfaktorfel. Ett gränsvärde (A eller B) på 120 blev nånstans runt 280-300 kanske, det gick i taket för 8 bitar och började om från noll och gick en bit upp. 255+nånting. Exakt vilket värde jag fick tog jag aldrig reda på, såg det på en lysdiods intensitet bara.
Nu fungerar det som sagt, men det vore skoj om nån kunde ha nån teori om varför det blev totalknas och varför kompilatorn inte varnat om det nu skulle vara formell risk för overflow eller nåt.
Och gärna lite optimeringstips också, den här beräkningen körs 48 gånger i interruptcontext.
GCC, Arduino Uno (Atmega328), om det är av betydelse.
V(x) = (A*x + B*(M-x))/M
V = Värdet jag vill ha. 8 bitar unsigned. Beräknas som long och trunkeras till bytestorlek.
A,B = Gränsvärden att interpolera mellan. 8 bitar unsigned.
M = Maxvärde för styrvariabeln x.
x = Går mellan 0 och M.
Fick det fungerande genom typecast med "unsigned long" på varje variabel och subuttryck. Jätteful kod, och det tog ganska mycket längre tid att göra beräkningen. Och jag kan inte riktigt inse hur teckenbit skulle påverka beräkningen. Alla värden och deluttryck ska bli positiva.
När det inte fungerade fick jag ett skumt skalfaktorfel. Ett gränsvärde (A eller B) på 120 blev nånstans runt 280-300 kanske, det gick i taket för 8 bitar och började om från noll och gick en bit upp. 255+nånting. Exakt vilket värde jag fick tog jag aldrig reda på, såg det på en lysdiods intensitet bara.
Nu fungerar det som sagt, men det vore skoj om nån kunde ha nån teori om varför det blev totalknas och varför kompilatorn inte varnat om det nu skulle vara formell risk för overflow eller nåt.
Och gärna lite optimeringstips också, den här beräkningen körs 48 gånger i interruptcontext.
GCC, Arduino Uno (Atmega328), om det är av betydelse.
Re: Interpolationsknas på Arduino
Det intressanta är väl hur koden såg ut, inte hur formeln ser ut?
Det finns ganska många klassiska fällor när man försöker göra såna där beräkningar.
Det finns ganska många klassiska fällor när man försöker göra såna där beräkningar.
Re: Interpolationsknas på Arduino
Har inte koden här och nu, men den implementerades i princip så som det var skrivet.
V = (A*x + B*(M-x));
V /= M;
Andra, formella variabelnamn bara.
A och B : arraynamn.structnamn.R (byte)
x och M : arraynamn.annatnamn
V = (A*x + B*(M-x));
V /= M;
Andra, formella variabelnamn bara.
A och B : arraynamn.structnamn.R (byte)
x och M : arraynamn.annatnamn
Re: Interpolationsknas på Arduino
Koden!
Du behöver inte posta igen förrens du postar koden.
Dels den som gav felet, dels den som nu fungerar.
Annars är det hela ganska meningslöst.
Du behöver inte posta igen förrens du postar koden.
Dels den som gav felet, dels den som nu fungerar.
Annars är det hela ganska meningslöst.
Re: Interpolationsknas på Arduino
Är det inte A*x och B*(M-x) som räknas ut som 8-bitars-multiplikationer och slår runt?
Vilken typ har x?
Jag skulle tro att A,B,x samt (M-x) måste castas till long innan du gångrar. Iaf om de delresultaten riskerar att överstiga 255. Kompilatorn vet väl inte vad x kan anta för värden, så den kommer inte kunna varna dig i det här fallet.
Se till att deklarera A,B och M som const (om de är det). Det kanske kan hjälpa kompilatorn med optimeringar, om den inte redan listat ut detta.
Om du kan välja så är det bra om M är en jämn 2-potens, för då gör kompilatorn nog om divisionen till en skift-operation istället.
Vilken typ har x?
Jag skulle tro att A,B,x samt (M-x) måste castas till long innan du gångrar. Iaf om de delresultaten riskerar att överstiga 255. Kompilatorn vet väl inte vad x kan anta för värden, så den kommer inte kunna varna dig i det här fallet.
Se till att deklarera A,B och M som const (om de är det). Det kanske kan hjälpa kompilatorn med optimeringar, om den inte redan listat ut detta.
Om du kan välja så är det bra om M är en jämn 2-potens, för då gör kompilatorn nog om divisionen till en skift-operation istället.
Re: Interpolationsknas på Arduino
Gjorde du så syns ju felet direkt: Du säger ju att V bara är en byte? Den första kodraden kommer alltså med största sannolikhet att generera en rejäl overflow.Wedge skrev:Har inte koden här och nu, men den implementerades i princip så som det var skrivet.
V = (A*x + B*(M-x));
V /= M;
Du borde alltså göra nåt i stil med
W = (A*x + B*(M-x));
V = W / M;
Där W är minst dubbla storleken mot A, B och M.
Det går kanske att lösa med casting men jag programmerar inte så mycket så jag har inte hundra koll.
Värt att notera är ju att kodar man i C med en optimerande kompilator så finns det ingen förlust i att skriva övertydligt.
Skriver du
C=A*x;
D=M-x;
E=B*D;
W=C+E;
V=W/M;
så kommer det att kompileras till samma kod som om du skriver som du skrivit. Fördelen är att det här skrivsättet ökar möjligheten till debugging eftersom du enklare kan kontrollera mellanresultaten och det är betydligt enklare att se en eventuell felplacerad "parantes".
Om jag nu inte gjort helt fel så kan dessutom (A*x + B*(M-x)) skrivas A*x+B*M-B*x (Ax+BM-Bx alltså).
Det i sin tur kan skrivas Ax-Bx+BM, bryt ut x och du får x(A-B)+BM.
Delar du nu hela det uttrycket med M så får du x(A-B)/M + B. Eftersom A, B och M såvitt jag förstått är konstanter så går det att skriva om till x*K+B där K är (A-B)/M.
K=(A-B)/M
V=x*K+B
Re: Interpolationsknas på Arduino
Det tycker jag är svårare att läsa. Då fattar man inte vad syftet är med beräkningen på samma sätt som när man skriver ut interpolationsformeln.C=A*x;
D=M-x;
E=B*D;
W=C+E;
V=W/M;
Hm... vad blir detta när A=120, B=10 och M=255.K=(A-B)/M
=> K=0
Tyvärr går det inte att flytta runt saker hursomhelst när det är heltalsaritmetik vi talar om.
Re: Interpolationsknas på Arduino
Du kan i såna fall göra K som en kvot, poängen var att du kan "bryta ut" B.
Mitt exempel var inte menat att vara tydligt, delar man upp FÖR mycket blir det rörigt ja. Men koden blir exakt samma om du kör:
V = (A*x + B*(M-x));
V /= M;
eller om du kör
W = (A*x + B*(M-x));
V = W / M;
eller om du kör
x_diff=M-x
W = (A*x + B*x_diff);
V = W / M;
Mitt exempel var inte menat att vara tydligt, delar man upp FÖR mycket blir det rörigt ja. Men koden blir exakt samma om du kör:
V = (A*x + B*(M-x));
V /= M;
eller om du kör
W = (A*x + B*(M-x));
V = W / M;
eller om du kör
x_diff=M-x
W = (A*x + B*x_diff);
V = W / M;
Re: Interpolationsknas på Arduino
> Det tycker jag är svårare att läsa.
Det beror mest på svårlästa variabelnamn. Med något annat
än C, D, E och W så kan det bli i princip hur lättläst som helst.
Det beror mest på svårlästa variabelnamn. Med något annat
än C, D, E och W så kan det bli i princip hur lättläst som helst.
Re: Interpolationsknas på Arduino
Jag håller inte med, men på den här punkten är man säkert olika.
Ibland tycker jag att läsbarheten blir bäst om själva matematiken visas tydligt, vilket jag tycker den gör i det första exemplet. Matematiska mellanresultat blir ofta svåra att hitta på bra variabelnamn till, t.ex. variabeln för "M-x"

Ibland tycker jag att läsbarheten blir bäst om själva matematiken visas tydligt, vilket jag tycker den gör i det första exemplet. Matematiska mellanresultat blir ofta svåra att hitta på bra variabelnamn till, t.ex. variabeln för "M-x"
Re: Interpolationsknas på Arduino
OK, om vi diskuterar just det faktiska fallet (jag vet inte riktigt vad
mellanresultaten står för så jag kan inte föreslå något bättre heller)
så kanske det inte är en bra idé, det var ju lite hårddraget också
i exemplet. Men generellt är beskrivande variabelnamn bättre än
enbokstavsnamn som var vanliga när man körde interpreterande
språk på system med trångt om minne.
mellanresultaten står för så jag kan inte föreslå något bättre heller)
så kanske det inte är en bra idé, det var ju lite hårddraget också
i exemplet. Men generellt är beskrivande variabelnamn bättre än
enbokstavsnamn som var vanliga när man körde interpreterande
språk på system med trångt om minne.

- Swech
- EF Sponsor
- Inlägg: 4750
- Blev medlem: 6 november 2006, 21:43:35
- Ort: Munkedal, Sverige (Sweden)
- Kontakt:
Re: Interpolationsknas på Arduino
Man kan ju dokumentera koden med en
tydlig beskrivning vad som beräknas
, och bryta ned det till något som passar
bättre för att få beräkningarna att inte slå runt
Swech
tydlig beskrivning vad som beräknas
, och bryta ned det till något som passar
bättre för att få beräkningarna att inte slå runt
Swech
Re: Interpolationsknas på Arduino
Det är nog ganska kompilator- och arkitektur-beroende hur man ska skriva för att den där funktionen ska bli så snabb som möjligt med full precision. C är dåligt på att beskriva den typen av beräkningar.
Man vill att multiplikationerna ska vara 8x8 bitar och producera 16-bitarsresultat. Därefter adderas dessa ihop som 16-bitarstal, för att till sist divideras och trunkeras till 8 bitar. Hur man skriver i C för att kompilatorn ska fatta detta är inte uppenbart. Möjligtvis skippa cast, men spara delresultaten i 16-bitars-variabler? Tror att avr-gcc tolkar det på rätt sätt iaf.
Man vill att multiplikationerna ska vara 8x8 bitar och producera 16-bitarsresultat. Därefter adderas dessa ihop som 16-bitarstal, för att till sist divideras och trunkeras till 8 bitar. Hur man skriver i C för att kompilatorn ska fatta detta är inte uppenbart. Möjligtvis skippa cast, men spara delresultaten i 16-bitars-variabler? Tror att avr-gcc tolkar det på rätt sätt iaf.
- Swech
- EF Sponsor
- Inlägg: 4750
- Blev medlem: 6 november 2006, 21:43:35
- Ort: Munkedal, Sverige (Sweden)
- Kontakt:
Re: Interpolationsknas på Arduino
Man kan ju skriva om...
W = (A*x + B*(M-x));
V = W / M;
(A*x + B(M-x)) / M
(A*x + B*M - B*x)/M
((A-B)*x + B*M)/M
B + (A-B)*X /M
Swech
W = (A*x + B*(M-x));
V = W / M;
(A*x + B(M-x)) / M
(A*x + B*M - B*x)/M
((A-B)*x + B*M)/M
B + (A-B)*X /M
Swech
Re: Interpolationsknas på Arduino
Såvitt jag minns så är det tvärtom väldigt tydligt specificerat i C hur sånt görs? Fördelen med C är ju att man explicit kan casta.superx skrev:Hur man skriver i C för att kompilatorn ska fatta detta är inte uppenbart.
Det som är kompilatorberoende är väl möjligen vad som sker om man INTE castar explicit? Men castar man så gör kompilatorn som man skriver.