Расширить DEIF, загрузку CAN и общую обработку сигналов

Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
This commit is contained in:
2026-10-24 15:40:51 +03:00
parent a5e46d4627
commit 41e24629ce
170 changed files with 43762 additions and 281 deletions
+9 -6
View File
@@ -13,7 +13,7 @@ from bisect import bisect_left, bisect_right
from .plot_decimation import PointTimes # Используем координаты X без копирования ряда и без недоступного в Python 3.8 параметра key.
from dataclasses import dataclass
from datetime import datetime, timezone
from .signal_reconstruction import METHODS, reconstruct
from .signal_reconstruction import BACKENDS, METHODS, reconstruct # Общие подписи решателей используются в легенде и CSV, чтобы различать результаты сравнения.
class FrozenPoints(tuple):
@@ -96,6 +96,7 @@ class Request:
output_count: int
degree: int
x_range: tuple | None
backend: str = "native" # Вариант входит в равенство запросов, поэтому две расчётные кривые могут сосуществовать.
@dataclass(frozen=True)
@@ -106,6 +107,7 @@ class Curve:
unique_count: int
rmse: float
pieces: tuple = ()
elapsed_ms: float = 0.0 # Сохраняем полное время расчёта отдельно от геометрии и оценки точности.
def piece_at(self, x):
for piece in self.pieces:
@@ -115,10 +117,11 @@ class Curve:
@property
def label(self):
return f"{self.request.series.label} · расчёт ({METHODS[self.request.method]})"
variant = " · " + BACKENDS[self.request.backend] if self.request.method == "polynomial" else "" # Дополняем название только у метода, имеющего альтернативный решатель.
return f"{self.request.series.label} · расчёт ({METHODS[self.request.method]}{variant})" # Подпись однозначно связывает слой графика и экспорт CSV с вариантом МНК.
def prepare(snapshot, key, method="pchip", output_count=1000, degree=2):
def prepare(snapshot, key, method="pchip", output_count=1000, degree=2, backend="native"): # Новый последний параметр не меняет существующие вызовы подготовки снимка.
"""Return a comparable request, or None when the source is not processable."""
if snapshot.blocked_reason:
return None
@@ -130,14 +133,14 @@ def prepare(snapshot, key, method="pchip", output_count=1000, degree=2):
selected = Series(selected.key, selected.label,
selected.points.between(left, right),
y_unit=selected.y_unit)
return Request(selected, snapshot.axis, snapshot.source, method, output_count, degree, snapshot.x_range)
return Request(selected, snapshot.axis, snapshot.source, method, output_count, degree, snapshot.x_range, backend) # Включаем выбранный решатель в идентичность запроса и проверку устаревших результатов.
def process(request):
if request is None:
raise ValueError("Нет доступного аналогового канала")
result = reconstruct(request.series.points, request.method, request.output_count, request.degree, with_model=True)
return Curve(request, tuple(result.points), result.input_count, result.unique_count, result.rmse, result.pieces)
result = reconstruct(request.series.points, request.method, request.output_count, request.degree, with_model=True, backend=request.backend) # Передаём явный выбор пользователя в общий тонкий порт без численных вычислений в UI.
return Curve(request, tuple(result.points), result.input_count, result.unique_count, result.rmse, result.pieces, result.elapsed_ms) # Результат сохраняет время и метрики, относящиеся к одному конкретному запуску.
def write_csv(curve, stream):