簡體   English   中英

Python延遲了Raspberry Pi

[英]Python delays on Raspberry Pi

我正在嘗試模擬校准研究儀器的復合動作潛力。 目標是以250 Hz輸出一定的10μV信號。 低電壓將在稍后處理,對我來說主要的問題是頻率。 下圖顯示了我正在嘗試制作的系統的概述。

在此輸入圖像描述

通過從活體動物獲取數據,並在MATLAB中處理數據,我制作了一個低噪聲信號,具有12位格式的789個值。 然后我克隆了存儲庫,我使用Git將其以csv格式存儲到Raspberry Pi中。 下面是我在RPi上編寫的Python腳本。 您可以跳過腳本中的def main來查看功能。

#!/usr/bin/python

import spidev
from time import sleep
import RPi.GPIO as GPIO
import csv
import sys
import math

DEBUG = False
spi_max_speed = 20 * 1000000
V_Ref = 5000
Resolution = 2**12
CE = 0

spi = spidev.SpiDev()
spi.open(0,CE)
spi.max_speed_hz = spi_max_speed

LDAQ = 22
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LDAQ, GPIO.OUT)
GPIO.output(LDAQ,GPIO.LOW)

def setOutput(val):
    lowByte = val & 0b11111111 #Make bytes using MCP4921 data sheet info
    highByte = ((val >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4
    if DEBUG :
        print("Highbyte = {0:8b}".format(highByte))
        print("Lowbyte =  {0:8b}".format(lowByte))
    spi.xfer2([highByte, lowByte])

def main():
    with open('signal12bit.csv') as signal:
        signal_length = float(raw_input("Please input signal length in ms: "))
        delay = float(raw_input("Please input delay after signal in ms: "))
        amplitude = float(raw_input("Please input signal amplitude in mV: "))
        print "Starting Simulant with signal length %.1f ms, delay %.1f ms and amplitude %.1f mV." % (signal_length, delay, amplitude)
        if not DEBUG : print "Press ctrl+c to close."
        sleep (1) #Wait a sec before starting
        read = csv.reader(signal, delimiter=' ', quotechar='|')
        try:
            while(True):
                signal.seek(0)
                for row in read: #Loop csv file rows
                    if DEBUG : print ', '.join(row)
                    setOutput(int(row)/int((V_Ref/amplitude))) #Adjust amplitude, not super necessary to do in software
                    sleep (signal_length/(data_points*1000) #Divide by 1000 to make into ms, divide by length of data
                sleep (delay/1000)
        except (KeyboardInterrupt, Exception) as e:
            print(e)
            print "Closing SPI channel"
            setOutput(0)
            GPIO.cleanup()
            spi.close()

if __name__ == '__main__':
    main()

這個腳本幾乎按預期工作。 將MCP4921 DAC的輸出引腳連接到示波器,可以很好地再現信號,並正確輸出后續延遲。

不幸的是,數據點的分離比我需要的要多得多。 我可以將信號塞入的最短時間約為79 ms。 這是因為在睡眠函數中除以789000,我知道從Python和Pi中要求太多,因為讀取csv文件需要時間。 但是,如果我嘗試手動制作陣列,並將這些值放在外而不是讀取csv文件,我可以實現超過6 kHz的頻率而不會丟失。

我的問題是這個

如何使此信號以250 Hz的頻率出現,並從用戶的輸入中可靠地降低? 我已經考慮過手動將789值寫入腳本中的數組,然后將SPI速度更改為適合250 Hz的任何值。 這將消除慢速csv閱讀器功能,但是你無法降低用戶輸入的頻率。 無論如何,消除對csv.read的需求會有很大幫助。 謝謝!

今天早些時候弄清楚了,所以我想我會在這里發布一個答案,以防將來有人遇到類似的問題。

由於幾個原因,睡眠()無法解決數據點之間內部延遲的問題。 我最終做的是以下內容

  • 所有數學和函數調用移出關鍵循環
  • 對傳輸值無延遲所需的時間進行線性回歸分析
  • 在MATLAB中將CSV文件中的數據點數量增加到“充足”(9600)
  • 計算滿足用戶所需信號長度所需的點數
  • 從現在較大的CSV文件中獲取均勻分隔的條目,以盡可能地匹配該點數。
  • 計算這些值,然后顯式計算SPI字節
  • 保存兩個字節列表,並直接在關鍵循環中輸出

下面是帶有一些輸入檢查的新代碼

#!/usr/bin/python

import spidev
from time import sleep
import RPi.GPIO as GPIO
import sys
import csv
import ast

spi_max_speed = 16 * 1000000 # 16 MHz
V_Ref = 5000 # 5V in mV
Resolution = 2**12 # 12 bits for the MCP 4921
CE = 0 # CE0 or CE1, select SPI device on bus
total_data_points = 9600 #CSV file length

spi = spidev.SpiDev()
spi.open(0,CE)
spi.max_speed_hz = spi_max_speed

LDAQ=22
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LDAQ, GPIO.OUT)
GPIO.output(LDAQ,GPIO.LOW)

def main():

    #User inputs and checking for digits
    signalLengthU = raw_input("Input signal length in ms, minimum 4: ")
    if signalLengthU.isdigit():
        signalLength = signalLengthU
    else:
        signalLength = 4

    delayU = raw_input("Input delay after signal in ms: ")
    if delayU.isdigit():
        delay = delayU
    else:
        delay = 0

    amplitudeU = raw_input("Input signal amplitude in mV, between 1 and 5000: ")
    if amplitudeU.isdigit():
        amplitude = amplitudeU
    else:
        amplitude = 5000

    #Calculate data points, delay, and amplitude
    data_points = int((1000*float(signalLength)-24.6418)/12.3291)
    signalDelay = float(delay)/1000
    setAmplitude = V_Ref/float(amplitude)

    #Load and save CSV file
    datain = open('signal12bit.csv')
    read = csv.reader(datain, delimiter=' ', quotechar='|')
    signal = []
    for row in read:
        signal.append(ast.literal_eval(row[0]))

    #Downsampling to achieve desired signal length
    downsampling = int(round(total_data_points/data_points))
    signalSpeed = signal[0::downsampling]
    listlen = len(signalSpeed)

    #Construction of SPI bytes, to avoid calling functions in critical loop
    lowByte = []
    highByte = []
    for i in signalSpeed:
        lowByte.append(int(i/setAmplitude) & 0b11111111)
        highByte.append(((int(i/setAmplitude) >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4)

    print "Starting Simulant with signal length %s ms, delay %s ms and amplitude %s mV." % (signalLength, delay, amplitude)
    print "Press ctrl+c to stop."
    sleep (1)

    try:
        while(True): #Main loop
            for i in range(listlen):
                spi.xfer2([highByte[i],lowByte[i]]) #Critical loop, no delay!
            sleep (signalDelay)
    except (KeyboardInterrupt, Exception) as e:
        print e
        print "Closing SPI channel"
        lowByte = 0 & 0b11111111
        highByte = ((0 >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4
        spi.xfer2([highByte, lowByte])
        GPIO.cleanup()
        spi.close()

if __name__ == '__main__':
    main()

結果正是我想要的。 下面是示波器的示例,信號長度為5 ms; 200赫茲。 謝謝你的幫助,伙計們!

示波器讀數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM