Median in Script mit ausgeben

Code-Stücke können hier veröffentlicht werden.
Antworten
Chronos81
User
Beiträge: 8
Registriert: Dienstag 2. Februar 2021, 15:58

Hallo zusammen,

ich habe ein Python Script laufen, welches zu bestimmten Zeiten ausgeführt wird und mit Hilfe eines Ultraschallsensors den Füllstand eines Heizöltanks misst.
Da es hier gewisse Unschärfen bei der Entfernungsermittlung gibt, lasse ich im Script eine Methode mehrmals ausführen und hole mir dann von den Werten den Mittelwert und verwende diesen im Folgenden (Wert Distance)
Allerdings gibt es hier einige Ausreißer und mir erscheint die Verwendung des Medians hier sinnvoller als die Mittelwertmethode. Leider bin ich was Python angeht eher ein Neuling. (Viel youtube, copypaste sowie Try&Error)
Ich habe zwar schon etwas mit dem Code herumgespielt bekomme aber keine brauchbaren Ergebnisse (Sprich code nicht ausführbar) unexpected unindent...

Eventuell könnt ihr mir hier einen kurzen Tipp geben wie ich den Median für Distance berechnen und ausführen kann. Im Idealfall als zusätzliche Variable. Ich danke euch bereits im Vorraus.

Code: Alles auswählen

  
#!/usr/bin/env python
# -*- coding: utf-8 -*-


# import required modules
import time
import datetime
import RPi.GPIO as GPIO


# define GPIO pins
GPIO.setwarnings(False)
GPIOTrigger = 18
GPIOEcho    = 17


# function to measure the distance
def MeasureDistance():
  # set trigger to high
  time.sleep(10.0)
  GPIO.output(GPIOTrigger, True)


  # set trigger after 10Â µs to low
  time.sleep(0.000001)
  GPIO.output(GPIOTrigger, False)


  # store initial start time
  StartTime = time.time()


  # store start time
  while GPIO.input(GPIOEcho) == 0:
    StartTime = time.time()


  # store stop time
  while GPIO.input(GPIOEcho) == 1:
    StopTime = time.time()


  # calculate distance
  TimeElapsed = StopTime - StartTime
  Distance = (TimeElapsed * 34400) / 2

  return Distance


# main function
def main():
  try:
#    while True:
      Distance0 = MeasureDistance()
      Distance01 = MeasureDistance()
      Distance02 = MeasureDistance()
      Distance03 = MeasureDistance()
      Distance04 = MeasureDistance()
      Distance05 = MeasureDistance()
      Distance06 = MeasureDistance()
      Distance07 = MeasureDistance()
      Distance08 = MeasureDistance()
      Distance09 = MeasureDistance()
      Distance10 = MeasureDistance()
      Distance11 = MeasureDistance()
      Distance12 = MeasureDistance()
      Distance13 = MeasureDistance()
      Distance14 = MeasureDistance()
      Distance15 = MeasureDistance()
      Distance16 = MeasureDistance()
      Distance17 = MeasureDistance()
      Distance18 = MeasureDistance()
      Distance19 = MeasureDistance()
      Distance20 = MeasureDistance()
      Distance21 = MeasureDistance()
      Distance22 = MeasureDistance()
      Distance23 = MeasureDistance()
      Distance24 = MeasureDistance()
      Distance25 = MeasureDistance()
      Distance26 = MeasureDistance()
      Distance27 = MeasureDistance()
      Distance28 = MeasureDistance()
      Distance29 = MeasureDistance()
      Distance30 = MeasureDistance()
      Distance31 = MeasureDistance()
      Distance32 = MeasureDistance()
      Distance33 = MeasureDistance()
      Distance34 = MeasureDistance()
      Distance35 = MeasureDistance()
      Distance36 = MeasureDistance()
      Distance37 = MeasureDistance()
      Distance38 = MeasureDistance()
      Distance39 = MeasureDistance()
      Distance40 = MeasureDistance()
      Distance_sum = Distance01 + Distance02 + Distance03 + Distance04 + Distance05 + Distance06 + Distance07 + Distance08 + Distance09 + Distance10 + Distance11 + Distance12 + Distance13 + Distance14 + Distance15 + Distance16 + Distance17 + Distance18 + Distance19 + Distance20 + Distance21 + Distance22 + Distance23 + Distance24 + Distance25 + Distance26 + Distance27 + Distance28 + Distance29 + Distance30 + Distance31 + Distance32 + Distance33 + Distance34 + Distance35 + Distance36 + Distance37 + Distance38 + Distance39 + Distance40
      Distance = round(Distance_sum / 40,1)
#    Meine Tanks haben Maximal 6000 Liter bei 153 cm Füllhöhe
#    Zusätzlich 1 cm Offset vom Einbauort des Sensors
      Fuellstand = 156.5 - Distance
      Liter = 6000 / 151 * Fuellstand
      Prozent = Fuellstand / 151 * 100
      Zeit = time.time()
      ZeitStempel = datetime.datetime.fromtimestamp(Zeit).strftime('%Y-%m-%d_%H:%M:%S')
      print (ZeitStempel), ("%.1f" % Fuellstand),("%.0f"  % Liter), ("%.0f" % Prozent)
      #("Entfernung: %.1f cm" % Distance), 
      time.sleep(2)


  # reset GPIO settings if user pressed Ctrl+C
  except KeyboardInterrupt:
    print("Measurement stopped by user")
    GPIO.cleanup()


