Sprunghafte Werte

Moderator: RevPiModIO

Post Reply
troll100
Posts: 31
Joined: 08 Jan 2020, 11:46

Sprunghafte Werte

Post by troll100 »

Hallo,
ich versuche über ein AIO Modul einen Temperaturverlauf möglichst genau aufzunehmen.
Allerdigs sind meine Werte sehr sprunghaft obwohl ich schon die geringste Zykluszeit eingesellt habe. Gibt es eie möglichkeit den Verlauf noch genauer darzustellen ?

Code: Select all

import revpimodio2
import threading
import time
import csv
import pandas

rpi=revpimodio2.RevPiModIO(autorefresh=True)
temp=[]
class RTDDemo():
    def ___init__(self):
       self.rpi = revpimodio2.RevPiModIO(autorefresh=True) 
        self.rpi.handlesignalend()
        self.cycleloop(self.cycle)
          

    def cycle(self):
       
        value = [rpi.io.RTDValue_1.value]
        Gradcelsius = value    
        print(Gradcelsius)
        return Gradcelsius
        #print("RTDValue_1:{}".format(Gradcelsius)+"°C")



if __name__ == "__main__":
    app=RTDDemo()

rpi.cycletime=5
t_end =time.time()+ 1*10 #(sec,min)


def save_data(temperature):
    append=[temperature]
    with open('/home/pi/Pt100/sensordaten.csv', 'a') as csvFile:
        writer= csv.writer(csvFile)
        writer.writerow(append)
        
    csvFile.close()
    
while time.time()< t_end:
    save_data(RTDDemo().cycle())
print("datastored")
User avatar
RevPiModIO
KUNBUS
Posts: 335
Joined: 20 Jan 2017, 08:44
Contact:

Re: Sprunghafte Werte

Post by RevPiModIO »

Moin Troll100!

Prüfe doch mal bitte deine Einstellung vom AIO Modul in piCtory! Da gibt es einen MEM-Wert "ADC_DataRate", der steht im default auf 5Hz = 200ms. Das AIO Modul erzeugt dann nur alle 200ms neue Werte, die dann über den RevPi / im Prozessabbild verfügbar sind! Den würde ich auf max 80 Hz setzen, da die piBridge eh nicht wirklich schneller ist und du Geschwindigkeit gegen Genauigkeit eintauscht.

Das müsste eigentlich deine Sprünge erklären. Ich hatte das mit einem Poti, welches der Benutzer dreht und ein Bild auf der Visualisierung verschiebt, das war auch sehr stockend (logischerweise) aber nach der Änderung im MEM war alles gut :D

PS: Der Quelltext ist momentan etwas "zerfallen", da du damit experimentierst, richtig?

Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
troll100
Posts: 31
Joined: 08 Jan 2020, 11:46

Re: Sprunghafte Werte

Post by troll100 »

Grüße Sven,
Prüfe doch mal bitte deine Einstellung vom AIO Modul in piCtory! Da gibt es einen MEM-Wert "ADC_DataRate", der steht im default auf 5Hz = 200ms. Das AIO Modul erzeugt dann nur alle 200ms neue Werte, die dann über den RevPi / im Prozessabbild verfügbar sind! Den würde ich auf max 80 Hz setzen, da die piBridge eh nicht wirklich schneller ist und du Geschwindigkeit gegen Genauigkeit eintauscht.

Das müsste eigentlich deine Sprünge erklären. Ich hatte das mit einem Poti, welches der Benutzer dreht und ein Bild auf der Visualisierung verschiebt, das war auch sehr stockend (logischerweise) aber nach der Änderung im MEM war alles gut
Habe ich gemacht, war tatsächlich auf 5 Hz; Habe ich es nun auf 80 Hz gestellt; die pictory config. gespeichert und dann den Treiber zurück gesetzt; bekomme nun etwas weniger sprunghafte werte;allerdings gibt "piTest -r ADC_DataRate " nur "4 dez" aus... Müsste doch eigentlich 80 dez anzeigen...
Ich solle hier vielleicht noch erwähnen, dass ich die Temperaturveränderung eines Prozesses überwache der maximal 2,5 Sekunden geht die Temperaturen springen hier schlagartig auf bis zu 120 °C. Das Startsignal zur Temperaturmessung Trigger ich hierbei über ein DIO Modul. - Das sollte der Connect doch eigentlich ohne Probleme schaffen oder ?

