Interpolationsknas på Arduino

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Interpolationsknas på Arduino

Inlägg av Wedge »

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.
Nerre
Inlägg: 27231
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Interpolationsknas på Arduino

Inlägg av Nerre »

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.
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Interpolationsknas på Arduino

Inlägg av Wedge »

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
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Interpolationsknas på Arduino

Inlägg av sodjan »

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.
superx
Inlägg: 1127
Blev medlem: 19 juni 2012, 23:28:16
Ort: Linköping

Re: Interpolationsknas på Arduino

Inlägg av superx »

Ä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.
Nerre
Inlägg: 27231
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Interpolationsknas på Arduino

Inlägg av Nerre »

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;
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.

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
superx
Inlägg: 1127
Blev medlem: 19 juni 2012, 23:28:16
Ort: Linköping

Re: Interpolationsknas på Arduino

Inlägg av superx »

C=A*x;
D=M-x;
E=B*D;
W=C+E;
V=W/M;
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.
K=(A-B)/M
Hm... vad blir detta när A=120, B=10 och M=255.
=> K=0

Tyvärr går det inte att flytta runt saker hursomhelst när det är heltalsaritmetik vi talar om.
Nerre
Inlägg: 27231
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Interpolationsknas på Arduino

Inlägg av Nerre »

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;
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Interpolationsknas på Arduino

Inlägg av sodjan »

> 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.
superx
Inlägg: 1127
Blev medlem: 19 juni 2012, 23:28:16
Ort: Linköping

Re: Interpolationsknas på Arduino

Inlägg av superx »

Jag håller inte med, men på den här punkten är man säkert olika. :wink:

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"
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Interpolationsknas på Arduino

Inlägg av sodjan »

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. :-)
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Interpolationsknas på Arduino

Inlägg av Swech »

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
superx
Inlägg: 1127
Blev medlem: 19 juni 2012, 23:28:16
Ort: Linköping

Re: Interpolationsknas på Arduino

Inlägg av superx »

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.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Interpolationsknas på Arduino

Inlägg av Swech »

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
Nerre
Inlägg: 27231
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Interpolationsknas på Arduino

Inlägg av Nerre »

superx skrev:Hur man skriver i C för att kompilatorn ska fatta detta är inte uppenbart.
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.

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.
Skriv svar