Fixed point uträkning i C

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Fixed point uträkning i C

Inlägg av dangraf »

Jag började diskutera fixed point uträkningar i tråden "Globala variabler och interrupt" men kännde att jag kom från ämnet, så jag fortsätter här.


Förklaring av problemet :

Hur fungerar en fixed point uträkning i C?
Jag kör just nu med floating point, men det tar ganska lång tid att utföra beräkningar och det hade varit roligt att veta hur man gör det på ett snabbare och effektivare sätt.

Just nu har jag ett uttryck på formen f(x) = k*x+m
som jag skrivit ner till

Kod: Markera allt

     po2 = 0.0449*(float)tempres+8.7860;
Där po2 står för "partial pressure oxygen" (partialtrycket för syrgas)

0.0449 är mitt "k" värde som jag multiplicerar med resultatet från AD omvandlaren.

8.7860 är min konstant "m" eftersom det finns en viss "bias" i systemet.

Just nu så spottar systemet ur sig tal mellan ca 0- 190 vilket motsvarar %syrgas. 160% syrgas kan man andas om man använder 100% syrgas att dyka med ner till 6m djup.

AD omvandlaren jag använder har en upplösning på 12 bitar. (ger värden från 0-4095).

Mitt önskväda mål är att ha en pressition på 1%. Jag har märkt att om jag har ett litet fel på "k" värdet, som knappt märks när man mäter syrgasen i luften (20.9%) så kan det bli åt helvete fel åt nått håll när man får större värden från AD omvandlaren då man når 160-190% syrgas. och det är VÄLDIGT VIKTIGT att det inte diffar några 10% när man når höga koncerntrationer eftersom kan leda till olyckor.

Mina frågor:
Hur gör jag för att använda fixed point uträknigar på ett smidigt sätt i C?

Är det samma sak som att använda heltal istället för flyttal och sedan själv bestämma vart "." tecknet skall vara?

finns det färdiga funktioner där man kan lägga in sitt fixed point tal för att omvandla det till en sträng bokstäver?

/ Daniel Grafström
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

Håller du på att konstruera en hemmabyggd rebreather? :)

Det vore kul att få veta lite mer om ditt projekt!

/Nitroxdykare Schnegel.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Intrressant...

Ger AD omvandlaren värden över hela området 0-4095 i det intressanta mätområdet ?

Är det så att du , så att säga, vill mäta med ADC'n och sedan visa resultatet ?
Var kommer i så fall det ackumulerade fel som du talade om in i bilden ?

Om det nu är så att du *bara* skall konvertera ADC värdet till något som skall visas, och om omräkningsformeln är komplicerad (jag vill väll inte säga att det är så här, men vill visa på möjligheten i alla fall), så kan man använda en "lookup tabell". Det kan ju aldrig bli fler än lite drygt 4.000 värden hur som helst. Sannolikt använder du inte hela ADC'ns omfång, eller hur ?

D.v.s att man i förväg beräknar "po2" för varje tänkbart värde från ADCn (i Excel t.ex) och sedan lägger man in en tabell (i programminnet) med resultatet.
Då behövs det inga beräkningar alls, bara en tabelluppslagning, vilket lär bli oslagbart snabbt... :-)

Ett vanligt sätt att hanterade det när antingen beräkningen är komplex eller man har stora krav på prestanda, och då man vill ha full kontroll på vilka po2 värden (t.ex) som varje ADC värde skall motsvara.

> "Är det samma sak som att använda heltal istället för flyttal och sedan själv bestämma vart "." tecknet skall vara? "

Ja, i princip.

> "finns det färdiga funktioner där man kan lägga in sitt fixed point tal för att omvandla det till en sträng bokstäver? "

"itoa" är väll en sån ? Du får själv lägga in decimalpunkten där den skall vara.

Men, du har en dsPIC med mycket programminne (i och för sig vet jag inte vad den gör förrutom det du har beskrivit), så du borde få in en tabell med olika po2 värden. Dessa värden kan beräknas i förväg med den noggranhet som krävs.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag har aldrig använd vara sig floating eller fixed point i mina program. Jag har alltid skalat upp så att heltal klarar av upplösningen och vid utläsning formatterar jag rätt. Detta sätt ger snabbhet i databehandlingen och enkel handhavande.

I ditt fall skulle jag använda "unsigned long" och stega upp alla värden till heltal, det är ju totalt likgiltigt om CPU:n räknar att 100% O2 är 100 eller 654, bara alla tal står i förhållande till varandra och du känner till det förhållande.

Om du har ett olinjärt förhållande är tabell en bra grej men jag ville inte använda det på linjäre saker, där räcker det med ett offset och en faktor.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Instämmer med Icecap här.
Det är ju linjärt, så en tabell är (som jag skrev) sannolikt overkill... :-)
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

