Forum: Mikrocontroller und Digitale Elektronik Sinus in ASM Realisieren


von Sinusman (Gast)


Lesenswert?

Hallo erstmal,

also ich hab einen etwas lustigen 8051 ähnlichen prozessor der sehr 
langsam ist und..

Addieren
Subrahieren
Shiften
und if abfragen kann.

und ich hab 2 Messwerte die mir X und Y werte darstellen, ich hab noch 
ca. 40 Zeilen an Code frei ( rest komplett verbraucht ), und würde gerne 
Radius ( auflöung von 3~4 Bit reicht vollkommen ) und Entfernung zum 
Mittelpunkt errechnen, Genauigkeit ist nicht ganz so tragisch.

Lookup Table oder gibts einen Mathe Guru der nen gute Trick kennt?

von Christoph db1uq K. (christoph_kessler)


Lesenswert?


von Joerg W. (joergwolfram)


Lesenswert?

Radius und Entfernung zum Mittelpunkt ist für mich dasselbe...
Sinus braucht man dafür nicht, dafür aber Pythagoras.

-  X soweit nach rechts schieben, bis nur 4 Bit übrigbleiben
   (bei 8-bit Werten 4x bei 16-Bit Werten da High-Byte 4x)

-  in zwei Register laden, Summe=0
a) solange zweites Register >0, erstes Register zur Summe addieren
   wenn zweites Register >0 dann springe nach a)

-  im Summenregister steht jetzt X^2

-  mit Y und einem anderen Summenregister genauso verfahren

-  beide Quadrate addieren

-  resultat=0, diff=1
   wenn bei der Summe ein Übertrag aufgetreten ist, resultat=16, diff=33

b) wenn diff>low(summe) dann ende
-  resultat=resultat+1, summe(low)=summe(low)-diff, diff=diff+2
-  goto b

Ob das jetzt in 40 "Zeilen" noch reingeht, weiss ich leider nicht.

Gruß Jörg

von Sinusman (Gast)


Lesenswert?

ja dürfte sich ausgehen, beim Cordic Algo muss ich soweit ichs bis jetzt 
verstanden hab einen atan Lookup Table bauen, denk nicht das ich soviel 
platz hab.

kannst du das in einem Pseudo C erklären? ( hab 8 Bit eingang und 8 Bit 
ausgang )

von Sinusman (Gast)


Lesenswert?

meinte nicht Radius sondern Winkel ...

Brauche Winkel & Radius :)

von Jankey (Gast)


Lesenswert?

diese ganzen erklärungen beruhen alle auf Floating Points, und da sind 
meistens, die Lookuptable für den atan is auch schon zu gross ...

von Pieter (Gast)


Angehängte Dateien:

Lesenswert?

moin moin,

anbei mal was in cordic...

  *   *   *   *  
..ca. 40 Zeilen an Code frei ..

das bedarf einer Erklärung, den Rest kann man googeln.

mfg
Pieter

von Jankey (Gast)


Lesenswert?

danke für die Info,

nunja ich vermute zurzeit eher das die Skalierung meiner zahlen das 
problem ist, meine Eingangswerte für X und Y sind 0 bis 255 und als 
ausgang hätte ich einen Radius von 0 bis 255 und einen Winkel von 0 bis 
8

der Mittelpunkt meines kreises ist x=127 y=127

ich glaub ich schaff es sogar 50 Zeilen rauszuboxen, problem ist mein 
Ram hat nur 16Bytes, wie genau die atan Lookup Table sein muss hab ich 
auch noch nicht abgecheckt ...

von Jankey (Gast)


Angehängte Dateien:

Lesenswert?

Also anstatt eines sinus hab ich ein "quasi Rechteck geschaffen, das is 
jetzt eine 255x255er Anzeige

code dazu:

uchar sinus( int z )
{
        int x = 255;
        int y = 0;

        int dx = 0;
        int dy = 0;

        int i = 0;

//        Form1->Memo1->Clear();

        for ( i = 0; i < 8 ; i++ )
        {
                        dx = x >> i;
                        dy = y >> i;

                if( z > 127 )
                {
                        x = x - dy;
                        y = y + dx;
                        z = z - atan(128>>i)*64;
                }
                else
                {
                        x = x + dy;
                        y = y - dx;
                        z = z + atan(128>>i)*64;
                }

//                Form1->Memo1->Lines->Add( 
AnsiString().sprintf("x:%dy:%dz:%d",x,y,z) );

        }

        return y;
}

