Problem bei der Berechnung von negativen Fließkommazahlen

Hallo Mein Name ist Jens,

im Rahmen eines Schulprojektes bin ich in die Arduino Welt eingetaucht. 8)

Seit einigen Tagen komme ich mit einem Problem nicht mehr weiter.

Bei der Berechnung ergeben sich immer abweichende Werte ich versteh allerdings nicht wieso….

Folgendes zur Aufgabenstellung:
Ermittelt werden soll der Alkoholanteil in mg in der Atemluft. :smiling_imp:

Hierzu verwende ich einen MQ-3 Sensor (link )

Anhand des Datenblattes und der Kennlinie habe ich mir ein Array geschrieben in dem die X Achse Y Achse die Steigung (m) und der Schnittpunkt mit y (b) eingetragen sind.

Dieses Array durchsuche ich nach x (RS/R0) und will dann y errechnen mit f(x)=m*x+b

Und genau hier tauchen die Probleme auf… da ich hier mit negativen Zahlen rechne….oder noch ein verständniss Problem mit den Datentypen habe….

Ich verwende den Arduino Mega 2560 der wohl nur 4 Byte also Float verarbeiten kann, richtig?

Das Ergebnis ist undefinierbar bzw. verändert sich Sporadisch trotz gleichbleibendem Input…

Ich hoffe einer von euch kann mir weiterhelfen :confused:

Gruß Jens

double Sensorwert = 0; 
double Quellspannung=5.0;
double AnalogPin=0;
double R1=10000.0; //Wert des bekannten Widerstands (der mitgelieferte 1,5k-Widerstand)
double Messwert;
double SpannungR2; //Spannung über dem zu messenden Widerstand
double Widerstand;



// Widerstände messen

//              _____
//            -|_R1__|- VCC
//AnalogPin  -' _____
//           '-|_R2__|- GND

// R2 = zu messender Widerstand


// Werte aus der Kennlie des MQ-3 Alkoholsensors Übernommen.
//Spalte: 0	1	2	3
//        x	y	m	b

double Array[22][4]= {
  {
    0.1  ,11  ,0  ,0  }
  , {
    0.018  ,10  ,-62.5  ,16.75  }
   , {
    0.124  ,9  ,-125  ,24.5  } 
  , {
    0.132  ,8  ,62.50,  16.25  }
  , {
    0.148  ,7  ,-50.00  ,14.40  }
    , {
    0.164  ,6.2  ,-75.00  ,18.50  }
    , {
    0.18  ,5  ,-40.00  ,12.20  }
    , {
    0.2  ,4.2  ,-22.64  ,8.73  }
    , {
    0.253  ,3  ,-11.48  ,5.907  }
    , {
    0.34  ,2    ,-6.00  ,4.04  }
    , {
    0.4  ,1.64  ,-4.86  ,3.57  }
    , {
    0.47  ,1.3  ,-3.75  ,3.05  }
    , {
    0.6  ,0.9  ,-2.00  ,2.10  }
    , {
    0.64  ,0.8  ,-2.50  ,2.40  }
     , {
    0.7  ,0.7  ,-1.67  ,1.867  }
     , {
    0.8  ,0.6  ,-1.00  ,1.40  }
     , {
    0.9  ,0.5  ,-1.00  ,1.40  }
     , {
    1.00 ,0.4  ,-1.00  ,1.40  }
     , {
    2.28  ,0.3  ,-0.08  ,0.48  }
     , {
    2.64  ,0.2  ,-0.28  ,0.93  }
     , {
    3.00  ,0.13  ,-0.18  ,0.70  }
     , {
    3.20  ,0.1  ,-0.15  ,0.58  }
};

void setup() {
Serial.begin(9600);
    
Serial.println(sizeof(float));
Serial.println(sizeof(double)); 

//Bei allen Arduino 8-Bit Controllern ist double=float= 4 Bytes
//Double ist zwar deklarierbar, aber tatsächlich - ein float!

//Nur beim 32-Bit Controller Arduino DUE hast Du als Datentyp double tatsächlich ein double mit 8 Bytes!

//http://arduino.cc/en/Reference/Double

}
void loop() {
  //Wiederstandsmessung
    //5 Messungen machen und Mittelwert bilden
  Messwert=0;
  for(int i=0;i<5;i++){
    Messwert+=analogRead(AnalogPin);
  }
  Messwert=trunc(Messwert/5);
  
  //Spannung berechnen
  SpannungR2=(Quellspannung/1023.0)*Messwert;
  
  //Berechnung: (R2 = R1 * (U2/U1))
  Widerstand=R1*(SpannungR2/(Quellspannung-SpannungR2));
  
  
 // Werte Zuordnen zur MQ-3 Kennlinie 
  int i,x,last;	
  double ergebnis,RS,R0;
  		
x=0;			

// Einlesen des Widerstandswertes noch ergänzen: RS/R0
 //analogRead(sensorPin);
//RS = Widerstand;
RS = 1600.00; //Wert festgelegt um die Berechnung zu testen
R0 = 1550.00; //Wiederstand bei 0 Promille
// Sensorwert = 1; //Dummy zum testen der Berechnung
Sensorwert = RS/R0; // Wiederstand einlesen  und Rechnen RS/RO

last = 0 ;	//letzer Wert des Zählers
i=0	;	// Zähler	
for(x=Sensorwert;Array[i][0] < Sensorwert && i < 22;i++)	;	//Solange der Wert für x kleiner als der Sensorwert	
{
  if (last == i)                                        // Solange die werte der Zähler nicht gleich sind gibt es noch einen höheren x wert in der Kennline 
    
     //f(x)=m*x+b
     {
      ergebnis=(Array[i][2]*Sensorwert+Array[i][3]); 
      
      
     i=last;                                           // Zählervariable "last" erhöhen damit nur einmal berechnet wird
     }

// Ausgabe im Serial Monitor

  if (Serial.available() > 0) // Zum anzeigen 1 eingeben...
  
 {
// Ausgabe Widerstandswert 
delay (1000);

  Serial.print("Spannung ueber R2 betraegt ");
  Serial.print(SpannungR2,2);
  Serial.println(" Volt!");   // Serial.println neue Zeile
  
  Serial.print("Der Widerstandswert hat ");
  Serial.print(Widerstand,2);
  Serial.println(" Ohm.");
  Serial.println();
  
 
  // Werte prüfen Zuordnung MQ-3 Kennline
  
  
    Serial.print(" RS = ");
    Serial.print(RS);
     
    Serial.print(" R0 = ");
    Serial.print(R0);
    Serial.println("  ");
  


   Serial.print(" Der Sensorwert also RS/R0 beträgt = ");
   Serial.print(Sensorwert);
   Serial.println("  ");
 
  
   Serial.println(" m*x+b ");
   Serial.println("bzw.:  Array[i][2]  *  Sensorwert  +  Array[i][3] ");
   Serial.print(Array[i][2]);
   Serial.print("*");
   Serial.print(Sensorwert);
   Serial.print("+");
   Serial.print(Array[i][3]);
    Serial.println("  ");
    
//     Serial.println(" Array[i][3] also b");
 //Serial.print(Array[i][3]);
   // Serial.println("  ");
 
   Serial.print(" Zaehlerstand fuer i = ");  
   Serial.print(i);
    Serial.println("  ");
    
  
  
   Serial.print(" Ergebniss = ");  
   Serial.print(ergebnis);
    Serial.println("  ");
    

 }      
}

}
double Array[22][4]= {
  {
    0.1  ,11  ,0  ,0  }

Ich weiß nicht obs was damit zu tun hat, aber ich würde es anders machen:

double Array[22][4]= {
  {
    0.1  ,11.0  ,0.0  ,0.0  }
RS = 1600.00; //Wert festgelegt um die Berechnung zu testen
R0 = 1550.00; //Wiederstand bei 0 Promille

Was erhoffst du dir von den zwei Nullen?

Poste mal die Ausgabe vom Serial Monitor. Kann mir nicht vorstellen, dass eine Berechnung mit exakt den selben Zahlen zu unterschiedlichen Ergebnissen führt.

Okay das Array hab ich mal angepasst hilft aber nicht :wink:

Ich hab mittlerweile noch etwas weiter gesucht und komme glaube ich langsam in die richtige Richtung…

Mein Arduino Mega kann anscheinend nur Float bzw. 4 Bit …

Wenn ich jetzt aus dem Array einen Wert der Variable z.B. “Ergebnis” zuweisen will erhalte ich bei der Ausgabe im Serialmonitor nur immer den Wert null…

Die Berechnung mit statischen Werten funktioniert übrigens einwandfrei…

Hier nochmal der Auszug des Serial Monitors zu dem ursprünglichen Programm:

RS = 1600.00 R0 = 1550.00

Der Sensorwert also RS/R0 beträgt = 1.03

mx+b
-0.08
1.03+0.48

Zaehlerstand fuer i = 18

Ergebniss = 3.53
%BAC = 0.00

RS = 1600.00 R0 = 1550.00

Der Sensorwert also RS/R0 beträgt = 1.03

mx+b
-0.08
1.03+0.48

Zaehlerstand fuer i = 18

**Ergebniss = 3.53 **
%BAC = 0.00

RS = 1600.00 R0 = 1550.00

Der Sensorwert also RS/R0 beträgt = 1.03

mx+b
-0.08
1.03+0.48

Zaehlerstand fuer i = 18

**Ergebniss = 3.53 **
%BAC = 0.00

Hier der Code etwas formatierter

double Sensorwert = 0; 
double Quellspannung=5.0;
double AnalogPin=0;
double R1=10000.0; //Wert des bekannten Widerstands (der mitgelieferte 1,5k-Widerstand)
double Messwert;
double SpannungR2; //Spannung über dem zu messenden Widerstand
double Widerstand;



// Widerstände messen

//              _____
//            -|_R1__|- VCC
//AnalogPin  -' _____
//           '-|_R2__|- GND

// R2 = zu messender Widerstand


// Werte aus der Kennlie des MQ-3 Alkoholsensors Übernommen.
//Spalte: 0	1	2	3
//        x	y	m	b

double Array[22][4]= {
  {
    0.1  ,11.0  ,0.0  ,0.0  }
  , {
    0.018  ,10  ,-62.5  ,16.75  }
   , {
    0.124  ,9  ,-125  ,24.5  } 
  , {
    0.132  ,8  ,62.50,  16.25  }
  , {
    0.148  ,7  ,-50.00  ,14.40  }
    , {
    0.164  ,6.2  ,-75.00  ,18.50  }
    , {
    0.18  ,5  ,-40.00  ,12.20  }
    , {
    0.2  ,4.2  ,-22.6415  ,8.728302  }
    , {
    0.253  ,3  ,-11.4943  ,5.908046  }
    , {
    0.34  ,2    ,-6.00  ,4.04  }
    , {
    0.4  ,1.64  ,-4.85714  ,3.582857  }
    , {
    0.47  ,1.3  ,-3.75  ,3.0625  }
    , {
    0.6  ,0.9  ,-2.00  ,2.10  }
    , {
    0.64  ,0.8  ,-2.50  ,2.40  }
     , {
    0.7  ,0.7  ,-1.66667  ,1.866667  }
     , {
    0.8  ,0.6  ,-1.00  ,1.40  }
     , {
    0.9  ,0.5  ,-1.00  ,1.40  }
     , {
    1.00 ,0.4  ,-1.00  ,1.40  }
     , {
    2.28  ,0.3  ,-0.07813  ,0.478125  }
     , {
    2.64  ,0.2  ,-0.27778  ,0.933333  }
     , {
    3.00  ,0.13  ,-0.19444  ,0.713333  }
     , {
    3.20  ,0.1  ,-0.15  ,0.58  }
};

void setup() 
      {
      Serial.begin(9600);
      Serial.println(sizeof(double));
      Serial.println(sizeof(double)); 
      
      //Bei allen Arduino 8-Bit Controllern ist double=double= 4 Bytes
      //double ist zwar deklarierbar, aber tatsächlich - ein double!
      
      //Nur beim 32-Bit Controller Arduino DUE hast Du als Datentyp double tatsächlich ein double mit 8 Bytes!
      
      //http://arduino.cc/en/Reference/double
      }
      
void loop() 
  {
  //Wiederstandsmessung
    //5 Messungen machen und Mittelwert bilden
  Messwert=0;
      for(int i=0;i<5;i++)
      {
        Messwert+=analogRead(AnalogPin);
      }
 
  Messwert=trunc(Messwert/5);
  
  //Spannung berechnen
  SpannungR2=(Quellspannung/1023.0)*Messwert;
  
  //Berechnung: (R2 = R1 * (U2/U1))
  Widerstand=R1*(SpannungR2/(Quellspannung-SpannungR2));
  
  
 // Werte Zuordnen zur MQ-3 Kennlinie 
 
 
  int i,last,x;	
  double RS,R0;	
  
  	
			

// Einlesen des Widerstandswertes noch ergänzen: RS/R0
//analogRead(sensorPin);
//RS = Widerstand;
RS = 1600.00;
R0 = 1550.00; //Wiederstand bei 0 Promille
// Sensorwert = 1; //Dummy zum testen der Berechnung
Sensorwert = RS/R0; // Wiederstand einlesen  und Rechnen RS/RO

last = 0 ;	//letzer Wert des Zählers
i=0	;	// Zähler

double ergebnisDummy,BACDummy,BAC;
double ergebnis;

x=0;
	
    for(x=Sensorwert;Array[i][0] < Sensorwert && i < 22;i++)	;	//Solange der Wert für x kleiner als der Sensorwert	
    {
     
          if (last == i)                                        // Solange die werte der Zähler nicht gleich sind gibt es noch einen höheren x wert in der Kennline 
          {
           //f(x)=m*x+b
           // Testwerte funktionieren
           ergebnisDummy=(-75.00*0.155)+18.50;                     // Kontrollrechnung
           BACDummy = ergebnisDummy * 0.21;                        // Kontrollrechnung
           
           // Brechnung mit Array - funktioniert noch nicht....
            //ergebnis = Array[i][2];                               //Test Ausgabe 1
           // ergebnis = Array[i][2]*Sensorwert;                  //Test Ausgabe 1
              ergebnis = Array[i][2]*Sensorwert +Array[i][3];     //Test Ausgabe 1
            //round (ergebnis),2;          
           //ergebnis=m*x+b; 
           
           
           
           //BAC = ergebnis * 0.21;                         //% BAC = breath mg/L * 0.21
        
           i=last;                                           // Zählervariable "last" erhöhen damit nur einmal berechnet wird
          }
    }		

  

// Ausgabe im Serial Monitor

            if (Serial.available() > 0) // Zum anzeigen 1 eingeben...
            {
             // Ausgabe Widerstandswert 
             delay (1000);
            
             Serial.print("Spannung ueber R2 betraegt ");
             Serial.print(SpannungR2,2);
             Serial.println(" Volt!");   // Serial.println neue Zeile
              
             Serial.print("Der Widerstandswert hat ");
             Serial.print(Widerstand,2);
             Serial.println(" Ohm.");
             Serial.println();
              
             // Werte prüfen Zuordnung MQ-3 Kennline
                           
             Serial.print(" RS = ");
             Serial.print(RS);
                 
             Serial.print(" R0 = ");
             Serial.print(R0);
             Serial.println("  ");
                    
             Serial.print(" Der Sensorwert also RS/R0 beträgt = ");
             Serial.print(Sensorwert);
             Serial.println("  ");
                           
             Serial.println(" m*x+b ");
             Serial.print(Array[i][2]);
             Serial.print("*");
             Serial.print(Sensorwert);
             Serial.print("+");
             Serial.print(Array[i][3]);
             Serial.println("  ");
                
             //Serial.println(" Array[i][3] also b");
             //Serial.print(Array[i][3]);
             //Serial.println("  ");
             
             Serial.print(" Zaehlerstand fuer i = ");  
             Serial.print(i);
             Serial.println("  ");
                                      
             Serial.print(" Ergebniss = ");  
             Serial.print(ergebnis);
             Serial.println("  ");
                
             Serial.print(" %BAC = ");  
             Serial.print(BAC);
             Serial.println("  ");
             
             
             
             
             
             
             Serial.print(" ErgebnissDummy = ");  
             Serial.print(ergebnisDummy);
             Serial.println("  ");
                
             Serial.print(" %BACDummy = ");  
             Serial.print(BACDummy);
             Serial.println("  ");
             
          
             }      

}

Die Ergebnisse sehen für mich gleich aus! Wo ist das Probelm?

Und was versuchst du mit den zwei Nullen nach dem Komma zu bezecken?

tweak87:

    for(x=Sensorwert;Array[i][0] < Sensorwert && i < 22;i++) ;

Das ist eine Tut-nix-Schleife.
Außer daß Dein Laufindex i erhöht wird, passiert da gar nichts.

Das Semikolon am Ende der Schleife mußt Du wohl löschen, denn ich gehe mal davon aus, dass in der Schleife der nachfolgende Codeblock zwischen den geschweiften Klammern ausgeführt werden soll und nicht die leere “;” “Tut-nix” Anweisung.

Im übrigen sieht mir die for-Bedingung auch insgesamt extrem fehlerverdächtig aus. Aber da Du den Laufindex völlig untypischerweise VOR der for-Bedingung auf 0 setzt, könnte der Laufindex natürlich trotzdem laufen.

Da hab ich den Wald vor lauter Bäumen nicht gesehen befürchte ich …

das mit dem x war mir gestern schon aufgefallen, warum auch immer ich das gemacht hatte :stuck_out_tongue:

Die Berechnungen habe ich jetzt erst nach der Schleife bzw. nachdem die Bedingung if (last == i) durchlaufen war und der Wert für das i festgelegt wurde durchgeführt, und siehe da es funktioniert.

for(i=0;meinArray[i][0] < Sensorwert && i < 22;i++)	;	//Solange der Wert für i kleiner als der Sensorwert	
     
    {
     
          if (last == i)                                        // Solange die werte der Zähler nicht gleich sind gibt es noch einen höheren x wert in der Kennline 
          {
          
           i=last;                                           // Zählervariable "last" erhöhen damit nur einmal berechnet wird
          }
    		
     ergebnis=0;
     ergebnis = meinArray[i][2]*Sensorwert+meinArray[i][3];
     
  
     BAC=0;
     BAC = ergebnis * 0.21;

tweak87:
Da hab ich den Wald vor lauter Bäumen nicht gesehen befürchte ich …

Also dann wolltest Du den Laufindex i bis zum Erreichen der Abbruchbedingung erhöhen, bis dahin nix tun, und erst danach soll der nachfolgende Code ausgeführt werden?

Der normale Gebrauch einer for-Schleife ist, dass man in der Schleife irgendwas macht, das vom Laufindex abhängt, z.B. eine einzelne Anweisung ausführen:

for(i=0;i< 22;i++) anweisung();  // von i=0 bis i=21 die "anweisung()" aufrufen

Oder einen Anweisungsblock in geschweiften Klammern ausführt:

for(i=0;i< 22;i++) // alle Anweisungen im Block von i=0 bis i=21 ausführen
{
  anweisung1();
  anweisung2();
  anweisung3();
  anweisung4();
}

Der Gebrauch Deiner for-Schleife, die nur den Schleifenindex bis zum Erreichen der Abbruchbedingung verändert, dabei aber überhaupt nichts macht (nur ein Semikolon ‘;’ nach for), ist eher ungewöhnlich, allerdings möglich.