gtld2-diag-scripts/maskVM.js

175 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

export function specModel(options) {
let __result = {}; //результат
let __model = options.src.base; //массив точек базовой линии для построения упрощенной модели спектра
let imin = 0; //левая граница коридора
let imax = 0; //правая граница коридора
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 }; //проверяем выход границы за размер массива
for (let j = imin; j <= imax; j++) { __model[j] = options.src.base[j] + level };
};
//формируем результат
__result["name"] = options.src.name + "_model";
__result["resolution"] = options.src.resolution;
__result["data"] = __model;
//отрисовка графика на plot
if (options.canvas != undefined) {
options.canvas.add(
{
color: options.color,
name: __result.name,
x: __result.resolution,
y: __model
}
);
};
return __result;
}; //построение упрощенной модели спектра
export function createMask(options) {
let result = {}; //результат
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) }; //проверяем максимальное кол-во гармоник в портрете
let df = 0; //отношение ширины фильтра частотному разрешению спектра
let dl = options.lvl; //разность уровней гармонической и случайной составляющей вибрации
if (options.filter != 0) {
df = options.src2.frequency / options.filter.width;
dl = 10 * Math.log10((options.lvl ** 2) / df + 1);
};
let k = options.coef; //коэффициент затухания
let x = 0; //индекс элемента массива для гармоники
let dx = 0; //коридор индексов
let xmin = 0; //левая граница коридора
let xmax = 0; //правая граница коридора
let correlation = 0; //коэффициент корреляции
function corr(a, b) {
let X = 0; //аргумент 1
let Y = 0; //аргумент 2
let Z = 0; //аргумент 3
let a_avg = a.reduce((acc, item) => (acc + item)) / a.length; //среднее значение массива 1
let b_avg = b.reduce((acc, item) => (acc + item)) / b.length; //среднее значение массива 2
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;
};
if (X <= 0) { return 0 } else { return X / (Math.sqrt(Y) * Math.sqrt(Z)) };
};
let arr1 = [];
let arr2 = [];
switch (options.type) {
case 0: //обычный ряд
for (let i = 1; i <= harms; i++) {
x = Math.trunc(i * options.freq / options.src2.resolution); //определяем инднекс элемента массива для гармоники
dx = Math.trunc(i * (options.freq * options.tol / 100) / options.src2.resolution); //коридор индексов массива для гармоники
xmin = x - Math.round(dx / 2); //определяем индекс левой границы коридора
xmax = x + Math.round(dx / 2); //определяем индекс правой границы коридора
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 }; //записываем значение глубины модуляции для коридора
dl = dl - (k * dl); //снижаем глубину модуляции с коэффициентом затухания
for (let j = xmin - 2; j <= xmax + 2; j++) {
arr1.push(mask[j]);
arr2.push(data[j]);
}; //формируем массивы портретной гармоники и спектра (модели) под портретом
correlation += corr(arr1, arr2); //рассчитываем корреляцию данных из массивов
};
break;
case 1: //четные составляющие
for (let i = 1; i <= harms; i++) {
x = Math.trunc(i * options.freq / options.src2.resolution); //инднекс элемента массива для гармоники
dx = Math.trunc(i * (options.freq * options.tol / 100) / options.src2.resolution); //коридор индексов массива для гармоники
xmin = x - Math.round(dx / 2); //определяем индекс левой границы коридора
xmax = x + Math.round(dx / 2); //определяем индекс правой границы коридора
if (xmax > options.src2.base.length) { xmax = options.src2.base.length - 2 }; //проверяем выход границы за размер массива
if (i % 2 > 0) {
for (let j = xmin; j <= xmax; j++) { mask[j] = options.src2.base[j] + k * dl }; //записываем значение глубины модуляции для коридора (нечетная гармоника)
} else {
for (let j = xmin; j <= xmax; j++) { mask[j] = options.src2.base[j] + dl }; //записываем значение глубины модуляции для коридора (четная гармоника)
dl = dl - (k * dl); //снижаем глубину модуляции с коэффициентом затухания
};
for (let j = xmin - 2; j <= xmax + 2; j++) {
arr1.push(mask[j]);
arr2.push(data[j]);
}; //формируем массивы портретной гармоники и спектра (модели) под портретом
correlation += corr(arr1, arr2); //рассчитываем корреляцию данных из массивов
};
break;
default:
break;
};
//формируем результат
result["name"] = options.name; //имя маски дефекта
result["corr"] = correlation / harms; //средняя корреляция
result["data"] = mask; //массив данных портрета
//отрисовка графика на plot
if (options.canvas != undefined) {
options.canvas.add(
{
color: options.color,
name: options.name + " (" + result.corr.toFixed(2) + ")",
x: options.src2.resolution,
y: mask
}
);
};
return result;
}; //построение портрета дефекта
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