Mittelwert mit float

Habe hier einen Sketch mit dem man einen Mittelwert von A0 berechnen kann. Nun möchte ich das parallel und separat im Programm auch für A1 machen. Nur leider geht es nicht so ohne weiteres. Hat jemand eine Idee ?

float puffer;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int sensor = analogRead(A0);
  float spannung = sensor * (5.0 / 1023.0) * 6;

  float mwert = mittelwert(spannung, puffer, 10);

  Serial.println(mwert);
}

// Berechnung gleitender Mttelwert--------------
float mittelwert( float Rohwert, float &buff, float faktor)
{
  float mi ;
  buff = buff - buff / faktor;
  buff = buff + Rohwert;
  mi = buff / faktor;

  return mi;

}

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

da stellt sich halt die Frage was du probiert hast.

Aber da du eh schon mit Referenzen und einem externen Puffer arbeitest, könntest du einen weiteren Puffer für den anderen Wert nehmen.
Oder ein Array.

float puffer[2];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int sensor = analogRead(A0);
  float spannung = sensor * (5.0 / 1023.0) * 6;

  float mwert = mittelwert(spannung, puffer[0], 10);
  Serial.println(mwert);

  float andereSpannung = analogRead(A1) * (5.0 / 1023.0) * 6;
  float ewert = mittelwert(andereSpannung, puffer[1], 10);
  Serial.println(ewert);

  Serial.println();

}

// Berechnung gleitender Mttelwert--------------
float mittelwert( float Rohwert, float &buff, float faktor)
{
  float mi ;
  buff = buff - buff / faktor;
  buff = buff + Rohwert;
  mi = buff / faktor;

  return mi;
}

Dann muss für jeden Ax ein eigener puffer benutzt werden.
Parallel geht mit einem Prozessor nicht, nur nacheinander.

Gruß Tommy

Edit: @noiasca war schneller :wink:

constexpr uint8_t kanaele {2};
constexpr uint8_t miNums {10};

struct
{
  const uint8_t readPin;
  uint16_t value[miNums];
  uint8_t idx;

} sensors[kanaele] = {{A0, {0}, 0}, {A1, {0}, 0}};

uint8_t x;

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Start...."));
  fillData();
}

void loop()
{
  setData();
  Serial.println(getData(x));
  x++;

  if (x >= kanaele)
  { x = 0; }
  delay(100);
}

float getData(const uint8_t channel)
{
  uint16_t myValue = 0;

  for (byte b = 0; b < miNums; b++)
  {
    myValue += sensors[channel].value[b];
  }

  return (myValue / miNums) * (5.0 / 1023.0) * 6;
}

void setData()
{
  for (byte b = 0; b < kanaele; b++)
  {
    sensors[b].value[sensors[b].idx] = analogRead(sensors[b].readPin);
    sensors[b].idx++;

    if (sensors[b].idx >= miNums)
    { sensors[b].idx = 0; }
  }
}

void fillData()
{
  for (byte a = 0; a < kanaele; a++)
    for (byte b = 0; b < miNums; b++)
    {
      sensors[a].value[b] = analogRead(sensors[a].readPin);
    }
}

Mal ausprobieren...

void mittelwert( float Rohwert, float &mi, const float faktor)
{
  mi = ((faktor - 1)*mi + Rohwert) / faktor;
}
  mittelwert(Rohwert_A0, mwert_A0, 10);
  mittelwert(Rohwert_A1, mwert_A1, 10);

Moin @thomas1189 ,

und hier noch eine Lösung mit einer Klasse ...

/*
  Forum: https://forum.arduino.cc/t/mittelwert-mit-float/1387560
  Wokwi: https://wokwi.com/projects/433205260614079489

  Berechnung gleitender und gewichteter Mittelwert im Vergleich

  ec2021
  2025/06/08

*/

constexpr float messwertZuSpannung {(5.0 / 1023.0) * 6.0};
constexpr int   fenster  {10};

class AnalogClass {
  private:
    float gewichtet  = 0;
    float mittelwert = 0;
    unsigned long buff;
    uint16_t buffer[fenster];
    byte pin;
    int index = 0;
    void berechneGewichtetenMittelWert() {
      buff = buff - buff / fenster + buffer[index];
      gewichtet = buff / fenster * messwertZuSpannung;
    }
    void berechneGleitendenMittelWert() {
      unsigned long summe = 0;
      for (int i = 0; i < fenster; i++) {
        summe += buffer[i];
      }
      summe = summe / fenster;
      mittelwert = summe * messwertZuSpannung;
    };
  public:
    void init(byte aPin) {
      pin = aPin;
    };
    void messen() {
      buffer[index] = analogRead(pin);
      berechneGleitendenMittelWert();
      berechneGewichtetenMittelWert();
      index++;
      if (index >= fenster) {
        index = 0;
      }
    };
    float getGleitend() {
      return mittelwert;
    }
    float getGewichtet() {
      return gewichtet;
    }
};