Code: Select all

import revpimodio2
import csv

class RTDDemo():
    def __init__(self):
        self.rpi = revpimodio2.RevPiModIO(autorefresh=True)
        self.rpi.handlesignalend()
        self.rpi.cycleloop(self.cycle)

    def cycle(self, ct):
        # read value of RTDValue_1 
        value = self.rpi.io.RTDValue_1.value
        print("{}".format(value))
        return value
        # print value to stdout
        
    def trigger(self, ct):
        us_on=self.rpi.io.I_1.value
        return us_on 

    def save_data(temperature):
        append=[temperature]
        with open('/home/pi/Pt100/sensordaten.csv', 'a') as csvFile:
            writer= csv.writer(csvFile)
            writer.writerow(append)
        csvFile.close()
    
if __name__ == "__main__":

    app=RTDDemo()

 while True:
    if app.trigger(5)==True:
        save_data(app.cycle(5))
        #print('1')
        if app.trigger(5)==False:
            save_data(app.cycle(5))
            #print('2')
            if app.trigger(5)==True:
                save_data(app.cycle(5))
                #print('3')
                if app.trigger(5)==False:
                    print('off')
                    break
                       
Das ist mein vorläufiger Code der die Temperaturen von meinem AIO Modul in eine CSV speichert, sobald das DIO Modul die Sequenz:

Code: Select all

True
True
True
False
False
False
False
True 
True
True 
True
ausgibt; - allerdings bricht die schleife nicht ab wenn nach dem letzen True das False kommt... weißt du vielleicht wieso ?

Und nochwas; ich bekomme immer eine

Code: Select all

RuntimeWarning: cycletime of 20 ms exceeded several times- can not hold cycle time !
- Ich habe doch nirgends eine Z.z von 20 ms eingestellt.

Besten Dank für den Support ! Ihr macht einen super Job !
User avatar
RevPiModIO
KUNBUS
Posts: 335
Joined: 20 Jan 2017, 08:44
Contact:

Re: Sprunghafte Werte

Post by RevPiModIO »

Moin troll100!

Da müssen wir dein Programm noch deutlich optimieren. Mit der piBridge kommen wir mit Glück auf 10ms Zykluszeit, das schaffen wir mit dem Python-Programm auch, aber nicht in der Form. Wir müssen die Daten im Zyklus sammeln und erst später schreiben, das Schreiben verbraucht zu viel Zeit im Zyklus, daher auch die Warnung mit den 20ms!

Ich würde das Programm mal etwas optimieren und hier posten. Ich muss mal schauen, ob ich heute noch dazu komme, sonst Sonntagabend!

Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
troll100
Posts: 31
Joined: 08 Jan 2020, 11:46

Re: Sprunghafte Werte

Post by troll100 »

Hallo Sven,
danke für die schnelle Rückmeldung! - Ja, habe ich mir schon fast gedacht, dass da noch Optimierungsbedarf besteht...
Wow super ! - Klar, dass stresst hier nicht.
Vielen Dank !
Gruß, troll100
User avatar
RevPiModIO
KUNBUS
Posts: 335
Joined: 20 Jan 2017, 08:44
Contact:

Re: Sprunghafte Werte

Post by RevPiModIO »

Hi troll100!

Ich habe jetzt mal einen Code vorbereitet, der sich den 80 Hz vom AIO mit einer Zykluszeit von 13 Millisekunden annähert. Damit solltest du das beste Ergebnis erzielen.

Der Code hat nun keine Ausgaben mehr auf der Konsole. Wenn er gestartet wird, wartet er auf den I_1 Input. Wenn der kommt, dann sammelt das System 2.5 Sekunden lang (der Wert kann ganz unten bei "measure_time=2.5" eingestellt werden) die Werte vom RDTValue_1. Den Wert und einen einfachen Timestamp übergibt die Zyklusfunktion in eine Queue. Damit ist die Funktion relativ schnell und sollte die Zykluszeit einhalten können, damit die RuntimeWarnings ausbleiben.
Ein anderer Thread in dem Programm (writer_thread) arbeitet parallel zur Zyklusfunktion und ist für das Auslesen der Daten aus der Queue, das Formatieren und das eigentliche schreiben verantwortlich. Er nimmt sich einen Wert aus der Queue, bereitet Datum und Uhrzeit bis zur Mikrosekunde vor und schreibt einen Zeile in die CSV Datei. Diese Vorgänge brauchen "viel" Rechenzeit und würden unsere Zyklusfunktion sehr langsam machen - Dementsprechend kommen RuntimeWarnings und wir "verpassen" im schlimmsten Fall sogar Werte.