von Karl H. (kbuchegg)


Lesenswert?

Jankey wrote:
> ausgang hätte ich einen Radius von 0 bis 255 und einen Winkel von 0 bis
> 8

0 bis 8?
0 bis 7 (inklusive) als Integer?

dazu brauchst du keinen atan, das geht mit Koordinatenvergleich
und einer if-then-else Kaskade.

  (px/py ... Koordinaten des Punktes
   mx/my ... Koordinaten des Mittelpunktes
1
  dx = px - mx
2
  dy = py - my
3
4
  if( dx > 0 )
5
    if( dy > 0 )
6
      if( dx > dy )
7
        Winkel = 0
8
      else
9
        Winkel = 1
10
    else
11
      if( dx > -dy )
12
        Winkel = 7
13
      else
14
        Winkel = 6
15
  else
16
    if( dy > 0 )
17
      if( -dx > dy )
18
        Winkel = 3
19
      else
20
        Winkel = 2
21
    else
22
      if( -dx > -dy )
23
        Winkel = 4
24
      else
25
        Winkel = 5

Einfach mal einen Kreis aufzeichnen, die 8 Sektoren einzeichnen
und überlegen, welche Abhängigkeiten für die X und Y Koordinaten
in jedem Sektor gelten.

von Jankey (Gast)


Lesenswert?

jein, 0 bis 7 und 0 bis 8 sollte möglich sein, 0 bis 248 für Winkel zb 
wäre wieder perfekt.

von Jankey (Gast)


Lesenswert?

Eigentlich suche ich sowas:

Angle[0~248] = aTan(y/x);

das aTan mit y/x zu realisieren mit Cordic erstellt sich als etwas 
schwierig, zumals ich nur 8 Bit Rechenbreite zur verfügung habe und alle 
mit 16 Bit und mehr rechnen. Koordinatenvergleich is keine Ausreichend 
genaue Methode.

lg

von Jankey (Gast)


Lesenswert?

so mit dem Ding schafft man einen Sauberen 8 Bit Sinus


Mittelpunkt ist 127




int i = 0;
for ( i = 0; i < 8 ; i++ )
{
      y -= (x >> i);
      x += (y >> i);
}

return y;

von Jankey (Gast)


Angehängte Dateien:

Lesenswert?

so, problem bei der Berechnung ist das er aus irgend einem Grund 2x den 
Winkel durchrechnet, hat eigentlich einer von denen die CORDIC hier 
gepostet haben auch wirklich mal versucht in einem uController 
nachzubauen?

uchar phi( int x , int y )
{
        int z = 128;
        int i = 0;
        int X = x;
        int Y = z;

        for (i = 1; i <= 10; ++i)
        {
                x >>= 1;
                z >>= 1;

                if( Z < 0 )
                {
                    Y += x;
                    Z -= z;
                }
                else
                {
                    Y -= x;
                    Z += z;
                }
        }

        return Z;
}

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Nein, hab auch bisher noch keinen Cordic benutzt, aber das ist die 
einfachste genaue Methode.
Gehts jetzt um den Radius oder den Winkel? Es gibt noch eine sehr simple 
Näherung für den Radius: Betrag der längeren Koordinate plus 0,4142 * 
der Betrag der kürzeren. Das stimmt exakt alle 45 Grad. Ich habs mal 
benutzt um niederfrequente AM zu demodulieren.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

"des Betrags" sollte das heißen

ja und die ganzzahlige Näherung:
Ich benutze 106/256 als Approximation von (Sqrt(2)-1) = 0,4142

von Jankey (Gast)


Lesenswert?

Also Winkel ist vorrangig, wenn der Radius "kann" egal sein, schöner 
wärs natürlich wenn ich ihn noch reinklopfen könnte, zurzeit überlege 
ich mithilfe eines Integrators eine Sinusähnliche Kennlinie nachzubauen 
...

irgendwie komm ich einfach nicht auf den Winkel von 255*atan(y/x)...

von Karl H. (kbuchegg)


Lesenswert?

Jankey wrote:

> irgendwie komm ich einfach nicht auf den Winkel von 255*atan(y/x)...

Rein aus dem Bauch heraus würde ich mal sagen: da gibt es auch
keine vernünftige Näherung. Der tan, und damit auch die
Umkehrfunktion, ist eine sehr unangenehme Funktion.

Mal anders aufgezäumt: Wozu brauchst du den das Ganze. Vielleicht
gibt es eine Möglichkeit ohne den Winkel auszukommen.

von Jankey (Gast)


Lesenswert?

ich hab 2 Eingangssignale als X und Y Positions und will die Richtung 
anzeigen in die die 2 Werte Zeigen, problem dabei, das system in das ich 
anzeigen will ist Radial ...

von Karl H. (kbuchegg)


Lesenswert?

Jankey wrote:
> ich hab 2 Eingangssignale als X und Y Positions und will die Richtung
> anzeigen in die die 2 Werte Zeigen,

Muss das eine Zahlenanzeige sein oder reicht ein Pfeil, der
in die richtige Richtung weist?

> X und Y Positions

sind das Positionen in einem kartesischen Koordinatensystem?


(Im Moment spukt mir der Begriff 'ähnliche Dreiecke' durch
den Kopf. Erzähl mal mehr über den Input)

von Jankey (Gast)


Lesenswert?

Ja Karthesische Eingangskoordinaten von 0 bis 255 auf X und Y, ausgang 
ist dann eine Polare sagen wir mal "anzeige" ...

von Karl H. (kbuchegg)


Lesenswert?

Jankey wrote:
> Ja Karthesische Eingangskoordinaten von 0 bis 255 auf X und Y, ausgang
> ist dann eine Polare sagen wir mal "anzeige" ...



Grrrrrr
Kannst du nicht mal ein bischen konkreter werden.
Was ist so schwer daran, zu sagen:

Ich habe einen Joystick und möchte die Auslenkung dem
Benutzer anzeigen.
* Als Anzeige habe ich ein LCD auf dem Auslenkung und Winkel
   in Form von Zahlen ausgegeben werden soll
* Als Anzeige habe ich ein graphisches LCD, auf dem ein Pfeil
   die aktuelle Joystick Stellung symbolisieren soll

Im ersten Fall kommt man um die Arcus-Winkelfunktionen Funktionen
nicht herum. In letzterem aber schon.

(*) Nur so als Beispiel. Ich weis ja nicht was du machen willst.

von Jankey (Gast)


Lesenswert?

kann ich leider nicht ( patent pending ), wie wäre denn letzteres 
möglich?

von Jankey (Gast)


Lesenswert?

*x = 1;
        float dx;
        *y = 0;
        int i = 0;

        *x = 0.6073*(*x);


        for( i = 0; i < 8 ; i++ )
        {
                dx = (*x);
                if( z>=0 )
                {
                        (*x) -= (*y)  * (1.0/pow(2,i)) ;
                        (*y) += dx * (1.0/pow(2,i)) ;
                        z -= atan((double)(1/pow(2,i)))*(180/M_PI);
                }
                else
                {
                        (*x) += (*y)  * (1.0/pow(2,i)) ;
                        (*y) -= dx * (1.0/pow(2,i)) ;
                        z += atan((double)(1/pow(2,i)))*(180/M_PI);
                }
        }


So hab jetzt diese Funktion hier mehr oder weniger aus dem Web Adaptiert 
und etwas modifiziert. als Input hat sie denk Winkel, als output X & Y, 
die funktion müsste man eigentlich nur umdrehen ... so irgendwie ...

von Karl H. (kbuchegg)


Lesenswert?

Jankey wrote:
> kann ich leider nicht ( patent pending ),

Ja genau. Weil hier hundertausend Leute rumhängen, die nur
darauf warten dass einer die Megaidee postet um sie zu
kopieren. Dafür sollen alle anderen im Nebel rumstochern
welches Problem du eigentlich hast.

> wie wäre denn letzteres
> möglich?

sagte ich doch schon: ähnliche Dreiecke und damit Strahlensatz

sei  Px/Py die Eingangsposition, Wertebereich zb. -1000 ... +1000
in beiden Achsen.

Sei weiters, Qx/Qy die gesuchte Endposition auf einem Kreis am
Display, wobei der Mittelpunkt wieder als 0 angenommen wird.

Dann gilt:

  L = sqrt( Px * Py + Py * Py )

  Qx = Px / L
  Qy = Py / L

und der Vektor QX/Qy ist sogar in der Länge proportional
dem Vektor Px/Py

Dein Display habe nun dem Mittelpunkt bei 127/127 und der
Kreis soll einen Durchmesser von 127 Pixel haben, somit
wird der Einheitsvektor Qx/Qy auf eine Länge von 127 gebracht
und um 127 Einheiten verschoben.

  Qx = ( Px / L ) * 127 + 127
  Qy = ( Py / L ) * 127 + 127

Und schliesslich soll der Pfeil auch noch in der Länge
proportional der Auslenkung in Px/Py sein. Bei einer
Auslenkung in der jeweiligen Achse von 1000 soll der Pfeil
bis an den Kreis heranreichen:

  Qx = ( Px * L  1000  L ) * 127 + 127
  Qy = ( Py * L  1000  L ) * 127 + 127

ein bischen kürzen

  Qx = ( Px / 1000 ) * 127 + 127
  Qy = ( Py / 1000 ) * 127 + 127

und siehe da, sogar die Wurzelberechnung braucht keiner mehr.

Jetzt mag dein Wertebereich für Px/Py nicht -1000 ... 1000 sein
sondern meinetwegen 0 ... 512 mit 256 als Mittenposition und
255 als Auslenkung zu beiden Seiten

  Qx = ( ( Px - 256 ) / 255 ) * 127 + 127
  Qy = ( ( Py - 256 ) / 255 ) * 127 + 127


Da das aber so trivial ist, fürchte ich, das wird dir als
jemand der an einem Patent arbeitet, nicht wirklich weiterhelfen.

von Jankey (Gast)


Lesenswert?

eigentlich eine gute Idee, nur das man /255*127 auch als /2 schreiben 
kann ..und wenn du dann auflößt kommt

Qx = (Px>>1 - 127)+127
Qy = (Py>>1 - 127)+127

Qx = Px>>1
Qy = Py>>1

daran erkennt man aber einen echten denker :) er beschäftigt sich mit 
leidenschaft.

