export class peakClass { constructor(args) { this.wave = args.src; this.freq = args.freq; this.visible = args.visible; if (args.spec != undefined) { this.spec = args.spec }; } __getLevels(rpm = this.freq * 60) { let __allert = 0; //уровень предупреждения, g switch (true) { case rpm <= 900: __allert = 3.0 * (rpm / 900) ** 0.75; //1.5 => 3.0 для формы Peak-To-Peak break; case (rpm > 900) && (rpm <= 4000): __allert = 3.0; //1.5 => 3.0 для формы Peak-To-Peak break; case (rpm > 4000) && (rpm <= 10000): __allert = 3.0 * (rpm / 4000) ** 0.5; //1.5 => 3.0 для формы Peak-To-Peak break; case rpm > 10000: __allert = 5.0; //3.0 => 5.0 для формы Peak-To-Peak default: break; }; return __allert }; //рассчет пороговых уровней __getParams(rpm = this.freq * 60) { let __wdt = 0; //граничная частота ФВЧ let __frq = 40 * this.freq; //граничная частота спектра let __lns = 800; //количество линий спектра let __avg = 1; //количество усреднений спектра switch (true) { case rpm <= 700: __wdt = 500; __lns = 800; break; case (rpm > 700) && (rpm <= 1500): __wdt = 1000; __lns = 800; break; case (rpm > 1500) && (rpm <= 3000): __wdt = 2000; __lns = 1600; break; case (rpm > 3000) && (rpm <= 4000): __wdt = 2000; __lns = 1600; case rpm > 4000: __wdt = 5000; __lns = 1600; default: break; }; return { filter: { frequency: __wdt }, spec: { frequency: __frq, lines: __lns, resolution: __frq / __lns, avg: __avg } }; }; //рассчет параметров спектра __getSpecSquare() { if (this.spec != undefined) { let __base = this.spec.base; //массив значений средней линии let __data = this.spec.data; //массив значений амплитуд let __lines = this.spec.data.length; //количества линий спектра let __res = this.spec.resolution; //частотное разрешения спектра (высота прямоугольной трапеции) let __start = 0; //стартовый индекс в массиве let __end = __lines; //конечный индекс в массиве let s0 = 0; //площадь под базовой линией let s1 = 0; //площадь всего спектра let s2 = 0; //площадь над базовой линией let s3 = 0; //площадь обнаруженных гармоник for (let i = __start; i <= __end - 1; i++) { s0 += __base[i] * __res; s1 += __data[i] * __res; let __delta = __data[i] - __base[i]; if (__delta >= 0) { s2 += __delta * __res }; if (__delta >= this.spec.peak_level) { s3 += __delta * __res }; }; return { base: s0, spec: s1, harm: s2, peak: s3 }; }; //определение площадей спектра } getWave() { let __allert = this.__getLevels(); let __fault = 2 * __allert; if (this.visible == true) { let __canvas = gtl.plots.add("Waveform"); let __alr = this.wave.values.map((item) => (item = __allert)); let __flt = this.wave.values.map((item) => (item = __fault)); __canvas.add({ color: this.wave.color, name: this.wave.name, x: this.wave.time, y: this.wave.values }); //рисуем форму сигнала __canvas.add({ color: 0xFFFF00, name: "allert", x: this.wave.time, y: __alr }); //рисуем порог предупреждения __canvas.add({ color: 0xFF0000, name: "fault", x: this.wave.time, y: __flt }); //рисуем порог опасности } return __allert } getCorr() { let __plot = []; //массив значений корреляции для графика let arr = this.wave.values; let arr2 = arr.concat(arr); //расширяем массив данных let lag = 0.5; let X = 0; //аргумент 1 let Y = 0; //аргумент 2 let T = Math.floor(arr.length * lag); //определяем количество индексов (шагов) для смещения массива let avg = arr.reduce((acc, item) => (acc + item)) / arr.length; //среднее значение массива Y = arr.reduce((acc, item) => (acc + (item - avg) ** 2), 0); //рассчитываем знаменатель функции for (let i = 0; i < T; i++) { X = 0; for (let j = 0; j < arr.length; j++) { X += (arr[j] - avg) * (arr2[j + i] - avg) }; __plot.push(X / Y); //записываем значение в массив коэффициентов }; //смещение массива let __plot0 = __plot.slice(Math.floor(0.01 * __plot.length)); //убираем из массива первый 1% значений коэффициента (т.к. в нуле всегда значение 1.0) let __max = Math.max(...__plot0); //определяем максимальное значение коэффициента if (this.visible == true) { let __canvas = gtl.plots.add("Correlation"); __canvas.add({ color: 0x00A550, name: "Корреляционная функция", x: this.wave.time, y: __plot }); }; //отрисовка графика на plot return __max; }; //рассчет автокорреляции getResult() { let __result = {}; //результат let __mech = 0; //механические проблемы let __lubr = 0; //проблемы со смазкой let __allert = this.getWave(); //рисуем пиковую форму сигнала и получаем порог предупреждения, g let __corr = this.getCorr(); //вычисляем автокорреляционную функцию (получаем максимум) let MaxPK = Math.max(...this.wave.values); //максимальное значение амплитуды на пиковой форме, g let FaultLevel = 2 * __allert; //уровень аварии для пиковой формы (Fault = 2 * Allert) let EstPE = Math.sqrt(__corr) * 100; //расчетный процент периодической энергии if (this.spec != undefined) { let GS = MaxPK / FaultLevel; //общая серьезность проблемы let SQpeak = this.__getSpecSquare().peak; //площадь обнаруженных гармонических составляющих let SQspec = this.__getSpecSquare().harm; //площадь над базовой линией let PE = (SQpeak ** 2 / SQspec ** 2); //доля периодической энергии let NPE = (SQspec ** 2 - SQpeak ** 2) / SQspec ** 2; //доля непериодической энергии __mech = GS * PE * 100; __lubr = GS * NPE * 100; __result = { mechBS: __mech * 0.8, //нормализованное значение (для индикатора 0-100 единиц) lubrBS: __lubr * 0.8, //нормализованное значение (для индикатора 0-100 единиц) }; } else { switch (true) { case EstPE >= 50: __mech = EstPE * MaxPK / FaultLevel; __lubr = (100 - EstPE) * MaxPK / FaultLevel; break; case (EstPE <= 50) && (EstPE > 30): EstPE = EstPE / 2; __mech = EstPE * MaxPK / FaultLevel; __lubr = (100 - EstPE) * MaxPK / FaultLevel; break; case EstPE < 30: __mech = 0 __lubr = MaxPK / FaultLevel; break; default: break; }; //определяем действительный расчетный процент периодической энергии __result = { mechBS: __mech, lubrBS: __lubr }; }; return __result; }; //оценка состояния методом PeakVM }