Hallo,
Ich brauche eine Funktion die bei Eingabe Wert 720 das Maximum 255 hat und bei 360 und 1080 den Wert 10.
Bei 0 und 1439 eine 5.
Wertebereich von 0 bis 1439 ( Also die Minuten eines Tages)
Ich habe also 5 Punkte die den Graphen definieren sollen.
Für die Interpolationsformel braucht es also eine Gleichung vierter Ordnung.
Ich habe also die Y Werte für 0/5 und 1439/5 ,360/10 ,720/255 ,1080/10 angegeben und berechnen lassen.
http://www.arndt-bruenner.de/mathe/scripts/gleichungssysteme.htm
a = 3,6e-9
b = -0,0000104417
c = 0,0089127224
d = -2,010656471
e = 5
Erwartet hatte ich einen Graphen der sich im ersten Quadranten befindet, im Nutzbereich um die 720 ist es quasi eine nach unten geöffnete Parabel würde ja fast passen, nur bei 356 bzw 1093 wandert er in den 4 Quadranten.
Klar könnte man jetzt sagen wenn ich im Sourcecode alles was < 5 ist zu 5 mache passt es fast.
Nur hätte da eine Formel für eine Parabel (ax²+bx+c) mit Scheitel 702/255 auch gereicht.
Wo mache ich den Denkfehler, brauche ich mehr Punkte in den beiden Bereichen also eine Grundform 5 oder 6 Ordnung ?
Ich denke, der Arduino mit seinen 4-byte float wird hier Grundsätzlich Schwierigkeiten haben.
Selbst im Excel sind ja schon abweichungen zu sehen.
Generell sieht mir das aber eher nach einer Glockenkurve aus als nach einer polinomischen, also y = exp(-x²)
wobei du x natürlich normieren mußt und y dann auch.
wenn also dein x von 0 bis 1440 läuft, und wir definieren
b als Breite der Glockenkurve
m als den Mittelpunkt der Glockenkurve und
h als die Höhe der Glockekurve
g grundhöhe der Kurve
dann gibt das die Formel:
y = exp(-1 *( (x - m)/b)²)*h+g
mit
b = 180
m = 720
h = 250
g = 5
gibt das eine ganz gut passende Kurve:

Es stellt sich aber doch die Frage, ob es nicht sinnvoller wäre eine Wertetabelle zu definieren und diese zwischen den Stützstellen linear zu interpolieren.
Besten Dank. 8)
Mit der Glockenkurve funktioniert dies ohne Einschränkung des Wertebereichs im Code.
Mit meinem Ansatz geht das natürlich nicht, wenn es ins Negative geht muss ich eingreifen, und den Default Min-Wert setzen
Die Steigungswerte (Ableitung) um den oberen Wendepunkt sind bei der Glockenkurve kleiner, und dies war entscheidend.
Es handelt sich um eine zeitabhängige Beleuchtung für ein Aquarium, der "Kunde" wollte diese Soll-Wertepaare.
Und um die Mittagszeit ist die Glocke für seinen Geschmack etwas zu schmal.
Gesehen ich das nicht, ich schreibe nur den Code und Poste es ihm zum Testen.
Ah, ok.
Mit diesem Hintergrund ist die Glockenfunktion aber ein mathematischer Overkill.
Es bietet sich natürlich eine sinusfunktion an. Schliesslich handelt es sich beim Sonnenumlauf um einen Kreis.
Aber mach dir einfach eine Tabelle mit Stützstellen, zwischen denen linear interpoliert wird.
Das ist viel einfacher und du kannst beliebige Kurvenformen darstellen.

