www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Sinus und Cosinus in einem µC ohne Fließkomma berechnen


Autor: Bob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Jörg B. (manos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie sieht es denn mit den Hochsprachen aus? Hat C und Basic in der 
Richtung nichts?

P.S. Welcher µC eigentlich?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau dir eine C Bibliothek an.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Martin Schneider (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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° ;-)

Autor: Bob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da kann man noch weiter sparen, es reicht IMHO 0-45° ;-)

Und wie kommst du ohne übertriebenen Rechenaufwand an den Rest?

Autor: ... (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
//Aufgabe 2
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 2.0*asin(1.0)
#define NEGATIV 1
#define POSITIV 0

//****Funktion um den Sinus mittels Taylorreihe mit n gliedern zu berechnen****
double taylorsin(double x,int n){
  int i;
  double sum;
  sum = 1.0;
  for(i=n; i >1 ; i--){
    sum = 1.0 - x*x*sum/(double)((2*i-2)*(2*i-1)); //numerisch stabil
  }
  sum *=x;
  return (sum);
}


//****Funktion mein_sin (für beliebige x aus R den Sinus zu berechnen)****
double mein_sin(double x){
  char sign=POSITIV;
  double erg;
  if (x < 0){
    sign = NEGATIV;     //Symmetrieausnutzung Vorzeichenwechsel
    x *= -1.0;         //Vorzeichen merken
  }

  x=fmod(x,2*PI);
                  //jetzt intervall 0 bis 2PI nur pos
  if (x > PI){         //Vorzeichenwechsel ist notwendig
                //z.B. 3PI/2 (y = -1) PI subtrahieren = PI/2 (y = 1)
    x -= PI;
    sign ^= 1;
  }
  if (x > PI/2.0) x = PI - x; //Symmetrieausnutzung
  if(x < PI/6.0) erg = taylorsin(x,8); // ist x in Bereich von 0 bis PI/ 6
  //einfach taylorsin aus
  else if (x < PI/3.0){
    x-=PI/6.0; // ist x in Bereich über PI/6 und unter PI/3
      // bringe x in Bereich unter PI/6
      x = taylorsin(x,8);
    erg = 0.5*(x * sqrt(3.0) + sqrt(1.0 - x*x));
  }
  else{
    x-=PI/3.0; //siehe oben
    x = taylorsin(x,8);
    erg = 0.5*(x + sqrt(3.0) * sqrt(1.0 - x*x));
  }
  if(sign!=POSITIV){
    erg *= -1;
  }
  return erg;
}

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe gerade, genau das wurde gemacht (mit den Wurzeln) denk na ja, 
wird wohl funktionieren.

Autor: 6632 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Cosinus kann man aus dem Sinus durch ableiten errechnen. Oder durch 
integrieren.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... wrote:
> #define PI 2.0*asin(1.0)

Das sieht aber mehr als gefährlich aus. Mach da wenigstens noch Klammern 
drumherum.

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wärs mit einem µC der sowas als Co-Prozessor onChip hat.
z.B. Infineons XC886CM.

Autor: Christoph Kessler (db1uq) (christoph_kessler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!"

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Walter Selg (waldo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jojo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Jojo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.