Variablenspeicherverbrauch reduzierbar?

Hallo,

habe meine PWM Excelberechung in Code umgesetzt.
Jetzt muß ich zwingend wegen der pow() Funktion float Variablen verwenden und das nicht zu wenig.
Kann man das Speicher sparender programmieren mit weniger float und damit die Rundungsfehler umgehen?
Wegen der Bruchrechnung für die Potenz sehe ich keinen Ansatz mit 1000 o.ä. zu multiplizieren und später wieder dividieren.

// Arduino Mega 2560

long  ENDWERT = 255;
long  AUFLOESUNG = 64;
float KRUEMMUNG = 2.5;
float ZWISCHENSTUFE = 1;
float ABSTUFUNG;
  int PWM_WERT;
  int LED = 13;
 
void setup()
{     
   Serial.begin(9600);
   
   ABSTUFUNG = (pow(ENDWERT,(1/KRUEMMUNG))-1)/(AUFLOESUNG-1);  // Berechnung der PWM Abstufung 
//  Serial.println(ABSTUFUNG,4); 
   
}

void loop()
{
   

   for (int i=1; i<=AUFLOESUNG; i++)                               // alle 64 Auflösungsstufen berechnen und ausgeben
      {
       PWM_WERT = (int) (pow(ZWISCHENSTUFE,KRUEMMUNG)) + 0.5;  // Berechnung und Rundung des analogen PWM Wertes 1 ... 255
       analogWrite(LED, PWM_WERT);                                 // PWM Ausgabe an LED
       delay(20);
       ZWISCHENSTUFE = ZWISCHENSTUFE + ABSTUFUNG;               // Berechnung des nächsten Basis-Wertes
//     Serial.print(i); Serial.print("  ");Serial.print(PWM_WERT); Serial.print("  ");
//     Serial.println(ZWISCHENSTUFE,4);
      }
	
       ZWISCHENSTUFE = 1;     // setzen auf Anfangswert, nachdem alle 64 Auflösungstufen durch sind 
	  
}

µC PWM Wert Berechnung.xlsx (26.2 KB)

floats brauchen 4 Byte Speicher. Ein Integer mit brauchbarem Wertebereich braucht etwa gleich viel Speicher. Zudem verwendest Du im Moment 3 floats, wie willst Du da gross Speicherplatz sparen?

Hallo,

ich ging immer davon aus das float Variablen den größten Speicher verbrauchen und das rechnen mit float immer am langsamsten von statten geht. Deshalb die Frage wie man float vermeiden kann. Bei bestimmten Berechnungen gibt es ja Tricks, nur sehe ich hier keinen Lösungsansatz. Wie mit 1000 zu multiplizieren um aus dem gewünschten Kommastellenbereich rauszukommen und später wieder zu dividieren und das dann alles mit int bzw. long zu machen. Zudem ich, wegen float, Rechenfehler erhalte. Der letzte berechnete PWM Wert müßte wieder 255,0 ergeben. Ich erhalte aber 254. Das ist nicht weiter dramatisch aber auch nicht schön. Es ist nicht der einzigste Rechen/Rundungsfehler. Das das mit float normal ist ist mir schon klar.

Wenn es in dem Fall nichts zu optimieren gibt wäre die Frage schon beantwortet. Ich wollte maximale Genauigkeit und maximalen Speed wenn er das alles selbst rechnen soll.

Ansonsten muß ich die fertigen Werte wieder in ein Array schreiben. Ich wollte auch mal sehen um wieviel das selbst rechnen langsamer ist im Vergleich mit Array.

Versuche mal, anstatt

       PWM_WERT = (int) (pow(ZWISCHENSTUFE,KRUEMMUNG)) + 0.5;  // Berechnung und Rundung des analogen PWM Wertes 1 ... 255

folgende Zeile zu verwenden:

       PWM_WERT = (int) (pow(ZWISCHENSTUFE,KRUEMMUNG) + 0.5);  // Berechnung und Rundung des analogen PWM Wertes 1 ... 255

Damit kriegst Du zumindest die Rundung korrekt hin.

Zur Geschwindigkeit: Aufwendig in Deiner Rechnung ist in erster Linie die pow()-Funktion. Sie wird normalerweise aus zwei Basisfunktionen (exp() und ln()) gebildet und beinhaltet zwei taylorsche Näherungsberechnungen. Würdest Du die Krümmung auf eine Ganzzahl legen, könntest Du Dir den Aufruf sparen und könntest durchgängig mit Integern rechnen.

Hallo,

ich sehe keinen Unterschied zwischen den Codezeilen. :wink:

Ich könnte mich erstmal auf Ganzzahlen beschränken. Das wäre nicht weiter schlimm. Du meinst dann, ich soll mit Ganzzahlen exp() und ln() verwenden?
Der Werte der Variablen Abstufung und damit der Wert der Variablen Zwischstufe sind aber Kommazahlen. Die muß ich dann irgendwie anders verrechnen um die Kommastellen zu verschieben?

hi,

ich sehe keinen Unterschied zwischen den Codezeilen.

