Files
templates/docs/reference-comparison.md
T
Andrey 41e24629ce Расширить DEIF, загрузку CAN и общую обработку сигналов
Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
2026-10-24 15:40:51 +03:00

211 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Сравнение сигналов с 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
сохраняются как пропуски; повторное время, бесконечности и повреждённые
строки отклоняются.
```python
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` — для отчёта |
```python
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, отмену, смену
записи, возврат к графику и полноэкранный режим.