Модели акустической диагностики
Создание моделей акустической диагностики оборудования
Введение
Подшипники качения являются критическими узлами большинства вращающихся механизмов: электродвигателей, редукторов, насосов, компрессоров. Их внезапный отказ приводит к остановке оборудования и дорогостоящему ремонту. При этом дефект развивается постепенно, и акустическая вибрация меняется задолго до полного разрушения. Задача состоит в том, чтобы по звуку работающего подшипника определить, какой именно его элемент изношен и насколько сильно.
В этой работе мы создадим модель машинного обучения, которая по акустическому сигналу оценивает степень износа трёх элементов подшипника: внутреннего кольца, внешнего кольца и тела качения. В нашем распоряжении четыре эталонных записи длиной 12 секунд: полностью исправный подшипник и три подшипника с полностью неисправными элементами. Из этих четырёх сигналов нужно получить модель, способную оценивать любую промежуточную степень износа от нуля до ста процентов.
Метод основан на смешивании сигналов. Мы разбиваем каждый эталонный сигнал на короткие сегменты, а затем создаём примеры с разной долей дефектной составляющей по формуле смешивания. Из каждого сегмента извлекаются диагностические признаки: статистики временной области, спектральные характеристики, энергии в частотных полосах и признаки огибающей. На этих признаках обучаются три модели случайного леса, каждая предсказывает износ своего элемента. В результате модель сохраняется в файл и готова к применению на новых сигналах, на основании которых будет выполняться диагностика ресурса каждого элемента подшипника.
Присоединение функций и библиотек
Подключим библиотеки, необходимые для работы с данными и обучения модели:
-
MAT – чтение акустических сигналов из файлов формата MATLAB.
-
WAV – запись сигналов в аудиофайлы и чтение WAV-файлов для диагностики.
-
Statistics – базовые статистические функции: среднее, медиана, стандартное отклонение, дисперсия.
-
StatsBase – расширенные статистики: асимметрия, эксцесс, квантили.
-
DSP – цифровая обработка сигналов, в частности преобразование Гильберта для вычисления огибающей.
-
FFTW – быстрое преобразование Фурье для спектрального анализа.
-
DecisionTree – реализация случайного леса для регрессии.
-
Random – фиксация генератора случайных чисел для воспроизводимости.
-
Serialization – сохранение обученной модели в файл JLS.
for pkg in (["MAT", "WAV", "Statistics", "DSP", "FFTW", "DecisionTree", "StatsBase", "Random", "Serialization"])
try
eval(Meta.parse("using $pkg"))
catch
Pkg.add(pkg)
eval(Meta.parse("using $pkg"))
end
end
Загрузим вспомогательные функции из внешних файлов:
media_player.jlсодержит интерактивный плеер для воспроизведения аудио;- функция
вычислить_признаки.jlвыполняет расчёт диагностических признаков из временного сигнала; - фуккция
выборка.jl, которая генерирует обучающие примеры путём смешивания сегментов.
include("media_player.jl")
include("вычислить_признаки.jl")
include("выборка.jl")
Исходные данные
Прочитаем файл Bearing.mat с четырьмя временными последовательностями акустических сигналов подшипника. Результатом станет словарь с ключами "normal", "roller", "inner", "outer", где каждому ключу соответствует матрица из 120000 отсчётов по 12 секунд. Эти данные послужат эталонными сигналами для обучения модели диагностики:
- normal — подшипник без дефектов, эталонное состояние;
- roller — подшипник с неисправностью тела качения;
- inner — подшипник с неисправностью на внутреннем кольце;
- outer — подшипник с неисправностью на наружном кольце.
подшипник = matread("Bearing.mat")
Преобразуем двумерные матрицы из MAT-файла в одномерные векторы длиной 120000 отсчётов для удобства обработки. Функция vec() преобразует матрицу в вектор, что необходимо для поэлементных операций при смешивании сигналов. Каждый вектор соответствует акустической записи подшипника с определённым типом дефекта.
норма = vec(подшипник["normal"]);
ролик = vec(подшипник["roller"]);
внутр = vec(подшипник["inner"]);
внеш = vec(подшипник["outer"]);
Выведем первые и последние значения нормального сигнала для визуального контроля загруженных данных.
display(норма)
Амплитуда находится в диапазоне примерно от -0.12 до +0.19, что соответствует исправному подшипнику с минимальной вибрацией. Этот сигнал станет эталоном, относительно которого будут оцениваться все дефекты.
Зададим частоту дискретизации сигналов. Нам известно, что записи длятся 12 секунд и содержат по 120 тысяч отсчётов, поэтому частота составляет 10 кГц. Это значение потребуется при вычислении спектральных признаков и частотных характеристик сигналов.
частота_дискретизации = 10000 # Гц
Воспроизведение и визуализация сигналов
Сохраним четыре эталонных сигнала в аудиофайлы формата WAV для возможности прослушивания. Каждый сигнал нормализуется делением на свой максимум. Частота дискретизации 10000 Гц записывается в заголовок WAV-файла.
wavwrite(норма/maximum(abs.(норма)), "Норма.wav", Fs=частота_дискретизации)
wavwrite(ролик/maximum(abs.(ролик)), "Ролик.wav", Fs=частота_дискретизации)
wavwrite(внутр/maximum(abs.(внутр)), "Внутр.wav", Fs=частота_дискретизации)
wavwrite(внеш/maximum(abs.(внеш)), "Внеш.wav", Fs=частота_дискретизации)
Встроим в скрипт интерактивный аудиоплеер для прослушивания и сравнения нормального и дефектного сигналов. Это позволит на слух заметить характерные щелчки при дефекте элементов и оценить различия между исправным и неисправным подшипником.
Воспроизведём аудиосигнал подшипника в нормальном состоянии.
media_player("$(@__DIR__)/Норма.wav", mode="audio")
Воспроизведём аудиосигнал подшипника с полностью неисправным телом качения.
media_player("$(@__DIR__)/Ролик.wav", mode="audio")
Построим сравнительный график первых 2000 отсчётов нормального сигнала и сигнала с дефектом тела качения. Норма показана синим, дефект оранжевым, что позволяет визуально оценить увеличение амплитуды и появление импульсных всплесков. Эти различия станут ключевыми признаками для модели машинного обучения.
гр_ролик = plot(1:2000, ролик[1:2000], xlabel="Отсчёты времени", ylabel="Амплитуда",
title="Нормальное состояние и дефект ролика", label="Дефект тела качения", linecolor=:orangered, linewidth=0.5)
plot!(гр_ролик, 1:2000, норма[1:2000], label="Нормальное состояние", linecolor=:blue, linewidth=0.7)
display(гр_ролик)
Прослушаем и визуализируем сигналы с дефектами внутреннего и внешнего колец аналогично предыдущим ячейкам. На графиках заметно существенное возрастание амплитуды: для внутреннего кольца — примерно в 6 раз, для внешнего — более чем в 10 раз по сравнению с нормой. Эти различия в амплитуде и форме сигнала критически важны для диагностики.
media_player("$(@__DIR__)/Внутр.wav", mode="audio")
гр_внутр = plot(1:2000, внутр[1:2000], xlabel="Отсчёты времени", ylabel="Амплитуда",
title="Нормальное состояние и дефект внутреннего кольца", label="Дефект внутреннего кольца", linecolor=:orangered, linewidth=0.5)
plot!(гр_внутр, 1:2000, норма[1:2000], label="Нормальное состояние", linecolor=:blue, linewidth=0.7)
display(гр_внутр)
media_player("$(@__DIR__)/Внеш.wav", mode="audio")
гр_внеш = plot(1:2000, внеш[1:2000], xlabel="Отсчёты времени", ylabel="Амплитуда",
title="Нормальное состояние и дефект внешнего кольца", label="Дефект внешнего кольца", linecolor=:orangered, linewidth=0.5)
plot!(гр_внеш, 1:2000, норма[1:2000], label="Нормальное состояние", linecolor=:blue, linewidth=0.7)
display(гр_внеш)
Деление на сегменты
Создадим функцию для разбиения длинного сигнала на короткие сегменты с заданным перекрытием. Перекрытие увеличивает количество обучающих примеров и лучше захватывает переходные процессы в сигнале. Функция будет использоваться как при формировании обучающей выборки, так и при диагностике новых сигналов.
function разделить_на_сегменты(сигнал, длина_сегмента, перекрытие=0.5)
шаг = Int(floor(длина_сегмента * (1 - перекрытие)))
сегменты = []
for i in 1:шаг:(length(сигнал) - длина_сегмента + 1)
push!(сегменты, сигнал[i:i+длина_сегмента-1])
end
return сегменты
end
Зададим длину сегмента 4000 отсчётов (0.4 секунды) и перекрытие 75%. Такая длина достаточна для захвата нескольких периодов вращения и стабильного вычисления признаков. Перекрытие 75% позволяет получить 117 сегментов из сигнала длиной 120000 отсчётов вместо 30 без перекрытия.
длина_сегмента = 4000
перекрытие = 0.75
Разделим все четыре исходных сигнала на сегменты длиной 4000 отсчётов с перекрытием 75%. Каждая переменная содержит массив из 117 векторов, которые станут базовыми блоками для создания обучающей выборки. Это обеспечивает достаточное разнообразие данных для обучения модели.
сегменты_норма = разделить_на_сегменты(норма, длина_сегмента, перекрытие);
сегменты_ролик = разделить_на_сегменты(ролик, длина_сегмента, перекрытие);
сегменты_внутр = разделить_на_сегменты(внутр, длина_сегмента, перекрытие);
сегменты_внеш = разделить_на_сегменты(внеш, длина_сегмента, перекрытие);
Генерация обучающей выборки
Зафиксируем начальное состояние генератора случайных чисел значением 42 для воспроизводимости результатов. Это гарантирует, что при каждом запуске будет генерироваться одинаковая последовательность случайных чисел. Особенно важно для отладки и сравнения разных версий модели.
Random.seed!(42)
Сгенерируем полную обучающую выборку, вызвав функцию выборка(). На выходе получим матрицу признаков X размером 31850×53 и матрицу целевых значений y размером 31850×3. Каждая строка содержит 53 признака для одного сегмента, а соответствующая строка — процент износа трёх элементов подшипника.
X_матрица, y_матрица = выборка(сегменты_норма, сегменты_ролик, сегменты_внутр, сегменты_внеш);
Выведем матрицу признаков для визуального контроля. Видны 53 столбца с числовыми значениями в разных диапазонах, где каждая строка соответствует одному обучающему примеру. Различный масштаб признаков указывает на необходимость нормализации перед подачей в модель.
X_матрица
Выведем матрицу целевых значений с тремя столбцами: процент износа внутреннего кольца, внешнего кольца и ролика. Большинство строк содержат различные комбинации значений от 0 до 100, а первые строки заполнены нулями — это примеры нормального состояния подшипника.
y_матрица
Нормализация
Выполним нормализацию: вычтем среднее и разделим на стандартное отклонение для каждого из 53 признаков. Это приведёт все признаки к единому масштабу с нулевым средним и единичной дисперсией. Нормализация необходима для корректной работы модели и последующего применения к новым данным.
средние = mean(X_матрица, dims=1)[:]
ско = std(X_матрица, dims=1)[:]
ско[ско .< 1e-10] .= 1.0
X_норм = (X_матрица .- средние') ./ ско'
Создадим функцию для нормализации новых признаков с использованием ранее вычисленных средних значений и среднеквадратичного отклонения (СКО). Она будет применяться к признакам, извлечённым из диагностируемого сигнала, чтобы привести их к тому же масштабу. Сохранение этих параметров вместе с моделью критически важно для корректной диагностики.
function нормализовать(пр)
return (пр .- средние) ./ ско
end
Обучение моделей
Создадим три независимые модели случайного леса (Random Forest) для предсказания износа каждого элемента подшипника. Модели для колец используют 400 деревьев с глубиной 35, а для ролика 600 деревьев с глубиной 50, поскольку его дефект сложнее детектировать из-за меньшей амплитуды. Каждая модель будет обучаться на своём целевом столбце матрицы y.
модель_внутр = DecisionTree.RandomForestRegressor(
n_trees=400, max_depth=35, min_samples_split=2, min_samples_leaf=1, rng=42)
модель_внеш = DecisionTree.RandomForestRegressor(
n_trees=400, max_depth=35, min_samples_split=2, min_samples_leaf=1, rng=43)
модель_ролик = DecisionTree.RandomForestRegressor(
n_trees=600, max_depth=50, min_samples_split=2, min_samples_leaf=1, rng=44)
Обучим каждую модель на соответствующем столбце целевых значений. модель_внутр учится предсказывать износ внутреннего кольца, модель_внеш – внешнего, модель_ролик– тела качения. Все три модели используют одну и ту же матрицу нормализованных признаков X_норм. Время выполнения данной кодовой ячейки может составить несколько минут.
DecisionTree.fit!(модель_внутр, X_норм, y_матрица[:, 1])
DecisionTree.fit!(модель_внеш, X_норм, y_матрица[:, 2])
DecisionTree.fit!(модель_ролик, X_норм, y_матрица[:, 3])
Сохранение моделей
Вычислим эталонные среднее квадратичное значение (root mean square – RMS) и размах нормального сигнала для будущей нормализации амплитуды новых записей. При диагностике сигнал будет масштабироваться так, чтобы его RMS совпадал с эталонным значением 0.073. Это позволит корректно обрабатывать сигналы, записанные с разным усилением.
эталонный_rms = sqrt(mean((норма .- mean(норма)) .^ 2));
эталонный_размах = maximum(abs.(норма .- mean(норма)));
Сохраним обученные модели и все сопутствующие параметры в файл модель_подшипника.jls через стандартный механизм сериализации Julia. В файл записываются три модели Random Forest, векторы средних и СКО для нормализации признаков, параметры сегментации сигналов и эталонные значения амплитуды. Время выполнения данной кодовой ячейки может составить около 15 минут. При последующей диагностике новых сигналов этот файл будет загружаться одной командой deserialize, избавляя от необходимости повторного обучения и сериализации.
serialize("модель_подшипника.jls", (
модель_внутр = модель_внутр,
модель_внеш = модель_внеш,
модель_ролик = модель_ролик,
средние_признаков = средние,
ско_признаков = ско,
длина_сегмента = длина_сегмента,
перекрытие = перекрытие,
частота_дискретизации = частота_дискретизации,
эталонный_rms = эталонный_rms,
эталонный_размах = эталонный_размах))
Заключение
Мы создали модель акустической диагностики подшипника, которая по сигналу определяет степень износа трёх его элементов. Модель обучена на 31 тысяче примеров, сгенерированных из четырёх эталонных записей путём сегментации и смешивания с разной долей дефекта. Каждый пример описан 53 признаками, отражающими амплитудные, частотные и импульсные характеристики сигнала. Три модели случайного леса предсказывают износ внутреннего кольца, внешнего кольца и тела качения.
Ключевые инженерные решения, принятые в работе, стоит выделить. Разбиение сигналов на короткие перекрывающиеся сегменты дало 468 базовых блоков вместо четырёх целых сигналов, что критически важно для обучения. Формула смешивания норма + степень * (дефект - норма) позволяет создавать искусственные примеры с любой степенью износа, не имея реальных записей промежуточных состояний. Модель для тела качения использует 600 деревьев вместо 400, потому что его дефект слабее по амплитуде и труднее детектируется.
Обученные модели и параметры нормализации сохраняются в файл модель_подшипника.jls. Этот файл содержит всё необходимое для диагностики новых исходных сигналов: три обученные модели, векторы средних и стандартных отклонений для нормализации признаков, параметры сегментации и эталонные значения амплитуды. Для применения созданной модели достаточно загрузить этот файл командой deserialize, и модель готова к работе без повторного обучения.