Parabel mit UC ATtiny2313 berechnen

OP #3209074
Lesenswert?

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?
Angehängte Dateien:
Gast #3209080
Lesenswert?

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.
Gast #3209230
Lesenswert?

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.
Gast #3209330
Lesenswert?

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
#3209802
Lesenswert?

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.
Moderator #3210049
Lesenswert?

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.
Angehängte Dateien:
Moderator #3210387
Lesenswert?

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¯⁸).
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren