Inhaltsverzeichnis

Sinus

sinus cosinus integer numbers

Das Beispiel ist in gforth codiert worden.

Erklärung

Um den Sinus eines Winkels mit ganzen Zahlen (integer) darstellen zu können, skaliert man passend zur Anwendung. Benötigt man z.B. vier Stellen des Sinuswertes, wird er mit 10K multipliziert ausgegeben.

In einem Mikrokontroller geht es bei so einer Funktion auch um eine Balance zwischen Speicherplatz und Rechenzeit. So hat es sich eingebürgert Stützwerte für den Sinus aus einer Tabelle zu entnehmen, und lediglich bei Bedarf Zwischenwerte zu berechnen. Als Index in so eine Tabelle eignet sich die Gradzahl besser als das Bogenmaß. Um die Tabelle klein zu halten, werden oft nur die Sinuswerte von 0 - 90 Grad abgelegt - also die erste Viertelwelle. Manchmal werden auch nur 45 Werte in 2-Grad-Schritten abgelegt.

Um nun alle ganzen Zahlen als Winkel verwenden zu können, muss ein gegebener Winkel auf diese ersten 90 Grad zurück geführt werden. Weil der Sinus eine periodische Funktion ist, können alle Gradzahlen durch entsprechende Phasenverschiebung einfach auf die erste Viertelwelle zurück geführt werden. Es muss dabei jedoch eine Korrektur für das Vorzeichen des Sinuswertes erfolgen.

Baut man den Algorithmus um den Tabellenzugriff

cell * sinustabelle + @

auf, erhält man folgenden Ablauf. Winkel zwischen 90 und 180 Grad werden in den ersten Quadranten gespiegelt.

180 swap - ( 90..180Grad — 0..90Grad )

Winkel zwischen 180 und 360 Grad werden eine Halbwelle tiefer geschoben.

180 - ( 180..360Grad — 0..180Grad )

Weil dabei das Vorzeichen wechselt, wird ein flag hinterlegt, mit dem zum Schluß das Vorzeichen angepasst wird.

true >r … r> IF negate THEN

Winkel größer als 360 Grad werden auf die erste Welle abgebildet.

360 mod

Und negative Gradzahlen werden in den positiven Bereich umgeklappt. Auch dabei wechselt das Vorzeichen, und ein weiteres Flag wird hinterlegt, mit dem das Vorzeichen umgekehrt werden kann.

dup 0< >r abs … r> IF negate THEN

Algorithmus

\ Sinus und Cosinus
\ Tabellengestützte Berechnung für ganze Zahlen.
\ Ergibt auf 10K skalierte Werte. 

\ Prototypische Lösung mittels:
\ Gforth 0.6.2, Copyright (C) 1995-2003 Free Software Foundation, Inc.

vocabulary sinus    sinus definitions     decimal

create sinustabelle  \ 0...90 Grad, Index in Grad 
0000 ,  0175 ,  0349 ,  0523 ,  0698 ,  0872 ,  
1045 ,  1219 ,  1392 ,  1564 ,  1736 ,  1908 , 
2079 ,  2250 ,  2419 ,  2588 ,  2756 ,  2924 ,  
3090 ,  3256 ,  3420 ,  3584 ,  3746 ,  3907 ,  
4067 ,  4226 ,  4384 ,  4540 ,  4695 ,  4848 ,  
5000 ,  5150 ,  5299 ,  5446 ,  5592 ,  5736 ,  
5878 ,  6018 ,  6157 ,  6293 ,  6428 ,  6561 ,  
6691 ,  6820 ,  6947 ,  7071 ,  7193 ,  7314 ,  
7431 ,  7547 ,  7660 ,  7771 ,  7880 ,  7986 ,  
8090 ,  8192 ,  8290 ,  8387 ,  8480 ,  8572 ,  
8660 ,  8746 ,  8829 ,  8910 ,  8988 ,  9063 ,  
9135 ,  9205 ,  9272 ,  9336 ,  9397 ,  9455 ,  
9511 ,  9563 ,  9613 ,  9659 ,  9703 ,  9744 , 
9781 ,  9816 ,  9848 ,  9877 ,  9903 ,  9925 ,  
9945 ,  9962 ,  9976 ,  9986 ,  9994 ,  9998 ,  
10000 , 

: sinus@        cell * sinustabelle + @ ;
: sin           ( grad -- sinus )
                dup 0< >r abs
                360 mod  
                dup 180 > if 180 - true >r else false >r then 
                dup  90 > if 180 swap - then  
                sinus@  
                r> if negate then 
                r> if negate then ;
: cos           90 + sin ;

( finis)

Verifikation

Da gforth die Funktion fsin bietet, kann ein Vergleich der Tabelleneinträge mit dem berechneten Wert durchgeführt werden. Jedem sin aus der Tabelle wird ein fsin gegenübergestellt.

