Hi allerseits,
hier Beitrag "CORDIC in VHDL" wurde ja ein CORDIC
im rotating-mode diskutiert/implementiert. Funktioniert auch prima.
Jetzt will ich aber die andere Richtung bauen: Also ich bekomme Sinus
und Cosinus von 2 ADCs und muss daraus einen Winkel berechnen.
Jetzt koennte ich ja einen CORDIC wie oben laufen lassen (wenn ich die
Magnitude/Zeigerlaenge haette) und mich da hin-iterieren (anstatt Winkel
frage ich halt <> Sinuswert ab). Pferdefuss ist halt, ich muss die
Amplitude kennen, um eingermassen genaue Ergebnisse zu bekommen (der
Motor, an dem der Eingangsdatensensor haengt dreht mit ~10000 RPM und
hat 12 Wicklungen 3-Phasen BLDC).
Laut www-Quellen muesste ich beim CORDIC im vectoring-mode eigentlich
den Anfangswert fuer Sin/Cos auf den gemessenen Wert setzen und die
Winkel waehrend der Iteration so aendern, dass der Sinuswert gegen Null
geht. Die aufaddierten Winkel waeren dann mein Ergebniss.
Ich kriege mit einem so umgebauten CORDIC (laut obigem Link) aber nur
Muell raus...
Hat jemand 'nen Tipp, wie das geht? Ich habe noch ein
Verstaendnisproblem, wie denn die 'Magnitude' da mit rein geht...
Gruss,
- berndl
Hallo, ich weiß leider nicht wie kompliziert der CORDIC so ist, aber
vielleicht geht das einfacher.
Den Winkel kann man ja über die Zeit bekommen, das ist ja proportional.
Also eine Sinus Periode hat eine bestimmte Zeitdauer, bei der Hälfte ist
180°, bei z.B. 0,1*Zeitdauer liegt 2*π*0,1.
Also was musst Du machen?
Einen bekannten Zeitpunkt bestimmen, z.B. den Nulldurchgang oder Maximum
oder Minimum und dann brauchst Du noch die Zeit einer Periodendauer oder
auch der Halben.
Ich würde also z.B. das Maximum bestimmen und dann die Zeit zwischen
jeweils zwai Maxima messen - und das dann meinetwegen mitteln. Wenn Du
das dann hast kannst Du immer schön rausfinden wo Du gerade bist.
http://www.mikrocontroller.net/articles/AVR-CORDIC
da sind ein paar Links, u.a. Basic-Stamp mit Cordic.
Der Cordic berechnet immer zwei Größen gleichzeitig, also Amplitude und
Winkel in dem Fall, entspechend Pythagoras und Arcustangens.
Da sollte sich die Amplitude eigentlich herausrechnen. Aber Erfahrung
hab ich damit keine.
Am Anfang musst du SIN und COS einmal anhand deiner Eingangswerte
setzen.
Dein Vektor steht nun irgendwo in der Gegend rum und du möchtest Winkel
und die Vektorlänge wissen.
Deshalb drehst Du Deinen Vektor nun mit Deiner gewünschten Anzahl an
Iterationsschritten hin und her, oder hörst auf wenn Dein Imaginaranteil
NULL wird. Dein Realanteil ist dann gerade Deine Vektorlänge.
Den Winkel bekommst Du, indem Du während der Iteration immer Deine
Teilwinkel aufsummierst.
Nun hast Du Vektorlänge und Winkel für einen Eingangswerte und das spiel
beginnt von vorne.
porter schrieb:> Am Anfang musst du SIN und COS einmal anhand deiner Eingangswerte> setzen.> Dein Vektor steht nun irgendwo in der Gegend rum und du möchtest Winkel> und die Vektorlänge wissen.
hmm, genau das (denke ich) habe ich implementiert:
1
y=sin; x=cos;
Dann, abhaengig vom Quadranten, den Winkel mit den CORDIC Werten (45,
26.56, 14.04, ... Grad) so aendern, dass y gegen Null geht. Dabei die
Winkel Vorzeichenrichtig aufsummieren.
Der Betrag ist mir uebrigens in dem Fall wurscht, ich kann die HW vorher
kalibrieren (bzw. Kalibrierwerte einrechnen in SIN und COS).
Na, dann muss ich die VHDL nochmal genauer studieren, ein
Verstaendnisproblem des Algorithmus meinerseits scheint es ja nicht zu
sein.
Danke!
Gustl Buheitel schrieb:> Hallo, ich weiß leider nicht wie kompliziert der CORDIC so ist, aber> vielleicht geht das einfacher.>> Den Winkel kann man ja über die Zeit bekommen, das ist ja proportional.>> Also eine Sinus Periode hat eine bestimmte Zeitdauer, bei der Hälfte ist> 180°, bei z.B. 0,1*Zeitdauer liegt 2*π*0,1.> Also was musst Du machen?>> Einen bekannten Zeitpunkt bestimmen, z.B. den Nulldurchgang oder Maximum> oder Minimum und dann brauchst Du noch die Zeit einer Periodendauer oder> auch der Halben.>> Ich würde also z.B. das Maximum bestimmen und dann die Zeit zwischen> jeweils zwai Maxima messen - und das dann meinetwegen mitteln. Wenn Du> das dann hast kannst Du immer schön rausfinden wo Du gerade bist.
hast prinzipiell recht, aber ich bekomme SIN und COS von einem Sensor,
der an einem Motor haengt. Und die Drehzahl ist alles andere als
konstant, im Gegenteil, das ist hochdynamisch. Und ich muss den Winkel
'in Echtzeit' rauskriegen, mit dem etwas anstellen und dann wieder SIN
und COS generieren. Also CORDIC im vectoring mode, dann interne
Bearbeitung, schliesslich CORDIC im rotating mode (oder einfacher per
LUT) und ausgeben via DAC.
Ich koennte natuerlich, bei bekannten SIN/COS max/min auch am Eingang
per LUT arbeiten, da bekomme ich bei leichten Amplitudenaenderungen aber
die Genauigkeit nicht hin.
Gustl Buheitel schrieb:> Ok, ja das mit der Max/Min Erkennung und der Periodendauer hat etwas> Latenz, minimal eine Periode :-)
tja, und da mein Motor 12 Wicklungen U/V/W hat ist zwischen U und V halt
nur 10 Grad. Und die SW, die die Sensordaten kriegt und den Motor regelt
muss also mit einer Genauigkeit von <5 Grad 'bespasst' werden. Und wenn
ich jetzt noch ADC/Logik/DAC dazwischen schalten will, muss ich
geschaetzt unter 2 Grad Fehler bleiben. Und das ganze natuerlich
'instant on', also ab der ersten Umdrehung. Einen Kalibrierungszyklus
koennte/kann ich mir vor Begin des eigentlichen Tests evtl. noch
goennen...
Naja ich meinte nur, also ich kenne mich mit Motoren nicht aus, aber
10000rpm sind eine Periodenlänge von 100us. Wenn Du da jetzt einen ADC
mit 100MSpS betreibst, also 1 Sample alle 10ns, dann sind das
10000Samples je Periode. Klar das ist dann noch nicht hübsch und man
muss vielleicht über ein paar Samples mitteln, oder Du verwendest einen
langsameren ADC mit nur 10MSpS, ... jedenfalls kann man da schon eine
sehr hohe Auflösung bekommen, also zeitlich, wenn man die 2π durch die
Samplezahl teilt.
Die Frage ist dann auch ob man überhaupt einen ADC benötigt, oder nur
eine Uhr (Takte zählen) und irgendetwas das einem sagt wann ein Max/Min
ist. Vielleicht gibt es da so einfache Steinchen die das können und
einen kurzen Impuls ausgeben wenn ein Max/Min ist.
Wenn man das hat und nur die Takte zwischen zwei Max/Min zählt, also
ohne ADC, dann weiß man auch wo man liegt. Z.B. hat man bei der
vorangegengenen Periode mit einer 100MHz Clock 10k Takte gezählt
zwischen zwei Max/Min, und jetzt in der laufenden Periode ist man beim
Takt 1234, dann liegt man vermutlich, also wenn die Periodenlänge von
einer zur nächsten Umdrehung nicht stark (was auch immer das ist)
schwankt, bei (2π/10k)*1234=44,424°.
Gustl Buheitel schrieb:> aber> 10000rpm sind eine Periodenlänge von 100us
aehm, bei z.B. 6000rpm dauert eine Umdrehung 10ms (nicht 100us!), das
geteilt durch 12 macht (grob) 900us, nochmal wegen UVW geteilt durch 3
macht also in etwa 300us die ich aufloesen muss. Mit ADCs, Logik, DACs
im Bereich von 5-10us bin ich da bei 2-3 Prozent 'Latenz'. Das
funktioniert schon, und ich koennte immer noch schnellere ADCs und DACs
verwenden...
Ups hatte rpm als rps gesehen, sorry!
300us/10ns ist trotzdem sehr fein auflösbar. Also Maximum erkennen mit
100MSpS ADC geht sehr schnell, also kleiner 10 Samples Latenz = 100ns.
Vielleicht gibt es auch Bausteine die das selber können, aber davon hab
ich keine Ahnung. Die Logik macht das dann auch in wenigen Takten. Da
bleibst du gut unter 1us. Vermutlich geht es auch ohne ADC wenn es
Bausteine gibt die z.B. anzeigen ob Max/Min oder Nulldurchgang und
Vorzeichen der Steigung, das könnte man auch mit einem langsamen ADC
machen, denn das Vorzeichen der Steigung bleibt über längere Zeit
gleich, da muss man dann nur noch den Nulldurchgang erkennen, also ein
Spannungsniveau, vielleicht mit einem Komparator?
Das Problem ist eben die Schwankung in der Periodenlänge. Wenn jetzt
beim Taktezählen mit 100MHz bei der einen 300us Periode 30k rauskommt,
und die nächste Periode nurnoch 250us lang ist, dann kommt kein sauberes
Ergebnis raus, sondern (zeitlich):
Max - 300us - Max - 250us - Max
Und wir legen fest: Max = 0° und wollen den Winkel 1000 Takte nach dem
2. Max, dann rechnen wir:
(2π/(alte_Periondenlänge/Taktperiode))*Anzahl_Takte_in_aktueller_Periode
=
(360°/30k)*1000 = 12°
Richtig wäre aber:
(360°/25k)*1000 = 14,4°
Ich weiß nicht wie stark de Periodendauern von einer zur darauffolgenden
Periode maximal schwanken, 300us und danach 250us finde ich schon
extrem.
Gustl Buheitel schrieb:> Also Maximum erkennen mit> 100MSpS ADC geht sehr schnell, also kleiner 10 Samples Latenz = 100ns.
Genau das geht bei mir nicht. Das System wird eingeschaltet ohne zu
Wissen, wo der Motor gerade steht, der Mikrocontroller faengt an mit dem
Motor rumzuspielen (um Endanschlag links/rechts rauszufinden) und schon
hier laufen die Ueberwachungen der Sensorwerte (SIN/COS). Und wenn da
was nicht passt, dann schaltet die SW ab und traegt einen Fehler ins
EEPROM ein.
Was ich machen koennte (ist aber auch ziemlicher Aufwand/Krampf) ist,
'vor' dem eigentlichen Test (wir machen hier hunderte Tests am
Stueck...) eine Kalibrierung durchfuehren (Motor macht ein paar
Umdrehungen und ich kriege die min/max Werte mit), das EEPROM loeschen,
und dann erst mit dem eigentlichen Test (evtl. hunderte Testcases)
anzufangen.
Mein Ziel ist halt: Instant On! Und mit dem was ich da bauen soll,
brauche ich halt ganz einfach aus einem gegebenen SIN/COS den Winkel, so
genau wie moeglich.
Ist/wird uebrigens ein sehr interessantes Projekt und macht jetzt schon
richtig Spass! Das kann im Lauf des Jahres noch lustig werden...
ups, ich glaube, ich habe auch meinen Fehler in der VHDL gefunden: In
dem im Eingangspost verlinkten Thread wurden die MSBs (->Vorzeichenbits)
explizit gesetzt. Fuer meine Anwendung hier habe ich da etwas an Logik
wegoptimiert (kann man im rotating mode wenn die Gegebenheiten passen),
also das explizite setzen der Sign-Bits.
Das geht aber mit dem CORDIC im vectoring-mode definitiv schief...
Ich ueberarbeite es mal und melde mich dann wieder...