Пытаетесь прочитать АЦП с помощью Cython на RPi 2 b+ через SPI (MCP3304, MCP3204 или MCP3008)?

Я хотел бы считать значения дифференциального напряжения с MCP3304 (5В VDD, 3,3В Vref, основной канал = 7, разностный канал = 6) подключен к RPi 2 b+ как можно ближе к максимальной частоте дискретизации MCP3304, равной 100 кс/с. Предпочтительно, я бы получил> 1 выборку за 100 мкс (> 10 ksps).

Добрый пользователь недавно предложил мне попробовать портировать мой код на C для некоторого увеличения скорости. Я ОЧЕНЬ новичок в C, поэтому решил попробовать Cython, но, похоже, не могу понять, как использовать прирост скорости на основе C.

Я предполагаю, что мне нужно написать файл .pyx, который включает в себя более простые средства доступа к битам/байтам АЦП через SPI, чем пакет Python, который я сейчас использую (обернутый в Python пакет gpiozero упаковка). 1) Это кажется правильным, и если да, то может кто-нибудь 2) пожалуйста, помогите мне понять, как правильно манипулировать битами/байтами для MCP3304 таким образом, чтобы получить прирост скорости от Cython ? Я видел учебные пособия по C для MCP3008, но у меня возникли проблемы с адаптацией этого кода, чтобы он соответствовал времени, указанному в спецификации MCP3304; хотя я мог бы адаптировать учебник MCP3008 (или другого ADC) для Cython, чтобы он соответствовал MCP3304.

Вот небольшой цикл .pyx, который я написал, чтобы проверить, насколько быстро я читаю значения напряжения. (Сроки, сколько времени потребуется, чтобы прочитать 25 000 образцов). Это примерно на 9% быстрее, чем прямо в Python.

# Load packages
import time
from gpiozero import MCP3304


# create a class to ping PD every ms for 1 minute
def pd_ping():
    cdef char *FILENAME = "testfile.txt"
    cdef double v
    # cdef int adc_channel_pd = 7
    cdef size_t i

    # send message to user re: expected timing
    print "Runing for ", 25000 , "iterations. Fingers crossed!"

    print time.clock()

    s = []
    for i in range(25000):
        v = MCP3304(channel = 7, diff = True).value *  3.3
        # concatenate
        s.append( str(v) )

    print "donezo" , time.clock()

    # write to file
    out = '\n'.join(s)
    f = open(FILENAME, "w")
    f.write(out)

person drewbles    schedule 06.07.2016    source источник


Ответы (1)


Вероятно, нет необходимости создавать объект MCP3304 для каждой итерации. Также преобразование из числа с плавающей запятой в строку может быть отложено.

s = []
mcp = MCP3304(channel = 7, diff = True)
for i in range(25000):
    v = mcp.value *  3.3
    s.append(v)

out = '\n'.join('{:.2f}'.format(v) for v in s) + '\n'

Если это умножение на 3.3 в данный момент не является строго необходимым, это можно сделать позже.

person J.J. Hakala    schedule 06.07.2016
comment
Невероятный! Это улучшило производительность чуть более чем в 10 раз (с ~ 33 секунд до 2 секунд. Спасибо! - person drewbles; 06.07.2016
comment
Примечание. Если это важно для потомков, я также удалил умножение на 3,3 и увеличил {:.2f} до {:.17f}, чтобы собрать как можно больше информации. Спасибо! - person drewbles; 06.07.2016
comment
Последующие действия, есть идеи, как я могу объявить (через cdef) список s? Интересно, может ли это дать мне еще больше улучшений скорости. - person drewbles; 06.07.2016
comment
@drewbles, возможно, лучше использовать фиксированный размер c или массив numpy, то есть что-то вроде cdef uint16_t buffer[25000] ... buffer[i] = mcp.value. uint16_t доступен после from libc.stdint cimport uint16_t. Для 13-битного АЦП '{:.4f}' .format(v) было бы разумно. - person J.J. Hakala; 07.07.2016
comment
Это значение mpc.value кажется двойным от 0 до 1, поэтому cdef double buffer[25000]. - person J.J. Hakala; 07.07.2016
comment
Спасибо. Выяснил, как использовать метод buffer[i], но, похоже, это не сильно ускоряет код, если вообще ускоряет. Есть ли хороший ресурс, на который вы могли бы указать мне для добавления массива numpy? Я читал на сайте python; звучит, может быть, быстрее, но я не могу понять, как определить numpy в этом контексте. - person drewbles; 07.07.2016