Ich suche eine effiziente Implementierung von ARCTAN fuer einen kleinen
Microcontroller. CORDIC ist mir zuviel. Es muss klein, schnell und ohne
Divisionen sein, Eingangsbereich Z.B. 32 Bit im 16.16 Format, um die
0,000x bei grossen X darstellen zu können, Rechnung in einem Quadranten,
Ausgang Winkel -/- 255, d.h. es reicht eine Genauigkeit von einem halben
Grad.
Die Rechnung müsste dann wohl auf ein Viertel Grad genau sein.
Tabelle würde Ich vermeiden wollen,
Eine Tabelle wäre aber wohl das Einfachste bei den wenigen Werten.
Den ARCTAN kann man auch mit einer Wurzel nachbilden, aber die ist auch
nicht einfacher zu berechnen. Nach mehreren Iterationen gibt es einen
Wert, der dann doch nur Ungenau ist.
Welcher Controller?
WS schrieb:> x(1+0,28x*x) und so?
Interessant. Aber in Wikipedia steht x/(1+0,28x*x) (für |X| <= 1, andere
Bereiche ähnlich), und die Division tut dem Meister offensichtlich weh.
Aber es ist nur eine Division.
CORDIC ist aber doch gerade für die lumpigen Rechner DIE Methode
schlechthin.
Was wäre, mit reduzierter Auflösung = weniger Rotationen zu agieren? Mit
4-5 Schritten müsste sich das doch machen lassen.
http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
Ansonsten heuristisch annähern, anhand der eigenen Anforderungen, sprich
lokal erlaubten Abweichungen und der benötigten Bereiche, wobei es sehr
viel knapper kaum gehen wird. Die billigste Lösung ist wohl die von den
Telekomikern/Iren hier:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.4931&rep=rep1&type=pdf
Weitere Denkanstösse hier:
http://www.convict.lu/Jeunes/Math/arctan.htm
Bei Näherungen muss man nur aufpassen, dass es keine minimalen Knicke
gibt und die Kurve monoton bleibt! Je nach Verwendungszweck muss sogar
auch die Ableitung monoton und vor allem stetig sein, daher darf es
keine Plateaus geben. Da fallen viele auf die Nase!
Ich sehe nicht den Grund und Vorteil für die Nutzung des Cordic, wenn
Ich dann doch wieder auf gespeicherte Werte zurückgreifen muss, die ich
aus Tabllen lesen soll. Dann kann ich gleich nähern.
Meister E. schrieb:> Ich sehe nicht den Grund und Vorteil für die Nutzung> des Cordic, wenn Ich dann doch wieder auf gespeicherte> Werte zurückgreifen muss, die ich aus Tabllen lesen soll.
Es ist Dir also völlig egal, ob Du eine Tabelle mit 512
Werten brauchst oder eine mit nur 16? Merkwürdig.
> Dann kann ich gleich nähern.
Dann mach doch. Ganz ohne Spott: Ich wäre gespannt auf
Deine Lösung.
Mit dem CORDIC wird es eben am schnellsten genau. Natürlich musst Du
mehrfach auf eine Tabelle zugreifen, aber das müsste man mit einer
diskreten Abschnittstabelle eben auch. Bei binärem hashing und Bei 512
Werten mindestens 9x. In der Zeit arbeitest Du auch 3-4 CORDIC
Iterationen ab.
Klar kann man mit noch weniger Stellen operieren und interpolieren, wenn
es die Anwendung hergibt, aber man darf eben nicht erwarten, dass man
mit dem Winkel nochmal irgendwelche Cosinüsse bilden und z.B. Realteil
errechnen kann zur weiteren Verwendung. Solche simplen Näherungen sind
i.d.R. finale Operationen für Anzeigen oder für Schätzungen am Besten
geeignet.
Ansonsten sind das Sonderfälle:
Ich habe mal eine Implementierung in VHDL gemacht, die sehr schnell sein
müsste und wobei der CORDIC-CORE einfach zu langsam war. Allerdings war
die Anwendung recht grob und diente nur der Schätzung einer
Winkelinformation. Ich habe einfach Werte <1.0 per Division gespiegelt,
um sie in den anderen Ast zu bekommen und den Ausgang der Division, die
ja als pipeline die bits von oben herunter sukzessive liefert, zur
Ansteuerung der hash table genutzt. Dann musste Ich nicht "warten" bis
das Divisionsergebnis komplett feststeht, sondern hat schon nach 2
Takten die erste Information, in welcher (lokalen) Hälfte der Tabelle
das Ergebnis liegt. So kann man das auch für Wurzeln machen.
Der Hauptvorteil war, dass man nur sehr geringe Auflösungen und auch
keine Multiplier für die Rechnung brauchte.
Die Methode ist aber definitiv mal nichts für Microcontroller.
Dirk B. schrieb:> Wie kommst du an den TAN (also den Einganganswert für den ARCTAN)?
Das war damals auch mein Problem ;-) Den nimmt man über einen
Tabellenwert. Das ist ja der Trick:
Beitrag "Cordic - Sinussignal"
Possetitjel schrieb:> Meister E. schrieb:> Es ist Dir also völlig egal, ob Du eine Tabelle mit 512> Werten brauchst oder eine mit nur 16? Merkwürdig.
Nein, es ist nicht egal. Bei der vorliegenden Applikation habe Ich nur
ein bissl ein Problem, viele Daten schnell hin und her zu bekommen, weil
Ich alles erst umständlich aus einem etnfernten RAM, wahrscheinlich ROM
heranschauffeln müsste.
Meister E. schrieb:> Possetitjel schrieb:>> Meister E. schrieb:>> Es ist Dir also völlig egal, ob Du eine Tabelle mit 512>> Werten brauchst oder eine mit nur 16? Merkwürdig.>> Nein, es ist nicht egal. Bei der vorliegenden Applikation> habe Ich nur ein bissl ein Problem, viele Daten schnell> hin und her zu bekommen, weil Ich alles erst umständlich> aus einem etnfernten RAM, wahrscheinlich ROM heranschauffeln> müsste.
Naja, das spricht doch für CORDIC; dort kann man mMn alles
mit Direktoperanden erschlagen, wenn man die Schleife abrollt.
Insofern verstehe ich Deine Argumente nicht.
Edi M. schrieb:> weil> Ich alles erst umständlich aus einem etnfernten RAM, wahrscheinlich ROM> heranschauffeln müsste.
Die wenigen Werte lassen sich eigentlich gut lokal speichern. Was ist
das für ein Controller, der arctan machen soll aber kaum Speicher hat?
Edi M. schrieb:> Aber es wird eine kleiner, mickriger mit wenig> Platz und wenig Strom.
Naja, Kernfrage ist, ob das Ding schnell multiplizieren
kann oder nicht.
Wenn nicht, wird's auf CORDIC hinauslaufen. Bangemachen
gilt nicht :)
Beim Algorithmus für ATAN kann ich nicht helfen; trotz
der i.d.R. beschissenen Erklärungen habe ich die
sin/cos-Variante verstanden -- wie man aber den ATAN mit
CORDIC berechnet, ist mir unklar.
Falls jedoch ein Multiplizierer vorhanden ist, gibt's
andere Möglichkeiten.
Possetitjel schrieb:> Beim Algorithmus für ATAN kann ich nicht helfen; trotz> der i.d.R. beschissenen Erklärungen habe ich die> sin/cos-Variante verstanden -- wie man aber den ATAN mit> CORDIC berechnet, ist mir unklar.
Das Prinzip für die ATAN Berechnung mit Cordic muss so sein, denke ich:
Du zerlegst Deinen Winkel in die Komponenten 45°, 22.5°, 11.25°, 5.65°,
2.8125°, 1.40625°, 0.703125° und 0.3515625°, das sollte reichen für das
geforderte halbe Grad Auflösung. Dann nimmst Du die komplexe Zahl 1+j*0
und drehst sie um diese Winkel nach dem Muster hier, hab ich schon mal
referenziert:
Beitrag "Goertzel-Algorithmus und Signed Fractional Format"
Die Drehungen normierst Du so, dass der Realteil 1 bleibt. Der
Imaginärteil nach den Drehungen ist der gesuchte Wert.
Wäre ein grosser Spass, das mal so zu versuchen.
Cheers
Detlef
Nochmal nachgedacht, das geht viel einfacher. Du rufst einfach die
Routine aus
Beitrag "Goertzel-Algorithmus und Signed Fractional Format"
so auf:
IntAtan2(foo,1). Eingangsdynamik sind allerdings 16Bit, weiß nicht, ob
das dem TO reicht.
Cheers
Detlef
W.S. schrieb:> Was ist denn mit einer stückweisen quadratischen Annäherung?
Geht beschissen, wegen der horizontalen Asymptote. Man muss
in ewig viele Teilintervalle zerlegen.
(Gut... ich hatte kubische Splines betrachtet. Macht keinen
großen Unterschied in der Kernaussage.)
> Etwas> rechnen können, wird auch der winzigste Winzigkontrolleur.
Ein alter Vorschlag von gjlayde sagt, für Winkel über 45°
die Beziehung atan(1/x) = 90 - atan(x) auszunutzen. Das
ist clever, setzt aber effiziente Berechnung von 1/x voraus.
Edi M. schrieb:> Diese Vereinfachungen kenne Ich natürlich, aber mit einer> Division bin Ich genau so weit.
Irgendwie ist das ermüdend.
Für den Kehrwert gibt es eine schnelle, gut konvergente
Iteration - aber die setzt voraus, dass man schnell
multiplizieren kann.
Fällt Dir jetzt vielleicht auf, warum ich weiter oben
nach dem Multiplizieren gefragt habe?
Detlef _. schrieb:> Nochmal nachgedacht, das geht viel einfacher. Du rufst> einfach die Routine aus> Beitrag "Goertzel-Algorithmus und Signed Fractional Format"> so auf:> IntAtan2(foo,1).
Ja, danke.
Hatte wohl ein gewaltiges Brett vor dem Kopf. Der Unterschied
liegt offenbar nur in Startwert, Drehrichtung und Abbruch-
kriterium -- der Algorithmus bleibt genau gleich.
Wenn man von (0;1) ausgeht und so dreht, dass phi gegen den
gewünschten Winkel geht, bekommt man (cos(phi);sin(phi)).
Geht man aber von (1;y) aus und wählt die Drehungen so,
dass y gegen Null geht, ist der Gesamt-Drehwinkel gerade
atan(y).
Edi M. schrieb:> Diese Vereinfachungen kenne Ich natürlich, aber mit einer Division> bin> Ich genau so weit. Ich denke nochmal etwas nach ...
Von nichts kommt nichts! Man kann kein Omelett machen ohne Eier zu
zerbrechen. Einen Tod muss man sterben.
Nahezu ohne Division würde eine altmodische Taylor-Reihe funktionieren.
arctan(x) = x - (x^3)/3 + (x^5)/5 - ... ; für |x| <= 1
Aber nur nahezu, man braucht die erwähnte Vereinfachung:
arctan(x) = pi/2 - arctan(1/x); für |x| > 1
Die Division durch die Konstanten kann man vermeiden wenn man 1, 1/3,
1/5, 1/7 als Konstanten ablegt und multipliziert. In den Konstanten kann
man noch das Vorzeichen einarbeiten, dann wird die Iterationsschleife
etwas einfacher 1, -1/3, 1/5, -1/7.
Die Reihe konvergiert langsam. Entweder nimmt man dass in Kauf, man
verzichtet auf Genauigkeit oder nimmt etwas anderes, z.b. eine
Tschebyscheff-Approximation. Die habe ich aber nicht im Kopf.
Ich würde noch mal über das Eingangs erwähnte
arctan(x) = x / (1 + 0,28125 x^2); für |x| <= 1
nachdenken. Auf
http://www.embedded.com/design/other/4216719/Performing-efficient-arctangent-approximation
dröselt das jemand schön auf. Hat man aus der Signalverarbeitung I, Q
Werte und braucht man arctan(Q/I) gilt:
arctan(Q/I)
= (Q / I) / (1 + 0,28125 * (Q / I)^2)
= (Q * I) / (I^2 + 0,28125 * Q^2)
D.h. die Division Q/I muss man nicht ausführen. Statt dessen hat man
zwei weitere Multiplikationen. Es bleibt aber die ursprüngliche Division
auf der rechten Seite.
Der nächste Trick ist dann (siehe Link), dass
0,28125 * Q^2 = (1/4 + 1/32) * Q^2 = Q^2/4 + Q^2/32
Hat man einen angestaubten Prozessor bei dem Schieben schneller als
Multiplizieren ist und ein Zahlensystem, bei dem nach Rechts schieben
einer Division durch 2 entspricht, bekommt man
Q^2/4 + Q^2/32 = (Q^2) >> 2 + (Q^2) >> 5
D.h. die Multiplikation mit 0,28125 kann man durch zwei Mal schieben
ersetzen.
arctan(Q/I)
= (Q * I) / (I^2 + (Q^2) >> 2 + (Q^2) >> 5)
Zum Schluss, das schreibe ich nicht ab (siehe Link), kann man Q/I noch
in acht Oktanten aufteilen um die Division 1/x in
arctan(x) = pi/2 - arctan(1/x); für |x| > 1
zu ungehen! D.h. die Division kann man sich auch sparen. Es bleibt aber
eine Division auf der rechten Seite. Einen Tod muss man sterben.
Jack schrieb:> arctan(Q/I)> = (Q / I) / (1 + 0,28125 * (Q / I)^2)> = (Q * I) / (I^2 + 0,28125 * Q^2)
Das finde Ich interessant!
Ich hatte bereits vor Tagen genau darauf hingewiesen:
Beitrag "Re: Effiziente Implementierung von ARCTAN fuer uCs"
Allerdings kannte Ich bisher nur die 0,28 aus der Wikipedia.
Wie ist die Abweichung zu 0,28125 erklären?
Ach jetzt sehe Ich es:
Jack schrieb:> Der nächste Trick ist dann (siehe Link), dass>> 0,28125 * Q^2 = (1/4 + 1/32) * Q^2 = Q^2/4 + Q^2/32
Ein wahrlich toller Trick, einfach die Kommastellen 3 und folgende
wegzulassen, um binär rechnen zu können.
Jack schrieb:> Nahezu ohne Division würde eine altmodische Taylor-Reihe funktionieren.
Ist noch aufwendiger, läuft auch zu sehr vom Ergebnis weg, alles
getestet.
Wahrscheinlich wird es eine stückweise Approximation, wo Ich nur linear
rechnen muss. Keine Division, keine grosse Tabelle.
W.S. schrieb:> Allerdings kannte Ich bisher nur die 0,28 aus der Wikipedia.>> Wie ist die Abweichung zu 0,28125 erklären?
So wie ich es gelernt habe wurde 0,28125 bewusst so gewählt, dass man
den Trick mit dem Schieben, bei entsprechendem Zahlensystem, anwenden
kann. Genaueres müsste im Original-Paper stehen. R. Lyons, "Another
contender in the arctangent race".
Allerdings habe ich das Paper nicht, daher vom Hörensagen: Die 0,28 sind
abgerundet. Ein genauerer Wert der Konstante ist 0,28086. Such man nach
einer in der Nähe von 0,28086 liegenden Zahl, bei der man Multiplizieren
durch Schieben ersetzen kann, landet man bei 1/4 + 1/32 = 0,28125.
0,28125 liegt sogar näher an 0,28086 als 0,28. Der maximale Fehler bei
0,28125 statt 0,28086 ist nur unwesentlich größer.
Auf der vergeblichen Suche nach dem Paper habe ich noch etwas gefunden:
arctan(x) = pi/4 * x; für |x| <= 1;
Viel einfacher dürfte es kaum gehen. Der Fehler soll in der zweiten
Stelle hinter dem Komma liegen. Navigieren würde ich damit nicht :-)
Hier eine Implementierung von mir, die ich vor längerer Zeit einmal für
einen at89C2051 (8051 Core) geschrieben habe. Mit dem sdcc Compiler
benötigte diese Routine 307 Byte und bei 12Mhz Taktfrequenz 1.2ms.
Interne Rechengenauigkeit sind 16Bit. Die sollte man sich gönnen, auch
wenn das Ergebnis nur 8Bit betragen soll.
Detlef _. schrieb:> R. Lyons: Understanding Digital Signal Processing>> Die arctan Approx. von Lyons steht auf S547, Kap. 13.21>> Cheers> Detlef
Ist das von dir verlinkte PDF eine Raubkopie?
Jack schrieb:> Nahezu ohne Division würde eine altmodische Taylor-Reihe> funktionieren.>> arctan(x) = x - (x^3)/3 + (x^5)/5 - ... ; für |x| <= 1
Ja. Allerdings sind die Taylor-Koeffizienten für diesen
Zweck nicht optimal. Der Fehler ist sehr ungleichmäßig
übers Intervall verteilt.
> Aber nur nahezu, man braucht die erwähnte Vereinfachung:>> arctan(x) = pi/2 - arctan(1/x); für |x| > 1
Ja. Kehrwert ist aber auch gut iterativ berechenbar.
> Die Reihe konvergiert langsam.
Naja... man kommt mit einem kubischen Polynom aus,
wenn man die Koeffizienten von Hand optimiert.
Restfehler im Intervall [0;1] ungefähr 0.3%.
Oplas schrieb:> Ist das von dir verlinkte PDF eine Raubkopie?
Sehr unwahrscheinlich.
Da von "... Gewalt gegen eine Person oder [...] Androhung
einer gegenwärtigen Gefahr für Leib und Leben..." mit
hoher Wahrscheinlichkeit keine Rede sein kann, ist der
Tatbestand des Raubes nicht gegeben.
Detlev T. schrieb:> Hier eine Implementierung von mir, die ich vor längerer Zeit einmal für> einen at89C2051 (8051 Core) geschrieben habe.
Die Tabelle ist - gerade im kleinen Winkelbereich - zu grob, denke Ich.
Warum keine rekursive Iteration?
Je nachdem was Du machen willst wär vielleicht auch mein hemdsärmeliger
Vier-Quadranten-Phasenfehler interessant:
https://gist.github.com/prof7bit/e7d2c7ca6eaa0240e13244bacb915d14
Diese äußerst innovative Funktion meinerseits (prior art!) braucht nur
eine einzige Division und eine Multiplikation, ist zwar nicht ganz
linear, geht dafür aber über alle 4 Quadranten und reicht locker für so
Sachen wie ne simple Tan-Lock-Loop, hab ich zuverlässig in ner
70m-Lichtschranke mit Software PLL am Werkeln bei 160kSamples/s (40kHz)
auf nem kleinen Cortex M0+.
Wie groß ist denn da der phase error? Den Scale Factor kann ich nicht
sehen.
Und warum hast Du den error nicht nochmal korrigiert? Der ist doch quasi
linear und damit abziehbar.
Ich komme nochmals zu meiner Darstellung weiter oben zurück: Näherung
gut und schön, aber aufpassen mit den Oberwellen. Wenn der ATAN genutzt
werden soll, um irgendwelche Winkel zurückzurechnen, auf die dann
geregelt werden soll, dann sind solche langsamen seichten Wellen, wie
sie in der phase error Funktion drin sind, mitunter tödlich, weil sie
Schwingungen vorgeben, die nicht drin sind und wenn dann irgendwo im
System die richtige Frequenz daherkommt, will heißen, ein Anstieg mit
dU/dt, dann gibt es Resonanzanregung und -verstärkung.
Jürgen S. schrieb:> Wie groß ist denn da der phase error?
kann man mit PLL_GAIN einstellen, ist proportional zu PLL_GAIN und in
erster Näherung proportional zum Winkel den der Vektor (q,i) mit der
q-Achse einschließt. Es ist invariant gegenüber der Amplitude.
> Den Scale Factor kann ich nicht sehen.
Sehen kann man das Ergebnis unten im Plot.
> Und warum hast Du den error nicht nochmal korrigiert? Der ist doch quasi
linear und damit abziehbar.
Was ist da linear und abziehbar? Was meinst Du?
> dann sind solche langsamen seichten Wellen, wie> sie in der phase error Funktion drin sind, mitunter tödlich, weil sie> Schwingungen vorgeben, die nicht drin sind und wenn dann irgendwo im> System die richtige Frequenz daherkommt, will heißen, ein Anstieg mit> dU/dt, dann gibt es Resonanzanregung und -verstärkung.
Ich sagte ja: "je nachdem was Du machen willst"
Ich selbst benutze das für eine PLL. Eine leichte Nichtlinearität im
Phasendetektor ist dort vollkommen irrelevant, man kann man die
Regelschleife problemlos so gutmütig einstellen daß sie nicht zum
Schwingen neigt. Schau Dir z.B. nur mal die Kennlinien anderer
gebräuchlicher Phasendetektoren an, manche sind sogar
amplitudenabhängig. Diese hier nicht!
> mitunter tödlich [...] Schwingungen vorgeben [...] Frequenz daherkommt
Geb mal ein konkretes Beispiel was Du meinst, das Gesagte erscheint mir
etwas nebulös formuliert, hast Du diese oder eine vergleichbare Funktion
schon mal in einer Phasenregelschleife eingesetzt? Ich finde keinerlei
Hinweise in der auffindbaren Literatur daß ein vergleichbares
Husarenstück jemals versucht wurde, deshalb hat das Ding scheinbar auch
noch keinen Namen. Die Performance in der Praxis zeigt alle
Eigenschaften einer "echten" 4Q-Tanlock-Loop.
Der einzige Grund für die Existenz dieses unortodoxen Hacks anstelle
eines echten 4Q-arctan() ist der geringe Rechenaufwand auch für
schwachbrüstige CPUs, Ziel der [meiner] Übung war es einen 4Q
Phasendetektor mit streng monotoner Kennlinie mit dem geringstmöglichen
Rechenaufwand zu implementieren weil alles andere in dem Fall die zur
Verfügung stehenden Ressourcen gesprengt hätte, damit ich damit eine
DPLL bauen kann die noch sparsam nebenher im Interrupt läuft.
Thomas U. schrieb:> Die Tabelle ist - gerade im kleinen Winkelbereich - zu grob, denke Ich.
Bist du sicher, dass du das Verfahren kennst/verstanden hast? Die
Auflösung geht bis 0.01% des Vollkreises. Das sollte für eine
Berechnung, die als Parameter nur mit integer gespeist wird, doch
reichen.
> Warum keine rekursive Iteration?
Hast du damit eine konkrete Implementierung oder ist das nur so dahin
geworfen? Das von mir angegebene Verfahren ist an die Leistung eines
8051 angepasst und verwendet daher nur Addition/Subtraktion und Shift.
Das ist der Vorteil dieses Verfahrens.
Bernd K. schrieb:> Jürgen S. schrieb:>> Wie groß ist denn da der phase error?> kann man mit PLL_GAIN einstellen,
Das war ja die Frage: Wie groß ist der eingestellt?
>> Den Scale Factor kann ich nicht sehen.> Sehen kann man das Ergebnis unten im Plot.
Ich sehe da nur einen unskalierten Wert von etwa 2. Was heißt das? 2%?
>> Und warum hast Du den error nicht nochmal korrigiert? Der ist doch quasi> linear und damit abziehbar.> Was ist da linear und abziehbar? Was meinst Du?
Wenn der Fehler so verläuft, wie in der roten Kurve, dann ist das so
ziemlich eine Gerade. Das bedeutet, die Differenz zwischen Falsch und
Richtig wäre abschnittsweise linear. Damit wäre sie sehr leicht zu
eliminieren, indem die Näherung noch ein Additiv mit k x X bekommt.
> Geb mal ein konkretes Beispiel was Du meinst, das Gesagte erscheint mir> etwas nebulös formuliert, hast Du diese oder eine vergleichbare Funktion> schon mal in einer Phasenregelschleife eingesetzt?
Ja und das Problem ergibt sich sowohl praktisch, als auch theoretisch:
Die Funktion ATAN ist dem Wesen nach monoton, hat also keine lokalen
Maxima. Baut man in Näherungen keine Knicke, sondern versucht Bögen zu
bekommen, erhält man mitunter solche Extremstellen. Bei Durchfahren der
Kennlinie wird dann nicht ein Fehlersignal erster- sondern zweiter
Ordnung in das System injiziert, welche je nach Dämpfung zu
Regelschwingungen führt, bzw diese verschärft.
> Ziel der Übung war es einen 4Q> Phasendetektor mit streng monotoner Kennlinie
Die Fehlerkennlinie scheint dieser Monotonie aber zu widersprechen. ?
Jürgen S. schrieb:> Bernd K. schrieb:>> Jürgen S. schrieb:>>> Wie groß ist denn da der phase error?>> kann man mit PLL_GAIN einstellen,> Das war ja die Frage: Wie groß ist der eingestellt?
Den stellst Du genau so ein wie Du ihn brauchst: Groß genug daß das
Ergebnis genügend Auflösung hat und gerade noch klein genug daß das
Ergebnis in jedem Falle ohne Überlauf in Deinen Integertypen passt, 14
Bit sollte reichen, das passt noch gut in nen signed short und hat
massig genug Auflösung. Das übliche Spielchen halt.
>>> Den Scale Factor kann ich nicht sehen.>> Sehen kann man das Ergebnis unten im Plot.> Ich sehe da nur einen unskalierten Wert von etwa 2. Was heißt das? 2%?
1
phase_error ≈ 2 * PLL_GAIN * Phasenwinkel/180°
>>> Und warum hast Du den error nicht nochmal korrigiert? Der ist doch quasi>> linear und damit abziehbar.>> Was ist da linear und abziehbar? Was meinst Du?> Wenn der Fehler so verläuft, wie in der roten Kurve, dann ist das so> ziemlich eine Gerade. Das bedeutet, die Differenz zwischen Falsch und> Richtig wäre abschnittsweise linear. Damit wäre sie sehr leicht zu> eliminieren, indem die Näherung noch ein Additiv mit k x X bekommt.
Schreibs bitte vollständig hin und zeig nen Plot vom Deiner Variante,
ich kann Deinen Ausführungen ansonsten beim besten Willen nicht nicht
folgen, sie erscheinen mir unvollständig und scheinen keinen Sinn zu
ergeben. Gib Dir bitte etwas mehr Mühe.
> Die Funktion ATAN ist dem Wesen nach monoton, hat also keine lokalen> Maxima. Baut man in Näherungen keine Knicke, sondern versucht Bögen zu> bekommen, erhält man mitunter solche Extremstellen. Bei Durchfahren der> Kennlinie wird dann nicht ein Fehlersignal erster- sondern zweiter> Ordnung in das System injiziert, welche je nach Dämpfung zu> Regelschwingungen führt, bzw diese verschärft.
Nein.
Wenn die Regelung schwingt stellst Du mit Fingerspitzengefühl die
Regelkonstanten in geeigneter Weise ein, so lange bis sie dem
gewünschten Verhalten ausreichend nahe kommt. Fertig.
>> Ziel der Übung war es einen 4Q>> Phasendetektor mit streng monotoner Kennlinie>> Die Fehlerkennlinie scheint dieser Monotonie aber zu widersprechen. ?
sie ist streng monoton steigend und stetig im gesamten
Definitionsbereich von [-180°, +180°[ wie unschwer am Plot zu erkennen
ist.
Bernd K. schrieb:> phase_error ≈ 2 PLL_GAIN Phasenwinkel/180°
Heiland! Die Formel sehe Ich auch. Die entscheidende Frage ist, wie es
hier im konkreten Beispiel eingestellt war.
Die Skala für die rote Fehlerkurve hat keine Einheit. Sie geht nur von 0
.. 2.
Was heisst hier 2?
2 Grad Phasenfehler? Hoffentlich nicht.
2% Phasenfehler. Hoffentlich nicht.
2 Digit nehme ich an?
Bernd K. schrieb:> Wenn die Regelung schwingt stellst Du mit Fingerspitzengefühl die> Regelkonstanten in geeigneter Weise ein, so lange bis sie dem> gewünschten Verhalten ausreichend nahe kommt. Fertig.
Jaha, das belastet aber die Regelreserve und Stabilität. Es gibt ja noch
mehr Schwingungen im System, die in die Regelung eingeprägt werden und
Regelbedarf erzeugen - nicht zuletzt die von Außen und jede
Nichtlinearität des Systems erzeugt ein zusätzliches Problem und da sind
die Schwingungen erster und vor allem zweiter Ordnung in vielen Systemen
ein Punkt.
Eine Näherung mag im Proportional monoton sein, ist es aber schon bei
der ersten Ableitung nicht mehr.
Jürgen S. schrieb:> Heiland! Die Formel sehe Ich auch. Die entscheidende Frage ist, wie es> hier im konkreten Beispiel eingestellt war.
Steht doch alles schwarz auf weiß da, guggst Du: PLL_GAIN=1, hast Du
eine Sehschwäche oder willst Du trollen? Langsam kommts mir so vor.
> Die Skala für die rote Fehlerkurve hat keine Einheit. Sie geht nur von 0> .. 2.
Erstens geht sie von -2 bis 2 und zweitens ist die Einheit volkommen
irrelevant denn die interessiert keinen denn die kann man sich
einstellen wie man sie braucht, am besten so daß die Integer immer gut
gefüllt sind, der Wert hat die Dimension eines Winkels und bei der
Konfiguration im Beispiel wäre die Einheit 1 "Viertelkreis", Also geht
der Wertebereich von -Halbkreis bis +Halbkreis, oder allgemeiner ist die
Einheit Kreis/(4*PLL_GAIN) oder meinetwegen auch pi/(2*PLL_GAIN) oder
90°/PLL_GAIN
> Was heisst hier 2?
Mein Gott, das steht doch da! 2 heißt in dem Fall 180° hinterher, -2
heißt 180° voraus und 0 heißt "der Zeiger steht so wie er soll" und wäre
zum Beispiel der Sollwert eines Phasenreglers, der Fehler wäre null. Ich
hab nen schönen Plot hinmalen lassen hast Du den nicht gesehen?
Was ist jetzt mit Deiner verbesserten Formel wo Du irgendwas von
irgendwo abziehen willst um es linear zu bekommen, wo kann man sich die
mal anschauen?
Außerdem will der OP gar keine PLL bauen sondern irgendwas anderes
machen, also schweifen wir sowieso vom Thema ab.
Detlev T. schrieb:> Bist du sicher, dass du das Verfahren kennst/verstanden hast? Die> Auflösung geht bis 0.01% des Vollkreises. Das sollte für eine> Berechnung, die als Parameter nur mit integer gespeist wird, doch> reichen.
Ich denke, daß Ich das verstanden habe, ja, Ich meine nur, daß es noch
genauer sein könnte, wenn die Tabelle genauer wäre, als mehr Werte hätte
oder mit einer größeren Auflösung arbeiten würde.
Bernd K. schrieb:> Steht doch alles schwarz auf weiß da, guggst Du: PLL_GAIN=1,
Es ging mir nur um die Sicherstellung, dass Ich Deine Grafik richtig
interpretiere.
Üblicherweise enthalten Diagramme im wissenschaftlichen Bereich eine
Skalierung der Y-Achse oder einen sonstigen Hinweis, damit man das
eindeutig ablesen kann und hier konkret ergibt sich nicht zwangsläufig,
dass Fehler unskaliert dargestellt sind, weil sie in der Regel so klein
sind, dass man sie 10fach oder 100fach einblenden muss, um den Verlauf
zu sehen.
Dass sich das aus dem PLL Gain errechnen lässt, konnte Ich nicht
ersehen, zumal Ich nirgendwo etwas von einem Setting mit "1" erspähen
konnte.
Momentan kann man gar nichts lesen, weil die Grafik verschwunden ist -
jedenfalls führt der link auf den Ich mich bezog ins Nichts. Ist das
wieder weggenommen worden?
Wie auch immer, Ich entnehme Deiner Darstellung dass es skalierbar ist.
Ich hatte mich innerlich etwas gewehrt, die Zahl 2 so zu lesen, dass es
Digit sind.
Fragen wir daher mal anders herum: Wie weit ließe sich das denn
verbessern? Erzähle mir jetzt itte aber nicht, dass Ich den PLL-GAIN
hochstellen muss.
Vielleicht frage Ich deshalb mal gleich direkter, dass Dir das Problem
etwas deutlicher wird:
Wie genau muss man Deine Lösung machen und wie umfangreich wird sie
dabei, um an die Qualität der Definition aus den Wiki heranzukommen?
Zu Deiner anderen Frage:
Falls Du meinen Vorschlag der abschnittsweisen Annäherung meinst: Diese
ist skalierbar, arbeitet also mit eine genügenden Anzahl von Schritten
und zwar so, dass der lokale Fehler optimiert wird. Ein Fehler von z.B.
2 Grad benötigt mit der einfachen Interpolation (aus der Erinnerung) so
etwa 12 Bereiche / Stützstellen und damit 4 Abfragen ("If Then"s)
Falls Du meinen Vorschlag der weiteren Unterteilung der Wiki-Annäherung
meinst: Man kann (und sollte!) speziell den Übergangsbereich zwischen
den Formeln um die Werte -0,28 und 0,28 jeweils mit einer Quadratischen
Kurve überbrücken / glätten. Das macht dann 5 Terme / Bereiche statt 3
beseitigt aber der Sprung an den Übergängen.
Jürgen S. schrieb:> Dass sich das aus dem PLL Gain errechnen lässt, konnte Ich nicht> ersehen,
Das ist doch offensichtlich wenn man sich die Funktion anschaut.
> zumal Ich nirgendwo etwas von einem Setting mit "1" erspähen> konnte.
Steht da schwarz auf weiß, dick und fett, willst Du mich verschaukeln?
Sprechen wir überhaupt von der selben Sache? Wieso kritisierst Du etwas
das Du gar nicht verstanden, bzw überhaupt noch nicht mal gesehen
geschweige denn gelesen hast?
Ich glaube das Missverständnis kommt vom gewählten Namen phase error mit
welchem hier nicht der tatsächliche Fehler zu atan2 gemeint ist.
Ich hab das mal kurz ausprobiert und komme mit Bernds funktion auf einen
maximalen Winkelfehler von +- 4°
Detlev T. schrieb:> Hier eine Implementierung von mir, die ich vor längerer Zeit einmal für> einen at89C2051 (8051 Core) geschrieben habe. Mit dem sdcc Compiler> benötigte diese Routine 307 Byte und bei 12Mhz Taktfrequenz 1.2ms.
Das ist der ganz normale Cordic, oder?
Wäre mal ein Vergleich der Verfahren interessant.
Lukas schrieb:> Ich glaube das Missverständnis kommt vom gewählten Namen phase error mit> welchem hier nicht der tatsächliche Fehler zu atan2 gemeint ist.
Das ist das Problem, daher hatte Ich in meinem Beitrag der ersten
Nachfrage schon konkret nach dem realen Fehler gefragt.
> Ich hab das mal kurz ausprobiert und komme mit Bernds funktion auf einen> maximalen Winkelfehler von +- 4°
Ja, soweit lässt sich das grafisch ablesen (+2/-2).
Aber damit ist die Frage immer noch offen:
Was ist der minimale Fehler?
Die Genauigkeit kann man nicht beliebig steigern, auch nicht durch den
PLL-Gain, weil - wenn man sich die "phase-Funktion" mal anschaut und
gedanklich nach unten klappt - irgendwann dahin kommt, dass die
Welligkeit relevant wird und die Monotonie verletzt.
Jürgen S. schrieb:>> Ich hab das mal kurz ausprobiert und komme mit Bernds funktion auf einen>> maximalen Winkelfehler von +- 4°> Ja, soweit lässt sich das grafisch ablesen (+2/-2).
Nein, das ist der Rückgabewert der Funktion. Der Winkelfehler wäre die
Differenz zwischen diesem und einem echten atan2() wenn man man sie
beide auf den selben Wertebereich skalieren und vergleichen würde.
ich habe sie damals phase_error() genannt weil das den Zweck beschreibt
für den ich sie damals eingesetzt habe: Der Zweck war: wie weit und in
welche Richtung ist das abgetastete Signal phasenverschoben zu einem
festen Sollwert, also in welche Richtung und wie stark muss ich den
Oszillator nachführen. Das "wie weit" ist einfach eine Zahl, beliebig
skaliert, einzige 2 Bedingungen: sie soll 0 erreichen wenn die
Phasenlage genau dem Soll entspricht und sie soll halbwegs
proportional zur Abweichung vom Sollwert sein. Skaliert wird der Wert
per Fingerspitzengefühl so daß sich die Regelschleife nicht daran
verschluckt und daß das Regelverhalten zufriedenstellend ist, also
welche absoluten Zahlen dabei herauskommen ist letztendlich vollkommen
egal, Hauptsache sie passen größenordnungsmäßig zur Verstärkung der
Regelschlefe so daß man den Regler so justieren kann daß es vernünftig
funktioniert. Sobald es sich eingeregelt hat hängt es dann eh nur noch
bei +- null herum.
Ich denke, das Prinzip der Methode ist hinreichend verstanden. Eine
ähnliche Herangehensweise findet sich z.B. bei analogen Frequenzteilern
und Suboszillatoren in Synthesizern.
Im Prinzip macht die PLL eigentlich das, was der CORDIC auch tut, er
berechnet den Wert aufgrund der aktuellen Annahme des Fortschritts und
"regelt" den Fehler auf Null. Der CORDIC geht den Weg halt zu Ende und
gibt den finalen Wert erst nach Erreichen des konvergierten Zielwertes
aus, die PLL gibt permanent einen Wert aus.
Was eben interessant wäre, ist die tatsächliche Abweichung gegenüber
sich z.B. dynamisch ändernden Eingangswerten. Die PLL entwickelt ja ihr
Eigenleben bis hin zur Resonanz, wenn dem Eingangsignal ein
entsprechendes Spektrum überlagert ist.