Das mit Patenten ist so: Wenn man irgendwo vor Veröffentlichung des 
Patents etwas darüber öffentlich gestellt hat is es sinnlos & nicht 
schützbar.

von 6635 (Gast)


Lesenswert?

Es ist klar, dass das resultat von atan() in radianten sind...

von Matthias L. (Gast)


Lesenswert?

Als Potenzreihe?

             x     1y     1y^3    2y^5
cot (y/x) = --- - ---- - ----- - ----- - ...
             y     3x    45x^3   945x^5

Vielleicht reicht es ja, bis ^3 zu rechnen, müsste man testen...?

==>


256cot(y/x) ~= 256(y/x)^-1  -  85(y/x)  -  6(y/x)^3

von Jankey (Gast)


Lesenswert?

Taylor Reihe is glaub ich zu gross ...


void cordic2( int *x , int *y , int *z )
{
        int dx;
        int i = 0;
        int ATAN[8]= { 128 , 64 , 32 , 16 , 8 , 4 , 2 , 1 };


        for( i = 0; i < 8 ; i++ )
        {
                dx = (*x);

//                if( *z>=0 )
                if( -(*y)>=0 )
                {
                        (*x) -= (*y)>>i  ;
                        (*y) += dx>>i ;
                        (*z) -= ATAN[i];
                }
                else
                {
                        (*x) += (*y)>>i;
                        (*y) -= dx>>i;
                        (*z) += ATAN[i];
                }
        }
}


ich glaub die richtung stimmt ...

von Jankey (Gast)


Lesenswert?

also der Algorithmus funktioniert jetzt ... zwar immer nur auf 1/4tel 
vom Kreis aber mit 4 If Abfragen bin ich ja wieder dort.

von Jankey (Gast)


Lesenswert?

Also nach langem hin und her, auf signed integer funktioniert es richtig 
gut, aber auf unsigned char ( 8 bit unsigned ) funktioniert es einfach 
nicht weils eigentlich in den Negativen bereich gehen müsste ..

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
Noch kein Account? Hier anmelden.