2024-06-26 04:54:10 +03:00
|
|
|
|
export function specModel(options) {
|
2024-07-23 05:00:01 +03:00
|
|
|
|
let __result = {}; //результат
|
|
|
|
|
let __model = options.src.base; //массив точек базовой линии для построения упрощенной модели спектра
|
2024-05-17 10:03:52 +03:00
|
|
|
|
let imin = 0; //левая граница коридора
|
|
|
|
|
let imax = 0; //правая граница коридора
|
2024-06-26 04:54:10 +03:00
|
|
|
|
for (let i = 0; i < options.src.peaks.length; i++) {
|
|
|
|
|
let freq = options.src.peaks[i].freq; //получаем значение частоты гармоники из массива обнаруженных гармоник
|
|
|
|
|
let level = options.src.peaks[i].level; //получаем значение уровня гармоники из массива обнаруженных гармоник
|
|
|
|
|
imin = Math.round((freq - freq * 0.5 * options.tol / 100) / options.src.resolution);
|
|
|
|
|
imax = Math.round((freq + freq * 0.5 * options.tol / 100) / options.src.resolution);
|
|
|
|
|
if (imax > options.src.base.length) { imax = options.src.base.length - 1 }; //проверяем выход границы за размер массива
|
2024-07-23 05:00:01 +03:00
|
|
|
|
for (let j = imin; j <= imax; j++) { __model[j] = options.src.base[j] + level };
|
2024-05-16 10:04:16 +03:00
|
|
|
|
};
|
|
|
|
|
|
2024-05-17 10:03:52 +03:00
|
|
|
|
//формируем результат
|
2024-07-23 05:00:01 +03:00
|
|
|
|
__result["name"] = options.src.name + "_model";
|
|
|
|
|
__result["resolution"] = options.src.resolution;
|
|
|
|
|
__result["data"] = __model;
|
2024-05-17 10:03:52 +03:00
|
|
|
|
|
|
|
|
|
//отрисовка графика на plot
|
2024-06-26 04:54:10 +03:00
|
|
|
|
if (options.canvas != undefined) {
|
|
|
|
|
options.canvas.add(
|
2024-05-21 05:42:23 +03:00
|
|
|
|
{
|
2024-06-26 04:54:10 +03:00
|
|
|
|
color: options.color,
|
2024-07-23 05:00:01 +03:00
|
|
|
|
name: __result.name,
|
|
|
|
|
x: __result.resolution,
|
|
|
|
|
y: __model
|
2024-05-21 05:42:23 +03:00
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
};
|
2024-05-16 10:04:16 +03:00
|
|
|
|
|
2024-07-23 05:00:01 +03:00
|
|
|
|
return __result;
|
2024-05-16 10:04:16 +03:00
|
|
|
|
}; //построение упрощенной модели спектра
|
|
|
|
|
|
2024-07-23 04:52:25 +03:00
|
|
|
|
export function createMask(options) {
|
2024-05-17 10:03:52 +03:00
|
|
|
|
let result = {}; //результат
|
2024-06-19 14:35:28 +03:00
|
|
|
|
let data = options.src1.data; //массив точек спектра для сравнения с портретом
|
|
|
|
|
let mask = options.src2.base; //массив точек базовой линии для построения портрета дефекта
|
|
|
|
|
let harms = options.harms; //кол-во гармоник портрета
|
|
|
|
|
if (options.freq * harms > options.src2.frequency) { harms = Math.trunc(options.src2.frequency / options.freq) }; //проверяем максимальное кол-во гармоник в портрете
|
2024-05-15 08:24:04 +03:00
|
|
|
|
let df = 0; //отношение ширины фильтра частотному разрешению спектра
|
2024-06-19 14:35:28 +03:00
|
|
|
|
let dl = options.lvl; //разность уровней гармонической и случайной составляющей вибрации
|
|
|
|
|
if (options.filter != 0) {
|
|
|
|
|
df = options.src2.frequency / options.filter.width;
|
|
|
|
|
dl = 10 * Math.log10((options.lvl ** 2) / df + 1);
|
2024-05-15 08:24:04 +03:00
|
|
|
|
};
|
2024-06-19 14:35:28 +03:00
|
|
|
|
let k = options.coef; //коэффициент затухания
|
2024-06-11 08:41:46 +03:00
|
|
|
|
let x = 0; //индекс элемента массива для гармоники
|
|
|
|
|
let dx = 0; //коридор индексов
|
2024-05-08 08:43:57 +03:00
|
|
|
|
let xmin = 0; //левая граница коридора
|
|
|
|
|
let xmax = 0; //правая граница коридора
|
2024-05-17 10:03:52 +03:00
|
|
|
|
let correlation = 0; //коэффициент корреляции
|
|
|
|
|
|
|
|
|
|
function corr(a, b) {
|
|
|
|
|
let X = 0; //аргумент 1
|
|
|
|
|
let Y = 0; //аргумент 2
|
|
|
|
|
let Z = 0; //аргумент 3
|
2024-06-27 04:02:44 +03:00
|
|
|
|
let a_avg = a.reduce((acc, item) => (acc + item)) / a.length; //среднее значение массива 1
|
|
|
|
|
let b_avg = b.reduce((acc, item) => (acc + item)) / b.length; //среднее значение массива 2
|
2024-05-17 10:03:52 +03:00
|
|
|
|
|
|
|
|
|
for (let i = 0; i < a.length; i++) {
|
|
|
|
|
X += (a[i] - a_avg) * (b[i] - b_avg);
|
|
|
|
|
Y += (a[i] - a_avg) ** 2;
|
|
|
|
|
Z += (b[i] - b_avg) ** 2;
|
|
|
|
|
};
|
2024-06-27 04:02:44 +03:00
|
|
|
|
|
2024-07-10 04:16:27 +03:00
|
|
|
|
if (X <= 0) { return 0 } else { return X / (Math.sqrt(Y) * Math.sqrt(Z)) };
|
2024-05-17 10:03:52 +03:00
|
|
|
|
};
|
2024-05-08 04:30:31 +03:00
|
|
|
|
|
2024-05-20 10:32:42 +03:00
|
|
|
|
let arr1 = [];
|
|
|
|
|
let arr2 = [];
|
2024-06-19 14:35:28 +03:00
|
|
|
|
switch (options.type) {
|
2024-05-17 10:03:52 +03:00
|
|
|
|
case 0: //обычный ряд
|
2024-05-15 08:21:54 +03:00
|
|
|
|
for (let i = 1; i <= harms; i++) {
|
2024-06-19 14:35:28 +03:00
|
|
|
|
x = Math.trunc(i * options.freq / options.src2.resolution); //определяем инднекс элемента массива для гармоники
|
|
|
|
|
dx = Math.trunc(i * (options.freq * options.tol / 100) / options.src2.resolution); //коридор индексов массива для гармоники
|
2024-06-11 08:41:46 +03:00
|
|
|
|
xmin = x - Math.round(dx / 2); //определяем индекс левой границы коридора
|
|
|
|
|
xmax = x + Math.round(dx / 2); //определяем индекс правой границы коридора
|
|
|
|
|
|
2024-06-19 14:35:28 +03:00
|
|
|
|
if (xmax > options.src2.base.length) { xmax = options.src2.base.length - 2 }; //проверяем выход границы за размер массива
|
|
|
|
|
for (let j = xmin; j <= xmax; j++) { mask[j] = options.src2.base[j] + dl }; //записываем значение глубины модуляции для коридора
|
2024-05-20 10:32:42 +03:00
|
|
|
|
dl = dl - (k * dl); //снижаем глубину модуляции с коэффициентом затухания
|
2024-05-21 05:42:23 +03:00
|
|
|
|
|
2024-05-17 10:03:52 +03:00
|
|
|
|
for (let j = xmin - 2; j <= xmax + 2; j++) {
|
|
|
|
|
arr1.push(mask[j]);
|
|
|
|
|
arr2.push(data[j]);
|
|
|
|
|
}; //формируем массивы портретной гармоники и спектра (модели) под портретом
|
|
|
|
|
correlation += corr(arr1, arr2); //рассчитываем корреляцию данных из массивов
|
2024-05-08 04:30:31 +03:00
|
|
|
|
};
|
|
|
|
|
break;
|
2024-05-17 10:03:52 +03:00
|
|
|
|
case 1: //четные составляющие
|
2024-05-20 10:32:42 +03:00
|
|
|
|
for (let i = 1; i <= harms; i++) {
|
2024-06-19 14:35:28 +03:00
|
|
|
|
x = Math.trunc(i * options.freq / options.src2.resolution); //инднекс элемента массива для гармоники
|
|
|
|
|
dx = Math.trunc(i * (options.freq * options.tol / 100) / options.src2.resolution); //коридор индексов массива для гармоники
|
2024-06-11 08:41:46 +03:00
|
|
|
|
xmin = x - Math.round(dx / 2); //определяем индекс левой границы коридора
|
|
|
|
|
xmax = x + Math.round(dx / 2); //определяем индекс правой границы коридора
|
|
|
|
|
|
2024-06-19 14:35:28 +03:00
|
|
|
|
if (xmax > options.src2.base.length) { xmax = options.src2.base.length - 2 }; //проверяем выход границы за размер массива
|
2024-05-08 08:43:57 +03:00
|
|
|
|
if (i % 2 > 0) {
|
2024-06-19 14:35:28 +03:00
|
|
|
|
for (let j = xmin; j <= xmax; j++) { mask[j] = options.src2.base[j] + k * dl }; //записываем значение глубины модуляции для коридора (нечетная гармоника)
|
2024-05-20 10:32:42 +03:00
|
|
|
|
} else {
|
2024-06-19 14:35:28 +03:00
|
|
|
|
for (let j = xmin; j <= xmax; j++) { mask[j] = options.src2.base[j] + dl }; //записываем значение глубины модуляции для коридора (четная гармоника)
|
2024-05-20 10:32:42 +03:00
|
|
|
|
dl = dl - (k * dl); //снижаем глубину модуляции с коэффициентом затухания
|
2024-05-08 08:43:57 +03:00
|
|
|
|
};
|
2024-05-20 10:32:42 +03:00
|
|
|
|
|
|
|
|
|
for (let j = xmin - 2; j <= xmax + 2; j++) {
|
|
|
|
|
arr1.push(mask[j]);
|
|
|
|
|
arr2.push(data[j]);
|
|
|
|
|
}; //формируем массивы портретной гармоники и спектра (модели) под портретом
|
|
|
|
|
correlation += corr(arr1, arr2); //рассчитываем корреляцию данных из массивов
|
2024-05-08 04:30:31 +03:00
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-17 10:03:52 +03:00
|
|
|
|
//формируем результат
|
2024-06-19 14:35:28 +03:00
|
|
|
|
result["name"] = options.name; //имя маски дефекта
|
2024-05-17 10:03:52 +03:00
|
|
|
|
result["corr"] = correlation / harms; //средняя корреляция
|
|
|
|
|
result["data"] = mask; //массив данных портрета
|
|
|
|
|
|
|
|
|
|
//отрисовка графика на plot
|
2024-06-20 02:36:01 +03:00
|
|
|
|
if (options.canvas != undefined) {
|
|
|
|
|
options.canvas.add(
|
2024-05-21 05:42:23 +03:00
|
|
|
|
{
|
2024-06-19 14:35:28 +03:00
|
|
|
|
color: options.color,
|
|
|
|
|
name: options.name + " (" + result.corr.toFixed(2) + ")",
|
|
|
|
|
x: options.src2.resolution,
|
2024-05-21 05:42:23 +03:00
|
|
|
|
y: mask
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
};
|
2024-05-08 04:30:31 +03:00
|
|
|
|
|
2024-05-17 10:03:52 +03:00
|
|
|
|
return result;
|
2024-07-23 04:52:25 +03:00
|
|
|
|
}; //построение портрета дефекта
|
|
|
|
|
|
|
|
|
|
export function getMask(options) {
|
|
|
|
|
let __result = {}; //результат
|
|
|
|
|
let __spec = options.src1; //источник данных для построения модели
|
|
|
|
|
let __set = options.src2; //источник данных для построения портретов дефектов
|
|
|
|
|
let __rows = Object.keys(__set); //массив ключей объекта (наименование портретов)
|
|
|
|
|
|
|
|
|
|
let __model = specModel(
|
|
|
|
|
{
|
|
|
|
|
src: __spec, //спектр для построения модели (объект)
|
|
|
|
|
tol: options.tol, //коридор обнаружения гармоники, %
|
|
|
|
|
color: options.color, //цвет модели в формате HEX
|
|
|
|
|
canvas: options.canvas //координатная плоскость для отрисовки
|
|
|
|
|
}
|
|
|
|
|
); //рисуем упрощенную модель спектра огибающей
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < __rows.length; i++) {
|
|
|
|
|
let __mask_name = __rows[i]; //имена портретов
|
|
|
|
|
let __mask = createMask(
|
|
|
|
|
{
|
|
|
|
|
name: __mask_name, //имя маски дефекта
|
|
|
|
|
src1: __model, //модель спектра для анализа (объект)
|
|
|
|
|
src2: __spec, //базовый спектр для построения портрета (объект)
|
|
|
|
|
filter: options.filter, //полосовой фильтр (для определения разницы амплитуд гармонической и случайной составляющей)
|
|
|
|
|
color: __set[__mask_name].clr, //цвет портрета в формате HEX
|
|
|
|
|
freq: __set[__mask_name].frq, //функциональная частота, Гц
|
|
|
|
|
harms: __set[__mask_name].hrm, //кол-во гармоник в портрете, шт
|
|
|
|
|
lvl: __set[__mask_name].lvl, //глубина модуляции сильного дефекта для портрета, %
|
|
|
|
|
tol: options.tol, //коридор обнаружения гармоники на портрете, %
|
|
|
|
|
type: __set[__mask_name].type, //тип портрета (0 - обычный ряд, 1 - четные составляющие)
|
|
|
|
|
coef: __set[__mask_name].coef, //коэффициент затухания гармоник портрета: дефект (0.05 - 0.10), износ (0.30 - 0.50)
|
|
|
|
|
canvas: options.canvas //координатная плоскость для отрисовки маски
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
if (__mask.corr >= 0.5) { __result[__mask.name] = __mask.corr }; //добавляем данные в результат
|
|
|
|
|
gtl.log.info("Вероятность: " + __mask.name, __mask.corr); //выводим корреляцию гармоник в лог
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return __result;
|
|
|
|
|
}; //оценка состояния методом maskVM
|