Durchschnittsbildung (1-1/1)

8. Arduino-Projekt: Glättung von Messreihen

Im "5. Arduino-Projekt: Temperaturmessung mit analogem Temperatursensor" haben Sie vielleicht gemerkt, dass durch die Messfehler starke Ausschläge im seriellen Plot oder Schwankungen in den Daten aufgetreten sind.

Ohne den Aufbau der Schaltung zu ändern kann das programmtechnisch durch eine größere Samplerate (Messungen pro Sekunde) und Durchschnittsbildung der Messwerte aufgefangen werden.

/**
 * Temperaturmessung mit TMP36 und Durchschnittsbildung
 */

// Pinbezeichnung des analogen Messeingang

const byte sensor = A0;

// Anzahl der Summanden, Zähler und summe

const int sampleTime = 1000;
const int num = 100;
int counter = 0;
float sum = 0.0;

// In der setup()-Funktion wird die serielle
// Schnittstell zum Anzeigen der Werte initialisiert
// und der Pin "sensor" auf INPUT geschaltet (braucht es
// eigentlich nicht, denn nach dem Reset sind alle
// Pins auf INPUT.

void setup() {

  Serial.begin(9600);

  pinMode(sensor,INPUT);
  
}

// Im loop() wird die Spannung am Pin "sensor" gemessen
// und in eine Tempteraturangabe in °C umgerechnet und
// über die serielle Anzeige (USB-Kabel übernimmt diese
// Funktion) ausgegeben.

void loop() {

  float temperature;
  float avg;

  // Anzahl der Summanden schon erreicht?
  if (counter >= num) {

    // durchschnitt errechnen
    avg = sum / num;
    
    // Ausgabe der Werte über die serielle Schnittstelle
  
    Serial.print("Grad Celsius: ");
    Serial.println(avg);

    // Zähler und summe zurücksetzen
    
    counter = 0;
    sum = 0.0;
    
  }

  // sensorValue enthält den Rohwert der gemessenen
  // Spannung. Der Arduino kann in der Standard-
  // konfiguration Spannungen mit einer Auflösung
  // von 10 Bit lesen. Damit lassen sich Werte von
  // 0 - 1023, also 1024 Werte abbilden.
  // Als Referenzspannung wird in der
  // Standardkonfiguration dabei die Betriebsspannung
  // von 5V verwendet. Man erhält also Rohwerte 
  // zwischen 0 (0V) und 1024 (5V).
  
  int sensorValue = analogRead(sensor);

  // Umrechnung des Rohwertes in Volt (s. oben)

  float volt = (sensorValue / 1024.0) * 5.0;

  // Umrechnung der Spannung in Temperatur. Die
  // verwendeten Werte ergeben sich aus dem Datenblatt
  // des Sensors.

  temperature = (volt - 0.5) * 100;

  // werte aufsummieren

  sum += temperature;

  // counter erhöhen
  
  counter++;

  // und etwas warten für die nächste Messung
  
  delay(sampleTime / num);

}

Einige Erläuterungen:

// Anzahl der Summanden, Zähler und summe

const int sampleTime = 1000;
const int num = 100;
int counter = 0;
float sum = 0.0;

sampleTime : die Konstante ist die Zeitdauer zwischen zwei Messausgaben in Millisekunden
num : Anzahl der Messungen pro Sampletime. Die Werte bedeuten, dass alle 10 ms (1000 ms / 100) eine Messung durchgeführt und 100 Messungen aufaddiert und als Durchschnitt ausgegeben werden
counter : zählt von 0 - 99, also 100 Messungen
sum : die Summe der Messungen, sie wird nach 100 Messungen durch 100 dividiert. Die Variable muss float sein und wird deshalb mit 0,0 initialisiert.

  float temperature;
  float avg;

temperature : enthält die aus den Spannungen am Sensor errechnete temperatur
avg : Durchschnittswert der Messungen, wird alle 1000 ms ausgegeben

Achtung: die beiden Variablen sind innerhalb der loop()-Funktion definiert und können nur dort verwendet werden und sie sind nicht initialisiert, haben also keinen Anfangswert. Das ist deshalb nicht notwendig, da die Variablen weiter unten in der loop()-Funktion einen definierten Wert erhalten.

  // Anzahl der Summanden schon erreicht?
  if (counter >= num) {

    // durchschnitt errechnen
    avg = sum / num;
    
    // Ausgabe der Werte über die serielle Schnittstelle
  
    Serial.print("Grad Celsius: ");
    Serial.println(avg);

    // Zähler und summe zurücksetzen
    
    counter = 0;
    sum = 0.0;
    
  }

if (Ausdruck) { Anweisungen; ... } : wenn der Ausdruck "wahr" ist, werden alle Anweisungen zwischen den geschwungenen Klammer ausgeführt, sonst übersprungen
counter >= num : gibt "wahr" zurück, wenn der counter größer als oder gleich groß wie num ist

Konkret heißt das, dass die in den geschwungenen Klammern stehende Durchschnitssberechnung und die serielle Ausgabe 100 mal übersprungen werden, dann einmal gemacht, wieder 100 mal übersprungen usw. Wichtig: das Zurücksetzen des Zählers und Durchschnitts (counter, sum) darf nicht vergessen werden.

  // werte aufsummieren

  sum += temperature;

  // counter erhöhen
  
  counter++;

sum += temperature : ist die kurze Form für sum = sum + temperature
counter++ : ist die kurze Form für counter = counter + 1, counter wir bei jedem Durchlauf um eins erhöht

Achtung: die Ausdrücke sind nicht als mathematische Formeln zu lesen, sonst würden sie im ersten Beispiel nur für einen speziellen Fall und im zweiten Beispiel überhaupt nie zutreffen. Das Programm macht vielmehr Folgendes: der rechts vom "ist gleich" (=) stehende Teil wird berechnet und danach in der Variablen links abgespeichert, wobei der alte Inhalt überschrieben wird. Beispiel: counter hat den Wert 4, der rechte Teil ist also 4 +1 ergibt 5, jetzt wird counter = 5 gesetzt, der alte Wert (4) ist verloren.

Kniffliges

1. Erweitere die Temperaturmessschaltung mit Hilfe der if-Anweisung und zusätzlicher Hardware so, das das Überschreiten oder Unterschreiten einer oderer mehrer Temperaturgrenzwerte mit Hilfe einer oder mehrer Leds signalisiert wird.

2. Erweitere die oben angeführte Schaltung so, dass eine angeschlossene Led mit zunehmender Temperatur schneller blinkt.

Angerer Harald - Freitag, 6. Dezember 2019 - Kategorien: ArduinoTutorials - Noch kein Kommentar ...