【问题标题】:Is there any way to make my Mcp3008 sampling uniform?有什么方法可以让我的 Mcp3008 采样均匀?
【发布时间】:2020-10-23 20:04:47
【问题描述】:

我正在使用ADC mcp3008采样传感器数据并收集它们直到10k。然后将其发送到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.1 毫秒。

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

PS: 我有个主意,有什么办法可以让我的时间戳精度达到 0.1ms?类似的东西:

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

欢迎提出更好的建议

【问题讨论】:

  • 至少我需要每 0.1ms 采样一次。现在在 0.1 毫秒内可能有 3 或 4 个数据。并在 0.1 毫秒内丢失一些数据。
  • 为什么要在同一个 ADC 上同时使用 6 个线程?
  • 进程是线程?作为我的测试,一个进程每个循环需要 1.7 秒。但是两个只花了 2.3s..等等.. 6 个进程总共花了将近 6s。所以我制作它们。如果有更好的解决方案来完成这项工作,很高兴知道。

标签: python raspberry-pi iot influxdb


【解决方案1】:

一些建议。

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

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

不过,我们可以尝试使您的采样循环编写得更好一些。 datetime.datetime.utcnow() 可能是一个缓慢的系统调用。改用time.perf_counter() 可能会得到更好的结果。您可能还想将 valcurrent_time 存储在循环内的列表中,并在不同的过程中在循环外组装完整的 json 主体,因为它看起来像你想要永远 10ksps(并在单独的过程中发送到 influxdb )。

通常,树莓派硬件未设置为在这些频率下对 ADC 进行连续实时采样。

【讨论】:

  • 感谢您的建议,但它不太适合我的需要。我需要实时而不只是计数器来进行进一步的时间同步工作。我的意思是找到一种方法使时间戳的精度为 0.1 毫秒,例如 0.123400000 秒。当influxdb中写入多个具有相同时间戳的数据时,influxdb将只保留一个。那么有什么办法可以将我的“datetime.datetime.utcnow()”或其他更快的时间戳写在influxdb中?
  • @YouLee - 我不完全明白。 InfluxDB 将写入您告诉它的时间戳。您拥有您所知道的 s、ms、us 等精度选项 - 您可以将它们用于写入和查询(读取)。否则,我不知道 InfluxDB 为您执行此操作的方法 - 它不希望您重写时间戳。为什么dt_round_microsec = math.floor(dt.microsecond/100)*100 不适合你?
  • 您决定采用什么解决方案?
猜你喜欢
  • 2021-12-29
  • 1970-01-01
  • 2017-07-12
  • 2018-04-10
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多