Hallo, Ich musste grad feststellen, dass mein ATTiny85 bei der Berechnung von separaten PWM-Werten für 3 RGB-LEDs an seine Grenzen stößt. Die Werte werden für Indizes von 0 bis INDEX_MAX nach dieser Formel berechnet(vereinfacht): >PWM = 255 * pwmIndex^EXPONENT / (INDEX_MAX^EXPONENT); wobei EXPONENT von 1.5 bis 2 und INDEX_MAX von 50 bis 100 variabel sein kann. D.h. bei index 0 ist ist die LED dunkel und bei index = INDEX_MAX auf 255. Die Exponentialberechnung im Quotienten habe ich schon durch einen festen Wert ersetzt, der nur berechnet wird, wenn sich einer der beiden Werte verändert. Danach konnte ich einen leichten Geschwindigkeitsgewinn feststellen, aber der ist leider nicht ausreichend. Für eine Variante mit fixen PWM-Tabellen bräuchte ich für meinen Ansatz hier 6 Stück mit INDEX_MAX Werten (habe ich noch nicht ausprobiert und müsste da auch einiges vom Code wieder verändern). In Internetz konnte ich nichts finden was mir zu Polynomberechnung in Festkommaarithmetik weiterhilft, deswegen hoff ich auf eure netten Tipps. Gruß Hannes
Wie wäre es mit einer Tabelle aus vorberechneten Werten und linearer Interpolation?
Bei solchen kleinen Zielbereichen (0-255) lohnt es sich, per Excel ein wenig zu nähern und dann Ersatzfunktionen zu suchen. Beispiel: erster Näherung bei pwmMax=50 und EXPONENT = 2: PWM = Index*255/50. Da wir die Abweichung schon klein, hat die Form eines Halbkreises. Näherung um "halbkreis" verfeinern: PWM = Index*255/50 - Index*(50-Index)/x. Mit x=9.8 wird die verbleibende Abweichung schon 0 über den ganzen Bereich. Bei z.B. EXPONENT = 1.5 und x=15 ergeben sich Abweichungen von max. 3 bis -6. (nur so als Beispiel) Spoiler: Die 9.8 bei ^2 ergeben sich als 50²/255. Aber auf so eine Formel kommt man in der Regel nicht analytisch, ausprobieren ist völlig ok. Und die Teiler bei anderen X sollten dann ebenso einfach sein. Bei kleineren Exponenten geht das (wie gesagt) nur näherungsweise, aber vermutlich ausreichend präzise.
Johannes H. schrieb: > Ich musste grad feststellen, dass mein ATTiny85 bei der Berechnung von > separaten PWM-Werten für 3 RGB-LEDs an seine Grenzen stößt. > > Die Werte werden für Indizes von 0 bis INDEX_MAX nach dieser Formel > berechnet(vereinfacht): > >PWM = 255 * pwmIndex^EXPONENT / (INDEX_MAX^EXPONENT); Wenn das lediglich eine 8-Bit PWM ist, dann kannst du sowieso nur eine überschaubare Anzahl an Zwischenstufen realisieren, vielleicht 50. Und dafür reicht dann eine vorberechnete Tabelle. Warum man den Exponenten (im Prinzip den Gamma-Wert) im Betrieb ändern können müßte, erschließt sich mir auch nicht. Einfach die feinstmögliche Stufung als Tabelle wählen und fertig. In meinem RGB-Moodlight habe ich eine ca. 10-Bit Soft-PWM mit ~200 exponentiell angeordneten Helligkeitsstufen. Beim langsamen Durchlaufen der Farben sieht man keine Helligkeitssprünge. Der limitierende Faktor ist bei dir mit Sicherheit die zu grobe 8-Bit PWM.
@Achim Eine lineare Approximation ist doch aber sinnfrei, wegen der logarithmischen Wahrnehmung des Auges. Bitte schau mal das Bild an, bei Deiner zweiten Formel stimmt irgendwas nicht ;) Aber so in der Richtung lässt sich vielleicht was finden. @Axel Das Problem ist, ich verwende die WS2812B RGB-LED mit integriertem PWM-Treiber und der generiert nur Werte von 0-255. Die Werte werden nicht im laufenden Betrieb geändert, aber zum Rausfinden der optimalen Wertekombination hab ich den Code so gestaltet, dass ich nur an wenigen Werten "drehen" muss. Wie hast Du denn das mit dem Farbwechsel von einer zur anderen Farbe gemacht?
Du sollst zwischen den vorraus errechneten Stützstellen linear interpolieren. Nicht alle Werte.
@Benedikt Aber das macht es ja dann wieder umständlicher. Ich will ja eben keine vorausberechneten Werte verwenden. Ich hab auch nicht ganz verstanden, wie Du das jetzt gemeint hast. @Achim Ok, wenn man mit dem Teiler (anstatt 9.8) etwas rumspielt sieht es schon ganz OK raus. Anbei das Bild mit angepasstem Teiler.
Johannes H. schrieb: > @Axel > Das Problem ist, ich verwende die WS2812B RGB-LED mit integriertem > PWM-Treiber und der generiert nur Werte von 0-255. Ja, gut. Dann hast du halt nicht mehr Helligkeitsstufen. > Die Werte werden nicht im laufenden Betrieb geändert, aber zum > Rausfinden der optimalen Wertekombination hab ich den Code so gestaltet, > dass ich nur an wenigen Werten "drehen" muss. Aha. Und wieso spielt dann die Geschwindigkeit bei der Berechnung der Tabelle überhaupt eine Rolle? Den optimalen Gamma-Wert mußt du doch nur einmal rausfinden (ich würde vorher mal danach googlen). Für die spätere Anwendung hast dann die vorberechnete Tabelle. > Wie hast Du denn das mit dem Farbwechsel von einer zur anderen Farbe > gemacht? Ich habe die Tabelle mit den vorberechneten Helligkeitsstufen, konkret sind das 204 Schritte mit einem Faktor von 1.02 zwischen aufeinander folgenden Stufen. Durch die exponentielle Kurve steigt der Helligkeitseindruck linear und man kann einfach durch die Tabelle laufen:
1 | for (i=0; i<=204; i++) { |
2 | red= pwmtable[i]; |
3 | blue= pwmtable[204-i]; |
4 | delay(); |
5 | }
|
Das macht z.B. einen Farbverlauf von blau über violett nach rot. Je kürzer delay() ist, desto schneller. Real natürlich nicht mit delay(), sondern als Zustandsautomat mit einem Timer-Interrupt als Trigger. Siehe dazu meinen Beitrag "noch ein AVR Moodlight" Wenn deine PWM nur 8 Bit hat, kannst du keine rein exponentielle Tabelle verwenden, weil irgendwann die Schritte kleiner als 1 werden. Man könnte dann aber die anfangs exponentielle Tabelle mit Schritten von 1 zu Ende führen. Das folgende kleine Perl-Programm spuckt dir eine solche Tabelle aus:
1 | perl -e '$f=1.02; for($x=255.0; $x>=0; ) { print int($x+0.5), " "; |
2 | $y= $x/$f; $x=(int($y+0.5)<int($x+0.5)) ? $y : $x-1 }' |
3 | |
4 | 255 250 245 240 236 231 226 222 218 213 209 205 201 197 193 189 186 |
5 | 182 179 175 172 168 165 162 159 155 152 149 146 144 141 138 135 133 |
6 | 130 128 125 123 120 118 115 113 111 109 107 105 103 101 99 97 95 93 |
7 | 91 89 88 86 84 82 81 79 78 76 75 73 72 70 69 68 66 65 64 63 61 60 |
8 | 59 58 57 56 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 |
9 | 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 |
10 | 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
Hallo Axel, >Aha. Und wieso spielt dann die Geschwindigkeit bei der Berechnung der >Tabelle überhaupt eine Rolle? Nein ich verwende ja eben keine Tabelle bzw. Tabellen. Denn für meinen jetzigen Ansatz bräuchte ich 6 Stück davon mit folgender PWM Charaktaristik: (0->255), (255->0), (0->127), (127->0), (127->255), (255->127) Das ist für den Farbübergang von einer zur nächsten Farbe nötig bzw. für die möglichen PWM-Kombinationen. Für meinen 1. Ansatz mit einer LED hatte ich das auch (aber umständlich) mit einer Tabelle gemacht, aber für die aktuelle Version mit 3 LEDs den Code stark modifiziert. Ich werde später Achims Formel mal ausprobieren, denn da muss ich ja bloß was in meiner bisherigen Formel austauschen. Sozusagen den Weg des geringsten Widerstandes ;)
Johannes H. schrieb: >>Aha. Und wieso spielt dann die Geschwindigkeit bei der Berechnung der >>Tabelle überhaupt eine Rolle? > Nein ich verwende ja eben keine Tabelle bzw. Tabellen. Jo mei. Dann halt "bei der Berechnung des PWM-Wertes". Ich dachte es wäre in dem Kontext klar, was gemeint ist. > Denn für meinen > jetzigen Ansatz bräuchte ich 6 Stück davon mit folgender PWM > Charaktaristik: > (0->255), (255->0), (0->127), (127->0), (127->255), (255->127) > > Das ist für den Farbübergang von einer zur nächsten Farbe nötig bzw. für > die möglichen PWM-Kombinationen. Kann es sein, daß du das mit den Tabellen noch nicht so richtig verstanden hast? Ich habe natürlich keine Tabellen für die einzelnen Programme. Es gibt nur eine Tabelle; die mappt Zahlen zwischen 0 (aus) und MAX_BRIGHT (bei mir 204, bei dir mit nur 8 Bit PWM-Auflösung entsprechend weniger) auf PWM-Werte. Und zwar derart, daß sich über die Tabelle ein als linear empfundener Helligkeitsverlauf ergibt. Wegen der im wesentlichen logarithmischen Kennlinie des Auges ist das eine Exponentialfunktion - das Verhältnis aufeinanderfolgender PWM-Werte ist immer gleich. Natürlich gibt es hier Einschränkungen: PWM-Stufen sind ganze Zahlen. Bzw. bei meiner Soft-PWM dürfen zwei PWM-Stufen nicht näher als 61 Takte liegen (so lange braucht die ISR). Deswegen schaffe ich trotz nominal 16 Bit Auflösung nur ca. 10 Bit reale Auflösung. Alle Lichtprogramme verwenden dann lineare Sweeps über diese Tabelle. Für meine Anwendung - psychedelische Lichtspielchen - ist das ausreichend. Wenn man andere Dinge vor hat, kann es notwendig sein, Zwischenwerte zu errechnen.
Johannes H. schrieb: > In Internetz konnte ich nichts finden was mir zu Polynomberechnung in > Festkommaarithmetik weiterhilft macht man auch nicht wirklich. Mach's lieber per Pseudodivision/Pseudomultiplikation. Das geht viel besser. Prinzip: a^b = a^(b1+b2+b3+...) = a^b1 * a^b2 * a^b3 ... usw. jetzt brauchst du dein b nur in Stücke zu zerlegen, derart, daß a^bx einer glatten Rechtsverschiebung entspricht, also vom Prinzip her a^b0 = 1 a^b1 = 1.1 a^b2 = 1.01 a^b3 = 1.001 a^b4 = 1.0001 und so weiter. Was im Dezimalen glatt aussieht, ist im binären genauso glatt. Damit wird die Multiplikation zu einer Addition des jeweilig um ein weiteres Bit rechtsverschobenen Multplikanden. Nochwas: man braucht nicht alle Stellen von b auszurechnen, denn der Rest gibt fast die doppelte Bitanzahl dazu. Für 16 Bit schätze ich, daß du nur b0..b5 ausrechnen mußt und dann den Rest als b6..15 addieren kannst. W.S.
Hallo W.S. Uff, Deinen Ansatz habe ich leider nicht wirklich verstanden. Könntest Du das bitte an Hand einer Beispielberechnung erläutern? Wenn a^b0 = 1, dann muss b0 ja 0 sein, aber wie man das mit b1 bis bn weiterführt erschließt sich mir nicht. Und eine Addition der Werte ergäbe ja dann 1+1.1+1.01+... also einen immer größer werdenden Wert, abhängig wieviele Exponentialglieder man in die Rechnung einbezieht. @Achim Deine Idee funktioniert gut und ich musste nur kleine Anpassungen am Code vornehmen. Danke dafür.
Johannes H. schrieb: > Wenn a^b0 = 1, dann muss b0 ja 0 sein Nein, kann auch 2 oder 3 oder 4 oder ... sein...falls a 1 ist. Sobald du eine von den beiden Variablen festlegst fällt die andere automatisch bei raus. So recht verstanden hab ich W.S. aber auch nicht. Ich finde z.B. dass 100.0 im dezimalen sehr glatt ausschaut. Warum jetzt aber 1100100 glatt aussehen soll vermag ich nicht zu sagen.
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.