有什么办法可以让我的Mcp3008采样统一吗?

Is there any way to make my Mcp3008 sampling uniform?

我正在做一项工作,使用 ADC mcp3008 样本传感器数据并收集它们,直到 10k.Then 将其发送到 influxdb。

所有这些工作应该在 1 秒内完成。就是这个意思。

现在的问题是,每条数据的时间戳很不均匀

如您所见:

我希望时间戳统一为 0.1 毫秒。我的意思是influsdb的时间精度应该是0.1ms。

但遗憾的是,写参数time_precision只有's'、'ms'、'u'或'n'。

所以我能做的就是让采样过程更加统一,对吧?

我使用多处理模块来完成这项工作。这是我的原始代码:

import Adafruit_GPIO.SPI as SPI # Import Adafruit GPIO_SPI Module
import Adafruit_MCP3008         # Import Adafruit_MCP3008
import serial
import time
import datetime
from influxdb import InfluxDBClient
from multiprocessing import Process, Queue
def producer(name):
    i=0
    while True:
        begin=time.time()
        body = []
        while i<10000:
            val = round(mcp.read_adc(0),4) #here read the data from SPI port
            current_time = datetime.datetime.utcnow()
            js = {
                "measurement": "Double",
                "time": current_time,
                "tags": {
                },
                "fields": {
                    "sensor2": val
                }
            }
            body.append(js)
            i+=1
        i=0
        res = client.write_points(body) #Send influxdb 10k data at once
        body.clear()
        end=time.time()-begin
        print(end,name)
           
if __name__ == "__main__":
    HW_SPI_PORT = 0 # Set the SPI Port. Raspi has two.
    HW_SPI_DEV  = 0 # Set the SPI Device
    mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(HW_SPI_PORT, HW_SPI_DEV))
    client = InfluxDBClient(host='XXXXX', port=8086, username='admin', password='admin', database= 'db',ssl=False, verify_ssl=False)
    p1 = Process(target=producer,args=(0,))
    p2 = Process(target=producer,args=(1,))
    p3 = Process(target=producer,args=(2,))
    p4 = Process(target=producer,args=(3,))
    p5 = Process(target=producer,args=(4,))
    p6 = Process(target=producer,args=(5,))
    p1.start()
    p2.start()
    p3.start()
    p4.start()
    p5.start()
    p6.start()

是啊...我不得不经历六个过程才能在平均一秒内完成..

那么有什么办法可以让采样统一呢? 像这样制作时间戳:

1603469938916'5'26000   -0.175
1603469938916'6'26000   -0.172
1603469938916'7'26000   -0.178
1603469938916'8'26000   -0.175
1603469938916'9'26000   -0.182

我的意思是时间精度0.1ms。

谢谢!这一定是个奇怪的问题。

PS: 我灵机一动,有什么方法可以让我的时间戳精度达到 0.1 毫秒吗?像 :

timestamp=datetime.datetime.utcnow()
...Some operation...
print(timestamp)

然后得到:1603469938916900000

可能有用。

是的,我找到了解决方案:

from datetime import datetime
import math
def format():
    dt = datetime.utcnow()
    dt_round_microsec = math.floor(dt.microsecond/100)*100 
    dt = dt.replace(microsecond=dt_round_microsec)
    return dt

欢迎提出更好的建议

一些建议。

  1. 如果需要对ADC进行统一采样,这个问题就比较难了。
  2. 如果您“只需要”统一的时间戳间距,您可以随意采样,然后时间戳设置为begin + iteration * 0.1ms。此选项不适用于任何类型的科学数据收集。 10k samples/sec 听起来你需要均匀间隔的采样(例如音频)。所以我会忽略选项 2.

对于选项 1,您需要循环具有一致的迭代时间。在 RPi 上使用 python 很难保证这一点(我假设您使用的是 Pi)。 RPi OS 不是实时的,因此您的循环可能会随机延迟。这里唯一真正的选择是使用外部微处理器以保证时序触发 ADC。

不过,我们可以尝试让您的采样循环写得更好一些。 datetime.datetime.utcnow() 可能是 slow-ish 系统调用。使用 time.perf_counter() 可能会获得更好的结果。您可能还想将 valcurrent_time 存储在循环内的列表中,而 assemble 完整的 json 正文存储在循环外的不同进程中,因为它看起来像您想要的永远 10ksps(并且也在单独的进程中发送到 influxdb)。

一般来说,raspberry pi 硬件未设置为在这些频率下对 ADC 进行连续 real-time 采样。