Hallo liebes Team, ich habe ein Problem. Ich habe einen Servomotor und dafür eine Steuerelektronik entworfen. In dem Servomotor ist ein Resolver verbaut. Jetzt habe ich meine Steuerelektronik für eine Resolverperiode so Programmiert das bei einer Periode des Resolvers einmal das Drehfeld herum läuft. Jetzt kommt das Problem. Meine Maschine ist eine 6pol Maschine aber der Resolver hat nur 2pole. Also habe ich für jede Resolverperiode 3 Maschinenperioden! Jetzt stehe ich vor einer Mauer und weiß nicht wie ich aus einer Resolverperiode so eben mal 3 mache!!! Hat jemand eine Idee oder so etwas schon einmal gemacht? Danke Gruß TNTBC
Eine konkrete Lösung für Dich habe ich nicht, aber ich würde mal nach dem Stichwort PLL suchen. http://www.elektronik-kompendium.de/public/schaerer/pll4046.htm Benötigst Du so etwas nicht sowieso für eine Drehzahlregelung?..oder wie synchronisierst Du die beiden Drehfelder?
TNTBC schrieb: > Jetzt stehe ich vor einer Mauer und > weiß nicht wie ich aus einer Resolverperiode so eben mal 3 mache!!! Winkel_elektrich = (Winkel_resolver * 3) % 360 Dein Resolver ist für deinen Motor ungünstig. Volker
Hallo Ralf, Ralf schrieb: > Benötigst Du so etwas nicht sowieso für eine Drehzahlregelung?..oder wie > synchronisierst Du die beiden Drehfelder? Die Synchronisation erfolgt über das Resolversignal, da ich weiß in welchen Sektor des 6 Quadrantenstellers ich mich befinde! und die Berechnung der Tastverhältnisse gehen über ualpha und ubeta. Eine PLL gibt mir ja nur die Frequenz des Jeweiligen Trägersignals aus. Das hilft mir aber nicht weiter da ich dabei nicht weiß wie ich die Maschine jetzt anzusteuern habe! Das weitere Problem der PLL ist, dass die Maschine einmal gedreht haben muss um eine gültige Frequenz zu haben. Ich habe eine Idee wie man es machen könnte wenn ich Sie rechnerische bewiesen haben werde ich sie mal Posten aber dennoch sammelt weitere Ideen Danke dir Ralf Gruß TNTBC
Hallo Volker Volker Zabe schrieb: > Winkel_elektrich = (Winkel_resolver * 3) % 360 Die Variante kenne ich, allerdings müsste ich mir dann den Sinus und Cosinus des Winkels neu errechnen und der Sinus und Cosinus des Resolvers wären unbrauchbar! Oder? Volker Zabe schrieb: > Dein Resolver ist für deinen Motor ungünstig. Japp, nur ist er fest verbaut von Werksseite aus!!! Gruß TNTBC
TNTBC schrieb: > Die Variante kenne ich, allerdings müsste ich mir dann den Sinus und > Cosinus des Winkels neu errechnen und der Sinus und Cosinus des > Resolvers wären unbrauchbar! Oder? Ja! Aber wie willst Du aus einem Sin/Cos-Signal 18(=3*6) Umschaltpunkte generieren, ohne über den Winkel zu gehen? Volker
Volker Zabe schrieb: > Aber wie willst Du aus einem Sin/Cos-Signal 18(=3*6) Umschaltpunkte > generieren, ohne über den Winkel zu gehen? Genau vor dem Problem stehe ich gerade. Ich will aber kein Arctan berechnen. Die Entscheidung der 6 Sektoren ging bis jetzt ganz gut ohne! Wenn es jedoch eine schnelle Möglichkeit gibt den Arctan zu berechnen dann werde ich darauf eingehen müssen!! Gruß TNTBC
TNTBC schrieb: > Die Entscheidung der 6 Sektoren ging bis jetzt ganz gut ohne! Das interessiert mich jetzt aber brennend. Wie hast du aus den 8 Segmenten des Sin/Cos-Signal (die man durch einfaches Vergleichen erhält) die 6 Umschaltpunkte generiert? > Wenn es jedoch eine schnelle Möglichkeit gibt den Arctan zu berechnen > dann werde ich darauf eingehen müssen! Ja gibt es. Alles in Integer. Du teilst das Sin/Cos-Signal in 8 Segmenten (wie oben beschrieben) auf, der Quotient bildet dann ein Index in einer Tabelle. Interpolieren brauchst du noch nicht einmal. Anbei ein Beispiel für ein 3-Phasiges System. Ist auch noch eine Wurzelberechnung drinnen. Volker
Volker Zabe schrieb: > Das interessiert mich jetzt aber brennend. Wie hast du aus den 8 > Segmenten des Sin/Cos-Signal (die man durch einfaches Vergleichen > erhält) die 6 Umschaltpunkte generiert? Ich habe es aus einer Vorlesung von Prof. Hambrecht der Beuthochschule Berlin. Ich habe ihn angefragt sobald er seine Zustimmung gibt werde ich die Methode posten. Volker Zabe schrieb: > Ja gibt es. Alles in Integer. Du teilst das Sin/Cos-Signal in 8 > Segmenten (wie oben beschrieben) auf, der Quotient bildet dann ein Index > in einer Tabelle. Interpolieren brauchst du noch nicht einmal. Die Frage ist, wenn ich jetzt zwei int16_t werte habe die um Null sind und ich gebe es in deine Funktion ein, funktioniert diese dann auch? Und was ist mit Werten über 30°. Ich bin ehrlich ich verstehe nicht was du in der arctan Funktion machst!!! Kannst du das mal beschreiben? Danke Gruß TNTbc
TNTBC schrieb: > Kannst du das mal beschreiben? Die Funktionen kannst du so nicht verwenden. Sie sind für ein Drei-Phasen-System (120°- Versatz) gedacht. - Du musst die Tabelle neu berechnen. - Kannst die Interpolation vernachlässigen [ atan30() ]. (Du brauchst eine Auflösung von ca 10°, ich brauchte 0,01°) Bei dir könnte es wahrscheinlich reichen, wenn du den Sinus im ersten Segment als linear ansiehst. - Die Aufteilung der Segmente neu schreiben (360° -> 90°)[ Cal_Winkel() ]. Es ging ums Prinzip, wie man Winkelfunktionen mit Integer-Werten berechnen kann. Dies sollte keine Vorgefertigte / Null-Denke Lösung sein! Drei-Phasen kann man (durch einfaches Vergleichen(siehe Cal_Winkel()) auf 12 Segmente aufteilen -> 30°. Das geht bei dir nicht. Volker
Ok ich gebe es zu ich bin zu tum für den Code!!!! Ich verstehe die Tabelle und den Ansatz nicht. Kannst du mir eine Seite oder irgendetwas geben um es besser zu verstehen?? Gruß TNTBC
Hallo, damit ich die Sache hier richtig beende! hier meine Lösung für den atan2. Danke an die Seite http://www.dsprelated.com/showmessage/10922/1.php Die Einheit benötigt laut Simulator:2388clk Im definitionbereich 0 <= alpha < 180;
1 | int16_t i_atan2(int16_t y, int16_t x) |
2 | {
|
3 | int16_t result = 0; |
4 | int16_t y2; |
5 | |
6 | if ((x | y) == 0) |
7 | return 0; /* give up */ |
8 | |
9 | if (y < 0) /* if we point downward */ |
10 | {
|
11 | result += -180; |
12 | y = -y; |
13 | x = -x; |
14 | }
|
15 | if (x < 0) /* if we point left */ |
16 | {
|
17 | result += 90; |
18 | y2 = y; |
19 | y = -x; |
20 | x = y2; |
21 | }
|
22 | if (y > x) /* 45 degrees or beyond */ |
23 | {
|
24 | result += 45; |
25 | y2 = y; |
26 | y -= x; |
27 | x += y2; |
28 | }
|
29 | if (2 * y > x) /* 26.565 degrees */ |
30 | {
|
31 | result += 26.565; |
32 | y2 = y; |
33 | y = 2 * y - x; |
34 | x = 2 * x + y2; |
35 | }
|
36 | if (4 * y > x) /* 14.036 degrees */ |
37 | {
|
38 | result += 14.036; |
39 | y2 = y; |
40 | y = 4 * y - x; |
41 | x = 4 * x + y2; |
42 | }
|
43 | if (8 * y > x) /* 7.125 degrees */ |
44 | {
|
45 | result += 7.125; |
46 | y2 = y; |
47 | y = 8 * y - x; |
48 | x = 8 * x + y2; |
49 | }
|
50 | |
51 | /* linear interpolation of the remaining 64-ant */
|
52 | result += (57) * y / x; |
53 | if(result != 0){ |
54 | if(result > 0) |
55 | |
56 | result++; |
57 | }
|
58 | return result; |
59 | }
|
TNTBC schrieb: > Kannst du mir eine Seite > oder irgendetwas geben um es besser zu verstehen? Im Prinzip macht mein Code das Gleiche wie deiner. Aber viel feiner (mehr Nachkommastellen), die du aber nicht brauchst und auf 3-Phasen ausgelegt. Durch die implizite Skalierung (Stichwort: Festpunkt-Arithmetik) ist der Code schlechter Nachtvollzierbar. Aber ich Versuchs mal:
1 | # define MOVE1 0x10000
|
2 | #define ANZAHL 13
|
3 | #define INTERVALL 5041
|
4 | const static t_stuetsstellen atan_table[ANZAHL] ={ |
5 | 0, 2386 |
6 | , 944754, 2198 |
7 | , 2757006, 2019 |
8 | , 5313604, 1850 |
9 | , 8473691, 1693 |
10 | , 12097609, 1549 |
11 | , 16057864, 1418 |
12 | , 20244280, 1300 |
13 | , 24565367, 1192 |
14 | , 28947482, 1096 |
15 | , 33332900, 1009 |
16 | , 37677470, 931 |
17 | , 41948268, 860 |
18 | };
|
19 | |
20 | unsigned short atan30(int U1,int U2) |
21 | {
|
22 | int index,flag; |
23 | unsigned long teiler,res; |
24 | |
25 | teiler = (unsigned long)U1 * MOVE1 + (MOVE1/2); |
26 | teiler /= U2; |
27 | |
28 | index = (int)(teiler/INTERVALL); |
29 | |
30 | res= atan_table[index].offset + atan_table[index].faktor * teiler; |
31 | res /= MOVE1; |
32 | |
33 | return (unsigned short) (res); |
34 | }
|
Würde man den COS-Wert durch den SIN-Wert im Bereich 0-45° teilen ergäbe das ein Wertebereich von 0-1. Dies ist in Integer nicht darstellbar. Deshalb verschiebe ich den Bereich um 16 Bit (*0x10000). Jetzt habe ich den Wertebereich von 0 bis 65535. Jetzt muss ich den Wertebereich auf meine Stützstellen in der Tabelle aufteilen. Ich dividiere durch 5041 (65536/13), so erhalte ich ein Index von 0 bis 12. Eine höhere Anzahl an Stützstellen ergaben keine höhere Genauigkeit. Damit hole ich mir den Stützstellenwert aus der Tabelle. Die Interpolation zwischen den Stützstellen ist etwas ungewöhnlich, Der Faktor ist nicht die Steigung zwischen den Stützstellen, sondern die Steigung von Null durch die Stützstelle. Erspart einige Rechnungen zur Laufzeit. Die Werte in der Tabelle sind so berechnet, das sie mir meinen Winkel in 0.01° mal 0x10000 ergeben. Das ergibt eine große Anzahl von Nachkommastellen bei den Rechnungen und damit einen kleinen Rundungsfehler. Des halb teile ich zum Schluss noch durch 0x10000. Ich hoffe es ist damit etwas klarer. Volker
Nachtrag: Hallo TNTBC, deine gepostete Funktion rechnet im Bereich 22,2 bis 26.5° bis zu -9,5° Falsch. Auch liefert sie nie das Ergebnis 1°. TNTBC schrieb: > result += 26.565; Du addierst eine double zu einem int16_t. Welchen Sinn macht das denn? Schaltest du immer die Compiler-Warnung ab? Annsonsten (wenn der Fehler gefunden wurde) eine nette kleine arctan-Funktion mit einem Fehler von +/- 1°. Volker
Hat mir ja keine Ruhe gelassen. Habe den Fehler gefunden und noch paar Kleinigkeiten geändert. Der Vergleich mit 8*y>x hat mehr Fehler produziert, als Genauigkeit gebracht. Eine Fixpoint Nachkommastelle und eine richtige Rundung brachten den Rest. Der maximale Fehler liegt jetzt bei - 0,6° / +0,7°. Im Anhang meine Testfunktion.
1 | #define FP 2
|
2 | |
3 | short i_atan2(short sinw, short cosw) |
4 | {
|
5 | short result = 0; |
6 | short temp; |
7 | |
8 | if ((cosw | sinw) == 0) |
9 | {
|
10 | return 0; /* give up */ |
11 | }
|
12 | |
13 | if (sinw < 0) /* 180 - 360 */ |
14 | {
|
15 | result = 180*FP; |
16 | sinw = -sinw; |
17 | cosw = -cosw; |
18 | }
|
19 | if (cosw < 0) /* 90 - 180 */ |
20 | {
|
21 | result += 90*FP; |
22 | temp = sinw; |
23 | sinw = -cosw; |
24 | cosw = temp; |
25 | }
|
26 | if (sinw > cosw) /* 45 - 90 */ |
27 | {
|
28 | result += 45*FP; |
29 | temp = sinw; |
30 | sinw -= cosw; |
31 | cosw += temp; |
32 | }
|
33 | if (2 * sinw > cosw) /* 26.565 degrees - 45 */ |
34 | {
|
35 | result += (short)(26.565*FP); |
36 | temp = sinw; |
37 | sinw = 2 * sinw - cosw; |
38 | cosw = 2 * cosw + temp; |
39 | }
|
40 | if (4 * sinw > cosw) /* 14.036 degrees - 26.565 */ |
41 | {
|
42 | result += (short)(14.036*FP); |
43 | temp = sinw; |
44 | sinw = 4 * sinw - cosw; |
45 | cosw = 4 * cosw + temp; |
46 | }
|
47 | |
48 | /* linear interpolation of the remaining 64-ant */
|
49 | result += 57*FP * sinw / cosw; |
50 | return (result+FP/2)/FP; |
51 | }
|
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.