Hallo, da ich für ein Problem den Sinus und Cosinus für beliebige Winkel in hundertstel Grad berechnen müsste und mir da die Wertetabelle zu groß wird (144kB), suche ich nach einer Möglichkeit den Sinus und Cosinus "live" zu berechnen. Also wie der Taschenrechner auch. Kann mir da jemand Tipps oder Rechenformeln geben?
Wie sieht es denn mit den Hochsprachen aus? Hat C und Basic in der Richtung nichts? P.S. Welcher µC eigentlich?
Tabelle einfach kleiner machen und linear oder kubisch interpolieren. Außerdem reicht es eine viertel Periode in der Tabelle zu halten. Je nach Qualitätsanforderung ist auch eine Parabelannäherung leicht und schnell zu realisieren. Vielleicht ist die Taylorreihenentwicklung der Sin/cos-Funktion eine Option. Ansonsten halt CORDIC.
Zwei Ideen: 1. Du brauchst ja nur den Sinus von 0..90° in der Tabelle zu halten, alles andere ergibt sich aus Quadrantenumrechnung und Verschiebungen. 2. Überlege, welche Genauigkeit notwendig ist. Man kann auch mit Reihenentwicklung oder wenigen Stützstellen und Interpolation dazwischen arbeiten. Ahoi, Martin
"Du brauchst ja nur den Sinus von 0..90° in der Tabelle zu halten, alles andere ergibt sich aus Quadrantenumrechnung und Verschiebungen" Da kann man noch weiter sparen, es reicht IMHO 0-45° ;-)
ja an eine C-Code Implementierung der Taylor Reihe habe ich gedacht. Die Idee in der C Bibliothek nachzusehn ist natürlich nicht schlecht. Lokal auf meinem Rechner hab ich mal in den math.c files gesucht und nichts gefunden. Aber mal sehn was sich noch finden lässt.
>Da kann man noch weiter sparen, es reicht IMHO 0-45° ;-)
Und wie kommst du ohne übertriebenen Rechenaufwand an den Rest?
1 | //Aufgabe 2
|
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | #include <math.h> |
5 | #define PI 2.0*asin(1.0)
|
6 | #define NEGATIV 1
|
7 | #define POSITIV 0
|
8 | |
9 | //****Funktion um den Sinus mittels Taylorreihe mit n gliedern zu berechnen****
|
10 | double taylorsin(double x,int n){ |
11 | int i; |
12 | double sum; |
13 | sum = 1.0; |
14 | for(i=n; i >1 ; i--){ |
15 | sum = 1.0 - x*x*sum/(double)((2*i-2)*(2*i-1)); //numerisch stabil |
16 | }
|
17 | sum *=x; |
18 | return (sum); |
19 | }
|
20 | |
21 | |
22 | //****Funktion mein_sin (für beliebige x aus R den Sinus zu berechnen)****
|
23 | double mein_sin(double x){ |
24 | char sign=POSITIV; |
25 | double erg; |
26 | if (x < 0){ |
27 | sign = NEGATIV; //Symmetrieausnutzung Vorzeichenwechsel |
28 | x *= -1.0; //Vorzeichen merken |
29 | }
|
30 | |
31 | x=fmod(x,2*PI); |
32 | //jetzt intervall 0 bis 2PI nur pos
|
33 | if (x > PI){ //Vorzeichenwechsel ist notwendig |
34 | //z.B. 3PI/2 (y = -1) PI subtrahieren = PI/2 (y = 1)
|
35 | x -= PI; |
36 | sign ^= 1; |
37 | }
|
38 | if (x > PI/2.0) x = PI - x; //Symmetrieausnutzung |
39 | if(x < PI/6.0) erg = taylorsin(x,8); // ist x in Bereich von 0 bis PI/ 6 |
40 | //einfach taylorsin aus
|
41 | else if (x < PI/3.0){ |
42 | x-=PI/6.0; // ist x in Bereich über PI/6 und unter PI/3 |
43 | // bringe x in Bereich unter PI/6
|
44 | x = taylorsin(x,8); |
45 | erg = 0.5*(x * sqrt(3.0) + sqrt(1.0 - x*x)); |
46 | }
|
47 | else{ |
48 | x-=PI/3.0; //siehe oben |
49 | x = taylorsin(x,8); |
50 | erg = 0.5*(x + sqrt(3.0) * sqrt(1.0 - x*x)); |
51 | }
|
52 | if(sign!=POSITIV){ |
53 | erg *= -1; |
54 | }
|
55 | return erg; |
56 | }
|
Bei 0-45° benötigte er dann sin UND cos, es liefe auf denselben Aufwand hinaus. Oder sin(x) = sqrt( 1 - (sin(90°-x))^2) ausnutzen. Aufgrund des Aufwands mit der Wurzel aber auch Käse.
Ich sehe gerade, genau das wurde gemacht (mit den Wurzeln) denk na ja, wird wohl funktionieren.
Den Cosinus kann man aus dem Sinus durch ableiten errechnen. Oder durch integrieren.
@ 6632 (Gast) >Den Cosinus kann man aus dem Sinus durch ableiten errechnen. Oder durch >integrieren. Was ja auch alles sehr einfach und schnell geht . . . Leute gibts.
... wrote:
> #define PI 2.0*asin(1.0)
Das sieht aber mehr als gefährlich aus. Mach da wenigstens noch Klammern
drumherum.
Wie wärs mit einem µC der sowas als Co-Prozessor onChip hat. z.B. Infineons XC886CM.
Laut http://www.eng.monash.edu.au/uicee/gjee/vol8no3/Risse.pdf verwenden Taschenrechner und x86-Prozessoren den CORDIC-Algorithmus, auch wenn es in der Literatur immer wieder anders behauptet wird. "Seit 1980 implementiert der 8087, der mathematische Coprozessor des 8086, in Hardware eine Reihe von Konstanten, trigonometrischen und logarithmischen Funktionen ... Die Indizien sind erdrückend: simple Taylor- Approximation allein kann diesen Implementierungen nicht zugrunde liegen!"
Der Hauptvorteil vom CORDIC ist, dass man keine Multiplikationen braucht, deshalb wird er gerne für Hardwareimplementierungen verwendet. Wenn man aber sowieso schon einen Multiplizierer im Controller hat ist Cordic nicht mehr unbedingt die beste Wahl, ich würde auch mal Polynomapproximation mit Horner-Schema ausprobieren. Wenn die Geschwindigkeit keine Rolle spielt ist es natürlich das einfachste die sin-Funktion aus der Compilerbibliothek zu benutzen.
Hallo, könnte man das wie folgt machen: Man legt eine Tabelle für sin und cos wie folgt an: phi_tab sin_tab cos_tab ------------------------------------ PI/4 sin(PI/4) cos(PI/4) PI/16 sin(PI/16) cos(PI/16) ... PI/16384 sin(PI/16384) cos(PI/16384) mit den Additionstheoremen für sin und cos: sin(x+y) = sin(x)cos(y) + cos(x)sin(y) cos(x+y) = cos(x)cos(y) - sin(x)sin(y) kann man sich an den Winkel heranrechnen und ist so theoretisch exakt! Man kann die Genauigkeit über die Länge der Tabelle bestimmen. berechne sin(phi) und cos(phi) Start: sin = 0 cos = 1 xphi = 0 Schleife i über die Tabelle: xphi= xphi + phi_tab(i) if xphi <= phi temp = sin*cos_tab(i) + cos*sin_tab(i) cos = cos*cos_tab(i) - sin*sin_tab(i) sin = temp else xphi = xphi - phi_tab(i) endif ende Schleife Mit einem Trick kann man etwas schneller sein: Man Skaliert den Winkel auf 90Grad (PI/2). Dann sind die Einsen im Bitmuster für den Winkel die Tabelleneiträge, die für die Näherung gebraucht werden: 56,25Grad = 45Grad + 11,25Grad = 10100..0 also die Zeilen für PI/4 und PI/16. Das ganze muss man sich natürlich mal in Fixpunktarithmetik anschauen. Waldo
Hallo! Wollte für meine Frage kein extra Thema aufmachen, und ich glaube es passt hier ganz gut rein... Im Großen und Ganzen geht es auch wieder um die Berechnung von böden trigonometrischen Funktionen: In meinem Programm muß ich öffters mit diesen Funktionen rechnen. Und aufgrund der kritischen Rechenzeit kann ich das nicht "online" machen. Darum habe ich für Sinus und Cosinus jeweils schon Tabellen mit stützwerten abgelegt, was dann so aussieht: for(i = 0; i <= 512; i++) { cosinus[i] = ( (int) (128 + 128 * cos((i 2 3.1416) / 512) * 0.99) ); sinus[i] = ( (int) (128 + 128 * sin((i 2 3.1416) / 512) * 0.99) ); } Im weitern Verlauf werde ich nur mit Festkommazahlen rechnen. Aber das soll nicht eure Sorge sein ;) . Ich hab nur grad irgendwie ein Problem mit der Formel für den ARCUS-Sinus und ARCUS-Cosinus. Für die will ich auch Tabellen anlegen, aber ich komm nicht auf die Formel... Kann mir die vielleicht jemand unter die Arme greifen? Danke, vG, Jojo
Jojo schrieb:
> auch Tabellen anlegen, aber ich komm nicht auf die Formel...
Wie wärs mit: die vorhandene Umstellen
Du hast
CosV = 128 + 128 * cos( Winkel )
CosV - 128 = 128 * cos( Winkel )
( CosV - 128 ) / 128 = cos( Winkel )
acos( ( CosV - 128 ) / 128 ) = Winkel
(Mit den 0.99 in deiner Formel hast du dir keinen Gefallen getan)
Hallo nochmal und danke für die rasche Antwort! Hm, jetzt, wo ich das so sehe hätte ich da auch selbst drauf kommen können ;) ... aber trotzdem danke, manchmal hab ich einfach ein Brett vor dem Kopf. Das mit dem Faktor 0,99 hab ich aus einer Formel, die ich im NEtz gefunden habe. Aber richtig, ob ich sie benutze oder weglasse macht keinen signifikanten Unterschied.
Jojo schrieb: > Das mit dem Faktor 0,99 hab ich aus einer Formel, die ich im NEtz > gefunden habe. Aber richtig, ob ich sie benutze oder weglasse macht > keinen signifikanten Unterschied. Doch, das tut es :-) Aber es löst ein Problem auf eine etwas seltsame Weise :-) Mal angenommen es wäre nicht da Der cos eines Winkels kann minimal -1 sein 128 + ( 128 * -1 ) = 0 aber: er kann maximal +1 sein 128 + ( 128 * 1 ) = 256 Und 256 ist nun mal zu gross für ein Byte :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.