jag håller på att bygga om min dolphin rebreader som i orginalutförande inte har någon syrgassensor och konstant gasflöde (halvsluten).
Jag vill bygga en syrgassensor och samtidigt bygga om den till ett i stort sätt helslutet system med elektronisk dosering av syrgas.
Men jag vill inte prata för mycket om det, eftersom det hela går rätt långsamt och jag vet inte om jag kommer ro i hamn projektet.
Men om det blir färdigt kommer jag försöka lägga upp en hemsida och visa vad jag gjort.

En lookup table skulle inte fungera eftesrom syrgassensorn behöver kalibreras med jämna mellanrum. Då måste man lägga in en helt ny tabell.

Jag har byggt elektroniken så att jag använder hela mätrområdet på AD omvandlaren. 0-3.3V

Jag vill kunna pressentera resulatet, men även använda det till andra beräkningar som att få fram %syrgas vid ytan osv.


Mitt inbillade fel vet jag inte riktigt vad jag ska kalla det.
Men jag tänkte såhär.
Om jag har en linje i ett diagram som är den riktiga utsignalen och lägger på nästa linje med den beräknade (baserat på heltal).
då verkar båda linjerna börja på samma ställe, men att de inte har exakt samma lutning. Det betyder att om man rör sig utåt på x axeln blir gapet mellan linjerna större och större.

Jag får väl börja trixa lite med unsigned long istället och försöka få det bli bättre :-)
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Du har alltså fel faktor!

Faktorn bestämmer lutningen på kurvan, offset avgör var den skär noll.

Du måste alltså justera din faktor så att den passar i topp-punktet om de 2 kurvar möts i nollpunktet.

Edit: förklarade inte så bra att det var användbart. Såhär tänkar jag:
Resultat = (Faktor * Input) + Offset.

Om dina linjer möts i punktet [Input = 0] är Offset rätt, om de sedan inte följs till toppnoteringen är din Faktor fel. Om den "Riktiga" är lägre än den uträknade är din faktor för stor, sen fär du gissa själv vad den är när den "Riktiga" är den högsta... ;-)
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

Hmm.. jag skulle nog tänka mig för både en och fyra gånger innan jag gav mig på ett hobbyprojekt som innefattar livsuppehållande utrustning och mikrokontrollers. Syrgasförgiftning är inte att leka med.

Jag jobbar med att utveckla hårdvara för säkerhetskritiska system, och jag vet vilka extrema krav som ställs på mjukvaran i form av validering etc.

Exempelvis så ställs det väldigt stora krav på kompilatorn, som måste vara MYCKET välbeprövad och väldokumenterad.

Dessutom måste du konstruera hårdvaran så att den blir helt "fail-safe", d.v.s en total urbuggning av uC:n ska inte leda till en farlig situation. I ditt fall är det ju inte det lättaste, eftersom både fallen med 0% syrgas och 100% syrgas är farliga.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Frågan är om det inte är enklare med den typen av valideringar i assembler baserade system. Det är ju lite mer "exakt" till sin karaktär. Eller också är det bara för att jag föredrar assembler... :-) :-)
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

Jo, vissa av de äldre system jag jobbar med har program skrivna i assembler. Tyvärr blir ju programmen väldigt svåröverskådliga om det ska göras mer komplicerade program.

Numera är det ADA som används som programspråk för våra system.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag är medveten om riskerna.
Anledningen till att jag använder C är för att det blir lättare att hitta/se fel i koden.
Jag har tänkt genom systemet väldigt många gånger och grundtanken är den att:
Om nått blir fel, skall den larma. Då tar man sin alternativa luftkälla och sticker direkt till ytan.
Det som kan bli fel är i stort sätt enbart att man får för mycket/lite syrgas. Därför har jag 2 processorer som oberoende av varandra skall mäta syrgashalten och kommunicera med varandra för att jämföra värdena. om något blir fel vill jag inte att systemet "fixar felet" utan säger bara ifrån så att jag kan avbryta dyket.

Man kanske skulle visa sitt projekt iaf, så att man kan få lite tips / trix hur man löser saker o ting..
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

2-processorsystem är en bra lösning, men du borde kanske överväga att låta feldetekteringen ligga i extern hårdvara.

Ex: En uC låter 2 utgångar gå till en XOR-grind. För att utgången på denna grind ska vara hög måste uC:n sätta dessa utgångar olika. Detta görs i pulser, så att utgången från XOR-grinden ger positiva pulser ut (med hög duty-cycle). Utgången på denna grind låter du via en transistor driva (-)-sidan av en reläspole, över vilken du kopplat en RC-länk med lagom tidskonstant.

Denna pulsade drivsignal återkopplar du även till uC:n för avläsning. På så sätt kan uC:n detektera om det t.ex. har blivit något hårvarufel i XOR-grinden eller liknande. Om ett sådant upptäcks, kan ett meddelande skickas till den andra uC:n att aktivera alarmet.

