Forum: FPGA, VHDL & Co. Cordic im vectoring-mode, wie?


von berndl (Gast)


Lesenswert?

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

von Gustl B. (-gb-)


Lesenswert?

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.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

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.

von porter (Gast)


Lesenswert?

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.

von berndl (Gast)


Lesenswert?

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!

von berndl (Gast)


Lesenswert?

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.

von Gustl B. (-gb-)


Lesenswert?

Ok, ja das mit der Max/Min Erkennung und der Periodendauer hat etwas 
Latenz, minimal eine Periode :-)

von berndl (Gast)


Lesenswert?

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...

von Gustl B. (-gb-)


Lesenswert?

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°.

von berndl (Gast)


Lesenswert?

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...

von Gustl B. (-gb-)


Lesenswert?

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.

von berndl (Gast)


Lesenswert?

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...

von berndl (Gast)


Lesenswert?

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...

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.