Median von 600 Werten

Hallo Leute,

ich stehe gerade vor einen Verständnisproblem.

Ich möchte mit dem Arduino Mega Druckdaten aufnehmen.
Nach einer vorgegebenen Zeit soll der Druck mit 1Hz über 10 Minuten aufgezeichnet werden und schließlich daraus der Median gebildet werden. Das ganze soll möglichst schnell ablaufen.

Habe mir jetzt mal die Library RunningMedian.h (Arduino Playground - RunningMedian) runtergeladen aber diese noch nicht ganz verstanden.
Zum test habe ich einfach ein Poti an A0 angeklemmt und mir das ganze auf ein Display anzeigen lassen. Jedoch wird der Median nicht über 600 Werte genommen sondern von keine Ahnung wie vielen.
Kann mir jemand helfen was ich wo ändern muss, um meinen Median über eine beliebige Anzahl an Werten zu berechnen?

#include <RunningMedian.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#define MEDIAN_SIZE 600

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

RunningMedian samples = RunningMedian(600);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print("Verstrichene Zeit [s]: ");
  Serial.print("\t");
  Serial.println("Spannung Drucksensor: ");
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.backlight(); // finish with backlight on

}

float SpDrSe;
float DruckMittel = 0;
float sum = 0;
float DruckArr[10];
float DruckMedian[600];
int k =0;
float p=0;




void loop() {
  for (int k = 0; k < 600; k++) {
    // put your main code here, to run repeatedly:
    float t = millis() / 1000.00;
    int DruckSensor = analogRead(A0);

    SpDrSe = 5.000 * DruckSensor / 1024.000; //Spannung Drucksensor
    

    for (int i = 0; i < 10; i++) {
      DruckArr[i] = 5.000 * analogRead(A0) / 1024.000; // Mittelwert über 10 Werte bilden
      delay(10);                                 // Abtastung mit 10 Hz
    }

    for (int j = 0; j < 10; j++) {
      sum = sum + DruckArr[j];                  // Mittelwert berechnen
    }
    DruckMittel = sum / 10;                     // Mittelwert berechnen
    p= DruckMittel * 41/10;

    // LCD Display
lcd.setCursor(0,0);
lcd.print("Spannung = ");
lcd.setCursor(11,0);
lcd.print(DruckMittel,3);
lcd.setCursor(17,0);
lcd.print("V");

lcd.setCursor(0,1);
lcd.print("Druck: ");
lcd.setCursor(7,1);
lcd.print(p,3);


lcd.setCursor(0,2);
lcd.print("Zeit = ");
lcd.setCursor(7,2);
lcd.print(t);
lcd.setCursor(14,2);
lcd.print("s");



    
    sum = 0;
    samples.add(DruckMittel);
    float m = samples.getMedian();
    DruckMedian[k]=DruckMittel;
    
    Serial.print(t);
    Serial.print("\t");
    Serial.print(DruckMittel, 4);
    Serial.print("\t");
    Serial.println(m,2);
    
    
    
    if (k == 599){
    Serial.println("Median ueber 600 Werte: ");
    Serial.println(DruckMedian [k]);
    
    k=0;
   lcd.clear();
   lcd.setCursor(0,3);
   lcd.print("Median600: ");
   lcd.setCursor(11,3);
   lcd.print(m,2);
    }
    }

  }

Du kennst den Unterschied zwischen Mittelwert und Median?

Für den Median brauchst Du einen Arduino mit genügend RAM, um die benötigten Werte zu speichern.

Ja kenne ich. Und ich benötige aber den Median. Der Mega genügend Ram.

github.com/RobTillaart:
RunningMedian(const uint8_t size);

RunningMedian(600) ist wohl nicht so ganz passend.
Wird vermutlich effektiv einenRunningMedian(88)ergeben.

Oder mit anderen Worten, die Lib ist nur bis 255 Werte geeignet. Wenn du mehr verarbeiten willst, musst du ausprobieren, ob sie nach ersetzen mit uint16_t wie gewünscht funktioniert. Dann ist die Zahl der Elemente praktisch nur durch die Ram-Größe begrenzt.

600 * 4 Byte = 2400 Byte nur für das Array. Da wird es wohl mindestens ein MEGA werden müssen.

Gruß Tommy

Hi

Was heißt 'möglichst schnell' bei einer Wartezeit von 10 Minuten?

Wenn Du nur diese eine Aufzeichnung brauchst und KEINEN runningMedian - reichen Dir 300 Werte im Speicher.

Array mit 300 Elementen nullen
Bei jedem Messwert von der Mitte beginnen und prüfen, ob

  • die aktuelle Stelle 0 ist -> Messwert dort eintragen, fertig
  • die aktuelle Stelle > dem Messwert ist --> eine Stelle nach unten --> sind wir bereits an Stelle 0, ALLE Stellen 1x nach oben schieben, Messwert an Stelle 0 eintragen
    ... Gleiches, bei < dem Messwert in entgegen gesetzter Richtung

So 'wandern' die kleinen Messwerte nach links, die Großen nach Rechts.
ALLES, was größer als der 300.ste Messwert ist, wird verworfen, da eh 'zu weit rechts'.

Nach 600 Messwerten sollte der Median an unserer Stelle 300 stehen (bzw. Mittelwert zw. 299 & 300).

Da dir Sortiererei während der Aufnahme geschieht (alle Sekunde), hast Du nach Ende der Messung als einzige Warterei das Auslesen des Wertes an Stelle 300 - sollte man mit leben können.

MfG