byte analogPins[] = {A0, A1, A2};
constexpr int pinZahl = sizeof(analogPins) / sizeof(analogPins[0]);

AnalogClass wert[pinZahl];

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < pinZahl; i++) {
    wert[i].init(analogPins[i]);
  }
}

void loop() {
  for (int i = 0; i < pinZahl; i++) {
    wert[i].messen();
    Serial.print(wert[i].getGleitend());
    Serial.print("\t");
  }
  Serial.println();
  for (int i = 0; i < pinZahl; i++) {
    Serial.print(wert[i].getGewichtet());
    Serial.print("\t");
  }
  Serial.println();
  trennZeile();
  delay(100);
}

void trennZeile() {
  for (int i = 0; i < pinZahl; i++) {
    Serial.print("-------");
  }
  Serial.println();
}

Zum Ausprobieren und Erweitern auf Wokwi:

https://wokwi.com/projects/433205260614079489

Weitere Analog-Pins müssen nur in dieser Zeile ergänzt werden:

byte analogPins[] = {A0, A1, A2};

z.B.:

byte analogPins[] = {A0, A1, A2, A3, A4};

@my_xy_projekt hat in seinem Sketch einen gleitenden Mittelwert mit einem Fenster von miNums Breite umgesetzt. Du hast im Gegensatz dazu einen gewichteten Mittelwert programmiert. Die Klasse setzt beides parallel um.

Zu Deinem Algorithmus:

// Berechnung gleitender Mttelwert--------------
float mittelwert( float Rohwert, float &buff, float faktor)
{
  float mi ;
  buff = buff - buff / faktor;
  buff = buff + Rohwert;
  mi = buff / faktor;
  return mi;
}

Das lässt sich auch so schreiben:

buff = buff -buff/faktor+Rohwert

Mit faktor = 10 dann auch so:

buff = 0.9 * buff +Rohwert

Der Wert im Puffer buff ist stabil, wenn 0.9*buff == Rohwert 0.1*buff == Rohwert erreicht ist.
[Edit: Korrigiert, siehe Post 8]

Auf Wokwi lässt sich das zeitliche Verhalten bei einem Fenster von 10 Messwerten und dem Faktor 10 bei der Gewichtung vergleichen.

Gruß
ec2021

Sollte das 0.1*buff sein?

Hallo thomas1189

Ich habe auch noch einen Sketch, der sich einfach anpassen läßt, falls plötzlich doch noch ein zusätzlicher analoge EIngang um die Ecke kommt. :slight_smile:

//https://forum.arduino.cc/t/mittelwert-mit-float/1387560
#define ProjectName "Mittelwert mit float"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum Pots {One, Two};
// make variables
constexpr uint8_t Potentiometer[] {A0,A1};
constexpr uint16_t InitValue {512};
constexpr uint8_t NumberOfSamples {10};
constexpr float   Scaling {5.0 / 1024.0 * 6.0};
// make structures
struct MITTELWERT
{
  uint8_t   potentiometer;
  uint16_t  buffer[NumberOfSamples];
  uint8_t   index;
  void make(uint8_t potentiometer_, uint16_t initValue)
  {
    Serial.println(__func__);
    potentiometer = potentiometer_;
    for (auto &buff : buffer) buff = initValue;
    index = 0;
  }
  float exec()
  {
    buffer[index] = analogRead(potentiometer);
    index = (index + 1) % NumberOfSamples;
    uint16_t value = 0;
    for (auto &buff : buffer) value = value + buff;
    return ((float) value * Scaling / (float)NumberOfSamples);
  }
};
//-----------------------------------------
// make objects
MITTELWERT mittelWert[sizeof(Potentiometer)];
//-----------------------------------------
// make application
void setup()
{
  Serial.begin(115200);
  for (uint8_t n = 0; n < 32; n++) Serial.println("");
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  uint8_t element = 0;
  for (auto &mw : mittelWert)
  {
    mw.make(Potentiometer[element], InitValue);
    element++;
  }
  delay(2000);
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  Serial.print(F("Potentiometer 1 = ")), Serial.println (mittelWert[One].exec());
  Serial.print(F("Potentiometer 2 = ")), Serial.println (mittelWert[Two].exec());
  delay(500); // for testing only
}
//------

Du hast recht! Danke! (Oben korrigiert)!