if __name__ == '__main__':
  # use GPIO pin numbering convention
  GPIO.setmode(GPIO.BCM)


  # set up GPIO pins
  GPIO.setup(GPIOTrigger, GPIO.OUT)
  GPIO.setup(GPIOEcho, GPIO.IN)


  # set trigger to false
  GPIO.output(GPIOTrigger, False)


  # call main function
  main()

 
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Python2 sollte man nicht mehr benutzen, das ist veraltet, benutze Python3.
`as` bei `import` ist zum Umbenennen da, GPIO wird aber gar nicht umbenannt, das `as` also unsinnig.
Warnungen sind dazu da, dass man sie behebt, nicht dass man sie ignoriert. Dazu muß aber GPIO.cleanup verlässlich aufgerufen werden, nicht nur bei Strg+C, was bei Dir ja eigentlich nicht auftritt.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht 2. Variablennamen und Funktionen werden komplett klein geschrieben.
Statt Variablen durchzunummerieren möchtest Du eine Liste benutzen, und statt die selbe Funktion 41 mal untereinander zu schreiben eine Schleife.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import datetime
import RPi.GPIO as GPIO

# define GPIO pins
TRIGGER_PIN = 18
ECHO_PIN    = 17


# function to measure the distance
def measure_distance():
    # set trigger to high
    time.sleep(10.0)
    GPIO.output(TRIGGER_PIN, True)
    # set trigger after 10Â µs to low
    time.sleep(0.000001)
    GPIO.output(TRIGGER_PIN, False)

    # store start time
    while GPIO.input(ECHO_PIN) == 0:
        pass
    start_time = time.time()

    # store stop time
    while GPIO.input(ECHO_PIN) == 1:
        pass
    stop_time = time.time()

    # calculate distance
    time_elapsed = stop_time - start_time
    distance = (time_elapsed * 34400) / 2
    return distance


def initialize():
    # use GPIO pin numbering convention
    GPIO.setmode(GPIO.BCM)

    # set up GPIO pins
    GPIO.setup(TRIGGER_PIN, GPIO.OUT)
    GPIO.setup(ECHO_PIN, GPIO.IN)

    # set trigger to false
    GPIO.output(TRIGGER_PIN, False)

def main():
    try:
        _ = measure_distance()
        distances = [measure_distance() for _ in range(40)]
        mean_distance = sum(distances) / len(distances)
        #    Meine Tanks haben Maximal 6000 Liter bei 153 cm Füllhöhe
        #    Zusätzlich 1 cm Offset vom Einbauort des Sensors
        fuellstand = 156.5 - mean_distance
        liter = 6000 / 151 * fuellstand
        prozent = fuellstand / 151 * 100
        print(f"{datetime.datetime.now():%Y-%m-%d_%H:%M:%S} {fuellstand:.1f} {liter:.0f} {prozent:.0f}")
        time.sleep(2)
      except KeyboardInterrupt:
        print("Measurement stopped by user")
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Den Median berechnet man am einfachsten, indem man die Liste mit den Distanzen sortiert und dann den mittleren Eintrag nimmt.

Code: Alles auswählen

median_distance = sorted(distances)[len(distances)//2]
Chronos81
User
Beiträge: 8
Registriert: Dienstag 2. Februar 2021, 15:58

Hallo Sirius3,

vielen Dank für deinen Hinweis, sowie für deinen bearbeiteten Code. Danke auch mit dem Hinweis auf Python3.

Allerdings habe ich nun Probleme mit den GPIO Settings bzw. mit dem Cleanup:

Hier die Fehlermeldung nachdem ich das Programm aufrufe:



pi@pizisterne:~ $ ./median.py
./median.py:64: RuntimeWarning: No channels have been set up yet - nothing to clean up! Try cleaning up at the end of your program instead!
GPIO.cleanup()
Traceback (most recent call last):
File "./median.py", line 68, in <module>
main()
File "./median.py", line 51, in main
_ = measure_distance()
File "./median.py", line 17, in measure_distance
GPIO.output(TRIGGER_PIN, True)
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)




So und jetzt bin ich überfragt :-(

Könntest du mir bitte nochmals unter die Arme greifen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du den Code gelesen hast, mußt Dir aufgefallen sein, dass initialize gar nicht aufgerufen wird:

Code: Alles auswählen

def main():
    initialize()
    ...
Chronos81
User
Beiträge: 8
Registriert: Dienstag 2. Februar 2021, 15:58

Hallo Sirius,
danke dir. ich habe es jetzt soweit hinbekommen.
War zu blind zu sehen dass die Methode nicht aufgerufen wurde.
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Den Median kann man auch mit "statistics.median" aus der Standardbibliothek von Python berechnen. Der Unterschied zur von Sirius3 gezeigten Methode (die statistics.median_high entspricht) besteht im Umgang mit einer geraden Anzahl von Elementen; in dem Fall wird das arithmetische Mittel gebildet.

Code: Alles auswählen

In [1]: from statistics import median

In [2]: l = [1, 2, 3, 4, 5, 6]

In [3]: median(l)
Out[3]: 3.5

In [4]: sorted(l)[len(l)//2]
Out[4]: 4
Antworten