Den andra uC:n gör du likadant med, med skillnad att den driver (+)-sidan av reläet. Relätungorna aktiverar sedan ditt alarm (reläets viloläge = alarm).

På detta får du en ganska hög säkerhet, eftersom det krävs många aktiva åtgärder för att larmet INTE ska aktiveras. Naturligvis får man finslipa detta mer, det här var bara lite snabb brainstorming.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

men vad är den stora fördelen med xor grinden jämfört med att skicka/taemot data över uarten?

jag tänkte nämligen att processorerna skulle byta datapaket med varandra och jämföra sina resultat. Jag tänkte även skicka med en kontrollbit för att se så att all data tagits emor rätt.

Om något blir fel skall en bit sättas hög från processorn. Denna bit kontrollerar en transistor som är kopplad till en summer som själv genererar sin "pip" signal.

För processorn kan väl inte ta emot data "av misstag"? Dessutom slipper jag mer extern elektronik som kan bli fuktskadad eller fungera konstigt om det av misstag skulle hamna saltkristaller eller liknande på den.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Att låta dom prata med varandra fungerar bra....i ett felfritt system! Du ska räkna så att ena CPU kan få totalspader och inte fatta något, detta kan mycket väl betyda att den ändå skickar ut hyggliga datapaket men ändå har spader och styr som en idiot.

Följande fel kan jag rent omedelbart tänka mig kan uppstå:
* Programmeringsbit släpper, har jag upplevd. Alltså att en bit/byte förlorar sitt nivå, kanske lite "glappigt" så att säga. Betyder att programmet som kör är okänd.
* Hårdvarafel, port pajar, ADC lägger av, har jag upplevd.
* Kallödning eller liknande fysisk fel, definitivt inte ovanligt.
* Programfel, logisk bomb typ. Uppstår när man inte har räknat ut extremfallen och sett vad som händer. Har jag sett allt för ofta fast sällsynt i mina program, det är min styrka.
* Sensorfel, säger sig själv.

I de "felsäkra" system som finns i flyg t.ex. är det 3 datorer som gör samma sak och ett hårdvarabaserat system avgör att de 2 mest lika system bestämmer, detta medför att 1 system kan gå i svart utan att det äventyrer flygjärnet.

Jag är själv CMAS** och jag skulle gärna göra ett sånt system själv men jag hade gjort ungefär som snigelviftaren säger med att låta (minst) 2 system göra det samma och sedan jämnföra resultaten med hårdvara, stämmer de inte säger hårdvaran ifrån.
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

dangraf skrev:men vad är den stora fördelen med xor grinden jämfört med att skicka/taemot data över uarten?

jag tänkte nämligen att processorerna skulle byta datapaket med varandra och jämföra sina resultat. Jag tänkte även skicka med en kontrollbit för att se så att all data tagits emor rätt.

Om något blir fel skall en bit sättas hög från processorn. Denna bit kontrollerar en transistor som är kopplad till en summer som själv genererar sin "pip" signal.

För processorn kan väl inte ta emot data "av misstag"? Dessutom slipper jag mer extern elektronik som kan bli fuktskadad eller fungera konstigt om det av misstag skulle hamna saltkristaller eller liknande på den.
Vitsen med att använda en XOR-grind på sättet jag beskrev är att man minskar risken för att ett hårvaru- eller mjukvarufel få farliga konsekvenser.
I ditt exempel är säkerheten avhängig en enda utport på processorn, och en enda transistor. Det blir således helt meningslöst att använda dubbla processorer.

MTBF på systemet (MTBF = Mean Time Between Failures) blir alltså inte bättre än för den enskilda transistorn som driver summern.

I mitt exempel måste bägge CPUerna fallera på ett osannolikt sätt, eller två transistorer få kortslutning samtidigt för att ett farligt fel ska kunna uppstå. Dessutom detekteras fel på transistor/grind, och mjukvaran kan då aktivera larmet.


Grundprincipen för sådana här system är att grundtillståndet är nödstopp/nödbroms eller liknande, och att det sedan krävs väldefinerade och aktiva utsignaler från åtminstone 2 CPUer för att nödbroms/nödstopp ska upphävas.

Dessutom bör du driva larmet med en separat, isolerad spänningsmatning (batteri). Dessutom bör systemet genomföra grundliga självtester vid uppstart, inklusive aktivering och manuell kvittens av larmet.

Vitsen med grundliga självtester är att felsannolikheten för elektronikkomponenter är exponentialfördelad (när man befinner sig i den plana delen av "badkarskurvan"). Exponentialfördelningen är minneslös, och det innebär att om du genom självtest vet att alla komponenter fungerar, så "nollställs" sannolikheten att någon komponent ska gå sönder.
Skriv svar