in einem fall werden die nachkommastellen von: (pow(ZWISCHENSTUFE,KRUEMMUNG)) + 0.5 abgeschnitten (bool ok = false;) im anderen fall von: (pow(ZWISCHENSTUFE,KRUEMMUNG) + 0.5) bool ok = true;

ich versuch auch schon in den letzten tagen, da eine gute funktion hinzukriegen, und es geht ja auch sehr gut. aber entweder großer speicherverbrauch oder langsam.

gruß stefan

Die Erklärung von Eisebaer trifft's leider nicht ganz.

In Deinem Code wird pow(ZWISCHENSTUFE,KRUEMMUNG) nach int gewandelt, dann 0.5 dazugezählt (also 0) und wieder nach int gewandelt (für das Resultat).

Meine Änderung setzt die Klammern so, dass erst das Ergebnis von pow(ZWISCHENSTUFE,KRUEMMUNG) + 0.5 nach int gewandelt wird, womit wirklich eine Rundung auf ganze Zahlen stattfindet. Mit Booleans hat das nichts zu tun, aber mit Operatoren-Prioritäten.

Float ist langsam und die Floats libs brauchen Platz. Du benutzt POW aber um x^2.5 zu berechnen, sonst für nichts. Und das nur für 64 verschiedene Werte. Leg das doch einfach vorberechnet in einem 64 Elemente großen Progmem Array ab. Dann die Werte einfach auslesen anstatt sie zu berechnen --> fertig. Schnell und mit Integerarithmetik.

hi,

Die Erklärung von Eisebaer trifft's leider nicht ganz.

was daran trifft's nicht?, aber egal.

das mit dem array funkt nicht, zumindest wenn doc das so ähnlich angegangen ist wie ich: wenn man immer 30 logarithmische zwischenstufen von 0-255 braucht, ist's ja noch leicht, aber was, wenn ich das zwischen 30 und 225 brauche? da kann man's nur berechnen...

zb wenn ich eine rgb-led von (0, 30, 100) in 30 schritten auf (255, 225, 150) dimmen wíll.

gruß stefan

oje, pylon, jetzt hab' ich erst Deine antwort ganz gelesen. das boolean-zeugs sollte scherzhalber andeuten, was richtig und was falsch ist...

gruß stefan

Für 30 Schritte braucht man ein Array mit 30 Elementen. Unter Umständen ist der Lookup dann eben eine Suche nach der richtigen Schaltschwelle. Selbst be 256 Stufen reicht da 1 kByte.

Ich glaube wir alle haben das richtige Alter eine Logaritmustabelle mal gesehen, wenn nicht benutzt zu haben. In Logaritmustabellen gibt es auch nur Werte zwischen 0 und 1.

Eisebaer, Du kannst im Array die Faktoren (zB von 0 bis 100 ohne Kommastellen) und diese dann mit der Differenz des Anfangs bzw Endwerts und dem Korrekturfaktor 1/100 multiplizieren und zum Anfangswert addieren. So bekommst Du in 30 Schriten von 100 zu 150 in logaritmiscer Abstufung.

Grüße Uwe

Hallo,

@ pylon: jetzt raff ich das. Ich habe ehrlich gesagt die andere Klammersetzung nicht gesehen und ewig beide Zeilen verglichen und wußte echt nicht was Du gemeint hast. Nächstesmal bitte die Klammern mit fett markieren. ;)

@ Udo: mit einem Array habe ich schon gemacht. Deshalb habe ich auch meine Exceltabelle erstellt. Ich wollte wissen wie schnell man die Berechnung machen kann.

@ Eisbär: mit RGB liegt noch in weiter Ferne. Ich spiele nur mit der Helligkeit von einfarbigen LED(s) rum.

hi,

Eisebaer, Du kannst im Array die Faktoren (zB von 0 bis 100 ohne Kommastellen) und diese dann mit der Differenz des Anfangs bzw Endwerts und dem Korrekturfaktor 1/100 multiplizieren und zum Anfangswert addieren. So bekommst Du in 30 Schriten von 100 zu 150 in logaritmiscer Abstufung.

versteh' ich jetzt mal überhaupt nicht, uwe, klingt aber interessant. kannst Du das genauer erklären?

gruß stefan

Stefan So ähnlich wie die E12 oder E24 Widerstandsabstufungen. Die Wiederholen sich auch in jeder Dekade. Die Faktoren sind 1,0; 1,2; 1,5; 1,8; 2,2; 2,7; 3,3; 3,9; 4,7; 5,6; 6,8; 8,2; 10 Grüße Uwe

hi, uwe,

interessanter ansatz, muß ich mal nachdenken...

gruß stefan

Das mit dem Table Lookup funktioniert garantiert. Wenn das nicht klappt macht Ihr was falsch. Hier ein Beispiel (für Quadratwurzeln und ohne Progmem, aber vom Prinzip her das Gleiche): https://gist.github.com/nightcracker/3481607.

Und jede Menge mehr Ansätze in die gleiche Richtung:

http://stackoverflow.com/q/4930307/2036917

Klar dort geht es um Quadratwurzeln, aber x^2.5 = (x^5)^0.5 = sqrt(x^5)

Oder alternativ: x^2.5 ist auch nichts anderes als die Lösung der Gleichung y^2 = x^5