Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки.
19 KiB
Сравнение сигналов с CSV-эталоном
Общее ядро set_devices.signal_reference и Qt-порт
set_devices.qt_ports.reference_comparison сравнивают измеренную запись с
эталоном. Они не импортируют приложение, не выбирают его каталоги и не
требуют конкретного движка отрисовки. Ядро использует только стандартную
библиотеку Python; Qt-порт поддерживает PySide6 и PySide2.
Численный API
Comparison.analysis содержит локальный параметрический отчёт:
summary, details, attention, findings, features, model_report.
Он рассчитывается set_devices.signal_diagnostics по тому же интервалу,
временному сдвигу и допускам. Исходные метрики используют все общие отсчёты;
объём выборки подбора моделей явно указан в model_report.
Добавлено необязательное поле с пустым словарём по умолчанию: прежний
конструктор Comparison с пятью аргументами сохраняет совместимость.
Для одинаковых известных обозначений Uce, Uge, Ic анализ различает
повторные полные переходы, усиленный звон Uce после выключения, отсутствие
переключения, растянутые фронты и временной сдвиг. Общие причины включают
смещение, шум и неопределённое изменение формы. Разные известные физические
каналы, недостаточное число точек и неполное покрытие отражаются в выводе.
На неизвестных каналах аппаратные гипотезы о снаббере и транзисторе не строятся.
set_devices.signal_fault_models подбирает смещение, масштаб, дрейф,
задержку, растяжение фронтов, постоянный уровень, кусочные прерывания и
затухающий отклик RLC. set_devices.signal_joint_models добавляет локальную
ВАХ Uce=U0+Rdiff*Ic, остаточный ток выключенного состояния и совпадение
провалов управления/проводимости по трём каналам.
compare(..., circuit=..., channels=...) принимает необязательные известные
inductance_h, capacitance_f, resistance_ohm в СИ и словарь связанных
каналов dict(measured=..., reference=...). GUI формирует эти снимки сам.
Однозначность физических имён и единиц проверяется до совместного анализа.
Глобальные модели сравниваются по BIC общей обучающей выборки и RMSE на каждой третьей отложенной точке. JSON сохраняет всех конкурентов, число параметров, формулы, критерии и ограничения. BIC не интерпретируется как вероятность аппаратного отказа. Без известного элемента R/L/C не выдаются три произвольных номинала: доступны только LC и R/L последовательного эквивалента полюсов.
ComparisonAnalysis в qt_ports.reference_results показывает одну строку
и кнопку отчёта с таблицей моделей и подробным текстом по образцу Android GUI. Компонент
используется и над исходным графиком, и в полной форме сравнения; изменение
входов, чтение другого эталона и ошибки очищают прежний анализ. JSON-экспорт
обоих видов включает analysis рядом с metrics. Ядро не использует сеть
или обученную модель; пороги признаков и ограничения указаны в подробностях.
Trace(name, times, values) содержит имя, строго возрастающие временные
метки в миллисекундах и амплитуды в единицах канала. trace_from_pairs
создаёт такой снимок из пар (time_ms, value); необязательный transform
применяет множитель или иное преобразование амплитуды.
read_reference(path, cancel=...) потоково читает UTF-8 CSV с необязательным
BOM. Первый столбец — time_ms либо timestamp с ISO-временем и явным
часовым поясом. Остальные столбцы имеют непустые уникальные имена каналов.
Поддерживаются запятая, точка с запятой и табуляция. Пустые ячейки и NaN
сохраняются как пропуски; повторное время, бесконечности и повреждённые
строки отклоняются.
from set_devices.signal_reference import compare, read_reference, trace_from_pairs # Ядро можно использовать без Qt и графика.
measured = trace_from_pairs('U (V)', [(0., 2.), (1., 4.), (2., 6.)]) # Время задано в миллисекундах, амплитуда — в вольтах.
reference = read_reference('reference.csv')['U (V)'] # Столбец выбирается по полному имени канала.
result = compare(measured, reference, absolute_tolerance=.1, relative_tolerance_pct=2.) # Допуск равен 0,1 В плюс 2% модуля эталона.
print(result.metrics['rmse']) # Показатель рассчитан по всем корректным точкам измерения в общем интервале.
compare возвращает Comparison: нормализованные кривые measured и
reference, остаток difference, эталон на сетке остатка expected и
словарь metrics. Статистика включает покрытие, пропуски, среднее смещение,
MAE, RMSE, СКО без смещения, максимальную ошибку и выходы за допуск.
Эталон линейно интерполируется на исходную сетку измерения без
экстраполяции и соединения через NaN. Остаток равен измерению минус эталон.
Допуск равен absolute_tolerance + relative_tolerance_pct / 100 * abs(reference);
равенство границе допуска не считается превышением. Экранная децимация
не участвует в расчёте.
По умолчанию начала записей совмещаются. align_start=False сохраняет
различие абсолютных начал; положительный shift_ms сдвигает эталон вправо.
interval=(start_ms, stop_ms) задаётся от начала измерения, обе границы
включены. Callback cancel() прерывает подготовку, чтение и сравнение через
InterruptedError.
Наложение на существующий график
Для добавления эталона в уже работающий график используйте
set_devices.qt_ports.reference_overlay.ReferenceOverlayPanel. Это
компактные параметры без canvas. Оригинальный график
остаётся у потребителя и продолжает показывать измерение при загрузке и
изменении эталона.
Конструктор принимает sources, parent, source_path и необязательный
path_provider с тем же смыслом, что в таблице ниже. load_reference(path)
автоматически читает CSV, совмещает выбранные каналы и рассчитывает показатели
в рабочем потоке. Отдельной кнопки запуска расчёта нет. Изменение канала,
сдвига, совмещения начал или допусков обновляет результат автоматически.
Сигнал changed сообщает потребителю, что overlay() вернёт актуальные
спецификации и точки одной дополнительной кривой. Потребитель добавляет
их к оригинальным рядам и общей легенде своего canvas. RESULT_KEY
отличает эталон от измерений; оранжевая кривая имеет подпись
Эталон: <канал>. Временные метки эталона уже находятся в исходной шкале
измерения: начало оригинала не обнуляется. Потребитель применяет своё
перебазирование короткой развёртки к обеим кривым одинаково.
set_sources(sources) обновляет кадр прибора или преобразование амплитуд,
сохраняя загруженный эталон. Сигнал remove_requested предлагает владельцу
удалить дополнительный слой и параметры. report() и раскрываемая строка
«Допуски и отчёт» предоставляют актуальную статистику и экспорт JSON.
Если общей части времени нет, кривая остаётся доступна, а показатели
заменяются объяснением отсутствия перекрытия. close() останавливает worker,
не закрывая график потребителя.
Истории, переданные в одном снимке sources, должны быть неизменяемыми;
для нового кадра передайте новую историю через set_sources. Порт
поддерживает PySide6 и PySide2 без импорта приложения.
Подробные показатели рядом с исходным графиком
ReferenceOverlayPanel.results — виджет ComparisonResults с полной
таблицей всех 14 показателей: покрытие, пропуски, смещение, MAE, RMSE,
СКО, максимум и его время, нормированная ошибка и выходы за допуск.
Потребитель размещает его в существующей боковой области рядом с canvas;
в SETGUI он открывается автоматически во вкладке «Отклонения и расчёты».
Сигнал results_requested кнопки «Расчёты» позволяет вернуться к этой
области после выбора обычной легенды.
Флажок results.delta_curve добавляет в overlay() кривую с ключом
DIFFERENCE_KEY. Её временные метки находятся в той же исходной шкале,
что эталон и оригинал. Исходные кривые сохраняются, отдельный canvas не
создаётся. Кнопка JSON рядом с таблицей экспортирует тот же актуальный
результат. Изменение параметров и ошибки очищают устаревшие показатели.
comparison_rows(metrics) из qt_ports.reference_results задаёт единые
подписи, порядок и единицы как для этой таблицы, так и для прежнего диалога.
Совместимые Qt-панель и отдельное окно
ReferenceComparisonPanel — обычный QWidget для существующей страницы
графика. Кнопка «К записи» испускает back_requested; потребитель сам
скрывает панель и возвращает исходный вид. При повторном показе той же
панели сохраняются эталон, параметры и рассчитанные показатели.
ReferenceComparisonDialog — отдельный QDialog с тем же расчётом и
настройками. Оба конструктора принимают:
| Параметр | Контракт |
|---|---|
sources |
Последовательность пар (source, points): source.name — имя, source.display_value(value) — преобразование амплитуды, points — полная неизменяемая история (time_ms, value) |
parent |
Родительский QWidget; для встроенной панели передайте страницу графика |
source_path |
Происхождение измерения для JSON-отчёта, по умолчанию пустая строка |
plot_factory |
Обязательная фабрика без аргументов, возвращающая настроенный QWidget графика |
series_factory |
Обязательная фабрика factory(key, name, color=..., timestamps=..., values=...), создающая кривую потребителя |
path_provider |
Необязательный callback filename → начальный путь; пустое имя используется для открытия эталона, reference_comparison.json — для отчёта |
from set_devices.qt_ports.reference_comparison import ReferenceComparisonPanel # Qt загружается только при импорте конкретного порта.
panel = ReferenceComparisonPanel( # Один компонент обслуживает выбор каналов, параметры, фоновый расчёт и экспорт.
sources=recording_channels, # Потребитель фиксирует полные истории и преобразование амплитуд до создания панели.
parent=chart_page, # Сравнение размещается в существующей рабочей области.
source_path=recording_filename, # Имя исходной записи попадёт в отчёт.
plot_factory=create_comparison_canvas, # Адаптер создаёт график с единой шкалой Y для обеих кривых.
series_factory=create_series, # Контейнеры кривых принадлежат используемому движку отрисовки.
path_provider=recording_path, # Папки и правила хранения остаются политикой потребителя.
) # Все функции и объекты адаптера задаются приложением до этого вызова.
chart_page.layout().addWidget(panel, 1) # Панель занимает свободное место страницы.
panel.back_requested.connect(show_recording) # Обработчик скрывает сравнение и возвращает исходный график.
Canvas должен предоставлять изменяемый список _series, методы
reset_interaction(), _sync_bounds(), стандартные update() и close(),
флажки axis_lock_x и axis_lock_y с setChecked(), поле axis_limits,
visible_bounds.left/right в миллисекундах и viewport типа
protocan.plot.Viewport. _sync_bounds() задаёт конечный ненулевой диапазон
X даже для пустого графика. Обе наложенные кривые используют одну шкалу Y;
автоматическое разделение каналов на независимые оси отключает адаптер.
Дополнительные кнопки canvas, подписи и правила снимков также настраиваются
в plot_factory.
Панель передаёт фабрике кривых полные массивы: их экранное сокращение остаётся ответственностью canvas. Временные поля интерфейса показывают микросекунды, ядро и JSON-отчёт используют миллисекунды. Явно различающиеся единицы в скобках имён каналов блокируют сравнение; автоматической конвертации нет.
Истории и настройки источников нельзя менять, пока панель использует их
снимок. При смене записи или преобразования канала закройте старую панель
и создайте новую. close() встроенной панели отменяет и дожидается worker;
уничтожение родителя также останавливает поток до удаления дочерних объектов.
Отдельный диалог откладывает закрытие до завершения кооперативной отмены.
load_reference(path) позволяет открыть эталон программно, report()
возвращает актуальный словарь отчёта либо None. Изменение входных
параметров очищает старые кривые и показатели до следующего расчёта.
Проверки
python/tests/test_reference_comparison_port.py проверяет внедрение
стороннего canvas, преобразование амплитуд, отклонение и экспорт с внешним
provider путей, а также API отдельного диалога. Его можно запустить из
каталога templates/python командой
python -m unittest discover -s tests -p test_reference_comparison_port.py.
python/tests/test_shared_library_boundary.py проверяет независимость
вычислительных модулей от GUI и Qt. Интеграционные проверки потребителя
дополнительно покрывают полные истории, общий масштаб Y, отмену, смену
записи, возврат к графику и полноэкранный режим.