Die Stabilität ergibt sich dann, wenn der Abzug vom bisherigen Puffer und der neue Rohwert identisch sind. Der Abzug ist natürlich 1/faktor*buff ...

Also, ganz grossen Dank an alle die hier mitgewirkt haben !!!!! Ich muss diesen Teil jetzt natürlich in mein Gesamtprojekt integrieren. Dies ist ein Solartracker der Linearmotoren antreibt. das Projekt an sich ist schon fertig. Das Problem ist jetzt, das es Verschattungen von Blättern an Bäumen gibt die die Sensoren verwirren und die Linearmotoren natürlich sofort reagieren.

Das soll doch bestimmt (5.0 / 1024.0) heißen?
Nicht weil es viel ausmacht, sondern weil es richtig ist.
Zudem stimmen die 5V nicht. Es ist immer mehr oder weniger.
An USB eher schwankende 4,5V

Grundregel:
Für absolute Messungen verwendet man eine externe oder interne Referenzspannung.
Für ratiometrische Messungen kann man sehr gut Vcc als Referenz verwenden.

Google suche zu "arduino uno v3 adc auflösung" egab:
"Beschreibung der Anschlüsse für den Arduino - Botland
Die Auflösung des ADC im Arduino beträgt 10 Bit. Das bedeutet, dass die Anzahl der Spannungsquantisierungsstufen am Eingang des Wandlers 1024 beträgt (nimmt Werte von 0-1023 an) und die Spannung mit einer Auflösung von 4,89mV gemessen wird.18.01.2023"

Woher soll ich das wissen, was der TO da rechnen will?
Bin ich wohl der falsche Adressat.

Richtig!
Wenn du einen Kuchen auf 6 Leute verteilen möchtest, dann musst du diesen auch durch 6 teilen, und nicht durch 5.

Zudem ist Atmel in seinen Datenblättern eindeutig!
Und die kennen sich schließlich mit ihrem eigenen ADC besser aus als vermutlich jeder von uns.

Nööö ....

0 (nul) bis 1023 ergibt 1024 stufen, und dein Beispiel mit dem Kuchen ist Unsinn.
Da du Immer recht hast beende ich die Diskussion.

Wieso?

Ich kann den Nachweis führen, dass Vref/1024 richtig ist!
Kannst du das Gegenteil nachweisen?

Natürlich ist es auch möglich, dass du schlauer bist, als die Atmel Entwickler.
Ich bin es nicht.

Stimmt, hat mich nicht getriggert, da der Fehler im vernachlässigbaren Bereich liegt ... (und ich mich auf die Mittelwertberechnung fokussiert hatte...)

@fony: 1024 ist schon der korrekte Teiler. Wenn Du Deine Küchenstücke mit 0 beginnend numerierst und das letzte Stück die Nummer 15 hat, hast Du 16 Stücke ... Es sei denn, jemand vernascht schon eines, bevor Du fertig bist. Deshalb besser den Zugriff auf die Torte sperren, bis Du fertig bist mit Schneiden und Zählen... :wink:

Hier noch eine Quelle zum Nachlesen bzgl. der erreichbaren Genauigkeiten und der von @combie bereits erwähnten Abhängigkeit von der Referenz:

https://42project.net/praezise-analoge-spannungsmessungen-mit-dem-arduino-anhand-einer-referenzspannung-messen/

Für Anwendungen mit geringen Genauigkeitsanforderungen oder dort, wo es nur um relative Spannungsdifferenzen geht, wird das kaum benötigt, aber es schadet nicht, es zu wissen ... :wink:

Ich führe mal den Nachweis:

Dabei verwende ich:

  1. Uref die Referenzspannung
  2. N die Anzahl Intervalle
  3. Ud das Spannungsintervall zwischen 2 Schaltschwellen

Es stehen hier 2 "Formeln" zur Debatte:

  1. Uref / N = Ud
  2. Uref / (N -1) = Ud

Angenommen: Uref = 5V

N = 1024 (10 Bit ADC)

5/1024 = 4,882mv
5/1023 = 4,887mv
Der Unterschied mag gering erscheinen.
Er wird größer je kleiner man N macht

Der extrem Fall:
N = 2 (1 Bit ADC)

5/2 = 2,5V
5/1 = 5V

Eine Schaltschwelle bei 2,5V ist genau das, was man bei einem 1 Bit ADC erwarten muss.

Der Autor ist nicht wirklich konsequent!

Einerseits zeigt er die richtige Formel aus dem Datenblatt und andererseits verwendet er die 1023 im Code.
Das bestätigt wieder:
Aufmerksam lesen, Wach sein.