På skoj så testade jag hur noggrann algoritmen är som funktion av antalet iterationer (och tabellstorlek) när den jobbar med flyttal. Jag körde in vinklar slumpade likformigt mellan -90 och +90 grader och kollade hur fel det blev.
För tex 7 iterationer är man alltid under en grad fel (max fel är 0.895 grader) och i medel är felet alltid under en halv grad (0.44 grader).
Denna lösning kräver en tabell om sju flyttal. Och klarar sig utan multiplikator.
Inget svar på någons fråga, men när jag letade runt i XC8-manualen om mattebibliotek stod det generellt att "använd PIC18 eller högre". Hittade sen denna intressanta länk (daterad 1991): https://www.ganssle.com/articles/atrig.htm
Working in C with lots of free memory we never have to worry about taking the sine or cosine of an angle. The compiler's libraries have trig resources; we just invoke the routines without giving them much thought. If only all of the embedded world were so easy! Too many of us fight for every last byte or microsecond. Maybe we can't afford the overhead of a standard math library. Perhaps we're working in assembly where such resources just don't exist.
Sammanfattningsvis var det mycket matnyttig information gällande trigonometriska funktioner i embedded-system.
När jag jobbade med signalbehandling i PIC16 på 90-talet så approximerade vi sinus med 1, 2, 2, 3 osv. Det gäller veta vilka övertoner man inför och ta bort dem i senare steg eller sampla så man inte får med dem. Undersampling med vikning var ett annat trick. Jag testade CORDIC då men det gick alldeles för långsamt för den tillämpningen (1-bits samplade telefonmodem).
Vad är det för beräkningar du egentligen vill göra?
Om det var det jag skulle göra så är det enkla astronomiberäkningar. Solens upp/nergång och om jag hittar vettig algoritm med alla konstanter även månen.
Har fått klart att räkna på solen. Den träffar de officiella tiderna ofta exakt, annars inom 1 minut. Räknar 1 iteration utifrån 06/18. Det exekveras lite drygt 250k instruktioner för detta. För månen blir det väl tre iterationer för att få det någotsånär exakt.
Och nej tack! Ingen strömhungrig och ohanterlig GHz-processor i BGA för att kunna programmera det i C. Ev. byter jag till en 16+ för att få mera stackdjup.
guckrum skrev: ↑12 november 2024, 20:00:49
På skoj så testade jag hur noggrann algoritmen är som funktion av antalet iterationer (och tabellstorlek) när den jobbar med flyttal. Jag körde in vinklar slumpade likformigt mellan -90 och +90 grader och kollade hur fel det blev.
För tex 7 iterationer är man alltid under en grad fel (max fel är 0.895 grader) och i medel är felet alltid under en halv grad (0.44 grader).
Denna lösning kräver en tabell om sju flyttal. Och klarar sig utan multiplikator.
En dum fråga från en programmeringsilliterat (jag gör det om jag måste, men har en ganska lång stege idag att klättra uppför fastän jag gärna skriver funktionsspecar är det inte samma sak) , är varje iteration ett varv i funktionen så det tar lika lång tid mellan N1 => N2 som N18 =>N19?
Ja, varje iteration tar lika långt tid. Eller lite tid, beroende på hur man tittar. Det är ju bara några få basala operationer per iteration, så man kan köra detta _väldigt_ fort på kisel.
För att återgå till den ursprungliga frågan, det är nog dessvärre tveksamt om noggrannheten i de lib jag har nu räcker för beräkning av månen. Testade en algoritm i C som gav bra resultat inom någon minut och ändrade double till float. Resultatet blev dessväre blaj med ett par timmars fel...
Float i gcc är väl 32 bits? Räknar den internt med 24 bit mantissa så är ju precisionen hyfsat usel. Libbet till PIC har 31 bit mantissa internt, den behåller ettan i de normaliserade talen. Blir ju lite bättre, men tveksamt. Skulle behövts en byte till.
Kanske skulle funka hyfsat för några år med en epoch i närtid? Nu används J2000 och bygger upp ett fel över 25 år. Det blir nästan 400 månvarv runt jorden...
Avståndet med meterupplösning är nog föga nödvändigt, det är annat som är avgörande. Just månen är besvärlig för att allt har så kort period och banan är dessutom ojämn. Positionen vid en given tidpunkt fås fram med uttryck typ l = 0.606434 + 0.03660110129 * Jd. Heltalen motsvarar en hel period, så det är decimaldelen som används. Det är många sådana uttryck som sedan genom svart magi ger närmevärden till RA och dec samt även avstånd.
Ju högre tal på Jd, ju fler perioder ligger i botten under decimaldelarna och bygger på felet. Sätts en ny epoch börjar det hela om från noll och ger bra närmevärden som sedan gradvis på nytt försämras. Så frågan är om precisionen med befintligt lib räcker för att hålla drägligt över ett år.
Kanske är bättre att interpolera i tabeller, men det känns som det skulle kunna räcka. De värden jag har anger fasläget med 6 siffror, men hela 11 för perioden. På ett år blir multiplikatorn 365, så drygt 8 siffror, precis vad som med nöd och näppe finns innan felet kryper över 6 siffror. Eller är jag "lost in space" med det resonemanget?
Sedan tillkommer en mängd beräkningar som introducerar fel, så totalt tappas minst en siffra. Det förekommer även summor/differenser och avviker exponenterna så kommer mantissorna att "glida isär" och skapa fel. så antagligen är svaret att det kanske inte kommer att hålla ens med perfekta ingångsvärden.
Det funkar ju bra med solen, så med tabellvärden på RA och dec borde det hålla. Fast när månen stryker horisonten på ett sätt som solen inte kan här på beboeliga latituder blir det väl mycket fel ändå. Obra vinkel kan indikeras så det framgår när resultatet är kass. Det är helt ok här.
Kanske CORDIC kan användas för att få ingångsvärden? Det är 6 värden som används. Jd är inget heltal, RA och dec måste kunna bestämmas vid exakta klockslag.
Ja, jag vet inte exakt vilka operationer du kör, men en möjlighet är att räkna allt som heltal med många bitar istället för att hålla på med floats. Flyttal är ju ofta inget vidare. Exempelvis blir en av dina konstanter efter multiplikation med 10^11 3660110129, vilket ryms i 32 bitar. Trigonometriska funktioner kan man då köra med heltals-CORDIC. Har du några realtidskrav?
Det är stora talområden, så antar flyttal trots allt är det bästa. Det är add/sub som är svagheten med flyttal. Finns inga tidskrav alls inom rimliga gränser. MCU skall bytas till en med stack som räcker utan att beräkningar måste synkas med interrupts.
Har nu konstaterat att 32-bit mantissa inte kommer att räcka för att räkna på månens tider. Med geometriberäkningen i float blir resultatet blaj, trots ingångsvärden räknade i double. Med allt i double slår det på enstaka minuer mot en tabell på nätet. Hade hoppats det skulle räckt med en närmare epoch för att undvika multiplicera upp fel över onödiga månvarv, men så enkelt var det inte .
Kan nog vara görbart att maxxa upp befintligt lib till 64-bit mantissa. 16F887 pallar det inte så bra. Däremot de nya 16+ eller 18 skall nog ha förutsättningarna. Det blir ett hyfsat jobb, men är görbart. Med testning i emulator på PC underlättas det mycket.
Frågan är om det verkligen krävs 64-bit mantissa. 48-bit kanske skulle räcka. Det är drygt 14 siffror och använda konstanter har 11 som mest. Känns som det skulle vara nog utan att extra fel skall krypa in. Add/sub där mantissorna "glider isär" kanske är ett problem ändå, så 64-bit behövs? Vad är Double internt, 56-bit kanske? IEEE double ar ju ojämnt med 52-bit mantissa, 11-bit exp. samt tecken.
Vad ska din 16F887 mer exakt göra?
Blev lite nyfiken bara.
Ett knep jag läst om är att man gör om decimaltal till heltal och gör matten där för att sedan presentera det som decimaltal.
Internformatet i det lib jag använder är 6 bytes. 32-bit mantissa med första ettan på plats, 8-bit exp och en hel byte för teckenbit. IEEE är 23 med ettan utelämnad, så här är 8 bit mer. De sista bitsen blir snabbt blaj, så räknar IEEE med 3 bytes mantissa för float så är det ju sk*t. Hur befintligt lib skulle funka rakt av är skrivet i stjärnorna... Förmodligen otillräckligt.
Det hela skall vara till en klocka som kan visa diverse astronomiska funkktioner. Soltider funkar perfekt med befintligt lib testat i emulator.
Månen har jag inte testat där, det är hyfsat stort jobb att portera och funkar det sk*t är det onödigt. Vill först maxxa upp fp och få det att fungera.