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?
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
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 )
diese ganzen erklärungen beruhen alle auf Floating Points, und da sind meistens, die Lookuptable für den atan is auch schon zu gross ...
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
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 ...
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; }
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.
jein, 0 bis 7 und 0 bis 8 sollte möglich sein, 0 bis 248 für Winkel zb wäre wieder perfekt.
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
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;
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; }
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.
"des Betrags" sollte das heißen ja und die ganzzahlige Näherung: Ich benutze 106/256 als Approximation von (Sqrt(2)-1) = 0,4142
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)...
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.
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 ...
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)
Ja Karthesische Eingangskoordinaten von 0 bis 255 auf X und Y, ausgang ist dann eine Polare sagen wir mal "anzeige" ...
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.
kann ich leider nicht ( patent pending ), wie wäre denn letzteres möglich?
*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 ...
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.
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.
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
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 ...
also der Algorithmus funktioniert jetzt ... zwar immer nur auf 1/4tel vom Kreis aber mit 4 If Abfragen bin ich ja wieder dort.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.