Hallo, ich möchte wie in der Grafik beschrieben eine rote LED in Form einer Parabel zu einer weißen LED dazu mischen. Zuerst wollte ich das über eine Wertetabelle machen, aber bei einem Array mit 256 int. Werten ist mein Datenspeicher um das 4-fache überschritten! Hat jemand einen Vorschlag (ohne den UC zu tauschen) was ich hier machen kann?
H. G. schrieb: > Array mit 256 int. Werten ist mein Datenspeicher um das 4-fache > überschritten! Kann ich mir nicht vorstellen. Das wären ja 8KB. 256 int-Werte brauchen 512 Byte. > Hat jemand einen Vorschlag (ohne den UC zu tauschen) was ich hier machen > kann? Die Parabel zur Laufzeit mit Festkommaarithmetik berechnen.
H. G. schrieb: > ich möchte wie in der Grafik beschrieben eine rote LED in Form einer > Parabel zu einer weißen LED dazu mischen. Naja, unter einer Parabel verstehe ich was anderes. Das in der Grafik sieht eher wie Kreissegmente aus. Aber egal, sie zeigen trotz der eigenwilligen Form eine wichtige Sache: Symmetrie. D.h.: den beklagten Speicheplatzbedarf kann man schonmal Vierteln, selbst wenn man das Konzept der der Lookup-Tabelle beibehält. Ansonsten halt berechnen. Google-Futter: "Newton-Iteration". Is' noch nicht so teuer bei 16-Bit. Wenn man sich noch ein schönes Verfahren zur Gewinung eines guten Startwerts ausdenkt, sollte man mit deutlich unter 100 Takten pro Funktionsaufruf auskommen können, würde ich mal ganz grob abschätzen.
H. G. schrieb: > ich möchte wie in der Grafik beschrieben eine rote LED in Form einer > Parabel zu einer weißen LED dazu mischen. Parabel? Das ist eher ne Zykloide oder Ellipsenbögen.
H. G. schrieb: > Array mit 256 int. Werten 1. Werte als Tabelle in den Flash legen -> "progmem" 2. Ein Viertelbogen reicht aus, der Rest ist nur Wiederholung rückwärtsund dann nochmal von vorn. 3. Gibt es auch Möglichkeiten, die Parabel (solls jetzt eine sein?) auszurechenen. Ein tiny braucht für ne SW-Multiplikation ca 20 Takte, die Formel einer Parabel mit y=a*x*x + b*x + c ist jetzt nicht so wahnsinnig komplex zu rechnen. 4. Kann man sie notfalls annähern -> Newton oder ähnliche
Look-Up Tabelle mit ca. 10 - 16 Stützpunkten und die Zwischenwerte interpolieren. Sollte fürs Auge mehr als ausreichend sein!
Norbert schrieb: > Look-Up Tabelle mit ca. 10 - 16 Stützpunkten und die Zwischenwerte > interpolieren. Sollte fürs Auge mehr als ausreichend sein! Das kling interessant! Hast du hier etwas mehr info? Wie geht interpolieren? Beispiel?
avr schrieb: > H. G. schrieb: >> Array mit 256 int. Werten ist mein Datenspeicher um das 4-fache >> überschritten! > > Kann ich mir nicht vorstellen. Das wären ja 8KB. 256 int-Werte brauchen > 512 Byte. Der ATtiny2313 hat nur 128 Bytes an SRAM! Was du hier meinst ist der Programmspeicher!
H. G. schrieb: > Der ATtiny2313 hat nur 128 Bytes an SRAM! > Was du hier meinst ist der Programmspeicher! Und genau da sollst du deine - vorberechnete und eincompilierte - Tabelle ablegen.
Wenn es wirklich eine Parabel werden soll — wozu braucht man da eine Tabelle?
Johann L. schrieb: > Wenn es wirklich eine Parabel werden soll — wozu braucht man da eine > Tabelle? Nun zugegeben, es war schlecht formuliert. Es ist keine Parabel sondern eher ein Kreisbogen!
Braucht man nicht, aber falls er das wie im Eingangspost geschrieben so machen will, dann im PROGMEM.
H. G. schrieb: > Norbert schrieb: >> Look-Up Tabelle mit ca. 10 - 16 Stützpunkten und die Zwischenwerte >> interpolieren. Sollte fürs Auge mehr als ausreichend sein! > > Das kling interessant! > Hast du hier etwas mehr info? Wie geht interpolieren? Beispiel? Im einfachsten Fall: linear interpolieren 5 Äpfel kosten 3 Euro, 12 Äpfel kosten 6 Euro (in der Menge wirds billiger). Wieviel kosten 7 Äpfel?
1 | y = f(x) = k*x + d |
Aufgabe: bestimme ein k und ein d, so dass die Beziehungen
1 | x = 5 -> y = f(5) = 3 |
2 | und x = 12 -> y = f(12) = 6 |
gelten. Na, wenn das eine lineare Interpolation ist, mit der allgemeinen Gleichung
1 | y = k * x + d |
und ich 2 Wertpaare x und y kenne, dann kann ich das ja mal einsetzen
1 | 3 = k * 5 + d |
2 | 6 = k * 12 + d |
macht 2 Gleichungen in 2 Unbekannten und das kann man lösen. Mit den dann bekannten Werten für k und d kann ich dann diese lineare Interpolation auf jeden beliebigen Wert für x anwenden und kriege den Wert für y. Jetzt hast du allerdings keine Gerade. D.h. eine lineare Interpolation wird dir da keine besonders guten Werte liefern. Das kann man aber umgehen. Schaut man nicht so genau hin, dann kann man deinen Kreisbogen sich auch aus zb 5 Geradenstücken zusammengesetzt vorstellen. Und für jedes Geradenstück kann man eine eigene lineare Interpolation ansetzen. Man muss halt vorher für einen bestimmten Wert von x feststellen, welche Gerade überhaupt zuständig ist. Aber das sollte ja kein Problem sein. Der Rest ist jetzt nur noch Organisation dieser Geraenabschnitte bzw. was damit gleichwertig ist, der 'Stützstellen', ein bischen raussuchen, zwischen welchen Stützstellen der x Wert liegt, für den gerechnet werden soll und ein wenig rechnen auf Grundschulniveau. Nichts was einen Tiny umhaut. Oder aber: Das was man mit einer Geraden kann, kann man natürlich auch mit einem Polynom höherer Ordnung machen. Zb. mit einem Polynom 2. Grades (eine Gerade wäre ein Polynom 1. Grades), mit der allgemeinen Gleichung
1 | y = f(x) = j*x^2 + k*x + d |
dann braucht man eben 3 Wertpaare um die Parameter j, k und d zu bestimmen. Aber im Endeffekt hat man dann eine Parabel durch diese 3 Wertpaare gelegt und interpoliert dann eben über diese Parabel. Auch hier wieder: hat meine seine Vorarbeiten auf dem Papier erledigt, dann bleibt da für den Tiny nicht mehr viel übrig. Durch das Quadrat muss man ein wenig vorsichtig sein, dass man keine Overflows in den Berechnungen hat, aber das muss man generell sowieso immer im Hinterkopf behalten.
Das Handrechnen lässt sich mit (Libre-)Office durch LINEST umgehen ;-) Dort bietet sich auch an gleich die Funktion mit der Näherung zu vergleichen
H. G. schrieb: > Es ist keine Parabel sondern eher ein Kreisbogen! Was heißt "eher"? Hast du die Kurve irgendwie berechnet, oder ist sie aus dem Gefühl heraus entstanden? Wenn letzteres der Fall ist, sind die Genauigkeitsanforderungen wahrscheinlich nicht allzu hoch. Du könntest die Kurve in deinem Bild dann bspw. durch die Funktion
approximieren. Diese erfordert (nach etwas Umformen) 3 Multiplikationen und 3 Additionen, ist also relativ leicht zu berechnen. Der dabei entstehende Fehler in der LED-Helligkeit dürfte mit dem Auge kaum wahrnehmbar sein. Im Anhang siehst du das Ergebnis für a=-9.84e-6, b=-3.70e-2 und c=154. Das Ganze wird auf dem ATtiny2313 natürlich nicht mit Floating-Point-, sondern mit Integer-Arithmetik berechnet. Dazu müssen die Parameter in Abhängigkeit des gewünschten Wertebereichs angepasst und die Zwischenergebnisse ggf. mit Shift-Operationen skaliert werden.
Yalu X. schrieb: > Du könntest die Kurve in deinem Bild dann bspw. durch die Funktion >
> approximieren. Diese erfordert (nach etwas Umformen) 3 Multiplikationen > und 3 Additionen, ... ...und zudem, daß kein Zwischenergebnis aus dem Wertebereich herausfällt, was bei einer Funktion 4. Grades rasch der Fall ist.
Johann L. schrieb: > ...und zudem, daß kein Zwischenergebnis aus dem Wertebereich > herausfällt, was bei einer Funktion 4. Grades rasch der Fall ist. Ja klar, siehe hier: Yalu X. schrieb: > Das Ganze wird auf dem ATtiny2313 natürlich nicht mit Floating-Point-, > sondern mit Integer-Arithmetik berechnet. Dazu müssen die Parameter in > Abhängigkeit des gewünschten Wertebereichs angepasst und die > Zwischenergebnisse ggf. mit Shift-Operationen skaliert werden. Das Ganze könnte dann etwa so aussehen:
1 | uint8_t dim2pwm(uint8_t x) { |
2 | int8_t x1 = x - 128; |
3 | uint16_t x2 = x1 * x1; |
4 | |
5 | return (uint8_t)(112 - ((3 * x2 + 0x10000) * x2 >> 24)); |
6 | }
|
x ist der Dim-Wert (0..255, 256 entspricht 100%), das Ergebnis ist der PWM-Wert für eine 8-Bit-PWM (0..255, 256 entspricht 100%). Es werden zwei 16-Bit- und eine 32-Bit-Multiplikation benötigt. Das Ergebnis ist im Anhang zu sehen. Evtl. kann man hier
1 | (3 * x2 + 0x10000) |
noch etwas handoptimieren, indem man die Multiplikation mit 3 durch Shift und Addition ersetzt (der GCC tut das nicht von selber). Die Paramater a, b und c der Funktion sind übrigens so gewählt, dass die Funktionswerte an den Stellen 0% (x=0), 25% (x=64), 50% (x=128) und damit aus Symmetriegründen auch an 75% (x=192) und 100% (x=256) mit dem Bild im Eingangsbeitrag übereinstimmt. Zufälligerweise ergibt das sehr rechnerfreundliche Parameter (a=-3·2¯²⁴ und b=-2¯⁸).
Spricht eigentlich etwas gegen die Verwendung von Fixed-Point Typen (fract, accum, ...), die der aktuelle avr-gcc ja von Hause aus unterstützt?
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.