In dem Beispiel ist die Tabelle für die Kurve “Sinus”:
min pwm
0 5
360 10
400 18
440 39
520 111
600 194
640 226
680 248
720 255
760 248
800 226
840 194
920 111
1000 39
1040 18
1080 10
1439 5
und für die Kurve “breiter”:
min pwm
0 5
360 10
380 18
410 39
460 111
540 194
580 226
640 248
720 255
800 248
860 226
900 194
980 111
1030 39
1060 18
1080 10
1439 5
Du siehst, du kannst hier beliebige Kurven basteln.
Streng genommen könntest du dir sogar die halbe Tabelle sparen, da symetrisch.
Eine ganz grundsätzliche Frage neben dem mathematischen Overkill ist noch, dass das Verhältnis zwischen PWM-Wert, Helligkeit und wahrgenommener Helligkeit sehr nichtlinear ist.
Am "interessantesten" sind die Zeitpunkte des Übergangs von "finsterster Nacht" nach PWM=1, 2, 3, ... . Danach wird es immer stufenloser, bis man ( und was ist mit fisch ??? ) ab ca. 200 praktisch gar keinen Unterschied mehr sieht ... 
Statt PWM etwas zu bauen, das anstelle der Sprünge (0, 1/255, 2/255) tatsächlich stufenlos arbeitet, das wäre Overkill nach meinem Geschmack 
Klar ist das der mathematische Overkill für diese Aquariumgeschichte.
Ist auch nicht für mich.
Ich habe ihm einen Testsketch gemacht, und mit der Lichtstärke und Ausgaben der PWM Werte und er hat mir gesagt wann er was haben wollte.
Mit diesen Werte habe ich dann gerechnet, mit der Erkenntnis das der Weg über ein Polynom nicht der Richtige ist.
Obwohl es schon funktioniert hat, wenn man den Wertebereich eingrenzt und das Maxium auf 255 begrenzt hat.
Die Lösung von Gunther mit den Tabellen und linearer interpolation zwischen den Stützwerten ist einfach und genial zugleich…
Ich habe den Thread nicht nur wegen dem Aquariumprojekt gestartet, sondern hauptsächlich auch deswegen wie man solche Aufgaben generell pragmatisch lösen kann. (Daher auch der Titel des Threads)
Und dies hat dieser Thread dank Gunter sehr gut gezeigt ! Karma++
Betrifft z.b. alle Sensoren mit nicht linearer Kennlinie und unbekannter Formel.
Kannst du bitte, nur zur vollstädnigkeit den Code reinhängen, den ich dir geschickt habe?
ich habe ihn nämlich nicht mehr 
Kein Problem.
Wobei ich den Code live noch nicht getestet habe.
Aber verstanden was dort gemacht wird.
Nur das hier verstehe ich nicht:
Mit dem Spiegeln, also wenn der Graph Symetrisch sein soll und das Array deswegen nur halb so groß zu sein braucht.
Diese Zeile :
_MoD = 1440 - _MoD; // Werte oberhalb 720 nach unten spiegeln, wegen Symetrie
Berechnet für _MoD <= 720 meiner Meinung nach den falschen Index, da fehlt wohl ein If ( _MoD >=720) ??
int LED_PWM (int _MoD){ // _MoD = Minute of Day
const int Tablength = 9;
const int Tab[Tablength][2]={ { 0 , 5 },
{360 , 10 },
{400 , 18 },
{440 , 39 },
{520 , 111 },
{600 , 194 },
{640 , 226 },
{680 , 248 },
{720 , 255 }};
_MoD = 1440 - _MoD; // Werte oberhalb 720 nach unten spiegeln, wegen Symetrie
// In Tabelle das passende Wertepaar suchen
int i = 0;
while (i < Tablength && _MoD > Tab[i][0]) i++;
// aus dem ermittelten Wertepaar und dem nächsten darüber den korrekten Wert interpolieren
int _out = ( ((Tab[i][1] - Tab[i-1][1])*( _MoD - Tab[i-1][0] ))
/ (Tab[i][0] - Tab[i-1][0] ))
+ Tab[i-1][1];
return _out;
}
rudirabbit:
Berechnet für _MoD <= 720 meiner Meinung nach den falschen Index, da fehlt wohl ein If ( _MoD >=720) ??
Ähem, ja, da hast natürlich recht. Das ist mit durchgerutscht.
Wobei du das ja nur brauchst, wenn du symetrische Kennfelder hast und nur die Hälfte ablegst um Speicher zu sparen.