Add shared waveform processing, generation and firmware image support
This commit is contained in:
54
python/set_devices/signal_reconstruction.py
Normal file
54
python/set_devices/signal_reconstruction.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""Thin host adapter for the shared C99 reconstruction/DAC algorithms."""
|
||||
from __future__ import annotations
|
||||
import ctypes as C
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from protocan.native import NativeProtocol
|
||||
|
||||
METHODS = {"polynomial": "Аппроксимация: полином МНК", "linear": "Интерполяция: линейная",
|
||||
"pchip": "Интерполяция: PCHIP", "spline": "Восстановление: кубический сплайн"}
|
||||
|
||||
@dataclass
|
||||
class Reconstruction:
|
||||
points: list
|
||||
input_count: int
|
||||
unique_count: int
|
||||
rmse: float
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def library():
|
||||
try:
|
||||
lib = NativeProtocol().lib
|
||||
pointer = C.POINTER(C.c_double)
|
||||
lib.set_signal_reconstruct.argtypes = [pointer, pointer, C.c_size_t, C.c_int, C.c_uint,
|
||||
C.c_size_t, C.c_int, pointer, pointer, pointer, pointer, C.c_size_t]
|
||||
lib.set_signal_reconstruct.restype = C.c_int
|
||||
lib.set_signal_dac12.argtypes = [pointer, C.c_size_t, C.c_double, C.POINTER(C.c_uint16)]
|
||||
lib.set_signal_dac12.restype = C.c_int
|
||||
return lib
|
||||
except (AttributeError, OSError, RuntimeError) as error:
|
||||
raise ValueError("Пересоберите SETProtocol с set_signal.c и set_wavegen.c") from error
|
||||
|
||||
def reconstruct(points, method="pchip", output_count=1000, degree=2, *, endpoint=True):
|
||||
if method not in METHODS or type(output_count) is not int or not 2 <= output_count <= 10000:
|
||||
raise ValueError("Неизвестный метод или число выходных точек вне 2…10000")
|
||||
count = len(points)
|
||||
if not 2 <= count <= 100000 or type(degree) is not int or not 1 <= degree <= 5:
|
||||
raise ValueError("Нужно 2…100000 исходных точек, степень 1…5")
|
||||
x, y = (C.c_double * count)(*(p[0] for p in points)), (C.c_double * count)(*(p[1] for p in points))
|
||||
ox, oy, meta = (C.c_double * output_count)(), (C.c_double * output_count)(), (C.c_double * 3)()
|
||||
work = (C.c_double * (14 * count + 128))()
|
||||
code = library().set_signal_reconstruct(x, y, count, list(METHODS).index(method), degree,
|
||||
output_count, int(endpoint), ox, oy, meta, work, len(work))
|
||||
if code:
|
||||
raise ValueError({1: "Недостаточно точек для выбранной степени или неверные параметры",
|
||||
2: "Нужны конечные значения и минимум две различные временные точки",
|
||||
3: "Неустойчивая аппроксимация: уменьшите степень"}.get(code, "Ошибка расчёта"))
|
||||
return Reconstruction(list(zip(ox, oy)), int(meta[0]), int(meta[1]), meta[2])
|
||||
|
||||
def dac12(volts, vref=3.3):
|
||||
data = (C.c_double * len(volts))(*volts)
|
||||
codes = (C.c_uint16 * len(volts))()
|
||||
if library().set_signal_dac12(data, len(data), vref, codes):
|
||||
raise ValueError("Расчётная кривая выходит за диапазон ЦАП 0…Vref; измените точки или метод")
|
||||
return tuple(codes)
|
||||
Reference in New Issue
Block a user