如何在不不断写入磁盘的情况下,以高频读取和累积传感器值(RPi 2 b+,MCP3304,Python)

2024-06-26 14:56:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用Raspberry Pi 2 Model B+通过MCP3304(5v VDD)从光电二极管读取红外强度的模拟数据,连续三次(读取间隔0.1ms,或10ksps),基于外部刺激,平均这些值,然后将它们与当前日期时间一起写入文本文件。光电二极管只是将数据读出到一个放大器,然后由放大器馈入MCP3304,MCP3304通过SPI将数据输入RPi。(本质上:RPi接收数字输入,通过MCP3304和串联信号放大器触发来自光电二极管的三个连续采样。这三个示例存储在内存中,取平均值,然后连同日期时间戳一起写入磁盘到现有的CSV文本文件中)。在

现在,我用下面的代码(SensorRead())得到了一个<;1kHz的采样。我对Python还很陌生(就这一点而言,还可以玩传感器和rpi!),并且认为我将类设置为获取三个独立的、连续的ADC样本的方式,以及可能的写入磁盘的设置可能会减慢我的速度。然而,我似乎找不到更好的方法。Edit1:我对RPi-GPIO中Python的最大采样率做了大量研究,它似乎远远超出了ADC在~1MHz或~1000ksps(例如12)的限制。Edit2:也许100 ksps的ADC最大采样率实际上是指可以读取多少位,而不是每秒可以采集多少个完整的12位样本?在

是的。就这样。MCP3304可以达到100ksps,但是Python的读取速率接近30ksps,如果将MCP3304每次迭代读取的24位分开,则接近1ksps



This link建议每次我想采集单个样本时都调用WiringPi可能会导致相当长的延迟。在

以及

2)对于我来说,有初级/中等水平的Python技能,是否有可能在内存中执行所有采样和每秒平均数,并且只写入磁盘,比如说,每分钟一次?编辑:您能告诉我一些相关链接/资源的方向吗?在

谢谢!在

注1:代码是“线程化”的,因为有一些其他函数同时运行。 注2:同时读取ADC上的差分信道,因此MCP3304命令中的“differential=True”

'''
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()

编辑:我用Cython得到了一些很好的结果,如this test-code I wrote to quantify how fast I could read my ADC所示。最后,我还编写了自己的函数来读取MCP3304——一旦一切都清理干净了,我会链接到它——我可以在Cython中进一步优化它。在


Tags: thetoinimporttrueledirtime
1条回答
网友
1楼 · 发布于 2024-06-26 14:56:32

关于你的问题有一点。一秒钟内的三个采样率是3Hz而不是100kHz。我觉得你要的是三个样品,间隔10美分。在

1)在MCP3304上使用运行Linux的Pi的10us采样周期?不太可能。做一些搜索。例如,请参见https://raspberrypi.stackexchange.com/questions/45386/microphone-via-spi,其中一个答案说他们使用C代码并避免使用SPI驱动程序实现了33us(33ksps)。另外,我怀疑您会发现Linux进程切换和其他线程会妨碍并影响采样率,尤其是当它们同时读取ADC时。如果您有一个专用的非Linux处理器来读取ADC,用C或汇编语言编程,并将三个样本输入Pi,则更可能出现这种情况。如果使用并行ADC,即不使用类似SPI的串行通信,则更容易。另请参见http://www.hertaville.com/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c.htmlhttps://www.raspberrypi.org/forums/viewtopic.php?f=93&t=83069

2)虽然使用MCP3304在10us周期内采样很难在Pi上实现,但平均值和写入绝对是可能的。在

我有一个解决你的问题的方法:如果你要做的就是对三个样本进行平均,为什么不在输入端前加一个老式的低通模拟滤波器,然后只取一个样本。嘿,普雷斯托,不需要硬实时广告,不需要担心其他进程,或内核中断!在

相关问题 更多 >