Расширить 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
+11 -9
View File
@@ -8,6 +8,7 @@ import io
import math
import json
from datetime import datetime
from functools import lru_cache # Таблица достижимых частот строится один раз для каждого аппаратного таймера MCU.
from set_devices.waveform import Waveform, generate as interpolate, load_recipe as load_interpolated_recipe
from set_devices.signal_reconstruction import dac12
@@ -15,13 +16,14 @@ from set_devices.signal_reconstruction import dac12
# TIM6 clock of the supported STM32F407 emulator firmware. The device protocol
# does not currently expose its timer clock; keep this hardware profile explicit.
F407_TIMER_HZ = 72_000_000
F407_SAMPLE_RATES = tuple(sorted({
rate
for divisor in range(1, math.isqrt(F407_TIMER_HZ) + 1)
if F407_TIMER_HZ % divisor == 0
for rate in (divisor, F407_TIMER_HZ // divisor)
if 1 <= rate <= 1_000_000
}))
@lru_cache(maxsize=16) # Небольшой кэш хранит аппаратные профили без повторного перебора делителей при построении сигнала.
def timer_sample_rates(timer_hz, sample_max=1_000_000): # Частоты задаются целочисленным делением TIM6 выбранного MCU, единицы обоих параметров — Гц.
if timer_hz <= 0 or sample_max <= 0: # Нулевые и отрицательные аппаратные параметры не описывают рабочий таймер.
raise ValueError("Частота таймера и предел выборок должны быть положительными") # Ошибка профиля выявляется до формирования таблицы DAC.
return tuple(sorted({rate for divisor in range(1, math.isqrt(timer_hz) + 1) if timer_hz % divisor == 0 for rate in (divisor, timer_hz // divisor) if 1 <= rate <= sample_max})) # Парные делители охватывают все точные частоты без перебора каждого значения до тактовой частоты.
F407_SAMPLE_RATES = timer_sample_rates(F407_TIMER_HZ) # Старый публичный экспорт сохраняет прежние результаты для профиля F407 72 МГц.
def nearest_f407_sample_rate(rate):
@@ -29,9 +31,9 @@ def nearest_f407_sample_rate(rate):
return min(F407_SAMPLE_RATES, key=lambda candidate: (abs(candidate - rate), candidate))
def generate(points, sample_rate=1000, vref=3.3, method="pchip", degree=2):
def generate(points, sample_rate=1000, vref=3.3, method="pchip", degree=2, *, backend="native"): # Прозрачно передаём выбранный настольный решатель общему генератору.
if method != "samples":
return interpolate(points, sample_rate, vref, method, degree)
return interpolate(points, sample_rate, vref, method, degree, backend=backend) # Расчёт остаётся в нативном порте; обработчик готовых отсчётов не требует МНК.
if type(sample_rate) is not int or not 1 <= sample_rate <= 1000000:
raise ValueError("Частота отсчётов должна быть 1…1000000 Гц")
if not math.isfinite(vref) or not 0 < vref <= 3.6: