Помните, я обещал рассказать про датасет, на котором можно сойти с ума? Ну вот, однажды пришли к нам инженеры производства и говорят, что надо помочь с отладкой. Цеха.
В одном из рулонов стали на 325-м метре образовалась продольная трещина, и теперь все в цеху хотят знать, где что случилось и почему. То есть надо проследить, что конкретно происходило с этим кусочком стали на протяжении всей его биографии.
Задача понятная: берём архитектора, берём данные со всех датчиков, архитектор совершает какую-то магию — и вот у нас готовый датасет для анализа.
И вот на «берём данные с датчиков» мы споткнулись в первый раз. Архитектор, умный адекватный мужик, привыкший работать с синтетическими данными и чистой математикой, чуть не сошёл с ума на нашем реальном производстве.
И уволился посреди проекта со словами, что его психика этого больше не выдержит.
Потому что в теории всё немного не так, как на практике — например, есть много случаев, когда последовательность, которая по определению должна быть монотонно возрастающей, может быть:
- Невозрастающей.
- Немонотонной.
В смысле, что это в принципе физически невозможно, но часто происходит. Ещё могут быть скачки во времени и другие нарушения причинно-следственной связи.
Знакомьтесь: цех! Цех, знакомься: хабрачитатели!
Дано: огромное литейно-прокатное производство, самая главная установка на котором — МНЛЗ (машина непрерывного литья заготовок). Сначала мы плавим металлолом, потом доводим жидкую сталь до кондиции и начинаем разливать. Ковш расплавленной стали выливают в МНЛЗ, которая подаёт жидкий металл в кристаллизатор, спускает по установке розлива стали, и на выходе получается мягкий, как пластилин, стальной брусок — сляб — длиной в среднем 25 метров и температурой около 900 градусов. Потом его катают через кучу оборудования и получают рулоны стали длиной до 1500 метров.
Та часть производства, с которой мы работали, принципиально выглядит так:
1) Льём жидкую сталь в машину слева. Оттуда она вытекает и попадает в кристаллизатор, где сначала получает твёрдую корочку на поверхности, а потом становится тем самым «бруском пластилина», только больше и другим.
2) Этот брусок едет в длинную печку выравнивать температуру, потом попадает в ролики черновой клети, из него делается условно сто метров толстого листа.
3) Дальше он подрезается, попадает в чистовую группу, где плющится до нужной толщины по ГОСТу и заказу, и в зависимости от этой самой толщины получается лист длиной от 300 до 1 000 метров.
4) Охлаждение, моталка — и вот у вас рулон стали, который так нужен клиентам.
Теперь, если на 325-м метре результирующего рулона — раковина, продольная трещина или ещё какой-то дефект, то это значит, что раньше в процессе что-то пошло не так. Например, это могут быть забившиеся форсунки в контуре охлаждения, и тогда получилась неравномерная корочка, и сляб слегка «повело». Или не тот режим охлаждения, и тогда сляб могло покрыть трещинами или в нём могли образоваться внутренние раковины. Или автоматике сказали, как охлаждать, а она не так охладила. Или человек, который выбрал уставку, зачем-то выбрал её от стали чуть другой марки. Или технолог придумал классную оптимизацию — всё просто летает, но есть нюанс.
Нам нужно создать универсальный инструмент, который подходил бы для анализа: всегда нужно докапываться до сути. Без данных в быстрой доступности поиск проблемы похож на отладку без отладчика, подсказок компилятора или брекпоинтов, а просто методом внимательного созерцания кода и попыток проиграть его в голове.
И вот тут как раз нас и позвали доработать датасет этого литейно-прокатного комплекса — детализировать информацию вплоть до уровня конкретных багов.
Зачем ловить конкретные баги
Представьте, что вы стоите в конце линии и наблюдаете дефект на рулоне. Можно просто взять и вырезать кусок с дефектом, это будет стоить какого-то количества времени и денег. А можно попробовать понять, почему он произошёл. И сравнить, например, стоимость какого-то текущего ремонта и выкидывания куска с дефектом в переплавку.
В результате нужно быстро сделать вывод, что и какую проблему вызывает, и из этого понять две важные вещи:
- Оптимальные режимы для разных сталей и изделий.
- Оптимальные действия, например, — останавливать разливку и чинить форсунки сразу или ремонтировать только после смены.
Словом, технологам это просто надо. Они верят, что, получив данные отладки, можно разговаривать друг с другом на одном языке. В смысле они и так на одном языке, но теперь ещё и с конкретной аргументацией, и с числами, и с вещдоками.
А нам надо собрать датасет. Очень просто.
Собираем датасет
Утрируя, на каждой машине есть контроллер, который непосредственно управляет автоматикой узла. Над контроллером — АСУТП, которая снимает с него данные и говорит ему, что делать.
Над АСУТП — уже MES, т. е. планирование производства, из которой АСУТП узнаёт заказы.
На производстве в режиме нон-стоп происходит двухсторонняя интеграция по цепочке: MES говорит, что нужно делать, АСУТП говорит, как это делать, а контроллер говорит: «Есть!» — и идёт исполнять приказанное. Затем докладывает о результатах АСУТП, а та, в свою очередь, упаковывает эту информацию и отправляет MES усреднённые данные о единице продукта.
Нам нужна телеметрия с узла.
Сам контроллер не хранит историю, просто регулярно перезаписывает во внутренней памяти текущие значения всех своих параметров (сигналов). Эти данные оттуда вычитывает АСУТП, которая хранит их буквально пару циклов в оперативке, потом строит по ним какой-то агрегат, а сам временной ряд удаляет (или вообще никуда не записывает). MES получает ещё более абстрактные данные уровня «Изделие № 882 готово».
Средние показатели нас не интересуют, нам надо искать конкретный сантиметр сляба, на котором что-то случилось, что вызвало дефект на 325-м метре листа. И что, собственно, было на узле, когда этот сантиметр его проезжал. То есть нам нужна та самая телеметрия со станка, которую генерит контроллер.
К счастью, такая детальная информация нужна не только технологам, но ещё и ремонтникам, которые озаботились вопросом заранее и подключили к контроллеру ещё одну систему, которая раз в 20 миллисекунд читает память контроллера и, как чёрный ящик в самолёте, записывает всё, что видит. С какими плясками с бубном мы учились читать с неё данные, долгосрочно хранить и обеспечивать доступ для анализа, можно почитать вот в этом посте, просто скажу, что это было не так чтобы совсем легко и быстро. В общем, для нужд анализа мы умеем читать память контроллера и собирать с него временные ряды сигналов телеметрии.
Телеметрия — это, скажем, тысяча датчиков по узлу, которые дают аналоговый сигнал, соединяются проводами с коробкой контроллера, а он каждый аналоговый сигнал дискретизирует и записывает с какой-то периодичностью в ячейку памяти, соответствующую тому или иному датчику.
До этого момента всё выглядит логично и совсем-совсем непсиходелично.
Всё, что нам нужно, — это поджойнить ряды.
Сама задача
- Итак, дефект на 325-м метре результирующего рулона.
- Поскольку его раскатали из полосы после черновых клетей, это 60-й метр первой полосы.
- Поскольку полосу сделали из сляба, это примерно 20-й метр искомого сляба.
- Теперь мы берём этот метр сляба и хотим посмотреть все события производства, связанные именно с ним. И поискать отклонения.
Именно в этот момент мы заподозрили, что с архитектором что-то не так.
Джойн не получается. Все события есть, временные ряды друг другу однозначно соответствуют.
Всё хорошо. И тут вдруг вылезает дичь. Например, решая простейшую задачу вроде «А когда же на оборудовании началась новая единица продукции?», достаточно посмотреть на действия делительных ножниц. После их срабатывания обычно сразу и начинается новая единица: у неё просто нет выбора. Примитивно? Да. Лезем в базу АСУТП. А в базе — всё те же данные, но со сдвигом на семь секунд.
ОК, делаем джойн со сдвигом. Но хитрая железяка ускользает от нас, уже в соседнем сэмпле она сдвинулась на полсекунды.
Начинаем искать закономерность и понимаем, что её нет. Точнее, мы не видим. Все данные правильные, читаются нормально, датчики работают, но последовательности гуляют одна относительно другой. Причём ошибка в районе пяти–семи секунд — плавающая, а как именно и куда она плавает, предсказать нельзя. Собственно, в этом месте архитектор, привыкший к тому, что математика — строгая наука, потерял спокойствие, сон и попытался сделать коррекцию.
Джойн с толерансом тоже не прокатил: железяка уж больно часто уворачивалась от нас во временных рядах.
Мы до сих пор не знаем точной причины сдвигов, но есть гипотеза, что это время на вычитывание с датчика, затем — запись в ячейку памяти, а потом — на чтение нашей системой, которая по приоритету ниже АСУТП. То есть мало того, что контроллер имеет свою задержку — ведь когда мы читаем данные с датчика, мы читаем не датчик, а делаем запрос на чтение в ячейку памяти, ему соответствующую, — так ещё мы находимся в очереди с командами и запросами АСУТП и вынуждены ждать, пока среди них не образуется окно. Возможно, дело в этом.
Мы пришли к разработчикам этого контура и предложили поковыряться, на что они очень резонно заметили:
— Так это, оно же работает.
— И?
— Ну и НЕ ТРОГАЙТЕ! Работает же!
Логика в их словах есть, потому что цена нашего проекта — десятки миллионов экономии, а цена косяка в очередях АСУТП — остановка производства. А это — всё непроизведённое за это время (то есть несколько сотен тонн стали) плюс у нас много машин с буквами «н» в названии, а это значит — «непрерывного». И это не значит, что они могут работать непрерывно, а значит, что они должны всегда работать непрерывно, потому что если их остановить, то изнутри придётся, например, доставать застывшую сталь. И не всегда это в принципе возможно без замены существенной части узла.
В итоге знаете что мы сделали? Перестали даже пытаться что бы то ни было заджойнить чётко по времени. То есть начали работать с массивом данных так, как есть, и решили, что разберёмся с тем, что мы произвели, уже на постобработке.
Окончательно архитектор решил завязать с заводом в тот момент, когда узнал, что не только математика, но и физика — это некая условность. Потому что не могут части железяки ползти с разной скоростью или не в том порядке.
Но, судя по данным, у нас ползут.
Полиция времени
Представьте, что у вас есть некий объект, который может двигаться по производственной линии только в одном направлении. Его катят по роликам, а он, соответственно, катится без остановки.
И вот в какой-то момент вдруг наступает некое событие, в ходе которого объект прыгает по стану на несколько метров вперёд или назад. В целом, если он прыгает вперёд, это совершенно рядовая ситуация, за которой следует коррекция трекинга. А вот если назад — это уже неприятно.
Потому что, во-первых, там уже находятся другие части этого же объекта. А во-вторых, потому что создаётся впечатление, будто один и тот же объект проходит одну и ту же координату дважды.
Короче, в коде АСУТП есть коррекции датчиков. Когда система по некоторому набору датчиков думает одно, а ещё один датчик показывает другое, АСУТП выбирает более надёжный датчик и считает его показания более приоритетными. Трекинг измеряется косвенно, например, МНЛЗ корректируется по пирометру. Когда реальный металл доезжает до датчика, это точно понятно по температуре, которую показывает прибор. Ну почти точно, потому что по факту воздух начинает греться чуть раньше, чем к датчику подходит сама железяка. Параллельно мы проверяем информацию по другим датчикам и вводим поправку на погрешность измерения.
Собственно, дальше в АСУТП срабатывает алгоритм из десятка-двух IF, который корректирует всё вокруг. С точки зрения более верхнеуровневых систем (в том числе нашей) это и означает прыжки во времени.
Так код оброс неким набором IF, но мы уже хорошо знаем, что с этими погрешностями нужно просто жить.
Разрезов 20, а кусков — 10
Следующий взрыв мозга случился в тот момент, когда мы начали считать изделия. Ножницы сработали 20 раз — значит, на линии должно быть 20 изделий. Логично? Логично. Но АСУТП почему-то учла только 10 из них. Там сляб режется на куски, и каждый кусок отделяется от другого ударом огромных ножниц. Если считать удары — у вас 20 кусков. Если считать куски — у вас 10 единиц продукции в АСУТП. Причём данным АСУТП, как показывает вся 15-летняя история существования цеха, вполне можно доверять. Получается, где-то по пути потеряли 10 слябов?!
Идём к технологам, они смотрят на данные, потом — на нас, потом — на данные и говорят:
— Так это, обрезь целиком в загрузочный лоток металлоприёмника не лезет.
Короче, как отправить большой кусок металла обратно в переплавку? Правильно, поделить его на куски, чтобы можно было удобнее его транспортировать. А где проще всего порезать металл?
Правильно, там, где есть ножницы и где этот металл горячий и пластичный. Ну они и нашинковали один из кусков в стружку, просто запустив ножницы с десяток раз на один кусок.
Это так и задумано.
Что мы сделали? Добавили виртуальный датчик ножниц, который собирал данные с обычного датчика ножниц, но, когда ножницы стучали слишком часто, превращал N подряд идущих ударов в один большой. То есть собрали детекцию шинковки — когда началась, когда закончилась: если там — шлёп-шлёп-шлёп-шлёп и слябы получаются по нескольку десятков сантиметров, то это шинковка. Нашинкованный кусок забирают технологи, это и есть примерно 70-сантиметровая линия отреза. И в данных, и в АСУТП дальше едет одинаковое количество кусков.
Аномалии трекинга и ножницы Шрёдингера
Разные датчики собирают данные с разной частотой: одни — чаще, другие — реже. Поэтому может получиться абсурдная ситуация, в которой для одного и того же значения трекинга мы получим несколько разных показателей, например, сигналов ножниц и в придачу — сложный вопрос, которому из них верить. Эдакие ножницы Шрёдингера, которые сработали и не сработали одновременно. Сначала мы можем получить фрейм FALSE, потом — два фрейма TRUE, а в трекинге все три значения будут одинаковыми.
Это особенности дискретизации аналогового сигнала датчиков. Что делать? Решать аномалии.
Если есть фрейм с TRUE для трекинга, то надо принудительно выставить флаг в TRUE для всех отсчётов сигнала с этим значением трекинга, тогда это не помешает дальнейшим преобразованиям. Ну просто срабатывание ножниц заняло три фрейма, а не один, так бывает.
Потом начали пропадать куски партии
В какой-то момент мы выяснили, что посреди стана пропадает ещё кусок сляба. Просто между черновыми и чистовыми клетями технолог может вырезать сантиметров двадцать, чтобы кусок лучше зашёл в приёмные валки. Не вопрос, это довольно простая коррекция, добавили ещё IF и пересчётов пропорций.
Следующий прикол был интереснее. Пакеты сигналов в разных системах состоят из отдельных файлов. Эти куски данных пронумерованы. Каждый кусок содержит два часа сигналов. У них есть последовательные идентификаторы. Мы думали, что можно читать последовательно.
Оказалось, что нет: чтобы понять логику нумерации, надо мыслить, как ковш стали.
Поскольку литейно-прокатный комплекс проектировался как единый объект, в коде это тоже отразилось, и учётной единицей стал именно ковш. То есть плавка определяет, какие из неё получаются слябы, а дальше они катятся и режутся на листы.
Так вот, если вы думаете, что плавка на машине непрерывной разливки стали — это непрерывное явление, то вы прогуливали логику. Работу самого ковша можно прерывать, если рядом есть второй ковш над буфером. То есть можно прекратить лить из одного ковша, подогнать другой, лить из него, а потом долить из первого ковша. Не самая стандартная ситуация, да, но причины так делать всё же бывают.
Пришлось переделывать движок сборки данных, но это было просто по сравнению с прошлыми доработками.
Итог
В условиях, когда есть только сырые данные узлов без координатной привязки, мы выделили ключевые события и построили виртуальную модель проката, которая позволяет ответить на вопрос, что было с 325-м метром полосы на всех предыдущих переделах вплоть до момента, пока этот метр даже ещё не знал, что он полоса, а был жидкостью.
Кодовая база инструмента примерно на 30 % состоит из алгоритма приведения датасета в приемлемое состояние. 70 % алгоритма — это IF для разных случаев жизни, когда на производстве нарушаются физические законы и искривляются пространство и время. Потому что в реальной жизни в данных всё далеко не так, как на бумаге. Монотонное инкрементное поле подвергается постоянной коррекции со стороны реального мира плюс возможны перекрытия данных и их потери.
Точность — до 10 сантиметров по финальной полосе в зависимости от длины и толщины рулона.
Технологи счастливы, теперь они пишут друг другу огромные письма с обоснованиями и всячески меняют процессы, пользуясь точным пониманием, где и что могло вызвать дефект.
А нам нужен новый архитектор. Желательно не перфекционист.
Данные на заводе как коробка шоколадных конфет: никогда не знаешь, какие законы физики, времени и пространства они нарушат сегодня. У нас весело, приходите!
Вакансии — тут.
За помощь в подготовке поста спасибо Филиппу Зорину.