fsin nimmt ein Bogenmaß in Fließkomma Darstellung, daher muss die Gradzahl dahin umgerechnet werden.

\ Verifikation
: .sin          sin 6 .r space ;

( rad = grad * pi / 180 )
: rad           d>f pi f* 180.0e0 f/ ;
: .fsin         s>d rad fsin 10e3 f* 14 6 4 f.rdp ;

: test          ( von bis -- )  swap DO cr i .sin  i .fsin LOOP ; 

Als Ergebnis erhalten wir:

Gforth 0.6.2, Copyright (C) 1995-2003 Free Software Foundation, Inc.
Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
Type `bye' to exit
0 91 tt 
     0       0.000000
   175     174.524064
   349     348.994967
   523     523.359562
   698     697.564737
   872     871.557427
  1045    1045.284633
  1219    1218.693434
  1392    1391.731010
  1564    1564.344650
  1736    1736.481777
  1908    1908.089954
  2079    2079.116908
  2250    2249.510543
  2419    2419.218956
  2588    2588.190451
  2756    2756.373558
  2924    2923.717047
  3090    3090.169944
  3256    3255.681545
  3420    3420.201433
  3584    3583.679495
  3746    3746.065934
  3907    3907.311285
  4067    4067.366431
  4226    4226.182617
  4384    4383.711468
  4540    4539.904997
  4695    4694.715628
  4848    4848.096202
  5000    5000.000000
  5150    5150.380749
  5299    5299.192642
  5446    5446.390350
  5592    5591.929035
  5736    5735.764364
  5878    5877.852523
  6018    6018.150232
  6157    6156.614753
  6293    6293.203910
  6428    6427.876097
  6561    6560.590290
  6691    6691.306064
  6820    6819.983601
  6947    6946.583705
  7071    7071.067812
  7193    7193.398003
  7314    7313.537016
  7431    7431.448255
  7547    7547.095802
  7660    7660.444431
  7771    7771.459615
  7880    7880.107536
  7986    7986.355100
  8090    8090.169944
  8192    8191.520443
  8290    8290.375726
  8387    8386.705679
  8480    8480.480962
  8572    8571.673007
  8660    8660.254038
  8746    8746.197071
  8829    8829.475929
  8910    8910.065242
  8988    8987.940463
  9063    9063.077870
  9135    9135.454576
  9205    9205.048535
  9272    9271.838546
  9336    9335.804265
  9397    9396.926208
  9455    9455.185756
  9511    9510.565163
  9563    9563.047560
  9613    9612.616959
  9659    9659.258263
  9703    9702.957263
  9744    9743.700648
  9781    9781.476007
  9816    9816.271834
  9848    9848.077530
  9877    9876.883406
  9903    9902.680687
  9925    9925.461516
  9945    9945.218954
  9962    9961.946981
  9976    9975.640503
  9986    9986.295348
  9994    9993.908270
  9998    9998.476952
 10000   10000.000000 ok

Grafische Darstellung

sinus 0..90 Grad

sinus 90..180 Grad

sinus negative Gradzahl, -180..-90

sinus negative Gradzahl, -90..0

(Die Zeichnungen dürfen frei verwendet werden. mka)

Sinusberechnung als lineare Interpolation

Im vorliegenden Fall kann davon ausgegangen werden, dass die Datenbereiche von x und y begrenzt sind. Man kann sich die Aufnahme der Sinusfunktion so vorstellen, dass eine Leiste der Länge L im Quadranten zwischen x- und y-Achse bewegt wird. In diesem Fall hat x den Wertebereich zwischen 0 (Leiste auf x-Achse) und dem rechten Winkel(Leiste auf y-Achse). y hat dann den Wertebereich zwischen 0 und L. In diesem Bereich gibt es fünf rationale Wertepaare:

(0;0),(1/3;1/2),(1/2;0,707);(2/3;0,866),(1;1), was den Werten für 0, 30, 45, 60 und 90 Grad entspricht.

Die Idee war es nun, die beiden Werte auf den Zahlenbereich von 32767 zu skalieren. Außerdem wurden noch zwei Stützwerte ergänzt, für 15 und 75 Grad.

variable sinus
5461 , \ Einteilung (= 32767/6 <=> 90° /6 )
0 , 8191 , 16383 , 23166 , 28376 , 31718 , 32767 , \ Werte

: schrittweite sinus 2 + @ ;
: stuetzwert ( wertnr --- wert ) 2 * 4 + sinus + @ ;

:sin (winkel --- wert )  schrittweite /mod
                         dup rot swap dup
                         stuetzwert swap 1 + stuetzwert swap -
                         schrittweite */
                         swap stuetzwert + ;


Man muß den Winkel entspechend mit „*/“ skalieren und anschließend auch das Ergebnis. Die Funktion bietet sich auch bei Anwendungen an, wo nur Stützwerte bekann sind, z.B. bei der Leuchtenberechnung.