О проекте
Команда: Verissimus
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
Система почасового прогноза нормализованной мощности двух ветротурбин на 24/48 часов. Связывает LightGBM, архив погоды NOAA GFS с контролем времени выпуска и LLM-оркестратор с инструментами, есть Streamlit-интерфейс и HTML-отчёт для жюри.
Как устроено
SCADA CSV агрегируется по часам с проверкой пропусков. Погодные признаки берутся из архивных выпусков NOAA GFS (GRIB2 через ecCodes), причём используется только выпуск, доступный на момент решения (23:00 предыдущего дня). LightGBM на ветре, температуре и календарных признаках даёт прогноз в шкале [0,1], затем применяется аффинная калибровка clip(a·raw+b,0,1), обученная на январе отдельно по турбинам и горизонтам. Пакетный replay февраля даёт 1344 строки с provenance и SHA-256. Необязательный чат на gpt-4o-mini вызывает инструменты (inspect_forecast, generate_agent_forecast) через компактный payload.
Ключевые решения
- LightGBM
- аффинная калибровка прогноза
- NOAA GFS GRIB2/ecCodes
- backtest с базовыми методами
- tool calling
- provenance/SHA-256
Метрики
Метрики точности в обрезанной части README; видно: 1344 строки прогноза февраля, 104 теста, JSON для LLM сжат на 87,72%
Особенности
Строгая защита от утечки будущего: погодный прогноз берётся по времени выпуска, подмена реанализом запрещена. Для каждого расчёта хранится provenance, сабмит проверяется офлайн-верификатором. Команда сама пометила старые скриншоты с МВт и R² как недостоверные. Первый коммит сделан 22.09 поздно вечером, основная работа 23.09.
Стек
Python · pandas · NumPy · scikit-learn · LightGBM · Streamlit · Plotly · Requests · ecCodes · unittest
Модели
GPT-4o-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-85a43815-verissimus.
README
README.mdEnergyAI — агент для прогноза нормализованной мощности ВЭС
Проект для кейса «Agentic AI для прогнозирования выработки ВЭС», HackAlem AI, трек «Энергетика». Исторический тестовый период: 1–28 февраля 2026 года, две турбины, прогноз на 24 или 48 часов.
Для жюри: быстрая проверка результата и запуск основного сценария.
Часовой пояс исходных данных и база нормализации организаторами не определены. В проекте явно принято допущение
Asia/Almaty. Прогноз сохраняет исходную безразмерную шкалу[0, 1]; значения не называются МВт, МВт·ч или денежной экономией без дополнительных подтверждённых параметров.
1. Название
EnergyAI — система почасового прогнозирования нормализованной мощности двух ветротурбин с LLM-оркестратором, ML-моделью и проверяемым архивом погодных выпусков.
2. Проблема и пользователи
Диспетчеру ВЭС нужен ожидаемый почасовой профиль мощности для планирования работы. Историческая проверка должна воспроизводить информацию, доступную в момент принятия решения, поэтому важны не только дата целевого часа, но и время выпуска и доступности погодного прогноза.
Проект рассчитывает нормализованную мощность по погодному прогнозу, сохраняет происхождение входов, выявляет неполные данные и позволяет повторить расчёт. Это исследовательский прототип; его практическая точность определяется полным временным тестом, а не видом графика или ответом LLM.
3. Что реализовано
- Чтение CSV организаторов, проверка числовых полей, часовая агрегация, учёт пропусков и неоднозначного времени.
- Модель LightGBM по ветру, температуре и календарным признакам; прогноз ограничен исходной шкалой
[0, 1]. - Зафиксированная аффинная калибровка прогноза мощности по ошибкам более ранних январских решений:
clip(a × raw_power + b, 0, 1). Это коррекция выходной мощности, а не изменение погодных данных GFS. Параметры отдельные для каждой турбины и горизонтов 1–24 / 25–48 часов. - Внешняя погода из исходных архивных выпусков NOAA GFS с фиксацией времени решения и выпуска. Подмена недоступного прогноза фактической погодой или реанализом запрещена.
- Прогнозы на 24/48 часов с проверкой полного множества часов и сохранением метаданных.
- Streamlit-интерфейс для запуска расчёта, просмотра графика и аудита. Кнопка «Рассчитать выбранный прогноз» и пакетный режим работают без OpenAI API.
- Автономный HTML-отчёт для жюри: встроенный SVG-график, все целевые часы, местное время и UTC, происхождение погоды, качество SCADA и ограничения. Отчёт открывается без CDN и API-ключей. Блок «Проверки прогноза» заново проверяет показанный снимок; отсутствие метаданных не считается успешной проверкой.
- Необязательный чат: один LLM-оркестратор вызывает разрешённые инструменты. Он не заменяет численную модель и не является отдельной «мультиагентной» ML-системой.
- Компактные ответы инструментов для LLM сохраняют почасовой прогноз и необходимое происхождение, исключая объёмные служебные списки GRIB-объектов. Полные доказательства остаются в локальных артефактах.
- Последовательная суточная симуляция февраля: 28 дат × 24 часа × 2 турбины = 1344 строки. При неполном ответе процесс завершается ошибкой и сохраняет предыдущий CSV.
- Сопроводительный JSON содержит идентификаторы расчётов, происхождение погоды и SHA-256 итогового CSV.
- Январский эксперимент калибровки с раздельными периодами подгонки и оценки, исходными погодными выпусками и простыми базовыми методами. Предыдущие результаты без калибровки сохранены для сравнения. Численные результаты и ограничения приведены ниже.
- Проверка сохранённой февральской выгрузки одной командой
scripts/verify_submission.py, без сети и исходных SCADA CSV. - Ограниченный автоматический цикл
watch_forecast.py: повторно проверяет входы одного исторического запроса, пересчитывает результат, фиксирует изменения и повторяет попытку после ошибки.
Старые изображения dashboard.png и agent_audit.png относятся к предыдущей версии. На них показаны неподтверждённые МВт, денежная экономия и R² без области применимости; они не являются доказательством качества текущего решения.
Статус файла сдачи: submission_february_2026.csv пересчитан с зафиксированной калибровкой: 56 успешных суточных расчётов, 1344 строки, все целевые часы 1–28 февраля для двух турбин. Рядом сохранён submission_february_2026.provenance.json с происхождением каждого запуска и метаданными калибровки. Проверены 5376 записей погодных источников. SHA-256 CSV: 292f5440cc017881eed9107b24e40ae5a30c80a2ab3262622ce89cf4448d7247. Это проверка полноты и воспроизводимости файла, не точности прогноза за февраль.
Краткий сценарий выступления с точными кнопками и командами: DEMO.md.
Готовый пример текущего прогноза turbine_1 на 1–2 февраля: автономный HTML-отчёт. Скачайте файл и откройте его в браузере; GitHub может показывать HTML как исходный текст.
4. Сценарий от входных данных до результата
- Пользователь выбирает турбину, целевую дату и горизонт. Начало периода — 00:00 в принятом часовом поясе.
- По умолчанию момент решения — 23:00 предыдущего дня. Например, для 1 февраля: решение
2026-01-31T23:00:00+05:00, первый целевой час2026-02-01T00:00:00+05:00. - Движок использует только доступную к решению историю SCADA и исходный погодный выпуск, прошедший проверку исторической доступности.
- Погода преобразуется в признаки LightGBM. К прогнозу мощности применяется зафиксированная калибровка, если её обучающие целевые часы уже доступны на момент решения. Проверяются совместимость исходного CSV, версия базовой модели, часовой пояс и временная граница. Получается ровно 24 или 48 почасовых значений нормализованной мощности.
- Система проверяет время, полноту, отсутствие дубликатов и конечность значений, сохраняет результат с идентификатором и журналом происхождения.
- Кнопка «Проверить обновление показанного прогноза» повторно запрашивает входы для того же момента решения и показывает изменение почасовых значений. Неизменные входы и версия модели сохраняют идентификатор результата. Для использования более позднего погодного выпуска задайте новый момент решения, предшествующий целевым часам.
- Пользователь скачивает почасовой CSV или автономный HTML-отчёт. Чат может прочитать сохранённый результат через
inspect_forecastи объяснить его; вызовы инструментов отображаются в журнале.
LLM помогает выбрать инструменты и объяснить результат. Погода, модель, числа и проверки рассчитываются Python-кодом.
5. Технологии
| Компонент | Реализация |
|---|---|
| Язык и окружение | Python 3.12, venv |
| Данные и ML | pandas, NumPy, scikit-learn, LightGBM |
| Архив погоды | NOAA GFS, HTTP-запросы Requests, GRIB2 через ecCodes |
| Интерфейс и отчёт | Streamlit, Plotly; HTML/CSS и встроенный SVG без внешних зависимостей |
| Необязательный AI-чат | OpenAI API, модель по умолчанию gpt-4o-mini, вызов инструментов |
| Конфигурация | Переменные окружения, python-dotenv для локального ключа чата |
| Проверки | unittest, подменённые ответы для отказов и неполных данных |
Версии зависимостей указаны в requirements.txt. GPU и NVIDIA API для реализованного численного процесса не требуются.
Проверка окружения 23 сентября 2026 года: зависимости установлены по requirements.txt в новый отдельный Python 3.12 venv на Windows; pip check не выявил конфликтов. Импорты основных модулей и нативная библиотека ecCodes 2.48.0 работают. Текущий полный набор из 104 автоматических тестов калибровки, отчётов, интерфейса и временных проверок прошёл; команда для повторения приведена ниже. Linux/macOS-команды приведены для установки, но на этих ОС данная проверка не выполнялась.
Отдельно выполнены два реальных сценария AI-агента: inspect_forecast (2 запроса, 5524 токена) и generate_agent_forecast (2 запроса, 5963 токена). Итого 4 запроса и 11 487 токенов по данным API; обезличенное подтверждение — validation/agent_smoke.json. Первый сценарий выполнен до установки калибровки, второй — уже с калиброванным движком. Для проверенного 48-часового результата компактное представление инструмента уменьшило JSON с 91 242 до 11 203 байт (на 87,72%); это объём текста, а не гарантированный процент экономии токенов. Эти проверки расходуют API-кредиты и не входят в автоматические тесты. Порядок ручного повторения и ограничения бюджета указаны ниже; NVIDIA API в реализованном процессе не используется.
6. Архитектура
SCADA CSV -> подготовка / временные границы -> LightGBM
^
NOAA GFS -> отбор исходного выпуска -> погода ---|
|
models/power_calibration.json -> коррекция мощности + контроль доступности
|
forecast_engine.py -> прогноз + аудит
^ |
app.py / batch_forecast.py v
кнопка / LLM-инструменты CSV / JSON / график / HTML
| Файл/каталог | Назначение |
|---|---|
forecast_engine.py | Подготовка, обучение, инференс, проверки, сохранение результата |
weather_archive.py | Получение и проверка архивных погодных выпусков |
power_calibration.py, models/power_calibration.json | Проверка и применение зафиксированной коррекции прогноза мощности |
app.py | Streamlit, интерфейс и необязательный чат |
reporting.py | Проверки сохранённого снимка и автономный HTML-отчёт |
agent_payload.py | Компактный результат инструмента для LLM без потери почасового ряда |
batch_forecast.py | Ежедневный replay февраля и безопасная запись CSV + provenance |
backtest.py | Временная проверка полного прогноза и двух базовых методов |
watch_forecast.py | Ограниченный автоматический цикл повторной проверки входов |
scripts/verify_submission.py | Проверка февральского CSV и его provenance без сети |
scripts/calibrate.py | Воспроизведение фиксированного январского эксперимента; запись кандидата в artifacts/ |
scripts/smoke_agent.py | Ограниченная ручная проверка реального OpenAI API |
validation/backtest.json | Полученные метрики, протокол и ссылки на исходные расчёты |
validation/backtest.predictions.csv | Почасовые прогнозы, фактическая мощность и базовые методы |
validation/baseline/ | Сохранённая проверка модели до калибровки |
validation/calibration/ | Протокол, параметры, обучающие/оценочные строки и происхождение данных калибровки |
validation/agent_smoke.json | Подтверждение двух реальных сценариев AI-агента без ключей |
docs/forecast_example.html | Готовый автономный отчёт по текущему 48-часовому прогнозу |
DEMO.md | Сценарий двухминутной демонстрации и ответы на вопросы жюри |
data/turbine_1.csv, data/turbine_2.csv | Исходные данные организаторов, размещаются локально |
.cache/weather/ | Локальный погодный кэш |
artifacts/runs/ | Результаты расчётов с метаданными |
artifacts/agent_audit.jsonl | Журнал событий |
artifacts/chat_trace.jsonl | Журнал шагов чата без сырых запросов и ключей |
tests/ | Автоматические проверки без платных LLM-вызовов |
Файл .env, локальная история, кэш и служебные артефакты не следует публиковать автоматически. Код не отправляет исходные SCADA CSV в OpenAI; необязательный чат получает пользовательский запрос и компактный результат инструмента с почасовым прогнозом и метаданными.
7. Установка и запуск
Нужны Python 3.12, Git, доступ к погодному архиву через интернет и исходные CSV. Выполняйте команды из корня проекта. Репозиторий команды закрытый: для клонирования необходим разрешённый организаторами доступ.
git clone https://github.com/BAITC-Hacks/hack-85a43815-verissimus.git
cd hack-85a43815-verissimus
Windows PowerShell
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m streamlit run app.py
Linux/macOS
python3.12 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m streamlit run app.py
На некоторых Linux-системах для LightGBM нужна системная библиотека OpenMP (libgomp1). При отсутствии её устанавливают средствами ОС. Декодирование GRIB требует работающего ecCodes, установленного с Python-зависимостями.
Создайте каталог data и положите в него неизменённые turbine_1.csv и turbine_2.csv, предоставленные организаторами. Эти файлы не включены в Git. Для жюри нужен доступ к тем же данным; право на их распространение уточняется отдельно. Без CSV приложение сообщает об отсутствии входов, а не генерирует вымышленные данные.
Для чата скопируйте .env.example в .env, затем впишите свой OPENAI_API_KEY. Ключ не нужен для пакетного запуска и кнопки расчёта. Не вставляйте ключи в README, исходники, снимки экрана или Git.
Выбор модели чата можно изменить переменной OPENAI_MODEL. Доступно два инструмента: generate_agent_forecast для расчёта и inspect_forecast для чтения сохранённого результата. Цикл ограничен шестью вызовами/шагами; денежные оценки без подтверждённых входов отключены.
При подтверждении организаторами другого часового пояса задайте SCADA_TIMEZONE до запуска процесса и пересоздайте результаты:
$env:SCADA_TIMEZONE = "Asia/Almaty"
export SCADA_TIMEZONE=Asia/Almaty
Не заменяйте историческую временную зону постоянным сдвигом +5: её правила различаются до и после реформы 2024 года.
При изменении исходных CSV или часового пояса потребуется заново проверить и подготовить калибровку: установленный артефакт связан с хешами данных и принятой зоной. Несовместимый артефакт вызывает явную ошибку.
8. Как проверить решение
В командах ниже python означает Python активированного виртуального окружения. Без активации используйте .\.venv\Scripts\python.exe в Windows или .venv/bin/python в Linux/macOS.
Проверки без внешних API
python -m unittest discover -s tests -v
python scripts/verify_submission.py
Автоматические тесты проверяют временные границы, калибровку, ошибки архивного источника, интерфейс/инструменты, экранирование HTML и сохранность предыдущих файлов. Они проверяют программу; это не измерение качества ML на феврале.
verify_submission.py проверяет уже сохранённые CSV и .provenance.json, включая контрольную сумму, точное покрытие часов, диапазон мощности, времена погодных источников, обучения и калибровки. Исходные SCADA CSV и интернет для этой команды не нужны. Ожидаемый результат полной выгрузки: status: success, row_count: 1344, daily_runs: 56, weather_sources_checked: 5376. Проверка относится к согласованности сохранённых доказательств; HTTP Last-Modified не заменяет независимый журнал первой публикации.
Короткий запуск с настоящей погодой
python batch_forecast.py --start 2026-02-01 --end 2026-02-01 --output artifacts/smoke_february_01.csv
Ожидается 48 строк: 24 целевых часа одной даты для каждой из двух турбин. Рядом появляется artifacts/smoke_february_01.provenance.json. При отсутствии погодного архива процесс должен завершиться ошибкой, не подставляя фактическую погоду.
Полный февраль
python batch_forecast.py --start 2026-02-01 --end 2026-02-28 --output submission_february_2026.csv
Ожидается 1344 строки, по 672 для турбины, без пропусков и дубликатов. Первый запуск скачивает внешние данные и может занять значительное время; следующий использует кэш. --refresh запрашивает обновление погодного входа.
Проверьте весь результат, включая контрольную сумму:
python scripts/verify_submission.py submission_february_2026.csv
CSV и JSON записываются во временные файлы, CSV заменяется последним. Проверка хеша обязательна: замена двух отдельных файлов не является единой транзакцией при аварийном выключении компьютера.
В .gitattributes для CSV и JSON отключено преобразование переводов строк: Git сохраняет их точные байты, чтобы контрольные суммы артефактов совпадали после checkout в Windows и Linux.
В интерфейсе выберите «Турбина», «Первый день прогноза» и «Горизонт, часы», нажмите «Рассчитать выбранный прогноз». При необходимости введите «Момент решения (ISO 8601)» с явным смещением. Проверьте источник и время выпуска, раскройте «Проверки прогноза», затем нажмите «Проверить обновление показанного прогноза». Ошибка отображается отдельно; последний успешный прогноз, если он есть, остаётся явно подписанным своим периодом и идентификатором. Кнопка «Скачать отчёт для жюри (HTML)» сохраняет файл с графиком и всеми часами, который открывается без интернета. Подробный сценарий находится в DEMO.md.
Ручная проверка настоящего AI-агента
python scripts/smoke_agent.py --run-live --scenario inspect
python scripts/smoke_agent.py --run-live --scenario forecast
Команды читают OPENAI_API_KEY из локального окружения/.env и обращаются к OpenAI через реальные run_agent и диспетчер инструментов. inspect проверяет чтение заранее рассчитанного снимка; forecast проверяет запуск расчёта по запросу агента. На каждый запуск — максимум три API-запроса, без автоматических повторов, тайм-аут 30 секунд и до 700 выходных токенов на запрос. Команды расходуют API-кредиты; без флага --run-live запросы не выполняются. Итоги сохраняются в локальных artifacts/live_smoke.json и artifacts/live_smoke_forecast.json. Команды не активируют промокоды или кредиты организаторов.
Калибровка прогноза мощности и её воспроизведение
Базовая модель LightGBM учится по SCADA, а в прогнозировании получает сеточную погоду GFS. Чтобы уменьшить систематическую ошибку выходной мощности, установлен зафиксированный артефакт models/power_calibration.json: clip(a × raw_power + b, 0, 1) с ridge-регуляризацией к преобразованию без изменений. Коэффициенты отдельные для двух турбин и диапазонов 1–24 / 25–48 часов. Поля ветра и температуры не корректируются.
Протокол эксперимента:
- Подгонка: решения с датами начала прогнозов 1–16 января, только целевые часы, завершённые к 16 января 18:00 UTC / 23:00 Asia/Almaty. Последний использованный целевой час начинается в 17:00 UTC. Параметры сохраняются до оценки и далее не переобучаются.
- Основная оценка: даты начала прогнозов 17–23 января, по 48 часов для каждой турбины. Последние целевые часы относятся к 24 января.
- Правило внедрения задано до расчёта оценочных метрик: общая MAE улучшается минимум на 5%, RMSE не ухудшается, ни одна группа «турбина × диапазон» не ухудшается по MAE более чем на 3%. Основной кандидат всегда
ridge_affine;ridge_bias— только дополнительное сравнение, а не выбор лучшего постфактум. - Это январский эксперимент выбора модели, не окончательный независимый тест. Более позднее окно 24–30 января уже рассматривалось до эксперимента. Поэтому отдельно приведён срез целевых часов до 24 января. Перекрывающиеся 48-часовые решения внутри каждого окна тоже не являются независимыми наблюдениями.
Результат основной оценки, 672 оценённые строки, покрытие 100%; ошибки в исходной безразмерной шкале:
| Метод | MAE | RMSE | Среднее смещение |
|---|---|---|---|
| LightGBM без калибровки | 0,3221 | 0,4377 | +0,2762 |
| LightGBM + зафиксированная калибровка | 0,2210 | 0,2862 | −0,0372 |
| Последнее доступное измерение | 0,3793 | 0,5030 | −0,0007 |
| Среднее доступной истории | 0,2906 | 0,3438 | +0,0174 |
По сравнению с базовой моделью MAE снижена на 31,38%, RMSE — на 34,61% на указанном январском окне. Это относительное изменение ошибок, не «процент точности» и не февральский результат. На отдельном срезе из 624 прогнозных строк с целевыми часами до 24 января MAE составляет 0,3280 → 0,2085, RMSE 0,4387 → 0,2728. Срез исключает целевые даты ранее просмотренного окна, но не устраняет повторение целевого часа в разных прогнозных решениях.
Точные значения и протокол: validation/calibration/report.json; строки — validation/calibration/predictions.csv, данные подгонки — validation/calibration/fit_predictions.csv, происхождение — validation/calibration/provenance.json.
В интерфейсе результат доступен в блоке «Эффект калибровки на последующих январских прогнозах»; он отделён от почасового февральского прогноза и проверки модели при измеренной погоде.
Воспроизведение эксперимента:
python scripts/calibrate.py --help
python scripts/calibrate.py --output artifacts/calibration_reproduction
Нужны исходные SCADA CSV и доступ к погодному архиву либо ранее наполненный кеш. Скрипт временно отключает установленную калибровку для получения базовых прогнозов, сохраняет параметры до вычисления оценочных метрик и создаёт calibration_candidate.json только в указанном каталоге. Он не заменяет models/power_calibration.json автоматически. Протокол, параметры, прогнозные строки и отчёт сохраняются рядом с кандидатом.
В рабочем движке калибровка применяется лишь при совместимых хешах CSV, версии LightGBM-модели, часовом поясе и допустимой временной границе. Для более ранних решений она не применяется с явным статусом. available_at означает момент, к которому доступны использованные обучающие целевые часы и погодные свидетельства; это не заявление, что данный программный артефакт был физически создан в январе.
Историческая проверка полного прогноза
python backtest.py --start 2026-01-24 --end 2026-01-30 --horizon 48 --output validation/backtest.json
Каждый день начала прогноза с 24 по 30 января воспроизводится отдельно; последние целевые часы относятся к 31 января. Момент решения — 23:00 предыдущего дня. Модель обучается только на завершённых часах SCADA, доступных до решения. Сравнение всех методов выполняется на одних и тех же целевых часах.
Реальный запуск завершён: 14 прогнозов × 48 часов = 672 строки, для всех строк найдено фактическое значение. В каждом сочетании турбины и диапазона горизонта — 168 оценённых строк, покрытие 100%. Это строки отдельных решений; соседние 48-часовые прогнозы перекрываются и не являются независимыми наблюдениями.
Метрики из validation/backtest.json, округление до четырёх знаков, исходная нормализованная шкала:
| Турбина | Горизонт, ч | MAE модели | MAE последнего значения | MAE среднего истории | RMSE модели | RMSE среднего истории |
|---|---|---|---|---|---|---|
| turbine_1 | 1–24 | 0,1933 | 0,4108 | 0,3371 | 0,2603 | 0,3763 |
| turbine_1 | 25–48 | 0,1999 | 0,4252 | 0,3129 | 0,2632 | 0,3505 |
| turbine_2 | 1–24 | 0,1984 | 0,4069 | 0,3378 | 0,2680 | 0,3765 |
| turbine_2 | 25–48 | 0,2094 | 0,4207 | 0,3225 | 0,2741 | 0,3605 |
«Последнее значение» — последняя завершённая мощность, известная в момент решения, сохраняемая на весь горизонт. «Среднее истории» — среднее всех доступных обучающих часов, также фиксированное на горизонт.
Таблица относится к текущей модели с калибровкой. По сравнению с исходной моделью на этом дополнительном, ранее просмотренном окне общая MAE составляет 0,2357 → 0,2003 (снижение на 15,05%), RMSE — 0,3400 → 0,2664. Улучшение неоднородно: на первых сутках MAE turbine_1 немного ухудшилась 0,1890 → 0,1933, turbine_2 — 0,1897 → 0,1984. На вторых сутках ошибки снизились. Общее смещение изменилось с +0,1996 на −0,0961: остаточное занижение тоже требует дальнейшей проверки. Нельзя переносить январское улучшение на февраль без фактической выработки.
Исходная проверка сохранена в validation/baseline/; точное сравнение фиксированных методов — validation/calibration/additional_jan24_30.json и соседний CSV. Более выгодный на этом окне дополнительный метод ridge_bias не выбран вместо заранее установленного основного кандидата: окно не используется для нового подбора параметров.
Интерфейс загружает этот отчёт и показывает метрики отдельно от проверки модели при измеренной погоде. Полные значения, включая RMSE и смещение базовых методов, сохраняются в JSON; строки для воспроизведения — в validation/backtest.predictions.csv.
Дополнительная проверка метода на декабре
Тот же фиксированный метод калибровки отдельно обучен на прогнозах с датами начала 1–16 декабря 2025 года и проверен на стартах 17–23 декабря: 672 строки, обе турбины, горизонты 48 часов. MAE уменьшилась 0,235739 → 0,216316 (−8,24%), RMSE — 0,338558 → 0,276962 (−18,19%); MAE улучшилась во всех четырёх группах «турбина × первые/вторые сутки».
Метод ранее выбирался на январе, поэтому это ретроспективная проверка его устойчивости на более раннем месяце, не независимое перспективное испытание. Декабрьские коэффициенты оценены только по более ранним декабрьским данным и зафиксированы до оценочного окна. Производственная январская калибровка и февральский файл не изменены. Протокол, таблица и команды воспроизведения включают все 46 запусков и погодные свидетельства.
python scripts/verify_december_robustness.py --output validation/december_robustness
Эта команда проверяет сохранённые материалы без сети и CSV организаторов. Полное повторение эксперимента описано по ссылке; оно требует исходных данных и архива NOAA.
Автоматическая повторная проверка входов
python watch_forecast.py --turbine turbine_1 --forecast-date 2026-02-01 --horizon 48 --cycles 3 --interval 60 --output artifacts/watch.jsonl
Команда делает начальный расчёт и ещё две проверки с интервалом 60 секунд. После первого цикла используется refresh=True: входы перечитываются из погодного архива, численный прогноз пересчитывается. Изменения и ошибки отображаются в терминале, неизменное состояние не создаёт повторных сообщений. Каждый исход записывается в JSONL. После ошибки следующий цикл повторяет попытку, сохраняя идентификатор последнего успешного результата.
Во всех циклах сохраняется один исторический момент решения: поздние публикации не становятся допустимыми только потому, что запрос повторён сегодня. По умолчанию решение на час раньше первого целевого часа; его можно задать через --issue-time с явным смещением. Ежедневное продвижение исторического момента выполняет batch_forecast.py.
Это ограниченный процесс в текущем терминале: после заданного числа циклов он завершается. Он не устанавливает фоновую службу или расписание ОС и не продолжает работу после закрытия процесса.
9. Данные, координаты и формат результата
CSV организаторов
Используются время, средний ветер (м/с), нормализованная активная мощность и температура (°C). Исторический период по заданию — март 2023 — 31 января 2026 включительно. Метки времени исходных CSV не содержат часовой пояс.
Принято допущение Asia/Almaty; оно не подтверждает намерения авторов набора. Часы неоднозначного перевода времени исключаются и отражаются в аудите. Для полного часа требуется шесть валидных десятиминутных наблюдений; пропуски не заполняются будущими значениями.
| Идентификатор | Широта | Долгота | Ссылка из задания |
|---|---|---|---|
turbine_1 | 43.645150 | 78.535604 | Координаты турбины 1 |
turbine_2 | 43.643198 | 78.538828 | Координаты турбины 2 |
Архивная погода
Используются исходные оперативные выпуски NOAA GFS 0,25°, а не склеенные первые часы разных запусков и не реанализ. Алгоритм выбирает один шестичасовой цикл, начиная с консервативного отступа в шесть часов от момента решения. Он проверяет HTTP Last-Modified каждого индекса и GRIB-объекта: время объекта не должно быть позже решения. Это сохранённое свидетельство доступности объекта в архиве, не независимый журнал первой публикации. В метаданных явно отражается ограничение доказательства.
Ветер рассчитывается по компонентам U/V на 100 м, температура — поле 2 м с переводом Кельвинов в °C. Используются исходные почасовые прогнозные сроки 1–120 часов без временной интерполяции. Высота 100 м не объявляется подтверждённой высотой ротора.
В пространстве выбирается ближайшая ячейка сетки: для обеих близких турбин это 43,75° N, 78,5° E, примерно в 12 км от объекта. Поэтому прогноз погоды у них одинаковый; различия прогнозов мощности обусловлены отдельными обученными моделями. Применение к гондоле требует калибровки.
Provenance содержит URL, прогнозный срок, границы байтов GRIB, Last-Modified, ETag, SHA-256 извлечённых сообщений, время решения и выпуска, координаты ячейки, высоты и единицы. Поле available_at — максимальное время архивных объектов, участвующих в расчёте. .cache/weather/ сохраняет извлечённую погоду с доказательствами; --refresh перечитывает источник. При отсутствии нужного выпуска или байтового диапазона расчёт завершается ошибкой.
Источники: NOAA GFS в реестре открытых данных AWS, описание продуктов GFS NOAA/NCEP.
Итоговый CSV
| Поле | Смысл |
|---|---|
turbine | turbine_1 или turbine_2 |
timestamp | Целевой час YYYY-MM-DD HH:MM:SS, местное время принятой зоны, без смещения для совместимости со старым CSV |
wind_speed_ms | Погодный прогноз скорости ветра, м/с |
temperature_c | Погодный прогноз температуры, °C |
predicted_power | Прогноз в исходной нормализованной шкале [0, 1] |
Во внутренних результатах время содержит явное смещение UTC. Интерфейс показывает местное время и UTC явно; скачивание из интерфейса дополнительно содержит time_local, time_utc и идентификаторы результата. Пять колонок таблицы выше описывают пакетный файл сдачи. В .provenance.json указаны зона, момент решения каждого запуска, метаданные погоды и хеш CSV. Формат пяти колонок сохранён для совместимости с проектом; организаторы не предоставили обязательную схему, поэтому он не называется официально утверждённым форматом сдачи.
10. Ограничения и интерпретация качества
- Нормализация неизвестна. Даже диапазон
[0, 1]сам по себе не подтверждает физическое p.u.P/P_rated. Без базы и формулы нормализации нельзя честно получить МВт или МВт·ч, агрегированную мощность всей ВЭС и финансовую экономию. - Часовой пояс — допущение. После уточнения его необходимо заменить и пересчитать обучение, погоду и итоговые файлы. Неоднозначные часы исторического перехода удаляются с учётом в аудите.
- R²/MAE при измеренной погоде не равны качеству прогноза на 48 часов. Такая валидация оценивает зависимость мощности от известной погоды и не включает погрешность NWP. Нельзя называть R² процентом точности или переносить эту метрику на февраль.
- Фактическая февральская мощность не предоставлена. Точность за февраль и предотвращённые потери не заявляются. Выполнена короткая временная проверка всего процесса на январских выпусках с базовыми методами и оценками горизонтов 1–24/25–48 часов; она не заменяет расширенный тест на разных сезонах и режимах работы.
- Различие обучающих и прогнозных входов. Модель мощности обучается на измерениях SCADA, а в работе получает погодный прогноз на сетке 0,25°. Зафиксированная январская коррекция изменяет прогноз мощности, не погодные поля. Она не решает пространственную и высотную калибровку GFS к датчику турбины.
- Короткий эксперимент и выбор модели. Январское улучшение получено на ограниченном периоде; соседние 48-часовые окна перекрываются. Окно 24–30 января было предварительно просмотрено, поэтому оно не представлено как новый независимый тест. На первых сутках этого дополнительного окна MAE после калибровки немного хуже исходной модели. Параметры не подбирались повторно по этим результатам.
- Оперативность SCADA — допущение. Метки приняты за начало десятиминутного интервала; завершённый час считается доступным сразу, без дополнительной задержки. Реальная задержка телеметрии не известна.
- Доступность погоды подтверждается свойствами архива.
Last-Modifiedне заменяет независимый журнал распространения прогнозов. Выбранная политика консервативна, но это допущение должно быть приемлемо для организаторов. - Нет подтверждённых нормативных порогов ГОСТ/КОРЭМ, официального тарифа БРЭ, подтверждённой паспортной мощности и доказанного ROI. Текст LLM не устанавливает соответствие нормативам.
- Погодный архив и интернет могут быть недоступны. В таком случае система сохраняет ошибку; полного результата за период нет. Кэш ускоряет повторение, но не должен маскировать отсутствие происхождения данных.
- Прототип не управляет оборудованием и не подключён к промышленной SCADA. Рекомендации агента не являются командами диспетчеризации.
Направления развития: расширить последовательную проверку калибровки на разные сезоны и новые периоды; обучать модель непосредственно на исторических NWP-входах; оценивать интервалы неопределённости; учитывать остановы и ограничения турбин; подтверждать мощность и единицы; подключить оперативные наблюдения и промышленный мониторинг.
11. Развёрнутая версия
Публичная deployed-версия не предоставлена. После локального запуска Streamlit обычно доступен по адресу http://localhost:8501; это локальный интерфейс, а не ссылка для удалённого жюри.
Авторы коммитов
История коммитов
- 2026-09-23 17:29docs: add December robustness evidence and jury quickstartMRXmark357
- 2026-09-23 16:41feat: calibrate wind forecasts and add reproducible jury reportsMRXmark357
- 2026-09-23 15:35fix: make historical wind forecasts auditable and reproducibleMRXmark357
- 2026-09-23 14:45docs: finalize README with screenshots and complete 11 hackathon criteriaMRXmark357
- 2026-09-23 14:24feat: add BEM balancing market risk assessment tool and ROI calculationMRXmark357
- 2026-09-23 14:07feat: complete end-to-end wind forecasting pipeline, batch simulation and submissionMRXmark357
- 2026-09-22 23:52first commitMRXmark357
Структура репозитория (104 файлов)
.env.example .gitattributes .gitignore DEMO.md JURY.md README.md agent_audit.png agent_payload.py app.py backtest.py batch_forecast.py dashboard.png docs/forecast_example.html forecast_engine.py models/power_calibration.json power_calibration.py reporting.py requirements.txt scripts/calibrate.py scripts/december_robustness.py scripts/smoke_agent.py scripts/verify_december_robustness.py scripts/verify_submission.py submission_february_2026.csv submission_february_2026.provenance.json tests/test_agent_payload.py tests/test_app.py tests/test_batch.py tests/test_calibrate_script.py tests/test_forecast_engine.py tests/test_power_calibration.py tests/test_reporting.py tests/test_submission_verifier.py tests/test_watch_forecast.py tests/test_weather_archive.py validation/agent_smoke.json validation/backtest.json validation/backtest.predictions.csv validation/baseline/backtest.json validation/baseline/backtest.predictions.csv validation/calibration/additional_jan24_30.json validation/calibration/additional_jan24_30.predictions.csv validation/calibration/fit_predictions.csv validation/calibration/fitted_before_evaluation.json validation/calibration/predictions.csv validation/calibration/provenance.json validation/calibration/report.json validation/december_robustness/README.md validation/december_robustness/evaluation_predictions.csv validation/december_robustness/fitted_before_evaluation.json validation/december_robustness/protocol.json validation/december_robustness/provenance.json validation/december_robustness/raw/turbine_1_2025-12-01_48.json validation/december_robustness/raw/turbine_1_2025-12-02_48.json validation/december_robustness/raw/turbine_1_2025-12-03_48.json validation/december_robustness/raw/turbine_1_2025-12-04_48.json validation/december_robustness/raw/turbine_1_2025-12-05_48.json validation/december_robustness/raw/turbine_1_2025-12-06_48.json validation/december_robustness/raw/turbine_1_2025-12-07_48.json validation/december_robustness/raw/turbine_1_2025-12-08_48.json validation/december_robustness/raw/turbine_1_2025-12-09_48.json validation/december_robustness/raw/turbine_1_2025-12-10_48.json validation/december_robustness/raw/turbine_1_2025-12-11_48.json validation/december_robustness/raw/turbine_1_2025-12-12_48.json validation/december_robustness/raw/turbine_1_2025-12-13_48.json validation/december_robustness/raw/turbine_1_2025-12-14_48.json validation/december_robustness/raw/turbine_1_2025-12-15_48.json validation/december_robustness/raw/turbine_1_2025-12-16_24.json validation/december_robustness/raw/turbine_1_2025-12-17_48.json validation/december_robustness/raw/turbine_1_2025-12-18_48.json validation/december_robustness/raw/turbine_1_2025-12-19_48.json validation/december_robustness/raw/turbine_1_2025-12-20_48.json validation/december_robustness/raw/turbine_1_2025-12-21_48.json validation/december_robustness/raw/turbine_1_2025-12-22_48.json validation/december_robustness/raw/turbine_1_2025-12-23_48.json validation/december_robustness/raw/turbine_2_2025-12-01_48.json validation/december_robustness/raw/turbine_2_2025-12-02_48.json validation/december_robustness/raw/turbine_2_2025-12-03_48.json validation/december_robustness/raw/turbine_2_2025-12-04_48.json validation/december_robustness/raw/turbine_2_2025-12-05_48.json validation/december_robustness/raw/turbine_2_2025-12-06_48.json validation/december_robustness/raw/turbine_2_2025-12-07_48.json validation/december_robustness/raw/turbine_2_2025-12-08_48.json validation/december_robustness/raw/turbine_2_2025-12-09_48.json validation/december_robustness/raw/turbine_2_2025-12-10_48.json validation/december_robustness/raw/turbine_2_2025-12-11_48.json validation/december_robustness/raw/turbine_2_2025-12-12_48.json validation/december_robustness/raw/turbine_2_2025-12-13_48.json validation/december_robustness/raw/turbine_2_2025-12-14_48.json validation/december_robustness/raw/turbine_2_2025-12-15_48.json validation/december_robustness/raw/turbine_2_2025-12-16_24.json validation/december_robustness/raw/turbine_2_2025-12-17_48.json validation/december_robustness/raw/turbine_2_2025-12-18_48.json validation/december_robustness/raw/turbine_2_2025-12-19_48.json validation/december_robustness/raw/turbine_2_2025-12-20_48.json validation/december_robustness/raw/turbine_2_2025-12-21_48.json validation/december_robustness/raw/turbine_2_2025-12-22_48.json validation/december_robustness/raw/turbine_2_2025-12-23_48.json validation/december_robustness/report.json validation/december_robustness/status.json validation/december_robustness/training_predictions.csv validation/december_robustness/verification.json watch_forecast.py weather_archive.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.