Wie man Sensorwerte bei hoher Frequenz liest und akkumuliert, ohne ständig auf die Festplatte zu schreiben (RPi 2 b +, MCP3304, Python)

Ich versuche, ein Himbeer-Pi 2-Modell B + zu verwenden, um analoge Daten auf IR-Intensität von einer Photodiode über einen MCP3304 (5v VDD) mit einer Rate von ~ 10kHz dreimal in einer Reihe (0,1 ms zwischen den Messungen oder einer Rate von 10 zu lesen Ksps) einmal jede Sekunde basierend auf einem externen Reiz, durchschnittlich diese Werte, dann schreiben sie an eine Textdatei zusammen mit der aktuellen datetime. Die Photodiode liest einfach Daten an einen Verstärker aus, der dann in den MCP3304 einfließt, der über SPI Daten in den RPi speist. (Im Wesentlichen erhält RPi einen digitalen Eingang, der drei aufeinanderfolgende Samples von der Photodiode über einen MCP3304 und einen Inline-Signalverstärker auslöst. Diese drei Samples werden im Speicher gespeichert, gemittelt und dann auf die Festplatte zusammen mit einem datetime Stempel auf eine bestehende CSV geschrieben Textdatei.) Das ist alles auf Python 2.7.

Wie es steht, bekomme ich eine Sampling von <1kHz mit dem untenstehenden Code (SensorRead ()). Ich bin sehr neu in Python (und mit Sensoren & RPis spielen, für diese Angelegenheit!), Und denke, wie ich meine Klasse eingerichtet habe, um drei separate, aufeinander folgende ADC-Samples zu nehmen und eventuell mein Setup für das Schreiben auf Festplatte kann mich verlangsamen Unten Allerdings kann ich nicht ganz einen besseren Weg finden. Edit1: Ich habe ein gutes bisschen Forschung über maximale Sampling-Raten über Python aus dem RPi GPIO gemacht und es scheint deutlich über die ADC-Einschränkung bei ~ 1MHz oder ~ 1000 ksps (zB 1 , 2 ) zu sein. Edit2: Vielleicht bezieht sich die ADC max Sample Rate von 100 ksps eigentlich auf, wie viele Bits gelesen werden können, anstatt wie viele volle 12-Bit-Samples pro Sekunde genommen werden können?

  • Das Abrufen von Binärdateiinhalten mithilfe von Javascript, Base64 kodiert es und umgekehrt decodiert es mit Python
  • Jep. Das war's. Der MCP3304 kann 100ksps machen, aber die Python-Leserate liegt näher bei 30ksps, die bei der Aufteilung zwischen den 24-Bits, die vom MCP3304 pro Iteration gelesen wurden, näher bei 1ksps liegt

    Meine beiden Fragen:
    1) Gibt es noch bessere Möglichkeiten, näher an die volle 100 ksps zu kommen, die im MCP3304-Spezifikationsblatt angekündigt werden? Dieser Link schlägt vor, dass WiringPi jedes Mal, wenn ich eine einzelne Probe nehmen möchte, eine beträchtliche Latenz verursachen kann.

    und

    2) ist es möglich, mit einem Anfänger / moderaten Level von Python Geschick für mich alle diese Sampling und pro Sekunde Mittelwert im Speicher zu tun, und nur auf Festplatte schreiben, sagen, einmal pro Minute? Bearbeiten: Können Sie mir bitte in die Richtung einiger verwandter Links / Ressourcen verweisen?

    Vielen Dank!

    Anmerkung 1: Der Code ist "Threaded", da es einige andere Funktionen gleichzeitig gibt. Anmerkung 2: Ich bin auch gleichzeitig das Lesen eines Differentialkanals auf dem ADC, also das "differential = True" im MCP3304 Befehl

    ''' FILENAME = "~/output_file_location/and/name.txt" adc_channel_pd = pin of the ADC from which analog signal is taken stimulus_in_pin = the the pin that receives the alert to begin sampling stimulus_LED_alert_pin = pin that goes "high" to illuminate an LED every time the stimulus_in_pin is triggered Vref = the reference voltage for the ADC (3.3v; VDD = 5V) ''' # import packages import wiringpi2 as wiringpi import time from gpiozero import MCP3304 import threading import datetime # Define important objects Vref = 3.3 adc_channel_pd = 7 stimulus_in_pin = 32 stimulus_LED_alert_pin = 16 # establish GPIO reading structure wiringpi.wiringPiSetupPhys() # set appropriate pin inputs and outputs (0 = input, 1 = output) wiringpi.pinMode(stimulus_in_pin, 0) wiringpi.pinMode(stimulus_LED_alert_pin, 1) # create a class to take 3 PD readings, then average them, immediately upon stimulus class SensorRead(threading.Thread): def __init__(self): super(SensorRead, self).__init__() self.daemon = True self.start() def run(self): for i in itertools.count(): if (wiringpi.digitalRead(stimulus_in_pin) == True): val_ir_1 = MCP3304(adc_channel_pd, True).value * Vref) val_ir_2 = MCP3304(adc_channel_pd, True).value * Vref) val_ir_3 = MCP3304(adc_channel_pd, True).value * Vref) voltage_ir = round( (float( (sum([val_ir_1,val_ir_2,val_ir_3])) / 3)) , 9) dt_ir = '%s' % datetime.datetime.now() f = open(FILENAME, "a") f.write("IR Sensor," + dt_ir + "," + str(voltage_ir) + "\n") f.close() # print to terminal so I can verify output in real time print "IR Sensor:", dt_ir,",",voltage_ir # blink ir light on board for visual verification of stimulus in real time wiringpi.digitalWrite(stimulus_LED_alert_pin, 1) time.sleep(0.5) wiringpi.digitalWrite(stimulus_LED_alert_pin, 0) # sleep to avoid noise post LED firings time.sleep(0.5) # run class SensorRead() 

    Bearbeiten: Ich habe am Ende ein paar tolle Ergebnisse mit Cython, wie in diesem Test-Code gezeigt, ich schrieb zu quantifizieren, wie schnell konnte ich meinen ADC lesen . Ich habe auch meine eigene Funktion geschrieben, um aus dem MCP3304 zu lesen – was ich verknüpfen werde, sobald es alles sauber ist -, dass ich in Cython weiter optimieren konnte.

  • Python Lambda Verschluss Scoping
  • Pythonschliessen + oop
  • Kannst du Verschlüsse erklären (wie sie sich auf Python beziehen)?
  • Python schließen lokale Variablen
  • Ändern Sie die Variablen eines Verschlusses in Python
  • One Solution collect form web for “Wie man Sensorwerte bei hoher Frequenz liest und akkumuliert, ohne ständig auf die Festplatte zu schreiben (RPi 2 b +, MCP3304, Python)”

    Ein Punkt über Ihre Frage. Drei Samples in einer Sekunde ist eine Rate von 3Hz nicht 100kHz. Klingt für mich wie, was du willst, ist drei Samples auseinander.

    1) 10us Probe Zeitraum auf MCP3304 mit Pi mit Linux? Vielleicht nicht. Mach ein paar suchen Siehe z. B. https://raspberrypi.stackexchange.com/questions/45386/microphone-via-spi wo eine Antwort sagt sie erreichten 33us (33ksps) mit C-Code und Vermeidung der SPI-Treiber. Auch ich vermute, Sie finden Linux-Prozess-Switching und andere Threads in den Weg und beeinflussen die Sample-Rate vor allem, wenn sie auch das Lesen der ADC. Dies kann wahrscheinlicher sein, wenn Sie einen dedizierten Nicht-Linux-Prozessor haben, um den ADC zu lesen, der in C- oder Assembler-Sprache programmiert ist, wobei die drei Samples dem Pi zugeführt werden. Einfacher, wenn Sie einen parallelen ADC verwenden, dh nicht mit SPI-ähnlichen seriellen Komms. Siehe auch http://www.hertaville.com/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c.html und https://www.raspberrypi.org/forums/ Viewtopic.php? F = 93 & t = 83069

    2) Während die Sampling bei 10us Periode mit dem MCP3304 auf Pi schwierig ist, ist die Mittelung und das Schreiben definitiv möglich.

    Ich habe eine Lösung für dein Problem, denn wenn du buchstäblich alles, was du mit den drei Samples machen willst, ist, sie zu mitteln, warum fügst du nicht einen altmodischen Tiefpass-Analog-Filter vor dem Eingabe-Pin und dann nimm einfach einen Sample . Hey Presto, keine Notwendigkeit für Hardish-Echtzeit-ADCing, keine Notwendigkeit, über andere Prozesse zu kümmern, oder Kernel-Interrupts!

    Python ist die beste Programmiersprache der Welt.