Klar kann es nun passieren, dass der Thread nicht "hinterher" kommt, da sich ja Zyklusfunktion und Thread die Rechenzeit teilen müssen, aber das macht in der Hinsicht nichts, da er nach einer Messung ja etwas länger Zeit hat um seine Arbeit zu erledigen :D

PS: Der Code in der Zyklusfunktion schaut auf die Flanke von I_1, wenn I_1 auf True wechselt, wird die Messung sofort gestartet. Während oder nach der Messung muss I_1 einmal den Status False annehmen, bevor ein weiteres True Signal eine weitere Messung startet.

Code: Select all


# -*- coding: utf-8 -*-
"""Measure values for a defined time and save to CSV."""
__author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2020 Sven Sager"
__license__ = "GPLv3"

import csv
from datetime import datetime
from queue import Queue
from threading import Thread
from time import time

import revpimodio2


class RTDDemo():
    """Measure RTD values for a defined time."""

    def __init__(self, measure_time: float, file_name: str):
        """
        Measure RTD values for a defined time on trigger.

        :param measure_time: Time in seconds
        """
        self._revpi_cycletime = 13

        # Amount of cycles to measure on trigger
        self.measure_cycles = int(measure_time * 1000 / self._revpi_cycletime)

        # Thread and queue to write CSV file
        self.file_name = file_name
        self.q = Queue()
        self.th = Thread(target=self.writer_thread)

        # RevPi with cleanup function
        self.rpi = revpimodio2.RevPiModIO(autorefresh=True)
        self.rpi.handlesignalend()

    def cycle(self, ct):

        # Init cycle tools with variables
        if ct.first:
            ct.var.counter = 0
            ct.var.running = False
            ct.var.mrk_input = False

        # Value changed on input to start measurement
        if not ct.var.mrk_input and self.rpi.io.I_1.value:
            # Save value to get the edge of input
            ct.var.mrk_input = True

            # Activate measurement
            ct.var.counter = 0
            ct.var.running = True

        # Start the work in the same cycle as input was triggered
        if ct.var.running:
            ct.var.counter += 1

            # Collect value and put to queue
            self.q.put_nowait((time(), self.rpi.io.RTDValue_1.value))

            if ct.var.counter == self.measure_cycles:
                # End collecting values on next cycle
                ct.var.counter = 0
                ct.var.running = False

        elif not self.rpi.io.I_1.value:
            # Reset marker to get the next edge of input after measurement only
            ct.var.mrk_input = False

    def start(self):
        """Start the cycle work"""
        self.th.start()
        self.rpi.cycleloop(self.cycle, cycletime=self._revpi_cycletime)

        # Tell thread to shutdown and wait
        self.q.put_nowait(None)
        self.th.join()

    def writer_thread(self):
        """Thread to write values to CSV file."""
        csv_fh = open(self.file_name, "a")
        csv_writer = csv.writer(csv_fh)

        # If this is the beginning of csv, write header
        if csv_fh.tell() == 0:
            csv_writer.writerow([
                "year", "month", "day",
                "hour", "minute", "second", "microsecond",
                "value"
            ])

        # Mainloop of this thread
        while True:
            value = self.q.get()
            if value is not None:
                # We got a value from cycle function

                # Process date time and the value in this thread, not in cycle function
                dt = datetime.fromtimestamp(value[0])
                csv_writer.writerow([
                    dt.year, dt.month, dt.day,
                    dt.hour, dt.minute, dt.second, dt.microsecond,
                    value[1]
                ])

                # Optional to write data immediately to disk
                csv_fh.flush()

            else:
                # Cleanup function requested us to stop
                break

        # Close CSV file
        csv_fh.close()


if __name__ == "__main__":
    app = RTDDemo(
        measure_time=2.5,
        file_name="/home/pi/Pt100/sensordaten.csv"
    )
    app.start()


Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
Post Reply