comment
This commit is contained in:
commit
97034c21cb
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"autoStartRecorder": false,
|
||||
"expendTreeOnStart": true,
|
||||
"lastTag": "частотный отклик freq-40000 resol-100",
|
||||
"projectTitle": "Частотный отклик",
|
||||
"projectUUID": "{91ae6936-d7c1-41f2-ac73-1fb5692a4011}",
|
||||
"syncURL": "",
|
||||
"useSync": false,
|
||||
"vacuumOnStart": false,
|
||||
"version": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,118 @@
|
|||
[
|
||||
{
|
||||
"RRDSize": 100,
|
||||
"analizerScriptName": "",
|
||||
"channelsToWrite": [
|
||||
],
|
||||
"comment": "",
|
||||
"daemonConfigName": "",
|
||||
"daemonScriptName": "",
|
||||
"defaultRecordTime": 10,
|
||||
"isDeviceSelected": false,
|
||||
"isRRDEnabled": false,
|
||||
"label": "СТ верх горизонталь",
|
||||
"masterValueModel": [
|
||||
],
|
||||
"runAnalizer": false,
|
||||
"stopRecorderFromScript": false,
|
||||
"tachoOptions": {
|
||||
"isTachoEnabled": false,
|
||||
"maxTacho": 1000,
|
||||
"minTacho": 0,
|
||||
"recalcTacho": false,
|
||||
"tachoChannel": 0,
|
||||
"tachoChannelName": "",
|
||||
"tachoFromInfo": 0,
|
||||
"tachoState": 0,
|
||||
"tachoValue": 0
|
||||
},
|
||||
"uuid": "{1ee51458-2b67-4738-8832-24a883abe26a}"
|
||||
},
|
||||
{
|
||||
"RRDSize": 100,
|
||||
"analizerScriptName": "",
|
||||
"channelsToWrite": [
|
||||
],
|
||||
"comment": "",
|
||||
"daemonConfigName": "",
|
||||
"daemonScriptName": "",
|
||||
"defaultRecordTime": 10,
|
||||
"isDeviceSelected": false,
|
||||
"isRRDEnabled": false,
|
||||
"label": "СТ низ вертикаль",
|
||||
"masterValueModel": [
|
||||
],
|
||||
"runAnalizer": false,
|
||||
"stopRecorderFromScript": false,
|
||||
"tachoOptions": {
|
||||
"isTachoEnabled": false,
|
||||
"maxTacho": 1000,
|
||||
"minTacho": 0,
|
||||
"recalcTacho": false,
|
||||
"tachoChannel": 0,
|
||||
"tachoChannelName": "",
|
||||
"tachoFromInfo": 0,
|
||||
"tachoState": 0,
|
||||
"tachoValue": 0
|
||||
},
|
||||
"uuid": "{5aba8185-bd6d-4469-a877-366899f020e9}"
|
||||
},
|
||||
{
|
||||
"RRDSize": 100,
|
||||
"analizerScriptName": "",
|
||||
"channelsToWrite": [
|
||||
],
|
||||
"comment": "",
|
||||
"daemonConfigName": "",
|
||||
"daemonScriptName": "",
|
||||
"defaultRecordTime": 10,
|
||||
"isDeviceSelected": false,
|
||||
"isRRDEnabled": false,
|
||||
"label": "СТ верх вертикаль",
|
||||
"masterValueModel": [
|
||||
],
|
||||
"runAnalizer": false,
|
||||
"stopRecorderFromScript": false,
|
||||
"tachoOptions": {
|
||||
"isTachoEnabled": false,
|
||||
"maxTacho": 1000,
|
||||
"minTacho": 0,
|
||||
"recalcTacho": false,
|
||||
"tachoChannel": 0,
|
||||
"tachoChannelName": "",
|
||||
"tachoFromInfo": 0,
|
||||
"tachoState": 0,
|
||||
"tachoValue": 0
|
||||
},
|
||||
"uuid": "{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}"
|
||||
},
|
||||
{
|
||||
"RRDSize": 100,
|
||||
"analizerScriptName": "",
|
||||
"channelsToWrite": [
|
||||
],
|
||||
"comment": "",
|
||||
"daemonConfigName": "",
|
||||
"daemonScriptName": "",
|
||||
"defaultRecordTime": 10,
|
||||
"isDeviceSelected": false,
|
||||
"isRRDEnabled": false,
|
||||
"label": "СТ низ горизонталь",
|
||||
"masterValueModel": [
|
||||
],
|
||||
"runAnalizer": false,
|
||||
"stopRecorderFromScript": false,
|
||||
"tachoOptions": {
|
||||
"isTachoEnabled": false,
|
||||
"maxTacho": 1000,
|
||||
"minTacho": 0,
|
||||
"recalcTacho": false,
|
||||
"tachoChannel": 0,
|
||||
"tachoChannelName": "",
|
||||
"tachoFromInfo": 0,
|
||||
"tachoState": 0,
|
||||
"tachoValue": 0
|
||||
},
|
||||
"uuid": "{da645bbe-04b5-4d5e-86de-3b5ba633addc}"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
export function getResponse(args) {
|
||||
let force = args.spec_force; //спектр силы
|
||||
let vibro = args.spec_vibro; //спектр вибрации
|
||||
let type = args.type; //способ вычисления отклика
|
||||
let view = args.view; //способ отображения спектра в линейных единицах или дБ
|
||||
|
||||
/* Алгоритм
|
||||
1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
4. Вычислить деление кросс-спектра на спектр силы.
|
||||
*/
|
||||
|
||||
/* Кросс-спектры
|
||||
Сигнал силы в комплексно-сопряжённом виде
|
||||
сигнал вибрации умножается на сигнал силы, а НЕ наоборот
|
||||
умножение комплексных чисел по формуле:
|
||||
(a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
(a1*a2-b1*b2) - действительная часть
|
||||
(a1*b2+b1*a2)i - мнимая часть
|
||||
*/
|
||||
|
||||
let n = force.data.length; // длина массива спектра
|
||||
let cross_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let cross_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = -force.imag[i]; // мнимая часть спектра силы сразу берём с обратным знаком
|
||||
|
||||
cross_real[i] = vReal * fReal - vImag * fImag;
|
||||
cross_imag[i] = vReal * fImag + vImag * fReal;
|
||||
}
|
||||
|
||||
// let cross_real2 = getCrossSpectrum(vibro.real, vibro.imag, force.real, force.imag).reXY;
|
||||
// gtl.log.info('Амплитуда кросс', cross_real)
|
||||
// gtl.log.info('Амплитуда кросс 2', cross_real2)
|
||||
|
||||
/* Вычисление частотного отклика
|
||||
деление комплексных чисел по формуле:
|
||||
(a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
(a*c-b*d) - действительная часть
|
||||
(a*d+b*c)i - мнимая часть
|
||||
*/
|
||||
let resp_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let resp_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
if (type == 0) {
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// ОШИБКА в моей формуле вычисления частотного отклика
|
||||
// ИПРАВИЛ на:
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c + b*d)/(c^2 + d^2) + (c*b - a*d)/(c^2 + d^2)i
|
||||
// (a*c + b*d)/(c^2 + d^2) - действительная часть
|
||||
// (c*b - a*d)/(c^2 + d^2)i - мнимая часть
|
||||
for (let i = 0; i < n; i++) {
|
||||
const cReal = cross_real[i]; // действительная часть кросс спектра
|
||||
const cImag = cross_imag[i]; // мнимая часть кросс спектра
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const denominator = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (cReal * fReal + cImag * fImag) / denominator;
|
||||
resp_imag[i] = (fReal * cImag - cReal * fImag) / denominator;
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const denominator = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (vReal * fReal + vImag * fImag) / denominator;
|
||||
resp_imag[i] = (fReal * vImag - vReal * fImag) / denominator;
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
let resp_ampl = new Float64Array(n); // типизированный массив для амплитуды
|
||||
let resp_phase = new Float64Array(n); // типизированный массив для фазы
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const rReal = resp_real[i]; // действительная часть спектра отклика
|
||||
const rImag = resp_imag[i]; // мнимая часто спектра отклика
|
||||
|
||||
resp_ampl[i] = Math.sqrt(rReal * rReal + rImag * rImag);
|
||||
if (view > 0) { resp_ampl = resp_ampl.map((item) => (item = 20 * Math.log10(item / 1e-6))) }; //переводим в дБ
|
||||
resp_phase[i] = Math.atan2(rImag, rReal) * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
// Приводим фазу к диапазону [0°, 360°]
|
||||
for (let i = 0; i < n; i++) {
|
||||
resp_phase[i] = resp_phase[i] % 360;
|
||||
if (resp_phase[i] < 0) { resp_phase[i] += 360 }
|
||||
}
|
||||
|
||||
let resp2 = getFrequencyResponse(vibro.real, vibro.imag, force.real, force.imag);
|
||||
let resp_ampl2 = resp2.magnitude;
|
||||
let resp_phase2 = resp2.phase;
|
||||
|
||||
// gtl.log.info('Амплитуда отклика', resp_ampl[0]);
|
||||
// gtl.log.info('Амплитуда отклика 2', resp_ampl2[0]);
|
||||
// gtl.log.info('Фаза отклика', resp_phase[0]);
|
||||
// gtl.log.info('Фаза отклика 2', resp_phase2[0]);
|
||||
|
||||
return {
|
||||
data: resp_ampl2,
|
||||
phase: resp_phase2,
|
||||
resolution: force.resolution
|
||||
}
|
||||
}; //рассчет перекрестного спектра
|
||||
|
||||
export function getAvgArray(arrays) {
|
||||
const length = arrays[0].length; //длина вложенного массива
|
||||
const result = new Array(length); //новый массив фиксированной длины, чтобы не пушить
|
||||
const numArrays = arrays.length; //количество вложенных массивов
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
let sum = 0;
|
||||
for (let j = 0; j < numArrays; j++) { sum += arrays[j][i] }
|
||||
result[i] = sum / numArrays;
|
||||
}
|
||||
|
||||
return result;
|
||||
}; //вычисление среднего массива
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function getCrossSpectrum(reX, imX, reY, imY) {
|
||||
const n = reX.length;
|
||||
const reXY = new Array(n); // действительная часть
|
||||
const imXY = new Array(n); // мнимая часть
|
||||
const power = new Array(n); // мощность кросс-спектра
|
||||
let phase = new Array(n); // фаза (радианы)
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
// Комплексное сопряжение спектра imY* (мнимая часть спектра силы сразу берём с обратным знаком)
|
||||
const a = reX[i], b = imX[i]; // X(f) = a + ib
|
||||
const c = reY[i], d = -imY[i]; // Y(f) = c + id
|
||||
|
||||
// Почастотное умножение
|
||||
reXY[i] = a * c - b * d; // действительная часть
|
||||
imXY[i] = b * c + a * d; // мнимания часть
|
||||
|
||||
// Мощность кросс-спектра
|
||||
power[i] = reXY[i] * reXY[i] + imXY[i] * imXY[i];
|
||||
|
||||
// Фаза = arctan(Im/Re)
|
||||
phase[i] = Math.atan2(imXY[i], reXY[i]);
|
||||
}
|
||||
|
||||
return { reXY, imXY, power, phase };
|
||||
}
|
||||
|
||||
|
||||
function getFrequencyResponse(reX, imX, reY, imY) {
|
||||
const n = reX.length;
|
||||
const magnitude = new Array(n); // амплитуда (линейная)
|
||||
const magnitudeDB = new Array(n); // амплитуда (дБ)
|
||||
let phase = new Array(n); // фаза (радианы)
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const a = reX[i], b = imX[i]; // X(f) = a + ib
|
||||
const c = reY[i], d = imY[i]; // Y(f) = c + id
|
||||
|
||||
// Знаменатель
|
||||
const denominator = c * c + d * d; // знаменатель исходный вариант
|
||||
// const denominator = a * a + b * b; // знаменатель вариант 2
|
||||
|
||||
// Избегаем деления на ноль
|
||||
if (Math.abs(denominator) < 1e-10) {
|
||||
magnitude[i] = 0;
|
||||
magnitudeDB[i] = -Infinity;
|
||||
phase[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Почастотное умножение
|
||||
const reH = (a * c + b * d) / denominator; // действительная часть
|
||||
const imH = (c * b - a * d) / denominator; // мнимая часть исходный вариант
|
||||
// const imH = (a * d - b * c) / denominator; // мнимая часть вариант 2 (поменял местами вычитаемые)
|
||||
|
||||
// Амплитуда
|
||||
magnitude[i] = Math.sqrt(reH * reH + imH * imH);
|
||||
|
||||
// Амплитуда в дБ
|
||||
magnitudeDB[i] = 20 * Math.log10(magnitude[i] / 1e-6);
|
||||
|
||||
// Приводим фазу сразу к диапазону [0°, 360°]
|
||||
phase[i] = Math.atan2(imH, reH) * RAD_TO_DEG % 360;
|
||||
if (phase[i] < 0) { phase[i] += 360 };
|
||||
}
|
||||
|
||||
return { magnitude, magnitudeDB, phase };
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
export function getResponse(args) {
|
||||
let force = args.spec_force; //спектр силы
|
||||
let vibro = args.spec_vibro; //спектр вибрации
|
||||
let type = args.type; //способ вычисления отклика
|
||||
let view = args.view; //способ отображения спектра в линейных единицах или дБ
|
||||
|
||||
/* Алгоритм
|
||||
1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
4. Вычислить деление кросс-спектра на спектр силы.
|
||||
*/
|
||||
|
||||
/* Кросс-спектры
|
||||
Сигнал силы в комплексно-сопряжённом виде
|
||||
сигнал вибрации умножается на сигнал силы, а НЕ наоборот
|
||||
умножение комплексных чисел по формуле:
|
||||
(a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
(a1*a2-b1*b2) - действительная часть
|
||||
(a1*b2+b1*a2)i - мнимая часть
|
||||
*/
|
||||
|
||||
let n = force.data.length; // длина массива спектра
|
||||
let cross_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let cross_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = -force.imag[i]; // мнимая часть спектра силы сразу берём с обратным знаком
|
||||
|
||||
cross_real[i] = vReal * fReal - vImag * fImag;
|
||||
cross_imag[i] = vReal * fImag + vImag * fReal;
|
||||
}
|
||||
|
||||
/* Вычисление частотного отклика
|
||||
деление комплексных чисел по формуле:
|
||||
(a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
(a*c-b*d) - действительная часть
|
||||
(a*d+b*c)i - мнимая часть
|
||||
*/
|
||||
let resp_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let resp_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
// ОШИБКА в моей формуле вычисления частотного отклика
|
||||
// ИПРАВИЛ на:
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c + b*d)/(c^2 + d^2) + (c*b - a*d)/(c^2 + d^2)i
|
||||
// (a*c + b*d)/(c^2 + d^2) - действительная часть
|
||||
// (c*b - a*d)/(c^2 + d^2)i - мнимая часть
|
||||
// ПЕРЕВОД формулы в используемые переменные:
|
||||
// const CF = fReal * fReal + fImag * fImag;
|
||||
// resp_real[i] = (cReal * fReal + cImag * fImag) / CF;
|
||||
// resp_imag[i] = (fReal * cImag - cReal * fImag) / CF;
|
||||
|
||||
if (type == 0) {
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const cReal = cross_real[i]; // действительная часть кросс спектра
|
||||
const cImag = cross_imag[i]; // мнимая часть кросс спектра
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const CF = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (cReal * fReal + cImag * fImag) / CF;
|
||||
resp_imag[i] = (fReal * cImag - cReal * fImag) / CF;
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const VF = vReal * vReal + fImag * fImag;
|
||||
resp_real[i] = (vReal * fReal - vImag * fImag) / VF;
|
||||
resp_imag[i] = (fReal * vImag + vReal * fImag) / VF;
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
let resp_ampl = new Float64Array(n); // типизированный массив для амплитуды
|
||||
let resp_phase = new Float64Array(n); // типизированный массив для фазы
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const rReal = resp_real[i]; // действительная часть спектра отклика
|
||||
const rImag = resp_imag[i]; // мнимая часто спектра отклика
|
||||
|
||||
resp_ampl[i] = Math.sqrt(rReal * rReal + rImag * rImag);
|
||||
if (view > 0) { resp_ampl = resp_ampl.map((item) => (item = 20 * Math.log10(item / 1e-6))) }; //переводим в дБ
|
||||
resp_phase[i] = Math.atan2(rImag, rReal) * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
// Приводим фазу к диапазону [0°, 360°]
|
||||
for (let i = 0; i < n; i++) {
|
||||
resp_phase[i] = resp_phase[i] % 360;
|
||||
if (resp_phase[i] < 0) { resp_phase[i] += 360 }
|
||||
}
|
||||
|
||||
return {
|
||||
data: resp_ampl,
|
||||
phase: resp_phase,
|
||||
resolution: force.resolution
|
||||
}
|
||||
}; //рассчет перекрестного спектра
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import QtQml
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
Item {
|
||||
id: mainWindow
|
||||
anchors.fill: parent
|
||||
|
||||
SplitView {
|
||||
id: splitView
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
|
||||
handle: Rectangle {
|
||||
implicitWidth: 6
|
||||
color: "darkgray"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
SplitView.preferredWidth: parent.width/2
|
||||
SplitView.maximumWidth: parent.width/100*75
|
||||
SplitView.minimumWidth: parent.width/100*25
|
||||
color: "gray"
|
||||
|
||||
ColumnLayout {
|
||||
Text{
|
||||
text: "gtld.node.name = " + gtld.node.name
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.node.uuid = " + gtld.node.uuid.toString()
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
|
||||
Text{
|
||||
text: "gtld.node.lastResult[\"tag\"] = " + gtld.node.lastResult["tag"] || "undefined";
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.node.lastResult.masterValues[\"skz\"] = " + gtld.node.lastResult.masterValues?.["skz"] || "undefined";
|
||||
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
|
||||
Text{
|
||||
text: "gtld.storage.selectLastResults({args}).length = "
|
||||
+ gtld.node.selectLastResults(
|
||||
{
|
||||
count: 5,
|
||||
tag: gtld.node.lastResult["tag"]
|
||||
}
|
||||
).length || "undefined";
|
||||
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
SplitView.preferredWidth: parent.width/2
|
||||
color: "lightGray"
|
||||
ListView{
|
||||
id: listView
|
||||
anchors.fill: parent
|
||||
|
||||
spacing: 5
|
||||
model: gtld.node.selectLastResults(
|
||||
{
|
||||
count: 5,
|
||||
tag: "tag",
|
||||
})
|
||||
|
||||
delegate: Rectangle {
|
||||
height: 60
|
||||
width: ListView.view.width
|
||||
color: "darkblue"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: "white"
|
||||
text: "skz = " + modelData["masterValues"]?.["skz"] + "; speed = " + modelData["masterValues"]?.["speed"]
|
||||
font.pointSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
import QtQml
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
Item {
|
||||
id: mainWindow
|
||||
anchors.fill: parent
|
||||
|
||||
SplitView {
|
||||
id: splitView
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
|
||||
handle: Rectangle {
|
||||
implicitWidth: 6
|
||||
color: "darkgray"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
SplitView.preferredWidth: parent.width/2
|
||||
SplitView.maximumWidth: parent.width/100*75
|
||||
SplitView.minimumWidth: parent.width/100*25
|
||||
color: "gray"
|
||||
|
||||
ColumnLayout {
|
||||
Text{
|
||||
text: "gtld.node.name = " + gtld.node.name
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.node.uuid = " + gtld.node.uuid.toString()
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.node.parent.uuid = " + gtld.node.parent.uuid.toString()
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.node.lastResult[\"tag\"] = " + gtld.node.lastResult?.[0]?.["tag"] || "undefined";
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Text{
|
||||
text: "gtld.storage.selectLastResults({args}).length = "
|
||||
+ gtld.node.selectLastResults(
|
||||
{
|
||||
count: 5,
|
||||
tag: gtld.node.lastResult?.[0]?.["tag"] || "undefined"
|
||||
}
|
||||
).length || "undefined";
|
||||
|
||||
font.pointSize: 18
|
||||
color: "white"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
SplitView.preferredWidth: parent.width/2
|
||||
color: "lightGray"
|
||||
ListView{
|
||||
id: listView
|
||||
anchors.fill: parent
|
||||
|
||||
spacing: 5
|
||||
model: gtld.node.selectLastResults(
|
||||
{
|
||||
count: 5,
|
||||
tag: "tag",
|
||||
}
|
||||
)
|
||||
|
||||
delegate: Rectangle {
|
||||
height: 60
|
||||
width: ListView.view.width
|
||||
color: "darkblue"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: "white"
|
||||
text: "record fileName = " + modelData?.["recordOptions"]?.["recordFileName"] +
|
||||
"; skz = " + modelData["masterValues"]?.["skz"] +
|
||||
"; speed = " + modelData["masterValues"]?.["speed"]
|
||||
font.pointSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"comment": "",
|
||||
"hw": {
|
||||
"channels": [
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
]
|
||||
},
|
||||
"ranges": [
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"comment": "",
|
||||
"hw": {
|
||||
"channels": [
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
]
|
||||
},
|
||||
"ranges": [
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"comment": "",
|
||||
"hw": {
|
||||
"channels": [
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
]
|
||||
},
|
||||
"ranges": [
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"comment": "",
|
||||
"hw": {
|
||||
"channels": [
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
]
|
||||
},
|
||||
"ranges": [
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
gtl.log.info("Анализатор", "Запущен");
|
||||
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[0]);
|
||||
|
||||
ausp.color = 0x0000ff00;
|
||||
ausp.frequency = 1600;
|
||||
ausp.lines = 800;
|
||||
ausp.average = 6;
|
||||
ausp.unit = gtl.spec.db;
|
||||
|
||||
var ausp2 = gtl.add_ausp(gtl.analog_inputs[1]);
|
||||
|
||||
ausp2.color = 0x000000ff;
|
||||
ausp2.frequency = 1600;
|
||||
ausp2.lines = 800;
|
||||
ausp2.average = 6;
|
||||
ausp2.unit = gtl.spec.db;
|
||||
|
||||
gtl.diagnostic.interval = 0.1;
|
||||
|
||||
let __counter = 0;
|
||||
|
||||
let __results = {
|
||||
"Потребное время измерений, секунд": ausp.acq_time,
|
||||
};
|
||||
|
||||
__results["Прошло времени, секунд"] = gtl.diagnostic.interval * __counter;
|
||||
__results["Статус рассчета"] = "в процессе";
|
||||
|
||||
gtl.results = __results;
|
||||
|
||||
function diagnose() {
|
||||
__counter++;
|
||||
|
||||
__results["Прошло времени, секунд"] = gtl.diagnostic.interval * __counter;
|
||||
__results["Статус рассчета"] = "в процессе";
|
||||
if (gtl.diagnostic.interval * __counter >= ausp.acq_time) {
|
||||
__results["Статус рассчета"] = "окончен";
|
||||
gtl.results = __results;
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
||||
gtl.results = __results;
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
"use strict";
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js");
|
||||
var mtx = gtl.import("bs_mtx.js");
|
||||
var def = gtl.import("bs_defs.js");
|
||||
|
||||
//настройки для датчика оборотов
|
||||
var filter_freq = gtl.add_filter_iir(gtl.analog_inputs[record.tachoOptions.tachoChannel]); //объявление переменной фильтра
|
||||
filter_freq.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_freq.type = gtl.filter_iir.lowpass; //тип фильтра (ФНЧ)
|
||||
filter_freq.order = 8; //порядок фильтра
|
||||
filter_freq.frequency = 10; //граничная частота фильтра
|
||||
|
||||
//определение частоты вращения
|
||||
var freq = gtl.add_value_freq(filter_freq);
|
||||
freq.time = 1;
|
||||
freq.avg_cnt = 6;
|
||||
//gtl.diagnostic.interval = /*1*/10;
|
||||
|
||||
//[Блок настройки параметров измерений]
|
||||
//мониторинговый спектр вибрации
|
||||
var ausp2 = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp2.name = "AUSPm"; //присвоение имени спектра
|
||||
ausp2.color = 0x0000ffff; //цвет линии спектра
|
||||
ausp2.frequency = 25600; //граничная частота спектра
|
||||
ausp2.lines = 1600; //разрешение спектра (количество линий)
|
||||
ausp2.average = 6; //количество усреднений
|
||||
ausp2.unit = gtl.spec.db; //отображение в дБ
|
||||
|
||||
//спектр вибрации
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp.name = "AUSPd"; //присвоение имени спектра
|
||||
ausp.color = 0x0000ff00; //цвет линии спектра
|
||||
ausp.frequency = 800; //граничная частота спектра
|
||||
ausp.lines = 800; //разрешение спектра (количество линий)
|
||||
ausp.average = 6; //количество усреднений
|
||||
ausp.unit = gtl.spec.db; //отображение в дБ
|
||||
ausp.smoothing_factor = 50; //коэффициент сглаживания спектра
|
||||
ausp.smoothed_line_color = 0x000000ff; //цвет линии сглаживания (средней линии)
|
||||
ausp.peak_level = 20; //порог обнаружения гармоник
|
||||
ausp.harm_tolerance = ausp.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//фильтр для формирования спектра огибающей
|
||||
var filter_spen = gtl.add_filter_iir(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной фильтра
|
||||
filter_spen.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_spen.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_spen.order = 10; //порядок фильтра
|
||||
filter_spen.frequency = 6400; //центральная частота полосового фильтра
|
||||
filter_spen.color = 255;
|
||||
filter_spen.width = 1482; //ширина полосы фильтра
|
||||
|
||||
//спектр огибающей
|
||||
var spen = gtl.add_spen(filter_spen); //назначение переменной спектра огибающей
|
||||
spen.name = "SPEN"; //присвоение имени спектра огибающей
|
||||
spen.color = 0x00ff0000; //цвет линии спектра огибающей
|
||||
spen.frequency = 200; //граничная частота спектра огибающей
|
||||
spen.lines = 200; //разрешение спектра огибающей (количество линий)
|
||||
spen.average = 8; //количество усреднений
|
||||
spen.unit = gtl.spec.db; //отображение в дБ
|
||||
spen.window = gtl.spec.hann; //окно
|
||||
spen.smoothing_factor = 100; //коэффициент сглаживания спектра
|
||||
spen.smoothed_line_color = 0xff004dff; //цвет средней линии
|
||||
spen.peak_level = 10; //порог обнаружения гармоник
|
||||
spen.harm_tolerance = spen.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//RMS и Amplitude в диапазоне спектра огибающей (контроль работы сил трения)
|
||||
var rms_spen = gtl.add_value_rms(filter_spen); //назначение переменной RMS (spen)
|
||||
var ampl_spen = gtl.add_value_ampl(filter_spen); //назначение переменной Amplitude (spen)
|
||||
rms_spen.name = "RMS (spen)" //присвоение имени RMS (spen)
|
||||
rms_spen.time = 0.5; //интервал расчета RMS (spen)
|
||||
ampl_spen.time = 0.5; //интервал расчета Amplitude (spen)
|
||||
rms_spen.avg_cnt = 4; //количество усреднений RMS (spen)
|
||||
ampl_spen.avg_cnt = 4; //количество усреднений Amplitude (spen)
|
||||
|
||||
//RMS виброскорости в диапазоне 10-1000 Гц.
|
||||
var int = gtl.add_intg(gtl.analog_inputs[signals[0].portNumber]); //интегрирование сигнала виброускорения
|
||||
int.taps = 1; //степень интегрирования (скорость из ускорения - 1-нарное интегрирование)
|
||||
//фильтрация сигнала в диапазоне
|
||||
var filter = gtl.add_filter_iir(int); //объявление переменной фильтра
|
||||
filter.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter.order = 10; //порядок фильтра
|
||||
filter.frequency = 505; //центральная частота полосового фильтра
|
||||
filter.width = 990; //ширина полосы фильтра
|
||||
//определение среднего квадратического значения виброскорости
|
||||
var rms_v = gtl.add_value_rms(filter); //объявление переменной СКЗ
|
||||
rms_v.time = 0.5; //время выборки
|
||||
rms_v.avg_cnt = 4; //количество усреднений
|
||||
|
||||
//[Диагностика]
|
||||
gtl.diagnostic.interval = freq.time * freq.avg_cnt;
|
||||
let state = record.tachoOptions.tachoState; //начальное состояние после выбора источника тахо сигнала
|
||||
|
||||
function diagnose() {
|
||||
switch (state) {
|
||||
case 0: // считаем частоту вращения и настраиваем спектры
|
||||
if (fnc.INSTABILITY() > fnc.tolerance()) {
|
||||
gtl.log.info("Критическая нестабильность частоты вращения, %", fnc.INSTABILITY() * 100);
|
||||
gtl.log.info("Результат:", "Диагностика прервана");
|
||||
//gtl.diagnostic.stop(); //принудительная остановка диагностики
|
||||
|
||||
let __result = {
|
||||
Result: false
|
||||
};
|
||||
gtl.results = __result;
|
||||
};
|
||||
|
||||
if (fnc.FREQ() <= fnc.FREQNESS()) {
|
||||
gtl.log.info("Частота вращения меньше минимально рекомендуемой", "Минимально рекомендуемая частота: " + fnc.FREQNESS());
|
||||
};
|
||||
|
||||
case 1: //частота вращения фиксированная
|
||||
case 2: //частота вращения из поля INFO (виброметр)
|
||||
filter_spen.frequency = fnc.filter_frequency(); //считаме фильтр для огибающей
|
||||
filter_spen.width = fnc.filter_width(); //определяем ширину фильтра
|
||||
spen.frequency = fnc.spec_params().frequency;
|
||||
spen.lines = fnc.spec_params().lines;
|
||||
ausp.frequency = fnc.spec_params().frequency;
|
||||
ausp.lines = fnc.spec_params().lines;
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
let time = []; //массив по времени набора данных
|
||||
time.push(ausp.acq_time);
|
||||
time.push(spen.acq_time);
|
||||
let max_acq = Math.max(...time);
|
||||
gtl.diagnostic.interval = max_acq;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: //выполняем анализ спектов
|
||||
ausp.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре вибрации
|
||||
spen.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре огибающей
|
||||
|
||||
//Вывод информации в лог
|
||||
//Расчет площади спектра вибрации: спектр, начало отсчета в Гц, граничная частота спектра
|
||||
var AQ = fnc.spec_square(ausp.data, ausp.frequency / 2, ausp.frequency);
|
||||
|
||||
gtl.log.info("Объект диагностики", options.rbModelName);
|
||||
gtl.log.info("FREQ", fnc.FREQ());
|
||||
gtl.log.info("FTF", fnc.BSFTF());
|
||||
gtl.log.info("BPFO", fnc.BSNUT());
|
||||
gtl.log.info("BPFI", fnc.BSSCR());
|
||||
gtl.log.info("BSF", fnc.BSBAL());
|
||||
gtl.log.info("Коридор обнаружения гармоники", fnc.tolerance());
|
||||
gtl.log.info("Полосовой фильтр (расчетный)", filter_spen.frequency);
|
||||
gtl.log.info("Ширина фильтра", filter_spen.width);
|
||||
gtl.log.info("Граничная частота SPEN", spen.frequency);
|
||||
gtl.log.info("Количество линий SPEN", spen.lines);
|
||||
gtl.log.info("Разрешение SPEN", spen.resolution);
|
||||
gtl.log.info("Ширина AUSP", ausp.frequency);
|
||||
|
||||
let spen_mx = mtx.bs_mtx(spen, filter_spen, true);
|
||||
let spen_df = def.bs_defs(spen_mx, true);
|
||||
let ausp_mx = mtx.bs_mtx(ausp, 0, false);
|
||||
|
||||
var res = {
|
||||
RMSA: rms_spen.value,
|
||||
RMSV: rms_v.value,
|
||||
PF: ampl_spen.value / rms_spen.value,
|
||||
SQR: AQ,
|
||||
matrix: spen_mx,
|
||||
defs: spen_df,
|
||||
};
|
||||
|
||||
gtl.results = res;
|
||||
gtl.diagnostic.stop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
|
||||
export function bs_defs(mtx, isDeep) {
|
||||
var res = {}; //результат
|
||||
if (isDeep = true) { var key = "dp" } else { var key = "lv" };
|
||||
var des = {
|
||||
FTF: { ds: "тел качения и сепаратора", dp: 8, lv: 20 },
|
||||
FREQ: { ds: "винта", dp: 13, lv: 20 },
|
||||
BSF: { ds: "тел качения", dp: 10, lv: 20 },
|
||||
BPFO: { ds: "гайки", dp: 15, lv: 20 },
|
||||
BPFI: { ds: "винта", dp: 8, lv: 20 },
|
||||
}; //описание функциональных частот
|
||||
|
||||
function get_note(harmsArr) {
|
||||
let note = "Износ"; //описание характера колебаний
|
||||
let cnt = 0; //количество значений в массиве
|
||||
for (let i = 0; i <= harmsArr.length - 1; i++) { if (harmsArr[i] > 0) { cnt++ }; };
|
||||
if (cnt >= 5) { note = "Дефект" };
|
||||
if (harmsArr[1] > harmsArr[0]) { note = "Перекос" };
|
||||
if (cnt > 0 && harmsArr[0] == 0 && harmsArr[1] == 0) { note = "Неидентифицированные изменения вибрации" };
|
||||
return note;
|
||||
};
|
||||
|
||||
function get_level(lvl, thres) {
|
||||
let level = "Сильный";
|
||||
switch (true) {
|
||||
case lvl < 0.5 * thres:
|
||||
level = "Слабый";
|
||||
break;
|
||||
case lvl < thres:
|
||||
level = "Средний";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}; return level;
|
||||
};
|
||||
|
||||
var rows = Object.keys(mtx); //массив ключей объекта (наборов гармоник)
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let arr = mtx[rows[i]]; //массив гармоник
|
||||
let lvl = Math.max(...arr); //определяем максимальное значение параметра из массива
|
||||
let sum = arr.reduce(function (a, b) { return a + b }, 0); //сумма элементов массива
|
||||
if (sum > 0) {
|
||||
let note = get_note(arr);
|
||||
res[rows[i]] = note + ' ' + des[rows[i]].ds + ': ' + get_level(lvl, des[rows[i]][key]) + ' (' + lvl + ')';
|
||||
};
|
||||
};
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
"use strict";
|
||||
|
||||
var ufc = gtl.import("user-functions.js");
|
||||
|
||||
export function bs_mtx(spec, filter, isDeep) {
|
||||
var num = 6; //глубина матрицы (количество гармоник)
|
||||
var level = 0; //уровень развития дефекта
|
||||
var res = {}; //результат
|
||||
|
||||
var set = {
|
||||
FTF: { nm: "Частота вращения сепаратора", fn: ufc.BSFTF(), md: 0, cl: 0xffff0000 },
|
||||
FREQ: { nm: "Частота вращения", fn: ufc.FREQ(), md: 0, cl: 0xff0000f0 },
|
||||
BSF: { nm: "Частота вращения (контакта) тел качения", fn: ufc.BSBAL(), md: 0, cl: 0xffFFB841 },
|
||||
BPFO: { nm: "Частота перекатывания тел качения по гайке", fn: ufc.BSNUT(), md: 0, cl: 0xffED3CCA },
|
||||
BPFI: { nm: "Частота перекатывания тел качения по винту", fn: ufc.BSSCR(), md: 0, cl: 0xff990090 }
|
||||
}; //набор функциональных частот
|
||||
|
||||
function mod_factor(dSpec, dFilter, ampl, base) {
|
||||
let dl = (ampl - base); //разность уровней гармонической и случайной составляющей вибрации
|
||||
let df = dSpec.resolution / dFilter.width; //отношение частотному разрешению спектра к ширине фильтра
|
||||
let mod = Math.sqrt((10 ** (dl / 10) - 1) * df) * 100;
|
||||
return mod;
|
||||
}; //определение глубины модуляции ВЧ составляющих
|
||||
|
||||
var rows = Object.keys(set); //массив ключей объекта (наборов гармонических рядов)
|
||||
//присваиваем набору гармоник переменную, добавляем гармоники: частота, кол-во (default = 10), цвет, вес.
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let lines = rows[i];
|
||||
let idx = 0; //индекс гармонического ряда
|
||||
let nms = set[lines].nm; //название гармонического ряда
|
||||
let frq = set[lines].fn; //расчетная частота
|
||||
let mod = set[lines].md; //модулирующая частота
|
||||
let clr = set[lines].cl; //предустановленный цвет
|
||||
let arr = []; //массив обнаруженных гармоник
|
||||
|
||||
lines = spec.add_harms_set(frq, num, clr, 2); //строим набор частот (гармонический ряд)
|
||||
lines.name = nms;
|
||||
idx = spec.index_of_harms_set(lines); //определяем индекс набора частот
|
||||
if (mod != 0) { spec.harms_sets[idx].modulate(mod, 2, clr, 0.5) }; //строим амплитудную модуляцию
|
||||
for (let j = 0; j <= num - 1; j++) {
|
||||
lines.harms[j].tolerance = (j + 1) * frq * ufc.tolerance(); //устанавливаем коридор обнаружения гармоники
|
||||
if (lines.harms[j].is_present == true) {
|
||||
switch (isDeep) {
|
||||
case true:
|
||||
level = Math.round(mod_factor(spec, filter, lines.harms[j].amplitude, lines.harms[j].base));
|
||||
break;
|
||||
case false:
|
||||
level = Math.round(lines.harms[j].level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
arr.push(level);
|
||||
} else { arr.push(0) };
|
||||
res[rows[i]] = arr;
|
||||
};
|
||||
};
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
"use strict";
|
||||
|
||||
let options = gtl.options; // параметры объекта
|
||||
|
||||
gtl.log.info("object.objectType", options.objectType);
|
||||
gtl.log.info("object.tachoRatio", options.tachoRatio);
|
||||
gtl.log.info("object.scriptName", options.scriptName);
|
||||
|
||||
switch (options.objectType) {
|
||||
case 0:
|
||||
gtl.log.info("Тип", "Тип объекта не задан");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gtl.log.info("Тип", "Подшипник скольжения");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// параметры подшипника качения
|
||||
gtl.log.info("Тип", "Подшипник качения");
|
||||
gtl.log.info("object.rbModelName", options?.rbModelName || "No Name");
|
||||
gtl.log.info("object.rbVendor", options?.rbVendor || "No Vendor");
|
||||
gtl.log.info("object.rbOuterD", options.rbOuterD);
|
||||
gtl.log.info("object.rbInnerD", options.rbInnerD);
|
||||
gtl.log.info("object.rbRollerD", options.rbRollerD);
|
||||
gtl.log.info("object.rbRollerCount", options.rbRollerCount);
|
||||
gtl.log.info("object.rbAngle", (options.rbAngle * 3.1415926) / 180);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// ШВП
|
||||
gtl.log.info("Тип", "ШВП");
|
||||
gtl.log.info("object.bsModelName", options?.bsModelName || "No Name");
|
||||
gtl.log.info("object.bsVendor", options?.bsVendor || "No Name");
|
||||
gtl.log.info("object.bsOuterD", options.bsOuterD);
|
||||
gtl.log.info("object.bsInnerD", options.bsInnerD);
|
||||
gtl.log.info("object.bsRollerD", options.bsRollerD);
|
||||
gtl.log.info("object.bsRollerCount", options.bsRollerCount);
|
||||
gtl.log.info("object.rbAngle", (options.bsAngle * 3.1415926) / 180);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gtl.log.info("Тип", "Редуктор");
|
||||
gtl.log.info("object.gtZ1", options.gtZ1);
|
||||
gtl.log.info("object.gtZ2", options.gtZ2);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gtl.log.info("Тип", "Ремень");
|
||||
gtl.log.info("object.bdD1", options.bdD1);
|
||||
gtl.log.info("object.bdD2", options.bdD2);
|
||||
gtl.log.info("object.bdL", options.bdL);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
gtl.log.info("Тип", "Зубчатый ремень");
|
||||
gtl.log.info("object.cbdZ1", options.cbdZ1);
|
||||
gtl.log.info("object.cbdZ2", options.cbdZ2);
|
||||
gtl.log.info("object.cbdZ3", options.cbdZ3);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
gtl.log.info("Тип", "Помпа");
|
||||
gtl.log.info("object.pmBlades", options.pmBlades);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
gtl.log.info("Тип", "Планетарный редуктор");
|
||||
gtl.log.info("object.pgZ1", options.pgZ1);
|
||||
gtl.log.info("object.pgZ2", options.pgZ2);
|
||||
gtl.log.info("object.pgZ3", options.pgZ3);
|
||||
gtl.log.info("object.pgN", options.pgN);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
gtl.log.info("Тип", "Турбина");
|
||||
gtl.log.info("object.trBlades", options.trBlades);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
gtl.log.info("Тип", "Электродвигатель");
|
||||
break;
|
||||
}
|
||||
|
||||
let record = gtl.options.record; // параметры записи
|
||||
gtl.log.info("record.uuid", record.uuid);
|
||||
gtl.log.info("record.recordFileName", record.recordFileName);
|
||||
gtl.log.info("record.recordPath", record.recordPath);
|
||||
gtl.log.info("record.recordType", record.recordType); // Link или Local
|
||||
gtl.log.info("record.recordFileSize", record.recordFileSize);
|
||||
gtl.log.info("record.timestamp", record.timestamp);
|
||||
gtl.log.info("record.playerTime", record.playerTime);
|
||||
gtl.log.info("record.playerChannelsCount", record.playerChannelsCount);
|
||||
gtl.log.info("record.playerRate", record.playerRate);
|
||||
gtl.log.info("record.playerComment", record.playerComment);
|
||||
gtl.log.info("record.playerDevice", record.playerDevice);
|
||||
|
||||
let signals = gtl.options.record.signalsModel; // массив сигналов
|
||||
signals.forEach((signal, index) => {
|
||||
// параметры сигнала с индексом index
|
||||
gtl.log.info(`signals[${index}].portNumber`, signal.portNumber); // номер канала
|
||||
gtl.log.info(`signals[${index}].name`, signal.name); // имя канала
|
||||
gtl.log.info(`signals[${index}].units`, signal.units); // единицы измерения
|
||||
gtl.log.info(`signals[${index}].sensitivity`, signal.sensitivity); // чувствительность (заданная при записи исходного сигнала)
|
||||
gtl.log.info(`signals[${index}].scaleFactor`, signal.scaleFactor); // масштабный коэффициент для чувствительность
|
||||
});
|
||||
|
||||
var point = gtl.options.point; // праметры точки
|
||||
gtl.log.info("point.label", point.label);
|
||||
gtl.log.info("point.uuid", point.uuid);
|
||||
gtl.log.info("point.comment", point.comment);
|
||||
|
||||
if (record.tachoOptions.isTachoEnabled) {
|
||||
gtl.log.info("record.tachoOptions.minTacho", record.tachoOptions.minTacho);
|
||||
gtl.log.info("record.tachoOptions.maxTacho", record.tachoOptions.maxTacho);
|
||||
switch (record.tachoOptions.tachoState) {
|
||||
case 0: // тахо сигнал берется из сигнала
|
||||
gtl.log.info("Режим тахометра", "Взять из сигнала");
|
||||
gtl.log.info(
|
||||
"record.tachoOptions.tachoChannel",
|
||||
record.tachoOptions.tachoChannel
|
||||
); // номер канала для тахо
|
||||
gtl.log.info(
|
||||
"record.tachoOptions.tachoChannelName",
|
||||
record.tachoOptions.tachoChannelName
|
||||
);
|
||||
break;
|
||||
|
||||
case 1: // значение тахо фиксированное
|
||||
gtl.log.info("Режим тахометра", "Фиксированное значение");
|
||||
gtl.log.info(
|
||||
"record.tachoOptions.tachoValue",
|
||||
record.tachoOptions.tachoValue
|
||||
); // фиксированное значение тахо
|
||||
break;
|
||||
|
||||
case 2: // значение тахо из поля INFO (виброметр)
|
||||
gtl.log.info("Режим тахометра", "Взять из поля INFO");
|
||||
gtl.log.info(
|
||||
"record.tachoOptions.tachoFromInfo",
|
||||
record.tachoOptions.tachoFromInfo
|
||||
); // значение тахо из инфо
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
gtl.log.info("Режим тахометра", "Тахометр не используется");
|
||||
}
|
||||
|
||||
function diagnose() {
|
||||
let __result = { skz: 1, speed: 2 };
|
||||
|
||||
gtl.results = __result;
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
"use strict";
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js");
|
||||
var mtx = gtl.import("gt_mtx.js");
|
||||
var def = gtl.import("gt_defs.js");
|
||||
|
||||
//настройки для датчика оборотов
|
||||
var filter_freq = gtl.add_filter_iir(gtl.analog_inputs[record.tachoOptions.tachoChannel]); //объявление переменной фильтра
|
||||
filter_freq.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_freq.type = gtl.filter_iir.lowpass; //тип фильтра (ФНЧ)
|
||||
filter_freq.order = 8; //порядок фильтра
|
||||
filter_freq.frequency = 10; //граничная частота фильтра
|
||||
|
||||
//определение частоты вращения
|
||||
var freq = gtl.add_value_freq(filter_freq);
|
||||
freq.time = 1;
|
||||
freq.avg_cnt = 6;
|
||||
//gtl.diagnostic.interval = /*1*/10;
|
||||
|
||||
//[Блок настройки параметров измерений]
|
||||
//мониторинговый спектр вибрации
|
||||
var ausp2 = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp2.name = "AUSPm"; //присвоение имени спектра
|
||||
ausp2.color = 0x0000ffff; //цвет линии спектра
|
||||
ausp2.frequency = 25600; //граничная частота спектра
|
||||
ausp2.lines = 1600; //разрешение спектра (количество линий)
|
||||
ausp2.average = 6; //количество усреднений
|
||||
ausp2.unit = gtl.spec.db; //отображение в дБ
|
||||
|
||||
//спектр вибрации
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp.name = "AUSPd"; //присвоение имени спектра
|
||||
ausp.color = 0x0000ff00; //цвет линии спектра
|
||||
ausp.frequency = 800; //граничная частота спектра
|
||||
ausp.lines = 800; //разрешение спектра (количество линий)
|
||||
ausp.average = 6; //количество усреднений
|
||||
ausp.unit = gtl.spec.db; //отображение в дБ
|
||||
ausp.smoothing_factor = 50; //коэффициент сглаживания спектра
|
||||
ausp.smoothed_line_color = 0x000000ff; //цвет линии сглаживания (средней линии)
|
||||
ausp.peak_level = 20; //порог обнаружения гармоник
|
||||
ausp.harm_tolerance = ausp.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//фильтр для формирования спектра огибающей
|
||||
var filter_spen = gtl.add_filter_iir(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной фильтра
|
||||
filter_spen.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_spen.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_spen.order = 10; //порядок фильтра
|
||||
filter_spen.frequency = 6400; //центральная частота полосового фильтра
|
||||
filter_spen.color = 255;
|
||||
filter_spen.width = 1482; //ширина полосы фильтра
|
||||
|
||||
//спектр огибающей
|
||||
var spen = gtl.add_spen(filter_spen); //назначение переменной спектра огибающей
|
||||
spen.name = "SPEN"; //присвоение имени спектра огибающей
|
||||
spen.color = 0x00ff0000; //цвет линии спектра огибающей
|
||||
spen.frequency = 200; //граничная частота спектра огибающей
|
||||
spen.lines = 200; //разрешение спектра огибающей (количество линий)
|
||||
spen.average = 8; //количество усреднений
|
||||
spen.unit = gtl.spec.db; //отображение в дБ
|
||||
spen.window = gtl.spec.hann; //окно
|
||||
spen.smoothing_factor = 100; //коэффициент сглаживания спектра
|
||||
spen.smoothed_line_color = 0xff004dff; //цвет средней линии
|
||||
spen.peak_level = 10; //порог обнаружения гармоник
|
||||
spen.harm_tolerance = spen.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//RMS и Amplitude в диапазоне спектра огибающей (контроль работы сил трения)
|
||||
var rms_spen = gtl.add_value_rms(filter_spen); //назначение переменной RMS (spen)
|
||||
var ampl_spen = gtl.add_value_ampl(filter_spen); //назначение переменной Amplitude (spen)
|
||||
rms_spen.name = "RMS (spen)" //присвоение имени RMS (spen)
|
||||
rms_spen.time = 0.5; //интервал расчета RMS (spen)
|
||||
ampl_spen.time = 0.5; //интервал расчета Amplitude (spen)
|
||||
rms_spen.avg_cnt = 4; //количество усреднений RMS (spen)
|
||||
ampl_spen.avg_cnt = 4; //количество усреднений Amplitude (spen)
|
||||
|
||||
//RMS виброскорости в диапазоне 10-1000 Гц.
|
||||
var int = gtl.add_intg(gtl.analog_inputs[signals[0].portNumber]); //интегрирование сигнала виброускорения
|
||||
int.taps = 1; //степень интегрирования (скорость из ускорения - 1-нарное интегрирование)
|
||||
//фильтрация сигнала в диапазоне
|
||||
var filter = gtl.add_filter_iir(int); //объявление переменной фильтра
|
||||
filter.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter.order = 10; //порядок фильтра
|
||||
filter.frequency = 505; //центральная частота полосового фильтра
|
||||
filter.width = 990; //ширина полосы фильтра
|
||||
//определение среднего квадратического значения виброскорости
|
||||
var rms_v = gtl.add_value_rms(filter); //объявление переменной СКЗ
|
||||
rms_v.time = 0.5; //время выборки
|
||||
rms_v.avg_cnt = 4; //количество усреднений
|
||||
|
||||
//[Диагностика]
|
||||
gtl.diagnostic.interval = freq.time * freq.avg_cnt;
|
||||
let state = record.tachoOptions.tachoState; //начальное состояние после выбора источника тахо сигнала
|
||||
|
||||
function diagnose() {
|
||||
switch (state) {
|
||||
case 0: // считаем частоту вращения и настраиваем спектры
|
||||
if (fnc.INSTABILITY() > fnc.tolerance()) {
|
||||
gtl.log.info("Критическая нестабильность частоты вращения, %", fnc.INSTABILITY() * 100);
|
||||
gtl.log.info("Результат:", "Диагностика прервана");
|
||||
//gtl.diagnostic.stop(); //принудительная остановка диагностики
|
||||
|
||||
let __result = {
|
||||
Result: false
|
||||
};
|
||||
gtl.results = __result;
|
||||
};
|
||||
|
||||
if (fnc.FREQ() <= fnc.FREQNESS()) {
|
||||
gtl.log.info("Частота вращения меньше минимально рекомендуемой", "Минимально рекомендуемая частота: " + fnc.FREQNESS());
|
||||
};
|
||||
|
||||
case 1: //частота вращения фиксированная
|
||||
case 2: //частота вращения из поля INFO (виброметр)
|
||||
filter_spen.frequency = fnc.filter_frequency(); //считаме фильтр для огибающей
|
||||
filter_spen.width = fnc.filter_width(); //определяем ширину фильтра
|
||||
spen.frequency = fnc.spec_params().frequency;
|
||||
spen.lines = fnc.spec_params().lines;
|
||||
ausp.frequency = fnc.spec_params().frequency;
|
||||
ausp.lines = fnc.spec_params().lines;
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
let time = []; //массив по времени набора данных
|
||||
time.push(ausp.acq_time);
|
||||
time.push(spen.acq_time);
|
||||
let max_acq = Math.max(...time);
|
||||
gtl.diagnostic.interval = max_acq;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: //выполняем анализ спектов
|
||||
ausp.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре вибрации
|
||||
spen.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре огибающей
|
||||
|
||||
//Вывод информации в лог
|
||||
//Расчет площади спектра вибрации: спектр, начало отсчета в Гц, граничная частота спектра
|
||||
var AQ = fnc.spec_square(ausp.data, ausp.frequency / 2, ausp.frequency);
|
||||
|
||||
gtl.log.info("Объект диагностики", options.rbModelName);
|
||||
gtl.log.info("FREQ", fnc.FREQ());
|
||||
gtl.log.info("FTF", fnc.GTF2());
|
||||
gtl.log.info("BPFO", fnc.GTFZ());
|
||||
gtl.log.info("Коридор обнаружения гармоники", fnc.tolerance());
|
||||
gtl.log.info("Полосовой фильтр (расчетный)", filter_spen.frequency);
|
||||
gtl.log.info("Ширина фильтра", filter_spen.width);
|
||||
gtl.log.info("Граничная частота SPEN", spen.frequency);
|
||||
gtl.log.info("Количество линий SPEN", spen.lines);
|
||||
gtl.log.info("Разрешение SPEN", spen.resolution);
|
||||
gtl.log.info("Ширина AUSP", ausp.frequency);
|
||||
|
||||
let spen_mx = mtx.gt_mtx(spen, filter_spen, true);
|
||||
let spen_df = def.gt_defs(spen_mx, true);
|
||||
let ausp_mx = mtx.gt_mtx(ausp, 0, false);
|
||||
|
||||
var res = {
|
||||
RMSA: rms_spen.value,
|
||||
RMSV: rms_v.value,
|
||||
PF: ampl_spen.value / rms_spen.value,
|
||||
SQR: AQ,
|
||||
matrix: spen_mx,
|
||||
defs: spen_df
|
||||
};
|
||||
|
||||
gtl.results = res;
|
||||
gtl.diagnostic.stop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
|
||||
export function gt_defs(mtx, isDeep) {
|
||||
var res = {}; //результат
|
||||
if (isDeep = true) { var key = "dp" } else { var key = "lv" };
|
||||
var des = {
|
||||
FREQ: { ds: "шестерни", dp: 20, lv: 20 },
|
||||
GTF2: { ds: "зубчатого колеса", dp: 20, lv: 20 },
|
||||
GTFZ: { ds: "зацепления шестерни", dp: 20, lv: 20 },
|
||||
GTFZ2: { ds: "зацепления зубчатого колеса", dp: 20, lv: 20 }
|
||||
}; //описание функциональных частот
|
||||
|
||||
function get_note(harmsArr) {
|
||||
let note = "Биение"; //описание характера колебаний
|
||||
let cnt = 0; //количество значений в массиве
|
||||
for (let i = 0; i <= harmsArr.length - 1; i++) { if (harmsArr[i] > 0) { cnt++ }; };
|
||||
if (cnt >= 5) { note = "Дефект" };
|
||||
if (harmsArr[1] > harmsArr[0]) { note = "Перекос" };
|
||||
if (cnt > 0 && harmsArr[0] == 0 && harmsArr[1] == 0) { note = "Неидентифицированные изменения вибрации" };
|
||||
return note;
|
||||
};
|
||||
|
||||
function get_level(lvl, thres) {
|
||||
let level = "Сильный";
|
||||
switch (true) {
|
||||
case lvl < 0.5 * thres:
|
||||
level = "Слабый";
|
||||
break;
|
||||
case lvl < thres:
|
||||
level = "Средний";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}; return level;
|
||||
};
|
||||
|
||||
var rows = Object.keys(mtx); //массив ключей объекта (наборов гармоник)
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let arr = mtx[rows[i]]; //массив гармоник
|
||||
let lvl = Math.max(...arr); //определяем максимальное значение параметра из массива
|
||||
let sum = arr.reduce(function (a, b) { return a + b }, 0); //сумма элементов массива
|
||||
if (sum > 0) {
|
||||
let note = get_note(arr);
|
||||
res[rows[i]] = note + ' ' + des[rows[i]].ds + ': ' + get_level(lvl, des[rows[i]][key]) + ' (' + lvl + ')';
|
||||
};
|
||||
};
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
"use strict";
|
||||
|
||||
var ufc = gtl.import("user-functions.js");
|
||||
|
||||
export function gt_mtx(spec, filter, isDeep) {
|
||||
var num = 6; //глубина матрицы (количество гармоник)
|
||||
var level = 0; //уровень развития дефекта
|
||||
var res = {}; //результат
|
||||
|
||||
var set = {
|
||||
FREQ: { nm: "Частота вращения", fn: ufc.FREQ(), md: 0, cl: 0xff0000f0 },
|
||||
GTF2: { nm: "Частота вращения второго вала", fn: ufc.GTF2(), md: 0, cl: 0xffFFB841 },
|
||||
GTFZ: { nm: "Зубцовая частота по шестерне", fn: ufc.GTFZ(), md: ufc.FREQ(), cl: 0xffED3CCA },
|
||||
GTFZ2: { nm: "Зубцовая частота по второму валу", fn: ufc.GTFZ(), md: ufc.GTF2(), cl: 0xff990090 }
|
||||
}; //набор функциональных частот
|
||||
|
||||
function mod_factor(dSpec, dFilter, ampl, base) {
|
||||
let dl = (ampl - base); //разность уровней гармонической и случайной составляющей вибрации
|
||||
let df = dSpec.resolution / dFilter.width; //отношение частотному разрешению спектра к ширине фильтра
|
||||
let mod = Math.sqrt((10 ** (dl / 10) - 1) * df) * 100;
|
||||
return mod;
|
||||
}; //определение глубины модуляции ВЧ составляющих
|
||||
|
||||
var rows = Object.keys(set); //массив ключей объекта (наборов гармонических рядов)
|
||||
//присваиваем набору гармоник переменную, добавляем гармоники: частота, кол-во (default = 10), цвет, вес.
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let lines = rows[i];
|
||||
let idx = 0; //индекс гармонического ряда
|
||||
let nms = set[lines].nm; //название гармонического ряда
|
||||
let frq = set[lines].fn; //расчетная частота
|
||||
let mod = set[lines].md; //модулирующая частота
|
||||
let clr = set[lines].cl; //предустановленный цвет
|
||||
let arr = []; //массив обнаруженных гармоник
|
||||
|
||||
lines = spec.add_harms_set(frq, num, clr, 2); //строим набор частот (гармонический ряд)
|
||||
lines.name = nms;
|
||||
idx = spec.index_of_harms_set(lines); //определяем индекс набора частот
|
||||
if (mod != 0) { spec.harms_sets[idx].modulate(mod, 2, clr, 0.5) }; //строим амплитудную модуляцию
|
||||
for (let j = 0; j <= num - 1; j++) {
|
||||
lines.harms[j].tolerance = (j + 1) * frq * ufc.tolerance(); //устанавливаем коридор обнаружения гармоники
|
||||
if (lines.harms[j].is_present == true) {
|
||||
switch (isDeep) {
|
||||
case true:
|
||||
level = Math.round(mod_factor(spec, filter, lines.harms[j].amplitude, lines.harms[j].base));
|
||||
break;
|
||||
case false:
|
||||
level = Math.round(lines.harms[j].level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
arr.push(level);
|
||||
} else { arr.push(0) };
|
||||
res[rows[i]] = arr;
|
||||
};
|
||||
};
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
"use strict";
|
||||
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js");
|
||||
var mtx = gtl.import("kn_mtx.js");
|
||||
var def = gtl.import("kn_defs.js");
|
||||
|
||||
//настройки для датчика оборотов
|
||||
var filter_freq = gtl.add_filter_iir(gtl.analog_inputs[record.tachoOptions.tachoChannel]); //объявление переменной фильтра
|
||||
filter_freq.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_freq.type = gtl.filter_iir.lowpass; //тип фильтра (ФНЧ)
|
||||
filter_freq.order = 8; //порядок фильтра
|
||||
filter_freq.frequency = 10; //граничная частота фильтра
|
||||
|
||||
//определение частоты вращения
|
||||
var freq = gtl.add_value_freq(filter_freq);
|
||||
freq.time = 1;
|
||||
freq.avg_cnt = 6;
|
||||
//gtl.diagnostic.interval = /*1*/10;
|
||||
|
||||
//[Блок настройки параметров измерений]
|
||||
//спектр вибрации
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp.name = "AUSP"; //присвоение имени спектра
|
||||
ausp.color = 0x0000ff00; //цвет линии спектра
|
||||
ausp.frequency = 800; //граничная частота спектра
|
||||
ausp.lines = 800; //разрешение спектра (количество линий)
|
||||
ausp.average = 6; //количество усреднений
|
||||
ausp.unit = gtl.spec.db; //отображение в дБ
|
||||
ausp.smoothing_factor = 50; //коэффициент сглаживания спектра
|
||||
ausp.smoothed_line_color = 0x000000ff; //цвет линии сглаживания (средней линии)
|
||||
ausp.peak_level = 20; //порог обнаружения гармоник
|
||||
ausp.harm_tolerance = ausp.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//фильтр для формирования спектра огибающей
|
||||
var filter_spen = gtl.add_filter_iir(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной фильтра
|
||||
filter_spen.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_spen.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_spen.order = 10; //порядок фильтра
|
||||
filter_spen.frequency = 6400; //центральная частота полосового фильтра
|
||||
filter_spen.width = 1482; //ширина полосы фильтра
|
||||
filter_spen.color = 255;
|
||||
|
||||
//спектр огибающей
|
||||
var spen = gtl.add_spen(filter_spen); //назначение переменной спектра огибающей
|
||||
spen.name = "SPEN"; //присвоение имени спектра огибающей
|
||||
spen.color = 0x00ff0000; //цвет линии спектра огибающей
|
||||
spen.frequency = 200; //граничная частота спектра огибающей
|
||||
spen.lines = 200; //разрешение спектра огибающей (количество линий)
|
||||
spen.average = 8; //количество усреднений
|
||||
spen.unit = gtl.spec.db; //отображение в дБ
|
||||
spen.window = gtl.spec.hann; //окно
|
||||
spen.smoothing_factor = 100; //коэффициент сглаживания спектра
|
||||
spen.smoothed_line_color = 0xff004dff; //цвет средней линии
|
||||
spen.peak_level = 10; //порог обнаружения гармоник
|
||||
spen.harm_tolerance = spen.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//RMS и Amplitude в диапазоне спектра огибающей (контроль работы сил трения)
|
||||
var rms_spen = gtl.add_value_rms(filter_spen); //назначение переменной RMS (spen)
|
||||
var ampl_spen = gtl.add_value_ampl(filter_spen); //назначение переменной Amplitude (spen)
|
||||
rms_spen.name = "RMS (spen)" //присвоение имени RMS (spen)
|
||||
rms_spen.time = 0.5; //интервал расчета RMS (spen)
|
||||
ampl_spen.time = 0.5; //интервал расчета Amplitude (spen)
|
||||
rms_spen.avg_cnt = 4; //количество усреднений RMS (spen)
|
||||
ampl_spen.avg_cnt = 4; //количество усреднений Amplitude (spen)
|
||||
|
||||
//RMS виброскорости в диапазоне 10-1000 Гц.
|
||||
var int = gtl.add_intg(gtl.analog_inputs[signals[0].portNumber]); //интегрирование сигнала виброускорения
|
||||
int.taps = 1; //степень интегрирования (скорость из ускорения - 1-нарное интегрирование)
|
||||
//фильтрация сигнала в диапазоне
|
||||
var filter = gtl.add_filter_iir(int); //объявление переменной фильтра
|
||||
filter.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter.order = 10; //порядок фильтра
|
||||
filter.frequency = 505; //центральная частота полосового фильтра
|
||||
filter.width = 990; //ширина полосы фильтра
|
||||
//определение среднего квадратического значения виброскорости
|
||||
var rms_v = gtl.add_value_rms(filter); //объявление переменной СКЗ
|
||||
rms_v.time = 0.5; //время выборки
|
||||
rms_v.avg_cnt = 4; //количество усреднений
|
||||
|
||||
//[Диагностика]
|
||||
gtl.diagnostic.interval = freq.time * freq.avg_cnt;
|
||||
let state = record.tachoOptions.tachoState; //начальное состояние после выбора источника тахо сигнала
|
||||
|
||||
function diagnose() {
|
||||
switch (state) {
|
||||
case 0: // считаем частоту вращения и настраиваем спектры
|
||||
if (fnc.INSTABILITY() > fnc.tolerance()) {
|
||||
gtl.log.info("Критическая нестабильность частоты вращения, %", fnc.INSTABILITY() * 100);
|
||||
gtl.log.info("Результат:", "Диагностика прервана");
|
||||
//gtl.diagnostic.stop(); //принудительная остановка диагностики
|
||||
|
||||
let __result = {
|
||||
Result: false
|
||||
};
|
||||
gtl.results = __result;
|
||||
};
|
||||
|
||||
if (fnc.FREQ() <= fnc.FREQNESS()) {
|
||||
gtl.log.info("Частота вращения меньше минимально рекомендуемой", "Минимально рекомендуемая частота: " + fnc.FREQNESS());
|
||||
};
|
||||
|
||||
case 1: //частота вращения фиксированная
|
||||
case 2: //частота вращения из поля INFO (виброметр)
|
||||
filter_spen.frequency = fnc.filter_frequency(); //считаме фильтр для огибающей
|
||||
filter_spen.width = fnc.filter_width(); //определяем ширину фильтра
|
||||
spen.frequency = fnc.spec_params().frequency;
|
||||
spen.lines = fnc.spec_params().lines;
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
let time = []; //массив по времени набора данных
|
||||
time.push(ausp.acq_time);
|
||||
time.push(spen.acq_time);
|
||||
let max_acq = Math.max(...time);
|
||||
gtl.diagnostic.interval = max_acq;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: //выполняем анализ спектов
|
||||
ausp.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре вибрации
|
||||
spen.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре огибающей
|
||||
|
||||
//Вывод информации в лог
|
||||
//Расчет площади спектра вибрации: спектр, начало отсчета в Гц, граничная частота спектра
|
||||
var AQ = fnc.spec_square(ausp.data, ausp.frequency / 2, ausp.frequency);
|
||||
|
||||
gtl.log.info("Объект диагностики", + options.rbModelName);
|
||||
gtl.log.info("Минимально необходимая частота вращения", fnc.FREQNESS());
|
||||
gtl.log.info("FREQ", fnc.FREQ());
|
||||
gtl.log.info("FTF", fnc.FTF());
|
||||
gtl.log.info("BPFO", fnc.BPFO());
|
||||
gtl.log.info("BPFI", fnc.BPFI());
|
||||
gtl.log.info("BSF", fnc.BSF());
|
||||
gtl.log.info("Коридор обнаружения гармоники", fnc.tolerance());
|
||||
gtl.log.info("Полосовой фильтр (расчетный)", filter_spen.frequency);
|
||||
gtl.log.info("Ширина фильтра", filter_spen.width);
|
||||
gtl.log.info("Граничная частота SPEN", spen.frequency);
|
||||
gtl.log.info("Количество линий SPEN", spen.lines);
|
||||
gtl.log.info("Разрешение SPEN", spen.resolution);
|
||||
gtl.log.info("Ширина AUSP", ausp.frequency);
|
||||
|
||||
let spen_mx = mtx.kn_mtx(spen, filter_spen, true);
|
||||
let spen_df = def.kn_defs(spen_mx, true);
|
||||
|
||||
var res = {
|
||||
RMSA: rms_spen.value,
|
||||
RMSV: rms_v.value,
|
||||
PF: ampl_spen.value / rms_spen.value,
|
||||
SQR: AQ,
|
||||
matrix: spen_mx,
|
||||
defs: spen_df
|
||||
};
|
||||
|
||||
gtl.results = res;
|
||||
gtl.diagnostic.stop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
"use strict";
|
||||
|
||||
export function kn_defs(mtx, isDeep) {
|
||||
var res = {}; //результат
|
||||
if (isDeep = true) { var key = "dp" } else { var key = "lv" };
|
||||
var des = {
|
||||
FTF: { ds: "Износ тел качения и сепаратора", dp: 8, lv: 20 },
|
||||
FREQ: { ds: "Износ внутреннего кольца", dp: 13, lv: 20 },
|
||||
BSF: { ds: "Дефект тел качения", dp: 10, lv: 20 },
|
||||
BPFO: { ds: "Дефект наружного кольца", dp: 15, lv: 20 },
|
||||
BPFI: { ds: "Дефект внутреннего кольца", dp: 8, lv: 20 },
|
||||
}; //описание функциональных частот
|
||||
|
||||
var rows = Object.keys(mtx); //массив ключей объекта (наборов гармоник)
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let arr = mtx[rows[i]]; //массив гармоник
|
||||
let delta = 0; //"расстояние" до дефекта
|
||||
for (let j = 0; j <= arr.length - 1; j++) {
|
||||
let limit = des[rows[i]][key]; //порог для гармоник
|
||||
if (arr[j] / limit >= 1) { limit = arr[j] };
|
||||
delta = delta + Math.pow(1 - arr[j] / limit, 2);
|
||||
};
|
||||
delta = Math.sqrt(delta);
|
||||
res[rows[i]] = delta;
|
||||
};
|
||||
|
||||
let values = Object.values(res); //собираем значения ключей объекта в массив
|
||||
let minValue = Math.min(...values); //определяем минимальное значение
|
||||
let minKey = Object.keys(res).find(minKey => res[minKey] === minValue); //определяем ключ по минимальному значению
|
||||
|
||||
return des[minKey].ds;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
"use strict";
|
||||
|
||||
var ufc = gtl.import("user-functions.js");
|
||||
|
||||
export function kn_mtx(spec, filter, isDeep) {
|
||||
var num = 6; //глубина матрицы (количество гармоник)
|
||||
var level = 0; //уровень развития дефекта
|
||||
var res = {}; //результат
|
||||
|
||||
var set = {
|
||||
FTF: { nm: "Частота вращения сепаратора", fn: ufc.FTF(), md: 0, cl: 0xffff0000 },
|
||||
FREQ: { nm: "Частота вращения", fn: ufc.FREQ(), md: 0, cl: 0xff0000f0 },
|
||||
BSF: { nm: "Частота вращения (контакта) тел качения", fn: ufc.BSF(), md: ufc.FTF(), cl: 0xffFFB841 },
|
||||
BPFO: { nm: "Частота перекатывания тел качения по наружному кольцу", fn: ufc.BPFO(), md: ufc.FTF(), cl: 0xffED3CCA },
|
||||
BPFI: { nm: "Частота перекатывания тел качения по внутреннему кольцу", fn: ufc.BPFI(), md: ufc.FREQ(), cl: 0xff990090 }
|
||||
}; //набор функциональных частот
|
||||
|
||||
function mod_factor(dSpec, dFilter, ampl, base) {
|
||||
let dl = (ampl - base); //разность уровней гармонической и случайной составляющей вибрации
|
||||
let df = dSpec.resolution / dFilter.width; //отношение частотному разрешению спектра к ширине фильтра
|
||||
let mod = Math.sqrt((10 ** (dl / 10) - 1) * df) * 100;
|
||||
return mod;
|
||||
}; //определение глубины модуляции ВЧ составляющих
|
||||
|
||||
var rows = Object.keys(set); //массив ключей объекта (наборов гармонических рядов)
|
||||
//присваиваем набору гармоник переменную, добавляем гармоники: частота, кол-во (default = 10), цвет, вес.
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let lines = rows[i];
|
||||
let idx = 0; //индекс гармонического ряда
|
||||
let nms = set[lines].nm; //название гармонического ряда
|
||||
let frq = set[lines].fn; //расчетная частота
|
||||
let mod = set[lines].md; //модулирующая частота
|
||||
let clr = set[lines].cl; //предустановленный цвет
|
||||
let arr = []; //массив обнаруженных гармоник
|
||||
|
||||
lines = spec.add_harms_set(frq, num, clr, 2); //строим набор частот (гармонический ряд)
|
||||
lines.name = nms;
|
||||
idx = spec.index_of_harms_set(lines); //определяем индекс набора частот
|
||||
if (mod != 0) { spec.harms_sets[idx].modulate(mod, 2, clr, 0.5) }; //строим амплитудную модуляцию
|
||||
for (let j = 0; j <= num - 1; j++) {
|
||||
lines.harms[j].tolerance = (j + 1) * frq * ufc.tolerance(); //устанавливаем коридор обнаружения гармоники
|
||||
if (lines.harms[j].is_present == true) {
|
||||
switch (isDeep) {
|
||||
case true:
|
||||
level = Math.round(mod_factor(spec, filter, lines.harms[j].amplitude, lines.harms[j].base));
|
||||
break;
|
||||
case false:
|
||||
level = Math.round(lines.harms[j].level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
arr.push(level);
|
||||
} else { arr.push(0) };
|
||||
res[rows[i]] = arr;
|
||||
};
|
||||
};
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
getNodeByName = (searchNodeName) => {
|
||||
let children = gtld.node.children;
|
||||
let child = undefined;
|
||||
|
||||
children.forEach((node) => {
|
||||
if (node.name == searchNodeName) {
|
||||
child = node;
|
||||
}
|
||||
});
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
let __pointUUID = getNodeByName("point").uuid.toString();
|
||||
|
||||
gtl.log.info("uuid", getNodeByName("point").uuid.toString());
|
||||
|
||||
gtl.results = { skz: 2, speed: 3, childUUID: __pointUUID };
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
"use strict";
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var imp = gtl.import("user-functions.js");
|
||||
|
||||
var gear0 = gtl.import("gt-gear-beat.js");
|
||||
var wheel0 = gtl.import("gt-wheel-beat.js");
|
||||
var gear1 = gtl.import("gt-gear-fault.js");
|
||||
var wheel1 = gtl.import("gt-wheel-fault.js");
|
||||
|
||||
//настройки для датчика оборотов
|
||||
var filter_freq = gtl.add_filter_iir(gtl.analog_inputs[record.tachoOptions.tachoChannel]); //объявление переменной фильтра
|
||||
filter_freq.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_freq.type = gtl.filter_iir.lowpass; //тип фильтра (ФНЧ)
|
||||
filter_freq.order = 8; //порядок фильтра
|
||||
filter_freq.frequency = 10; //граничная частота фильтра
|
||||
|
||||
//определение частоты вращения
|
||||
var freq = gtl.add_value_freq(filter_freq);
|
||||
freq.time = 1;
|
||||
freq.avg_cnt = 6;
|
||||
//gtl.diagnostic.interval = /*1*/10;
|
||||
|
||||
//[Блок настройки параметров измерений]
|
||||
//мониторинговый спектр вибрации
|
||||
var ausp2 = gtl.add_ausp(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной спектра вибрации
|
||||
ausp2.name = "AUSPm"; //присвоение имени спектра
|
||||
ausp2.color = 0x0000ffff; //цвет линии спектра
|
||||
ausp2.frequency = 1600; //граничная частота спектра
|
||||
ausp2.lines = 1600; //разрешение спектра (количество линий)
|
||||
ausp2.average = 6; //количество усреднений
|
||||
ausp2.unit = gtl.spec.db; //отображение в дБ
|
||||
|
||||
//спектр вибрации
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной спектра вибрации
|
||||
ausp.name = "AUSPd"; //присвоение имени спектра
|
||||
ausp.color = 0x0000ff00; //цвет линии спектра
|
||||
ausp.frequency = 800; //граничная частота спектра
|
||||
ausp.lines = 800; //разрешение спектра (количество линий)
|
||||
ausp.average = 6; //количество усреднений
|
||||
ausp.unit = gtl.spec.db; //отображение в дБ
|
||||
ausp.smoothing_factor = 50; //коэффициент сглаживания спектра
|
||||
ausp.smoothed_line_color = 0x000000ff; //цвет линии сглаживания (средней линии)
|
||||
ausp.peak_level = 20; //порог обнаружения гармоник
|
||||
ausp.harm_tolerance = ausp.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//фильтр для формирования спектра огибающей
|
||||
var filter_spen = gtl.add_filter_iir(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной фильтра
|
||||
filter_spen.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_spen.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_spen.order = 10; //порядок фильтра
|
||||
filter_spen.frequency = 6400; //центральная частота полосового фильтра
|
||||
filter_spen.color = 255;
|
||||
filter_spen.width = 1482; //ширина полосы фильтра
|
||||
|
||||
//спектр огибающей
|
||||
var spen = gtl.add_spen(filter_spen); //назначение переменной спектра огибающей
|
||||
spen.name = "SPEN"; //присвоение имени спектра огибающей
|
||||
spen.color = 0x00ff0000; //цвет линии спектра огибающей
|
||||
spen.frequency = 400; //граничная частота спектра огибающей
|
||||
spen.lines = 400; //разрешение спектра огибающей (количество линий)
|
||||
spen.average = 8; //количество усреднений
|
||||
spen.unit = gtl.spec.db; //отображение в дБ
|
||||
spen.window = gtl.spec.hann; //окно
|
||||
spen.smoothing_factor = 100; //коэффициент сглаживания спектра
|
||||
spen.smoothed_line_color = 0xff004dff; //цвет средней линии
|
||||
spen.peak_level = 10; //порог обнаружения гармоник
|
||||
spen.harm_tolerance = spen.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//RMS и Amplitude в диапазоне спектра огибающей (контроль работы сил трения)
|
||||
var rms_spen = gtl.add_value_rms(filter_spen); //назначение переменной RMS (spen)
|
||||
var ampl_spen = gtl.add_value_ampl(filter_spen); //назначение переменной Amplitude (spen)
|
||||
rms_spen.name = "RMS (spen)" //присвоение имени RMS (spen)
|
||||
rms_spen.time = 0.5; //интервал расчета RMS (spen)
|
||||
ampl_spen.time = 0.5; //интервал расчета Amplitude (spen)
|
||||
rms_spen.avg_cnt = 4; //количество усреднений RMS (spen)
|
||||
ampl_spen.avg_cnt = 4; //количество усреднений Amplitude (spen)
|
||||
|
||||
//RMS и Amplitude в УВЧ диапазоне 10-25 кГц (контроль разрыва масляной пленки)
|
||||
var filter_uhf = gtl.add_filter_iir(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной фильтра (предварительный)
|
||||
filter_uhf.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_uhf.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_uhf.order = 10; //порядок фильтра
|
||||
filter_uhf.frequency = 17500; //центральная частота полосового фильтра
|
||||
filter_uhf.width = 15000; //ширина полосы фильтра
|
||||
|
||||
var rms_uhf = gtl.add_value_rms(filter_uhf); //назначение переменной RMS
|
||||
var ampl_uhf = gtl.add_value_ampl(filter_uhf); //назначение переменной Amplitude
|
||||
rms_uhf.name = "RMS (uhf)" //присвоение имени RMS (uhf)
|
||||
rms_uhf.time = 0.5; //интервал расчета RMS (uhf)
|
||||
ampl_uhf.time = 0.5; //интервал расчета Amplitude (uhf)
|
||||
rms_uhf.avg_cnt = 4; //количество усреднений RMS (uhf)
|
||||
ampl_uhf.avg_cnt = 4; //количество усреднений Amplitude (uhf)
|
||||
|
||||
//Виброскорость в дипазоне 2-1000 Гц (вибромониторинг)
|
||||
var filter2_1000 = gtl.add_filter_iir(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной фильтра (предварительный)
|
||||
filter2_1000.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter2_1000.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter2_1000.order = 10; //порядок фильтра
|
||||
filter2_1000.frequency = 501; //центральная частота полосового фильтра
|
||||
filter2_1000.width = 998; //ширина полосы фильтра
|
||||
var filter2_1000v = gtl.add_intg(filter2_1000); // интегрирование
|
||||
filter2_1000v.taps = 1; // степень интегрирования (скорость из ускорения - 1-нарное)
|
||||
|
||||
var rms_v2 = gtl.add_value_rms(filter2_1000v); //назначение переменной RMS(V)
|
||||
rms_v2.name = "RMS(V) 2-1000 Гц" //присвоение имени RMS(V)
|
||||
rms_v2.time = 0.5; //интервал расчета RMS(V)
|
||||
rms_v2.avg_cnt = 4; //количество усреднений RMS(V)
|
||||
|
||||
//Виброскорость в дипазоне 10-1000 Гц (вибромониторинг)
|
||||
var filter10_1000 = gtl.add_filter_iir(gtl.analog_inputs[signals[0].signalChannel]); //назначение переменной фильтра (предварительный)
|
||||
filter10_1000.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter10_1000.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter10_1000.order = 10; //порядок фильтра
|
||||
filter10_1000.frequency = 505; //центральная частота полосового фильтра
|
||||
filter10_1000.width = 990; //ширина полосы фильтра
|
||||
var filter10_1000v = gtl.add_intg(filter10_1000); // интегрирование
|
||||
filter10_1000v.taps = 1; // степень интегрирования (скорость из ускорения - 1-нарное)
|
||||
|
||||
var rms_v10 = gtl.add_value_rms(filter10_1000v); //назначение переменной RMS(V)
|
||||
rms_v10.name = "RMS(V) 10-1000 Гц" //присвоение имени RMS(V)
|
||||
rms_v10.time = 0.5; //интервал расчета RMS(V)
|
||||
rms_v10.avg_cnt = 4; //количество усреднений RMS(V)
|
||||
|
||||
//[Диагностика]
|
||||
gtl.diagnostic.interval = freq.time * freq.avg_cnt;
|
||||
let state = record.tachoOptions.tachoState; //начальное состояние после выбора источника тахо сигнала
|
||||
let acq_time = 0;
|
||||
|
||||
function diagnose() {
|
||||
switch (state) {
|
||||
case 0: // считаем частоту вращения и настраиваем спектры
|
||||
if (imp.INSTABILITY() > imp.tolerance()) {
|
||||
gtl.log.info("Критическая нестабильность частоты вращения, %", imp.INSTABILITY() * 100);
|
||||
gtl.log.info("Результат:", "Диагностика прервана");
|
||||
//gtl.diagnostic.stop(); //принудительная остановка диагностики
|
||||
|
||||
let __result = {
|
||||
Result: false
|
||||
};
|
||||
gtl.results = __result;
|
||||
};
|
||||
|
||||
if (imp.FREQ() <= imp.FREQNESS()) {
|
||||
gtl.log.info("Частота вращения меньше минимально рекомендуемой", "Минимально рекомендуемая частота: " + imp.FREQNESS());
|
||||
};
|
||||
|
||||
//установка стандартной ширины спектра огибающей и количества линий спектра
|
||||
spen.frequency = imp.standart_width(imp.spec_width().es);
|
||||
spen.lines = imp.standart_lines(imp.spec_lines());
|
||||
filter_spen.frequency = imp.filter_frequency();
|
||||
ausp.frequency = imp.standart_width(imp.spec_width().as1);
|
||||
//ausp.lines = imp.standart_lines();
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
var acq_times = [];
|
||||
acq_times.push(ausp.acq_time);
|
||||
acq_times.push(spen.acq_time);
|
||||
acq_time = Math.max(...acq_times);
|
||||
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 1: //частота вращения фиксированная
|
||||
//установка стандартной ширины спектра огибающей и количества линий спектра
|
||||
spen.frequency = imp.standart_width(imp.spec_width().es);
|
||||
spen.lines = imp.standart_lines(imp.spec_lines());
|
||||
filter_spen.frequency = imp.filter_frequency();
|
||||
ausp.frequency = imp.standart_width(imp.spec_width().as1);
|
||||
//ausp.lines = imp.standart_lines();
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
var acq_times = [];
|
||||
acq_times.push(ausp.acq_time);
|
||||
acq_times.push(spen.acq_time);
|
||||
acq_time = Math.max(...acq_times);
|
||||
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 2: //частота вращения из поля INFO (виброметр)
|
||||
//установка стандартной ширины спектра огибающей и количества линий спектра
|
||||
spen.frequency = imp.standart_width(imp.spec_width().es);
|
||||
spen.lines = imp.standart_lines(imp.spec_lines());
|
||||
filter_spen.frequency = imp.filter_frequency();
|
||||
ausp.frequency = imp.standart_width(imp.spec_width().as1);
|
||||
//ausp.lines = imp.standart_lines();
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
var acq_times = [];
|
||||
acq_times.push(ausp.acq_time);
|
||||
acq_times.push(spen.acq_time);
|
||||
acq_time = Math.max(...acq_times);
|
||||
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: //выполняем анализ спектов
|
||||
ausp.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре вибрации
|
||||
spen.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре огибающей
|
||||
|
||||
//Вывод информации в лог
|
||||
//Расчет площади спектра вибрации: спектр, начало отсчета в Гц, граничная частота спектра
|
||||
var AQ = imp.spec_square(ausp2.data, 800, ausp2.frequency);
|
||||
|
||||
gtl.log.info("Объект диагностики", "Подшипник качения " + options.rbModelName);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", acq_time);
|
||||
gtl.log.info("FREQ", imp.FREQ());
|
||||
gtl.log.info("Минимально необходимая частота вращения", imp.FREQNESS());
|
||||
gtl.log.info("Площадь спектра", AQ);
|
||||
gtl.log.info("Нестабильность частоты вращения, %", imp.INSTABILITY() * 100);
|
||||
gtl.log.info("FTF", imp.FTF());
|
||||
gtl.log.info("BPFO", imp.BPFO());
|
||||
gtl.log.info("BPFI", imp.BPFI());
|
||||
gtl.log.info("BSF", imp.BSF());
|
||||
gtl.log.info("Центральная частота полосового фильтра", filter_spen.frequency);
|
||||
gtl.log.info("Количество долей октавного фильтра", n);
|
||||
gtl.log.info("Коэффициент для октавного фильтра", kf);
|
||||
gtl.log.info("Граничная частота спектра", imp.spec_width().es);
|
||||
gtl.log.info("Расчетное количество линий", imp.spec_lines());
|
||||
gtl.log.info("Расчетное разрешение спектра", imp.spec_resolution());
|
||||
gtl.log.info("Расчетный коридор обнаружения, %", imp.tolerance() * 100);
|
||||
gtl.log.info("Стандартная граничная частота", spen.frequency);
|
||||
gtl.log.info("Стандартное кол-во линий", spen.lines);
|
||||
gtl.log.info("СКЗ(A) ВЧ вибрации", rms_spen.value);
|
||||
gtl.log.info("СКЗ(A) УВЧ вибрации", rms_uhf.value);
|
||||
gtl.log.info("ПФ(A) в ВЧ диапазоне", ampl_spen.value / rms_spen.value);
|
||||
gtl.log.info("ПФ(A) в УВЧ диапазоне", ampl_uhf.value / rms_uhf.value);
|
||||
gtl.log.info("СКЗ(V) 2-1000 Гц", rms_v2.value);
|
||||
gtl.log.info("СКЗ(V) 10-1000 Гц", rms_v10.value);
|
||||
|
||||
let def = {};
|
||||
//var indx = 0;
|
||||
def["Биение шестерни"] = gear0.defect(); //indx (spen = 0, ausp = 0)
|
||||
def["Биение зубчатого колеса"] = wheel0.defect(); //indx (spen = 1, ausp = 1)
|
||||
def["Дефект зубьев шестерни"] = gear1.defect(); //indx (spen = 2, ausp = 2)
|
||||
def["Дефект зубьев зубчатого колеса"] = wheel1.defect(); //indx (spen = 3, ausp = 3)
|
||||
|
||||
var res = {
|
||||
RMSA: rms_spen.value,
|
||||
PF: ampl_spen.value / rms_spen.value,
|
||||
RMS_V2: rms_v2.value,
|
||||
RMS_V10: rms_v10.value,
|
||||
SQR: AQ,
|
||||
defects: def
|
||||
};
|
||||
|
||||
gtl.results = res;
|
||||
gtl.diagnostic.stop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
|
||||
export function rb_defs(mtx, isDeep) {
|
||||
var res = {}; //результат
|
||||
if (isDeep = true) { var key = "dp" } else { var key = "lv" };
|
||||
var des = {
|
||||
FTF: { ds: "тел качения и сепаратора", dp: 8, lv: 20 },
|
||||
FREQ: { ds: "внутреннего кольца", dp: 13, lv: 20 },
|
||||
BSF: { ds: "тел качения", dp: 10, lv: 20 },
|
||||
BPFO: { ds: "наружного кольца", dp: 15, lv: 20 },
|
||||
BPFI: { ds: "внутреннего кольца", dp: 8, lv: 20 },
|
||||
}; //описание функциональных частот
|
||||
|
||||
function get_note(harmsArr) {
|
||||
let note = "Износ"; //описание характера колебаний
|
||||
let cnt = 0; //количество значений в массиве
|
||||
for (let i = 0; i <= harmsArr.length - 1; i++) { if (harmsArr[i] > 0) { cnt++ }; };
|
||||
if (cnt >= 5) { note = "Дефект" };
|
||||
if (harmsArr[1] > harmsArr[0]) { note = "Перекос" };
|
||||
if (cnt > 0 && harmsArr[0] == 0 && harmsArr[1] == 0) { note = "Неидентифицированные изменения вибрации" };
|
||||
return note;
|
||||
};
|
||||
|
||||
function get_level(lvl, thres) {
|
||||
let level = "Сильный";
|
||||
switch (true) {
|
||||
case lvl < 0.5 * thres:
|
||||
level = "Слабый";
|
||||
break;
|
||||
case lvl < thres:
|
||||
level = "Средний";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}; return level;
|
||||
};
|
||||
|
||||
var rows = Object.keys(mtx); //массив ключей объекта (наборов гармоник)
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let arr = mtx[rows[i]]; //массив гармоник
|
||||
let lvl = Math.max(...arr); //определяем максимальное значение параметра из массива
|
||||
let sum = arr.reduce(function (a, b) { return a + b }, 0); //сумма элементов массива
|
||||
if (sum > 0) {
|
||||
let note = get_note(arr);
|
||||
res[rows[i]] = note + ' ' + des[rows[i]].ds + ': ' + get_level(lvl, des[rows[i]][key]) + ' (' + lvl + ')';
|
||||
};
|
||||
};
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
"use strict";
|
||||
|
||||
var ufc = gtl.import("user-functions.js");
|
||||
|
||||
export function rb_mtx(spec, filter, isDeep) {
|
||||
var num = 6; //глубина матрицы (количество гармоник)
|
||||
var level = 0; //уровень развития дефекта
|
||||
var res = {}; //результат
|
||||
|
||||
var set = {
|
||||
FTF: { nm: "Частота вращения сепаратора", fn: ufc.FTF(), md: 0, cl: 0xffff0000 },
|
||||
FREQ: { nm: "Частота вращения", fn: ufc.FREQ(), md: 0, cl: 0xff0000f0 },
|
||||
BSF: { nm: "Частота вращения (контакта) тел качения", fn: ufc.BSF(), md: ufc.FTF(), cl: 0xffFFB841 },
|
||||
BPFO: { nm: "Частота перекатывания тел качения по наружному кольцу", fn: ufc.BPFO(), md: ufc.FTF(), cl: 0xffED3CCA },
|
||||
BPFI: { nm: "Частота перекатывания тел качения по внутреннему кольцу", fn: ufc.BPFI(), md: ufc.FREQ(), cl: 0xff990090 }
|
||||
}; //набор функциональных частот
|
||||
|
||||
function mod_factor(dSpec, dFilter, ampl, base) {
|
||||
let dl = (ampl - base); //разность уровней гармонической и случайной составляющей вибрации
|
||||
let df = dSpec.resolution / dFilter.width; //отношение частотному разрешению спектра к ширине фильтра
|
||||
let mod = Math.sqrt((10 ** (dl / 10) - 1) * df) * 100;
|
||||
return mod;
|
||||
}; //определение глубины модуляции ВЧ составляющих
|
||||
|
||||
var rows = Object.keys(set); //массив ключей объекта (наборов гармонических рядов)
|
||||
//присваиваем набору гармоник переменную, добавляем гармоники: частота, кол-во (default = 10), цвет, вес.
|
||||
for (let i = 0; i <= rows.length - 1; i++) {
|
||||
let lines = rows[i];
|
||||
let idx = 0; //индекс гармонического ряда
|
||||
let nms = set[lines].nm; //название гармонического ряда
|
||||
let frq = set[lines].fn; //расчетная частота
|
||||
let mod = set[lines].md; //модулирующая частота
|
||||
let clr = set[lines].cl; //предустановленный цвет
|
||||
let arr = []; //массив обнаруженных гармоник
|
||||
|
||||
lines = spec.add_harms_set(frq, num, clr, 2); //строим набор частот (гармонический ряд)
|
||||
lines.name = nms;
|
||||
idx = spec.index_of_harms_set(lines); //определяем индекс набора частот
|
||||
if (mod != 0) { spec.harms_sets[idx].modulate(mod, 2, clr, 0.5) }; //строим амплитудную модуляцию
|
||||
for (let j = 0; j <= num - 1; j++) {
|
||||
lines.harms[j].tolerance = (j + 1) * frq * ufc.tolerance(); //устанавливаем коридор обнаружения гармоники
|
||||
if (lines.harms[j].is_present == true) {
|
||||
switch (isDeep) {
|
||||
case true:
|
||||
level = Math.round(mod_factor(spec, filter, lines.harms[j].amplitude, lines.harms[j].base));
|
||||
break;
|
||||
case false:
|
||||
level = Math.round(lines.harms[j].level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
arr.push(level);
|
||||
} else { arr.push(0) };
|
||||
res[rows[i]] = arr;
|
||||
};
|
||||
};
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
"use strict";
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js");
|
||||
var mtx = gtl.import("rb_mtx.js");
|
||||
var def = gtl.import("rb_defs.js");
|
||||
|
||||
//настройки для датчика оборотов
|
||||
var filter_freq = gtl.add_filter_iir(gtl.analog_inputs[record.tachoOptions.tachoChannel]); //объявление переменной фильтра
|
||||
filter_freq.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_freq.type = gtl.filter_iir.lowpass; //тип фильтра (ФНЧ)
|
||||
filter_freq.order = 8; //порядок фильтра
|
||||
filter_freq.frequency = 10; //граничная частота фильтра
|
||||
|
||||
//определение частоты вращения
|
||||
var freq = gtl.add_value_freq(filter_freq);
|
||||
freq.time = 1;
|
||||
freq.avg_cnt = 6;
|
||||
//gtl.diagnostic.interval = /*1*/10;
|
||||
|
||||
//[Блок настройки параметров измерений]
|
||||
//мониторинговый спектр вибрации
|
||||
var ausp2 = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp2.name = "AUSPm"; //присвоение имени спектра
|
||||
ausp2.color = 0x0000ffff; //цвет линии спектра
|
||||
ausp2.frequency = 25600; //граничная частота спектра
|
||||
ausp2.lines = 1600; //разрешение спектра (количество линий)
|
||||
ausp2.average = 6; //количество усреднений
|
||||
ausp2.unit = gtl.spec.db; //отображение в дБ
|
||||
|
||||
//спектр вибрации
|
||||
var ausp = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной спектра вибрации
|
||||
ausp.name = "AUSPd"; //присвоение имени спектра
|
||||
ausp.color = 0x0000ff00; //цвет линии спектра
|
||||
ausp.frequency = 800; //граничная частота спектра
|
||||
ausp.lines = 800; //разрешение спектра (количество линий)
|
||||
ausp.average = 6; //количество усреднений
|
||||
ausp.unit = gtl.spec.db; //отображение в дБ
|
||||
ausp.smoothing_factor = 50; //коэффициент сглаживания спектра
|
||||
ausp.smoothed_line_color = 0x000000ff; //цвет линии сглаживания (средней линии)
|
||||
ausp.peak_level = 20; //порог обнаружения гармоник
|
||||
ausp.harm_tolerance = ausp.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//фильтр для формирования спектра огибающей
|
||||
var filter_spen = gtl.add_filter_iir(gtl.analog_inputs[signals[0].portNumber]); //назначение переменной фильтра
|
||||
filter_spen.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter_spen.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter_spen.order = 10; //порядок фильтра
|
||||
filter_spen.frequency = 6400; //центральная частота полосового фильтра
|
||||
filter_spen.color = 255;
|
||||
filter_spen.width = 1482; //ширина полосы фильтра
|
||||
|
||||
//спектр огибающей
|
||||
var spen = gtl.add_spen(filter_spen); //назначение переменной спектра огибающей
|
||||
spen.name = "SPEN"; //присвоение имени спектра огибающей
|
||||
spen.color = 0x00ff0000; //цвет линии спектра огибающей
|
||||
spen.frequency = 200; //граничная частота спектра огибающей
|
||||
spen.lines = 200; //разрешение спектра огибающей (количество линий)
|
||||
spen.average = 8; //количество усреднений
|
||||
spen.unit = gtl.spec.db; //отображение в дБ
|
||||
spen.window = gtl.spec.hann; //окно
|
||||
spen.smoothing_factor = 100; //коэффициент сглаживания спектра
|
||||
spen.smoothed_line_color = 0xff004dff; //цвет средней линии
|
||||
spen.peak_level = 10; //порог обнаружения гармоник
|
||||
spen.harm_tolerance = spen.resolution; //диапазон поиска гармоник +/-
|
||||
|
||||
//RMS и Amplitude в диапазоне спектра огибающей (контроль работы сил трения)
|
||||
var rms_spen = gtl.add_value_rms(filter_spen); //назначение переменной RMS (spen)
|
||||
var ampl_spen = gtl.add_value_ampl(filter_spen); //назначение переменной Amplitude (spen)
|
||||
rms_spen.name = "RMS (spen)" //присвоение имени RMS (spen)
|
||||
rms_spen.time = 0.5; //интервал расчета RMS (spen)
|
||||
ampl_spen.time = 0.5; //интервал расчета Amplitude (spen)
|
||||
rms_spen.avg_cnt = 4; //количество усреднений RMS (spen)
|
||||
ampl_spen.avg_cnt = 4; //количество усреднений Amplitude (spen)
|
||||
|
||||
//RMS виброскорости в диапазоне 10-1000 Гц.
|
||||
var int = gtl.add_intg(gtl.analog_inputs[signals[0].portNumber]); //интегрирование сигнала виброускорения
|
||||
int.taps = 1; //степень интегрирования (скорость из ускорения - 1-нарное интегрирование)
|
||||
//фильтрация сигнала в диапазоне
|
||||
var filter = gtl.add_filter_iir(int); //объявление переменной фильтра
|
||||
filter.kind = gtl.filter_iir.butterworth; //тип окна
|
||||
filter.type = gtl.filter_iir.bandpass; //тип фильтра (полосовой)
|
||||
filter.order = 10; //порядок фильтра
|
||||
filter.frequency = 505; //центральная частота полосового фильтра
|
||||
filter.width = 990; //ширина полосы фильтра
|
||||
//определение среднего квадратического значения виброскорости
|
||||
var rms_v = gtl.add_value_rms(filter); //объявление переменной СКЗ
|
||||
rms_v.time = 0.5; //время выборки
|
||||
rms_v.avg_cnt = 4; //количество усреднений
|
||||
|
||||
//[Диагностика]
|
||||
gtl.diagnostic.interval = freq.time * freq.avg_cnt;
|
||||
let state = record.tachoOptions.tachoState; //начальное состояние после выбора источника тахо сигнала
|
||||
|
||||
function diagnose() {
|
||||
switch (state) {
|
||||
case 0: // считаем частоту вращения и настраиваем спектры
|
||||
if (fnc.INSTABILITY() > fnc.tolerance()) {
|
||||
gtl.log.info("Критическая нестабильность частоты вращения, %", fnc.INSTABILITY() * 100);
|
||||
gtl.log.info("Результат:", "Диагностика прервана");
|
||||
//gtl.diagnostic.stop(); //принудительная остановка диагностики
|
||||
|
||||
let __result = {
|
||||
Result: false
|
||||
};
|
||||
gtl.results = __result;
|
||||
};
|
||||
|
||||
if (fnc.FREQ() <= fnc.FREQNESS()) {
|
||||
gtl.log.info("Частота вращения меньше минимально рекомендуемой", "Минимально рекомендуемая частота: " + fnc.FREQNESS());
|
||||
};
|
||||
|
||||
case 1: //частота вращения фиксированная
|
||||
case 2: //частота вращения из поля INFO (виброметр)
|
||||
filter_spen.frequency = fnc.filter_frequency(); //считаме фильтр для огибающей
|
||||
filter_spen.width = fnc.filter_width(); //определяем ширину фильтра
|
||||
spen.frequency = fnc.spec_params().frequency;
|
||||
spen.lines = fnc.spec_params().lines;
|
||||
ausp.frequency = fnc.spec_params().frequency;
|
||||
ausp.lines = fnc.spec_params().lines;
|
||||
|
||||
//определение минимально необходимой длительности сигнала для проведения диагностики
|
||||
let time = []; //массив времени набора данных
|
||||
time.push(ausp.acq_time);
|
||||
time.push(spen.acq_time);
|
||||
let max_acq = Math.max(...time);
|
||||
gtl.diagnostic.interval = max_acq;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: //выполняем анализ спектов
|
||||
ausp.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре вибрации
|
||||
spen.clear_harms_sets(); //сброс отрисовки набора гармоник в спектре огибающей
|
||||
|
||||
//Вывод информации в лог
|
||||
//Расчет площади спектра вибрации: спектр, начало отсчета в Гц, граничная частота спектра
|
||||
var AQ = fnc.spec_square(ausp.data, ausp.frequency / 2, ausp.frequency);
|
||||
|
||||
gtl.log.info("Объект диагностики", options.rbModelName);
|
||||
gtl.log.info("Минимально необходимая частота вращения", fnc.FREQNESS());
|
||||
gtl.log.info("FREQ", fnc.FREQ());
|
||||
gtl.log.info("FTF", fnc.FTF());
|
||||
gtl.log.info("BPFO", fnc.BPFO());
|
||||
gtl.log.info("BPFI", fnc.BPFI());
|
||||
gtl.log.info("BSF", fnc.BSF());
|
||||
gtl.log.info("Коридор обнаружения гармоники", fnc.tolerance());
|
||||
gtl.log.info("Полосовой фильтр (расчетный)", filter_spen.frequency);
|
||||
gtl.log.info("Ширина фильтра", filter_spen.width);
|
||||
gtl.log.info("Граничная частота SPEN", spen.frequency);
|
||||
gtl.log.info("Количество линий SPEN", spen.lines);
|
||||
gtl.log.info("Разрешение SPEN", spen.resolution);
|
||||
gtl.log.info("Ширина AUSP", ausp.frequency);
|
||||
|
||||
let spen_mx = mtx.rb_mtx(spen, filter_spen, true);
|
||||
let spen_df = def.rb_defs(spen_mx, true);
|
||||
let ausp_mx = mtx.rb_mtx(ausp, 0, true);
|
||||
|
||||
var res = {
|
||||
RMSA: rms_spen.value,
|
||||
RMSV: rms_v.value,
|
||||
PF: ampl_spen.value / rms_spen.value,
|
||||
SQR: AQ,
|
||||
matrix: spen_mx,
|
||||
defs: spen_df
|
||||
};
|
||||
|
||||
gtl.results = res;
|
||||
gtl.diagnostic.stop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
let __result = { skz: 1,
|
||||
test_array: [ { col1: {}, col2: 2, col3: 3}, { col1: [], col2: 2, col3: 3}, { col2 : 5, col3: 6.3, col4: "ddd", col5: true } ],
|
||||
test_object: { col1: [1, 2, 3, 4, 5, 6], col2: ["dd", true, 0.5], col3: [], col4: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
test_simple_array: [1, 2, 3, 4, 5, {}, [], true, 6, 7, 8, 9, 10] };
|
||||
|
||||
gtl.results = __result;
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
//параметры подшипника качения
|
||||
var rbModelName = options.rbModelName || "No Name";
|
||||
var rbVendor = options.rbVendor || "No Vendor";
|
||||
var rb_inner = options.rbInnerD || 0; //диаметр внутреннего кольца
|
||||
var rb_outer = options.rbOuterD || 0; //диаметр наружного кольца
|
||||
var rb_roller = options.rbRollerD || 0; //диаметр тела качения
|
||||
var rb_rollerCount = options.rbRollerCount || 0; //количество тел качения
|
||||
var rb_angle = (options.rbAngle * Math.PI) / 180 || 0; //угол контакта тел качения (рад.)
|
||||
var rb_cage = (rb_inner + rb_outer) / 2; //диаметр сепаратора (средний диаметр)
|
||||
|
||||
//параметры ШВП
|
||||
var bsModelName = options.bsModelName || "No Name";
|
||||
var bsVendor = options.bsVendor || "No Vendor";
|
||||
var bs_inner = options.bsInnerD || 0; //диаметр внутреннего кольца
|
||||
var bs_outer = options.bsOuterD || 0; //диаметр наружного кольца
|
||||
var bs_roller = options.bsRollerD || 0; //диаметр тела качения
|
||||
var bs_rollerCount = options.bsRollerCount || 0; //количество тел качения
|
||||
var bs_angle = (options.bsAngle * Math.PI) / 180 || 0; //угол контакта тел качения (рад.)
|
||||
var bs_cage = (bs_inner + bs_outer) / 2; //средний диаметр
|
||||
|
||||
//параметры редуктора
|
||||
var gtZ1 = options.gtZ1 || 0; //количество зубьев шестерни
|
||||
var gtZ2 = options.gtZ2 || 0; //количество зубьев зубчатого колеса
|
||||
|
||||
//параметры ременной передачи
|
||||
var bdD1 = options.bdD1 || 0; //диаметр ведущего шкива
|
||||
var bdD2 = options.bdD2 || 0; //диаметр ведомого шкива
|
||||
var bdL = options.bdL || 0; //длинна ремня
|
||||
|
||||
//параметры зубчатой ременной передачи
|
||||
var cbdZ1 = options.cbdZ1 || 0; //количество зубьев ведущего шкива
|
||||
var cbdZ2 = options.cbdZ2 || 0; //количество зубьев ведомого шкива
|
||||
var cbdZ3 = options.cbdZ3 || 0; //количество зубьев ремня
|
||||
|
||||
//параметры насоса
|
||||
var pmBlades = options.pmBlades || 0; //количество лопастей насосного колеса
|
||||
|
||||
//параметры планетарной передачи
|
||||
var pgZ1 = options.pgZ1 || 0; //количество зубьев солнца
|
||||
var pgZ2 = options.pgZ2 || 0; //количество зубьев саттелитов
|
||||
var pgZ3 = options.pgZ3 || 0; //количество зубьев короны
|
||||
var pgN = options.pgN || 0; //количество саттелитов
|
||||
|
||||
//параметры турбины
|
||||
var trBlades = options.trBlades || 0; //количество лопастей крыльчатки турбины
|
||||
|
||||
//параметры электродвигателя
|
||||
//var trBlades = options.trBlades || 0; //количество лопастей крыльчатки турбины
|
||||
|
||||
export function FREQ() {
|
||||
let FR = 0;
|
||||
switch (record.tachoOptions.tachoState) {
|
||||
case 0:
|
||||
FR = freq.value * options.tachoRatio;
|
||||
break;
|
||||
case 1:
|
||||
FR = record.tachoOptions.tachoValue * options.tachoRatio;
|
||||
break;
|
||||
case 2:
|
||||
FR = record.tachoOptions.tachoFromInfo * options.tachoRatio;
|
||||
break;
|
||||
}; return FR;
|
||||
}; //определение частоты вращения в зависимости от источника тахо сигнала (FREQ)
|
||||
|
||||
export function INSTABILITY() {
|
||||
let freq_max = Math.max(...freq.values);
|
||||
let freq_min = Math.min(...freq.values);
|
||||
let instability = (freq_max - freq_min) / freq.value;
|
||||
return instability;
|
||||
}; //нестабильность частоты вращения в %
|
||||
|
||||
//определение вспомогательных коэффициентов k1 и k2 для подшипников качения и ШВП
|
||||
var rb_k1 = 0.5 * (1 - (rb_roller / rb_cage) * Math.cos(rb_angle));
|
||||
var rb_k2 = 0.5 * (1 + (rb_roller / rb_cage) * Math.cos(rb_angle));
|
||||
var bs_k1 = 0.5 * (1 - (bs_roller / bs_cage) * Math.cos(bs_angle));
|
||||
var bs_k2 = 0.5 * (1 + (bs_roller / bs_cage) * Math.cos(bs_angle));
|
||||
|
||||
export function FREQNESS() {
|
||||
let R = (rb_inner / 2) + (rb_roller / 2); //расстояние до центра тяжести тела качения
|
||||
let freqness = (Math.sqrt(9.81 / (4 * (Math.PI ** 2) * R / 1000))) / rb_k1;
|
||||
return freqness;
|
||||
}; //минимально необходимая частота вращения для компенсации силы тяжести центробежной силой
|
||||
|
||||
export function FTF() { return rb_k1 * FREQ(); }; //частота вращения сепаратора (FTF)
|
||||
export function BPFO() { return rb_k1 * FREQ() * rb_rollerCount; }; //частота перекатывания тел качения по наружному кольцу (BPFO)
|
||||
export function BPFI() { return rb_k2 * FREQ() * rb_rollerCount; }; //частота перекатывания тел качения по внутреннему кольцу (BPFI)
|
||||
export function BSF() { return 2 * FREQ() * (rb_cage / rb_roller) * rb_k1 * rb_k2; }; //частота вращения (контакта) тел качения (BSF)
|
||||
|
||||
export function BSFTF() { return bs_k1 * FREQ(); }; //частота вращения сепаратора (перемещения тел качения)
|
||||
export function BSNUT() { return bs_k1 * FREQ() * bs_rollerCount; }; //частота перекатывания тел качения по гайке
|
||||
export function BSSCR() { return bs_k2 * FREQ() * bs_rollerCount; }; //частота перекатывания тел качения по винту
|
||||
export function BSBAL() { return 2 * FREQ() * (bs_cage / bs_roller) * bs_k1 * bs_k2; }; //частота вращения (контакта) тел качения
|
||||
|
||||
export function BDF2() { return FREQ() * (bdD1 / bdD2) }; //частота вращения ведомого шкива
|
||||
export function BDFB() { return FREQ() * (Math.PI * bdD1 / bdL) }; //частота вращения ремня
|
||||
|
||||
export function CBFZ() { return FREQ() * cbdZ1; }; //зубцовая частота
|
||||
export function CBDF2() { return FREQ() * (cbdZ1 / cbdZ2) }; //частота вращения ведомого шкива
|
||||
export function CBDFB() { return FREQ() * (cbdZ1 / cbdZ3) }; //частота вращения ремня
|
||||
|
||||
export function PMFBLD() { return FREQ() * pmBlades; }; //лопастная частота
|
||||
|
||||
export function GTFZ() { return FREQ() * gtZ1; }; //зубцовая частота
|
||||
export function GTF2() { return FREQ() * (gtZ1 / gtZ2); }; //частота вращения второго вала редуктора
|
||||
|
||||
export function PGF2() { return (0.5 * FREQ() * pgZ1) / (pgZ1 + pgZ2); }; //частота вращения выходного вала планетарной передачи
|
||||
export function PGFSAT() { return (0.5 * FREQ()) * (pgZ1 / pgZ2) * ((pgZ1 + 2 * pgZ2) / (pgZ1 + pgZ2)); }; //частота вращения саттелита
|
||||
export function PGFZ() { return pgZ2 * PGFSAT() }; //зубцовая частота
|
||||
|
||||
export function TRFBLD() { return FREQ() * trBlades; }; //лопастная частота
|
||||
|
||||
export function filter_frequency() {
|
||||
let filter = 6013.41 * Math.log(0.266935 * FREQ() + 1.1201);
|
||||
return filter;
|
||||
}; //расчетная центральная частота полосового фильтра для спектра огибающей
|
||||
|
||||
export function filter_width(number) {
|
||||
let n = 3;
|
||||
if (number != null) { n = number };
|
||||
let kf = (2 ** (1 / n) - 1) / ((2 ** (1 / n)) ** (1 / 2)); //коэффициент для полосового фильтра
|
||||
let width = kf * filter_frequency();
|
||||
return width;
|
||||
}; //ширина фильтра спектра огибающей
|
||||
|
||||
export function tolerance() {
|
||||
let tol = 0;
|
||||
switch (options.objectType) {
|
||||
case 0: //объект не выбран
|
||||
break;
|
||||
case 1: //подшипник скольжения
|
||||
break;
|
||||
case 2: //подшипник качения
|
||||
tol = (2 * FTF()) / (5 * BPFO());
|
||||
break;
|
||||
case 3: //ШВП
|
||||
tol = (2 * BSFTF()) / (5 * BSNUT());
|
||||
break;
|
||||
case 4: //редуктор
|
||||
tol = (2 * FREQ()) / (5 * GTFZ());
|
||||
break;
|
||||
case 5: //ременная передача
|
||||
break;
|
||||
case 6: //зубчатый ремень
|
||||
break;
|
||||
case 7: //помпа
|
||||
break;
|
||||
case 8: //планетарый редуктор
|
||||
tol = (2 * PGF2()) / (5 * PGFZ());
|
||||
break;
|
||||
case 9: //турбина
|
||||
break;
|
||||
case 10: //электродвигатель
|
||||
break;
|
||||
}; return tol;
|
||||
}; //максимальный коридор обнаружения гармоник (tolerance)
|
||||
|
||||
export function spec_params() {
|
||||
let frq = 200; //ширина спектра
|
||||
let res = 400; //частотное разрешение
|
||||
function getStandart(value) {
|
||||
let arr = [50, 100, 200, 400, 800, 1600, 3200, 6400, 12800]; //массив стандартных величин
|
||||
let t = arr[0];
|
||||
if (value >= arr[arr.length - 1]) { t = arr[arr.length - 1] } else {
|
||||
for (let i = 0; i <= arr.length - 1; i++) {
|
||||
if (value > arr[i]) { t = arr[i + 1] };
|
||||
};
|
||||
}; return t
|
||||
};
|
||||
|
||||
switch (options.objectType) {
|
||||
case 0: //объект не выбран
|
||||
break;
|
||||
case 1: //подшипник скольжения
|
||||
frq = 20 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 2: //подшипник качения
|
||||
frq = 5 * BPFI() + 4 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 3: //ШВП
|
||||
frq = 5 * BSSCR() + 4 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 4: //редуктор
|
||||
frq = 3 * GTFZ() + 4 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 5: //ременная передача
|
||||
frq = 400;
|
||||
res = BDFB() / 4;
|
||||
break;
|
||||
case 6: //зубчатый ремень
|
||||
frq = 400;
|
||||
res = CBDFB() / 4;
|
||||
break;
|
||||
case 7: //помпа
|
||||
frq = 3 * PMFBLD() + 4 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 8: //планетарый редуктор
|
||||
frq = 3 * PGFZ() + 4 * FREQ();
|
||||
res = PGF2() / 8;
|
||||
break;
|
||||
case 9: //турбина
|
||||
frq = 3 * TRFBLD() + 4 * FREQ();
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
case 10: //электродвигатель
|
||||
frq = 400;
|
||||
res = FREQ() / 8;
|
||||
break;
|
||||
}; return {
|
||||
frequency: getStandart(frq),
|
||||
lines: getStandart(getStandart(frq) / res),
|
||||
resolution: getStandart(frq) / getStandart(getStandart(frq) / res)
|
||||
};
|
||||
};
|
||||
|
||||
export function spec_square(data, bnd, frq) {
|
||||
let lines = data.length; //определение количества линий спектра вибрации
|
||||
let res = frq / lines; //определение частотного разрешения спектра вибрации (основание прямоугольной трапеции)
|
||||
let start = 1; //переменная для определения стартового индекса в массиве
|
||||
let S = 0; //переменная расчетной площади спектра вибрации
|
||||
if (bnd !== 0) { start = lines - Math.round((frq - bnd) / res) }; //начальная точка отсчета в массиве (стартовый индекс)
|
||||
for (let i = start - 1; i <= lines - 2; i++) { S = S + res * ((data[i] + data[i + 1]) / 2) }; //вычисляем площадь спектра вибрации
|
||||
return S;
|
||||
}; //определение площади спектра
|
||||
|
||||
export function mod_factor(ampl, base) {
|
||||
let dl = (ampl - base); //разность уровней гармонической и случайной составляющей вибрации
|
||||
let df = spec_params().resolution / filter_width(); //отношение частотному разрешению спектра к ширине фильтра
|
||||
let mod = Math.sqrt((10 ** (dl / 10) - 1) * df) * 100;
|
||||
return mod;
|
||||
}; //определение условной глубины модуляции
|
||||
|
||||
export function deep_factor(ampl, base) {
|
||||
let deep = (ampl - base) / (ampl + base) * 100;
|
||||
return deep;
|
||||
}; //определение условной глубины модуляции
|
||||
|
||||
export function ampl_factor(ampl, base) {
|
||||
let crest = (ampl / base);
|
||||
return crest;
|
||||
}; //определение амплитудного коэффициента
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
"use strict";
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
let getResponse = gtl.import("getResponse.js").getResponse;
|
||||
let getAvgArray = gtl.import("getResponse.js").getAvgArray;
|
||||
|
||||
let plot_ausp = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_resp_ampl = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_resp_phase = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
let plot_avg_resp = gtl.plots.add("Средний частотный отклик"); // средний частотный отклик
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра unit/dB (0/1)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
let ranges = gtl.options.customOptions.ranges;
|
||||
gtl.player.custom_ranges = ranges; // задание диапазонов плеера
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
let spec_view = view_ == 0 ? gtl.spec.unit : gtl.spec.db; // условие отображения спектров в дБ или линейном виде
|
||||
let src_force = gtl.analog_inputs[signals[0].portNumber]; // источник сигнала силы
|
||||
let channel = 1; //номер первого канала вибрации
|
||||
|
||||
let force = gtl.create_ausp({
|
||||
src: src_force, // сигнал силы
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: view
|
||||
});
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
let ausps = []; //массив объектов спектров вибрации по каналам
|
||||
let phases = []; //массив объектов ФЧХ по каналам
|
||||
let ausps_data = []; //массив данных спектров после каздого удара
|
||||
let resps_data = []; //массив данных откликов после каждого удара
|
||||
|
||||
for (let i = channel; i < signals.length; i++) { }; //цикл по каналам
|
||||
|
||||
let ausp = gtl.create_ausp({
|
||||
src: gtl.analog_inputs[signals[channel].portNumber], // сырой сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: spec_view
|
||||
});
|
||||
|
||||
let phase_delta = gtl.create_pfc({
|
||||
src0: src_force, // сигнал силы, относительно него вычисляем дельту фазы
|
||||
src1: gtl.analog_inputs[signals[channel].portNumber], // сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: gtl.phase.deg,
|
||||
range: gtl.phase.positive,
|
||||
is_single: false
|
||||
});
|
||||
|
||||
let time_window = 0.0001 // временное окно наблюдения
|
||||
let time_impulse = time_impulse_ == 0 ? gtl.acq_time + 0.01 : time_impulse_; // условие выбора длительности импульса
|
||||
// let time_pre = time_window / 2; // время предыстории
|
||||
// let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
/* Функция диагностики.
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну диапазона и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // первичный интервал запуска функции диагностики
|
||||
gtl.log.info('Время импульса', time_impulse);
|
||||
|
||||
function diagnose() {
|
||||
|
||||
if (!is_ranges) {
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(gtl.player.custom_ranges));
|
||||
gtl.log.info("Количество диапазонов в плеере", ranges.length);
|
||||
gtl.log.info("Установленный интервал запуска диагностики", time_impulse);
|
||||
gtl.log.info("acq_time", gtl.acq_time);
|
||||
}
|
||||
|
||||
if (tries > 0) {
|
||||
gtl.log.info("Количество элементов массива force", force.data.length);
|
||||
gtl.log.info("Количество элементов массива ausp", ausp.data.length);
|
||||
gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`);
|
||||
gtl.log.info('Диапазон плеера', JSON.stringify(gtl.player.custom_ranges));
|
||||
|
||||
// Отображаем спектр силы
|
||||
plot_ausp.add({
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы - удар №${tries}, N`,
|
||||
x: force.resolution,
|
||||
y: force.data,
|
||||
tags: [`Спектр силы, N`]
|
||||
});
|
||||
|
||||
// Отображаем автоспектр вибрации
|
||||
plot_ausp.add({
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала 1 - удар №${tries}, g`,
|
||||
x: ausp.resolution,
|
||||
y: ausp.data,
|
||||
tags: ["Cпектр вибрации, g"]
|
||||
});
|
||||
|
||||
// Вычисляем спектр отклика
|
||||
let rsp = getResponse({
|
||||
spec_force: force, //спектр силы
|
||||
spec_vibro: ausp, //спектр вибрации
|
||||
type: variant_freq_resp, //способ вычисления отклика
|
||||
view: 0 //способ отображения спектра в линейных единицах или дБ
|
||||
});
|
||||
|
||||
// Отображаем спектр отклика
|
||||
plot_resp_ampl.add({
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала 1 - удар №${tries}, g/N`,
|
||||
x: resolution,
|
||||
y: rsp.data,
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
|
||||
ausps_data.push(ausp.data);
|
||||
resps_data.push(rsp.data);
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries > ranges.length) {
|
||||
gtl.log.info('Вычисление среднего отклика', `processing...`);
|
||||
|
||||
const avgResponse = getAvgArray(resps_data); //вычисляем средний отклик
|
||||
|
||||
// Отображаем средний спектр отклика
|
||||
plot_avg_resp.add({
|
||||
color: 0xff3dcc,
|
||||
name: `Амплитуда среднего частотного отклика, g/N`,
|
||||
x: resolution,
|
||||
y: avgResponse,
|
||||
tags: ["Амплитуда среднего частотного отклика, g/N"]
|
||||
});
|
||||
|
||||
gtl.log.info('Вычисление среднего отклика', `done!`);
|
||||
gtl.diagnostic.stop();
|
||||
|
||||
}; // останавливаем диагностику после окончания диапазонов
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
"use strict";
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
let getResponse = gtl.import("getResponse.js").getResponse;
|
||||
let getAvgArray = gtl.import("getResponse.js").getAvgArray;
|
||||
|
||||
let plot_ausp = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_resp_ampl = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_resp_phase = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
let plot_avg_resp = gtl.plots.add("Средний частотный отклик"); // средний частотный отклик
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра unit/dB (0/1)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
let spec_view = view_ == 0 ? gtl.spec.unit : gtl.spec.db; // условие отображения спектров в дБ или линейном виде
|
||||
let src_force = gtl.analog_inputs[signals[0].portNumber]; // источник сигнала силы
|
||||
let channel = 1; //номер первого канала вибрации
|
||||
|
||||
let force = gtl.create_ausp({
|
||||
src: src_force, // сигнал силы
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: view
|
||||
});
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
let ausps = []; //массив объектов спектров вибрации по каналам
|
||||
let phases = []; //массив объектов ФЧХ по каналам
|
||||
let ausps_data = []; //массив данных спектров после каздого удара
|
||||
let resps_data = []; //массив данных откликов после каждого удара
|
||||
|
||||
for (let i = channel; i < signals.length; i++) { }; //цикл по каналам
|
||||
|
||||
let ausp = gtl.create_ausp({
|
||||
src: gtl.analog_inputs[signals[channel].portNumber], // сырой сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: spec_view
|
||||
});
|
||||
|
||||
let phase_delta = gtl.create_pfc({
|
||||
src0: src_force, // сигнал силы, относительно него вычисляем дельту фазы
|
||||
src1: gtl.analog_inputs[signals[channel].portNumber], // сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: gtl.phase.deg,
|
||||
range: gtl.phase.positive,
|
||||
is_single: false
|
||||
});
|
||||
|
||||
let time_window = 0.0001 // временное окно наблюдения
|
||||
let time_impulse = time_impulse_ == 0 ? gtl.acq_time + 0.01 : time_impulse_; // условие выбора длительности импульса
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Порог для отслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: src_force,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
/* Функция диагностики.
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну диапазона и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = gtl.options.record.playerTime; // первичный интервал запуска функции диагностики
|
||||
gtl.log.info('Время импульса', time_impulse);
|
||||
|
||||
function diagnose() {
|
||||
if (!is_ranges) {
|
||||
// gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.player.custom_ranges = [ranges[0]]; // добавляем первый диапазон в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(gtl.player.custom_ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
|
||||
gtl.log.info("Количество диапазонов в плеере", ranges.length);
|
||||
gtl.log.info("Установленный интервал запуска диагностики", time_impulse);
|
||||
gtl.log.info("acq_time", gtl.acq_time);
|
||||
}
|
||||
|
||||
if (tries > 0) {
|
||||
gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`);
|
||||
gtl.log.info('Диапазон плеера', JSON.stringify(gtl.player.custom_ranges));
|
||||
|
||||
// Отображаем спектр силы
|
||||
plot_ausp.add({
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы - удар №${tries}, N`,
|
||||
x: force.resolution,
|
||||
y: force.data,
|
||||
tags: [`Спектр силы, N`]
|
||||
});
|
||||
|
||||
// Отображаем автоспектр вибрации
|
||||
plot_ausp.add({
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала 1 - удар №${tries}, g`,
|
||||
x: ausp.resolution,
|
||||
y: ausp.data,
|
||||
tags: ["Cпектр вибрации, g"]
|
||||
});
|
||||
|
||||
// Вычисляем спектр отклика
|
||||
let rsp = getResponse({
|
||||
spec_force: force, //спектр силы
|
||||
spec_vibro: ausp, //спектр вибрации
|
||||
type: variant_freq_resp, //способ вычисления отклика
|
||||
view: 0 //способ отображения спектра в линейных единицах или дБ
|
||||
});
|
||||
|
||||
// Отображаем спектр отклика
|
||||
plot_resp_ampl.add({
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала 1 - удар №${tries}, g/N`,
|
||||
x: resolution,
|
||||
y: rsp.data,
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
|
||||
ausps_data.push(ausp.data);
|
||||
resps_data.push(rsp.data);
|
||||
|
||||
gtl.player.custom_ranges = [ranges[tries]]; // устанавливаем следующий диапазон
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries > ranges.length) {
|
||||
gtl.log.info('Вычисление среднего отклика', `processing...`);
|
||||
|
||||
const avgResponse = getAvgArray(resps_data); //вычисляем средний отклик
|
||||
|
||||
// Отображаем средний спектр отклика
|
||||
plot_avg_resp.add({
|
||||
color: 0xff3dcc,
|
||||
name: `Амплитуда среднего частотного отклика, g/N`,
|
||||
x: resolution,
|
||||
y: avgResponse,
|
||||
tags: ["Амплитуда среднего частотного отклика, g/N"]
|
||||
});
|
||||
|
||||
gtl.log.info('Вычисление среднего отклика', `done!`);
|
||||
gtl.diagnostic.stop();
|
||||
|
||||
}; // останавливаем диагностику после окончания диапазонов
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
"use strict";
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
let getResponse = gtl.import("getResponse.js").getResponse;
|
||||
|
||||
let plot_ausp = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_resp_ampl = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_resp_phase = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра unit/dB (0/1)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
let spec_view = view_ == 0 ? gtl.spec.unit : gtl.spec.db; // условие отображения спектров в дБ или линейном виде
|
||||
let src_force = gtl.analog_inputs[signals[0].portNumber]; // источник сигнала силы
|
||||
let channel = 1; //номер первого канала вибрации
|
||||
|
||||
let force = gtl.create_ausp({
|
||||
src: src_force, // сигнал силы
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: view
|
||||
});
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
let ausps = []; //массив объектов спектров вибрации по каналам
|
||||
let phases = []; //массив объектов ФЧХ по каналам
|
||||
for (let i = 1; i <= signals.length -1; i++) {
|
||||
let ausp = gtl.create_ausp({
|
||||
src: gtl.analog_inputs[signals[i].portNumber], // сырой сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: spec_view
|
||||
});
|
||||
ausps.push(ausp);
|
||||
}; //цикл по каналам
|
||||
|
||||
let phase_delta = gtl.create_pfc({
|
||||
src0: src_force, // сигнал силы, относительно него вычисляем дельту фазы
|
||||
src1: gtl.analog_inputs[signals[channel].portNumber], // сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.rectangular,
|
||||
view: gtl.phase.deg,
|
||||
range: gtl.phase.positive,
|
||||
is_single: false
|
||||
});
|
||||
|
||||
let time_window = 0.0001 // временное окно наблюдения
|
||||
let time_impulse = time_impulse_ == 0 ? gtl.acq_time + 0.01 : time_impulse_; // условие выбора длительности импульса
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Порог для отслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: src_force,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
/* Функция диагностики.
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = gtl.options.record.playerTime; // первичный интервал запуска функции диагностики
|
||||
gtl.log.info('Время импульса', time_impulse);
|
||||
|
||||
function diagnose() {
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
|
||||
gtl.log.info("Количество диапазонов в плеере", ranges.length);
|
||||
gtl.log.info("Установленный интервал запуска диагностики", time_impulse);
|
||||
gtl.log.info("acq_time", gtl.acq_time);
|
||||
}
|
||||
|
||||
if (tries > 0) {
|
||||
gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`)
|
||||
// Отображаем спектр силы
|
||||
plot_ausp.add({
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы - удар №${tries}, N`,
|
||||
x: force.resolution,
|
||||
y: force.data,
|
||||
tags: [`Спектр силы, N`]
|
||||
});
|
||||
|
||||
|
||||
for (let i = 0; i < ausps.length; i++) {
|
||||
// Отображаем автоспектр вибрации
|
||||
plot_ausp.add({
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${i+1} - удар №${tries}, g`,
|
||||
x: ausps[i].resolution,
|
||||
y: ausps[i].data,
|
||||
tags: ["Cпектр вибрации, g"]
|
||||
});
|
||||
|
||||
// Вычисляем спектр отклика
|
||||
let rsp = getResponse({
|
||||
spec_force: force, //спектр силы
|
||||
spec_vibro: ausps[i], //спектр вибрации
|
||||
type: variant_freq_resp, //способ вычисления отклика
|
||||
view: 0 //способ отображения спектра в линейных единицах или дБ
|
||||
});
|
||||
|
||||
// Отображаем спектр отклика
|
||||
plot_resp_ampl.add({
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${i+1} - удар №${tries}, g/N`,
|
||||
x: resolution,
|
||||
y: rsp.data,
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
|
||||
// Отображаем фазовый спектр отклика
|
||||
plot_resp_phase.add({
|
||||
color: 0xff3dcc,
|
||||
name: `Фаза частотного отклика канала ${i+1} - удар №${tries}, °`,
|
||||
x: resolution,
|
||||
y: rsp.phase,
|
||||
tags: ["Фаза частотного отклика, °"]
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries > ranges.length) gtl.diagnostic.stop(); // останавливаем диагностику после окончания диапазонов
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
export function getResponse(args) {
|
||||
let force = args.spec_force; //спектр силы
|
||||
let vibro = args.spec_vibro; //спектр вибрации
|
||||
let type = args.type; //способ вычисления отклика
|
||||
let view = args.view; //способ отображения спектра в линейных единицах или дБ
|
||||
|
||||
/* Алгоритм
|
||||
1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
4. Вычислить деление кросс-спектра на спектр силы.
|
||||
*/
|
||||
|
||||
/* Кросс-спектры
|
||||
Сигнал силы в комплексно-сопряжённом виде
|
||||
сигнал вибрации умножается на сигнал силы, а НЕ наоборот
|
||||
умножение комплексных чисел по формуле:
|
||||
(a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
(a1*a2-b1*b2) - действительная часть
|
||||
(a1*b2+b1*a2)i - мнимая часть
|
||||
*/
|
||||
|
||||
let n = force.data.length; // длина массива спектра
|
||||
let cross_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let cross_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = -force.imag[i]; // мнимая часть спектра силы сразу берём с обратным знаком
|
||||
|
||||
cross_real[i] = vReal * fReal - vImag * fImag;
|
||||
cross_imag[i] = vReal * fImag + vImag * fReal;
|
||||
}
|
||||
|
||||
// let cross_real2 = getCrossSpectrum(vibro.real, vibro.imag, force.real, force.imag).reXY;
|
||||
// gtl.log.info('Амплитуда кросс', cross_real)
|
||||
// gtl.log.info('Амплитуда кросс 2', cross_real2)
|
||||
|
||||
/* Вычисление частотного отклика
|
||||
деление комплексных чисел по формуле:
|
||||
(a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
(a*c-b*d) - действительная часть
|
||||
(a*d+b*c)i - мнимая часть
|
||||
*/
|
||||
let resp_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let resp_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
if (type == 0) {
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// ОШИБКА в моей формуле вычисления частотного отклика
|
||||
// ИПРАВИЛ на:
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c + b*d)/(c^2 + d^2) + (c*b - a*d)/(c^2 + d^2)i
|
||||
// (a*c + b*d)/(c^2 + d^2) - действительная часть
|
||||
// (c*b - a*d)/(c^2 + d^2)i - мнимая часть
|
||||
for (let i = 0; i < n; i++) {
|
||||
const cReal = cross_real[i]; // действительная часть кросс спектра
|
||||
const cImag = cross_imag[i]; // мнимая часть кросс спектра
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const denominator = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (cReal * fReal + cImag * fImag) / denominator;
|
||||
resp_imag[i] = (fReal * cImag - cReal * fImag) / denominator;
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const denominator = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (vReal * fReal + vImag * fImag) / denominator;
|
||||
resp_imag[i] = (fReal * vImag - vReal * fImag) / denominator;
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
let resp_ampl = new Float64Array(n); // типизированный массив для амплитуды
|
||||
let resp_phase = new Float64Array(n); // типизированный массив для фазы
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const rReal = resp_real[i]; // действительная часть спектра отклика
|
||||
const rImag = resp_imag[i]; // мнимая часто спектра отклика
|
||||
|
||||
resp_ampl[i] = Math.sqrt(rReal * rReal + rImag * rImag);
|
||||
if (view > 0) { resp_ampl = resp_ampl.map((item) => (item = 20 * Math.log10(item / 1e-6))) }; //переводим в дБ
|
||||
resp_phase[i] = Math.atan2(rImag, rReal) * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
// Приводим фазу к диапазону [0°, 360°]
|
||||
for (let i = 0; i < n; i++) {
|
||||
resp_phase[i] = resp_phase[i] % 360;
|
||||
if (resp_phase[i] < 0) { resp_phase[i] += 360 }
|
||||
}
|
||||
|
||||
let resp2 = getFrequencyResponse(vibro.real, vibro.imag, force.real, force.imag);
|
||||
let resp_ampl2 = resp2.magnitude;
|
||||
let resp_phase2 = resp2.phase;
|
||||
|
||||
// gtl.log.info('Амплитуда отклика', resp_ampl[0]);
|
||||
// gtl.log.info('Амплитуда отклика 2', resp_ampl2[0]);
|
||||
// gtl.log.info('Фаза отклика', resp_phase[0]);
|
||||
// gtl.log.info('Фаза отклика 2', resp_phase2[0]);
|
||||
|
||||
return {
|
||||
data: resp_ampl2,
|
||||
phase: resp_phase2,
|
||||
resolution: force.resolution
|
||||
}
|
||||
}; //рассчет перекрестного спектра
|
||||
|
||||
export function getAvgArray(arrays) {
|
||||
const length = arrays[0].length; //длина вложенного массива
|
||||
const result = new Array(length); //новый массив фиксированной длины, чтобы не пушить
|
||||
const numArrays = arrays.length; //количество вложенных массивов
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
let sum = 0;
|
||||
for (let j = 0; j < numArrays; j++) { sum += arrays[j][i] }
|
||||
result[i] = sum / numArrays;
|
||||
}
|
||||
|
||||
return result;
|
||||
}; //вычисление среднего массива
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function getCrossSpectrum(reX, imX, reY, imY) {
|
||||
const n = reX.length;
|
||||
const reXY = new Array(n); // действительная часть
|
||||
const imXY = new Array(n); // мнимая часть
|
||||
const power = new Array(n); // мощность кросс-спектра
|
||||
let phase = new Array(n); // фаза (радианы)
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
// Комплексное сопряжение спектра imY* (мнимая часть спектра силы сразу берём с обратным знаком)
|
||||
const a = reX[i], b = imX[i]; // X(f) = a + ib
|
||||
const c = reY[i], d = -imY[i]; // Y(f) = c + id
|
||||
|
||||
// Почастотное умножение
|
||||
reXY[i] = a * c - b * d; // действительная часть
|
||||
imXY[i] = b * c + a * d; // мнимания часть
|
||||
|
||||
// Мощность кросс-спектра
|
||||
power[i] = reXY[i] * reXY[i] + imXY[i] * imXY[i];
|
||||
|
||||
// Фаза = arctan(Im/Re)
|
||||
phase[i] = Math.atan2(imXY[i], reXY[i]);
|
||||
}
|
||||
|
||||
return { reXY, imXY, power, phase };
|
||||
}
|
||||
|
||||
|
||||
function getFrequencyResponse(reX, imX, reY, imY) {
|
||||
const n = reX.length;
|
||||
const magnitude = new Array(n); // амплитуда (линейная)
|
||||
const magnitudeDB = new Array(n); // амплитуда (дБ)
|
||||
let phase = new Array(n); // фаза (радианы)
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const a = reX[i], b = imX[i]; // X(f) = a + ib
|
||||
const c = reY[i], d = imY[i]; // Y(f) = c + id
|
||||
|
||||
// Знаменатель
|
||||
const denominator = c * c + d * d; // знаменатель исходный вариант
|
||||
// const denominator = a * a + b * b; // знаменатель вариант 2
|
||||
|
||||
// Избегаем деления на ноль
|
||||
if (Math.abs(denominator) < 1e-10) {
|
||||
magnitude[i] = 0;
|
||||
magnitudeDB[i] = -Infinity;
|
||||
phase[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Почастотное умножение
|
||||
const reH = (a * c + b * d) / denominator; // действительная часть
|
||||
const imH = (c * b - a * d) / denominator; // мнимая часть исходный вариант
|
||||
// const imH = (a * d - b * c) / denominator; // мнимая часть вариант 2 (поменял местами вычитаемые)
|
||||
|
||||
// Амплитуда
|
||||
magnitude[i] = Math.sqrt(reH * reH + imH * imH);
|
||||
|
||||
// Амплитуда в дБ
|
||||
magnitudeDB[i] = 20 * Math.log10(magnitude[i] / 1e-6);
|
||||
|
||||
// Приводим фазу сразу к диапазону [0°, 360°]
|
||||
phase[i] = Math.atan2(imH, reH) * RAD_TO_DEG % 360;
|
||||
if (phase[i] < 0) { phase[i] += 360 };
|
||||
}
|
||||
|
||||
return { magnitude, magnitudeDB, phase };
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
export function getResponse(args) {
|
||||
let force = args.spec_force; //спектр силы
|
||||
let vibro = args.spec_vibro; //спектр вибрации
|
||||
let type = args.type; //способ вычисления отклика
|
||||
let view = args.view; //способ отображения спектра в линейных единицах или дБ
|
||||
|
||||
/* Алгоритм
|
||||
1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
4. Вычислить деление кросс-спектра на спектр силы.
|
||||
*/
|
||||
|
||||
/* Кросс-спектры
|
||||
Сигнал силы в комплексно-сопряжённом виде
|
||||
сигнал вибрации умножается на сигнал силы, а НЕ наоборот
|
||||
умножение комплексных чисел по формуле:
|
||||
(a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
(a1*a2-b1*b2) - действительная часть
|
||||
(a1*b2+b1*a2)i - мнимая часть
|
||||
*/
|
||||
|
||||
let n = force.data.length; // длина массива спектра
|
||||
let cross_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let cross_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = -force.imag[i]; // мнимая часть спектра силы сразу берём с обратным знаком
|
||||
|
||||
cross_real[i] = vReal * fReal - vImag * fImag;
|
||||
cross_imag[i] = vReal * fImag + vImag * fReal;
|
||||
}
|
||||
|
||||
/* Вычисление частотного отклика
|
||||
деление комплексных чисел по формуле:
|
||||
(a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
(a*c-b*d) - действительная часть
|
||||
(a*d+b*c)i - мнимая часть
|
||||
*/
|
||||
let resp_real = new Float64Array(n); // типизированный массив для действительной части
|
||||
let resp_imag = new Float64Array(n); // типизированный массив для мнимой части
|
||||
|
||||
// ОШИБКА в моей формуле вычисления частотного отклика
|
||||
// ИПРАВИЛ на:
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c + b*d)/(c^2 + d^2) + (c*b - a*d)/(c^2 + d^2)i
|
||||
// (a*c + b*d)/(c^2 + d^2) - действительная часть
|
||||
// (c*b - a*d)/(c^2 + d^2)i - мнимая часть
|
||||
// ПЕРЕВОД формулы в используемые переменные:
|
||||
// const CF = fReal * fReal + fImag * fImag;
|
||||
// resp_real[i] = (cReal * fReal + cImag * fImag) / CF;
|
||||
// resp_imag[i] = (fReal * cImag - cReal * fImag) / CF;
|
||||
|
||||
if (type == 0) {
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const cReal = cross_real[i]; // действительная часть кросс спектра
|
||||
const cImag = cross_imag[i]; // мнимая часть кросс спектра
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const CF = fReal * fReal + fImag * fImag;
|
||||
resp_real[i] = (cReal * fReal + cImag * fImag) / CF;
|
||||
resp_imag[i] = (fReal * cImag - cReal * fImag) / CF;
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i++) {
|
||||
const vReal = vibro.real[i]; // действительная часть спектра вибрации
|
||||
const vImag = vibro.imag[i]; // мнимая часть спектра вибрации
|
||||
const fReal = force.real[i]; // действительная часть спектра силы
|
||||
const fImag = force.imag[i]; // мнимая часть спектра силы
|
||||
|
||||
const VF = vReal * vReal + fImag * fImag;
|
||||
resp_real[i] = (vReal * fReal - vImag * fImag) / VF;
|
||||
resp_imag[i] = (fReal * vImag + vReal * fImag) / VF;
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
let resp_ampl = new Float64Array(n); // типизированный массив для амплитуды
|
||||
let resp_phase = new Float64Array(n); // типизированный массив для фазы
|
||||
const RAD_TO_DEG = 180 / Math.PI; //перевод радиан в градусы
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const rReal = resp_real[i]; // действительная часть спектра отклика
|
||||
const rImag = resp_imag[i]; // мнимая часто спектра отклика
|
||||
|
||||
resp_ampl[i] = Math.sqrt(rReal * rReal + rImag * rImag);
|
||||
if (view > 0) { resp_ampl = resp_ampl.map((item) => (item = 20 * Math.log10(item / 1e-6))) }; //переводим в дБ
|
||||
resp_phase[i] = Math.atan2(rImag, rReal) * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
// Приводим фазу к диапазону [0°, 360°]
|
||||
for (let i = 0; i < n; i++) {
|
||||
resp_phase[i] = resp_phase[i] % 360;
|
||||
if (resp_phase[i] < 0) { resp_phase[i] += 360 }
|
||||
}
|
||||
|
||||
return {
|
||||
data: resp_ampl,
|
||||
phase: resp_phase,
|
||||
resolution: force.resolution
|
||||
}
|
||||
}; //рассчет перекрестного спектра
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
"use strict";
|
||||
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
var plot_0 = gtl.plots.add("Спектр ускорения (канал 0)"); // спектр ускорения канала 0
|
||||
var plot_1 = gtl.plots.add("Спектр ускорения (канал 1)"); // спектр ускорения канала 1
|
||||
var plot_2 = gtl.plots.add("Спектр ускорения (канал 2)"); // спектр ускорения канала 2
|
||||
var plot_3 = gtl.plots.add("Спектр силы (канал 3)"); // спектр ускорения канала 3
|
||||
var plot_0_3 = gtl.plots.add("Перекрёстный спектр (каналы 0 и 3)"); // перекрёстный спектр каналов 0 и 3
|
||||
var plot_1_3 = gtl.plots.add("Перекрёстный спектр (каналы 1 и 3)"); // перекрёстный спектр каналов 1 и 3
|
||||
var plot_2_3 = gtl.plots.add("Перекрёстный спектр (каналы 2 и 3)"); // перекрёстный спектр каналов 2 и 3
|
||||
var plotSpecTransfer_0_3 = gtl.plots.add("Спектр передаточной функции (каналы 0 и 3)"); // спектр передаточной функции каналов 0 и 3
|
||||
var plotSpecTransfer_1_3 = gtl.plots.add("Спектр передаточной функции (каналы 1 и 3)"); // спектр передаточной функции каналов 1 и 3
|
||||
var plotSpecTransfer_2_3 = gtl.plots.add("Спектр передаточной функции (каналы 2 и 3)"); // спектр передаточной функции каналов 2 и 3
|
||||
var plotTransfer_0_3 = gtl.plots.add("Передаточная функция (каналы 0 и 3)"); // передаточная функция каналов 0 и 3
|
||||
var plotTransfer_1_3 = gtl.plots.add("Передаточная функция (каналы 1 и 3)"); // передаточная функция каналов 1 и 3
|
||||
var plotTransfer_2_3 = gtl.plots.add("Передаточная функция (каналы 2 и 3)");; // передаточная функция каналов 2 и 3
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ПЕРЕДАТОЧНОЙ ФУНКЦИИ (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы (вибропреобразователь и молоток).
|
||||
// 2. Вычислить среднее значение по амплитудам (по обоим спектрам).
|
||||
// 3. Поочерёдно вычесть из каждого элемента амплитудного спектра соответствующее среднее значение,
|
||||
// записать массивы разниц.
|
||||
// 4. Перемножить значения массивов разниц, записать массив произведений.
|
||||
// 5. Разделить значения массива произведений на массив амплитудного спектра силы,
|
||||
// записать массив передаточной функции.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Пороги и прочие изменяемые параметры
|
||||
var ausp_frequency = 1000; // граничная частота спектра
|
||||
var ausp_average = 1; // количество усреднений спектра
|
||||
var ausp_lines = 4; // множитель количества линий спектра (на 1 Гц)
|
||||
var ausp_smoothing_factor = 100; // усреднение средней линии
|
||||
var ausp_peak_level = 0.001 // порог обнаружения гармоник РЕДАКТИРОВАТЬ НА РЕАЛЬНЫХ СИГНАЛАХ
|
||||
var ausp_tolerance = 1; // диапазон поиска гармоники по ширине +/- Гц
|
||||
var average = 6; // количество усреднений объекта АФЧХ (когерентность и разница фаз)
|
||||
// var ausp_unit = gtl.spec.db; // отображение амплитуды в дБ
|
||||
var ausp_unit = gtl.spec.unit; // отображение амплитуды в м/с^2
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
|
||||
// Канал_0
|
||||
var ausp_acсel_0 = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_0.color = 0x04ff00; // цвет спектра
|
||||
ausp_acсel_0.name = "Спектр ускорения (канал 0)"; // имя спектра
|
||||
ausp_acсel_0.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_0.frequency = ausp_frequency;
|
||||
ausp_acсel_0.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_0.average = ausp_average;
|
||||
ausp_acсel_0.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_0.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_0.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_0.peak_level = ausp_peak_level;
|
||||
ausp_acсel_0.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Канал_1
|
||||
var ausp_acсel_1 = gtl.add_ausp(gtl.analog_inputs[signals[1].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_1.color = 0xcad714; // цвет спектра
|
||||
ausp_acсel_1.name = "Спектр ускорения (канал 1)"; // имя спектра
|
||||
ausp_acсel_1.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_1.frequency = ausp_frequency;
|
||||
ausp_acсel_1.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_1.average = ausp_average;
|
||||
ausp_acсel_1.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_1.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_1.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_1.peak_level = ausp_peak_level;
|
||||
ausp_acсel_1.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Канал_2
|
||||
var ausp_acсel_2 = gtl.add_ausp(gtl.analog_inputs[signals[2].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_2.color = 0xff8800; // цвет спектра
|
||||
ausp_acсel_2.name = "Спектр ускорения (канал 2)"; // имя спектра
|
||||
ausp_acсel_2.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_2.frequency = ausp_frequency;
|
||||
ausp_acсel_2.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_2.average = ausp_average;
|
||||
ausp_acсel_2.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_2.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_2.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_2.peak_level = ausp_peak_level;
|
||||
ausp_acсel_2.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_3
|
||||
var ausp_force_3 = gtl.add_ausp(gtl.analog_inputs[signals[3].portNumber]); // объявление переменной спектра
|
||||
ausp_force_3.color = 0x000000ff; // цвет спектра
|
||||
ausp_force_3.name = "Спектр силы (канал 3)"; // имя спектра
|
||||
ausp_force_3.color = 0x00ff0000; // красный цвет спектра
|
||||
ausp_force_3.frequency = ausp_frequency;
|
||||
ausp_force_3.lines = ausp_frequency * ausp_lines;
|
||||
ausp_force_3.average = ausp_average;
|
||||
ausp_force_3.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_force_3.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_force_3.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_force_3.peak_level = ausp_peak_level;
|
||||
ausp_force_3.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_acсel_0.acq_time, ausp_acсel_1.acq_time, ausp_acсel_2.acq_time, ausp_force_3.acq_time) + 0.1;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 20; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
// Массивы значений
|
||||
var ausp_accel_0_data = ausp_acсel_0.data; // массив уровней спектра ускорения 0
|
||||
var ausp_accel_1_data = ausp_acсel_1.data; // массив уровней спектра ускорения 1
|
||||
var ausp_accel_2_data = ausp_acсel_2.data; // массив уровней спектра ускорения 2
|
||||
var ausp_force_3_data = ausp_force_3.data; // массив уровней спектра силы 3
|
||||
|
||||
|
||||
gtl.log.info("ausp_data.length", ausp_force_3_data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
gtl.log.info("ausp_frequency", ausp_frequency);
|
||||
gtl.log.info("ausp_lines", ausp_lines);
|
||||
gtl.log.info("-", "-");
|
||||
|
||||
|
||||
// // Пример вычисления среднего по значениям массива
|
||||
// var arr = [1, 1, 1, 1, 1, 2];
|
||||
// var average = 0; // среднее значение массива
|
||||
// let sum = 0; // сумма всех чисел массива
|
||||
// for (let i = 0; i < arr.length; i += 1)
|
||||
// {
|
||||
// sum += arr[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
// }
|
||||
// average = sum / arr.length; // возвращаем среднее арифметическое
|
||||
// gtl.log.info("average test array", average);
|
||||
// gtl.log.info("summ test array", sum);
|
||||
// gtl.log.info("length test array", arr.length);
|
||||
|
||||
|
||||
// Получение массивов для формулы передаточной функции
|
||||
|
||||
// Канал_0 (ausp_accel_0_data)
|
||||
// среднее и сумма
|
||||
var aver_ausp_accel_0_data = 0; // среднее значение массива
|
||||
var sum_ausp_accel_0_data = 0; // сумма всех чисел массива
|
||||
for (let i = 0; i < ausp_accel_0_data.length; i += 1)
|
||||
{
|
||||
sum_ausp_accel_0_data += ausp_accel_0_data[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
aver_ausp_accel_0_data = sum_ausp_accel_0_data / ausp_accel_0_data.length;
|
||||
// запись массивов (Y_i - Y_average)
|
||||
var delta_y_aver_ausp_accel_0_data = []; // массив
|
||||
for (let i = 0; i < ausp_accel_0_data.length; i++)
|
||||
{
|
||||
delta_y_aver_ausp_accel_0_data.push(ausp_accel_0_data[i] - aver_ausp_accel_0_data);
|
||||
}
|
||||
|
||||
// Канал_1 (ausp_accel_1_data)
|
||||
// среднее и сумма
|
||||
var aver_ausp_accel_1_data = 0; // среднее значение массива
|
||||
var sum_ausp_accel_1_data = 0; // сумма всех чисел массива
|
||||
for (let i = 0; i < ausp_accel_1_data.length; i += 1)
|
||||
{
|
||||
sum_ausp_accel_1_data += ausp_accel_1_data[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
aver_ausp_accel_1_data = sum_ausp_accel_1_data / ausp_accel_1_data.length;
|
||||
// запись массивов (Y_i - Y_average)
|
||||
var delta_y_aver_ausp_accel_1_data = []; // массив
|
||||
for (let i = 0; i < ausp_accel_1_data.length; i++)
|
||||
{
|
||||
delta_y_aver_ausp_accel_1_data.push(ausp_accel_1_data[i] - aver_ausp_accel_1_data);
|
||||
}
|
||||
|
||||
// Канал_2 (ausp_accel_2_data)
|
||||
// среднее и сумма
|
||||
var aver_ausp_accel_2_data = 0; // среднее значение массива
|
||||
var sum_ausp_accel_2_data = 0; // сумма всех чисел массива
|
||||
for (let i = 0; i < ausp_accel_2_data.length; i += 1)
|
||||
{
|
||||
sum_ausp_accel_2_data += ausp_accel_2_data[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
aver_ausp_accel_2_data = sum_ausp_accel_2_data / ausp_accel_2_data.length;
|
||||
// запись массивов (Y_i - Y_average)
|
||||
var delta_y_aver_ausp_accel_2_data = []; // массив
|
||||
for (let i = 0; i < ausp_accel_2_data.length; i++)
|
||||
{
|
||||
delta_y_aver_ausp_accel_2_data.push(ausp_accel_2_data[i] - aver_ausp_accel_2_data);
|
||||
}
|
||||
|
||||
// Канал_3 (ausp_force_3_data)
|
||||
// среднее и сумма
|
||||
var aver_ausp_force_3_data = 0; // среднее значение массива
|
||||
var sum_ausp_force_3_data = 0; // сумма всех чисел массива
|
||||
for (let i = 0; i < ausp_force_3_data.length; i += 1)
|
||||
{
|
||||
sum_ausp_force_3_data += ausp_force_3_data[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
aver_ausp_force_3_data = sum_ausp_force_3_data / ausp_force_3_data.length;
|
||||
// запись массивов (Y_i - Y_average)
|
||||
var delta_y_aver_ausp_force_3_data = []; // массив
|
||||
for (let i = 0; i < ausp_force_3_data.length; i++)
|
||||
{
|
||||
delta_y_aver_ausp_force_3_data.push(ausp_force_3_data[i] - aver_ausp_force_3_data);
|
||||
}
|
||||
|
||||
|
||||
// Получение передаточной функции (спектра передаточной функции)
|
||||
|
||||
// Канал_0 & Канал_3
|
||||
var Saf_0_3 = []; // массив перекрёстного спектра ускорения каналов 0 и 3
|
||||
for (let i = 0; i < ausp_accel_0_data.length; i++)
|
||||
{
|
||||
Saf_0_3.push(delta_y_aver_ausp_accel_0_data[i] * delta_y_aver_ausp_force_3_data[i]);
|
||||
}
|
||||
var sum_Saf_0_3 = 0; // сумма всех чисел массива перекрёстного спектра Saf_0_3
|
||||
for (let i = 0; i < Saf_0_3.length; i += 1)
|
||||
{
|
||||
sum_Saf_0_3 += Saf_0_3[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
var HaF_0_3 = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_0_3.length; i++)
|
||||
{
|
||||
HaF_0_3.push(Saf_0_3[i] / ausp_force_3_data[i]);
|
||||
}
|
||||
var HaF_0_3_sum = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_0_3.length; i++)
|
||||
{
|
||||
HaF_0_3_sum.push(sum_Saf_0_3 / ausp_force_3_data[i]);
|
||||
}
|
||||
|
||||
// Канал_1 & Канал_3
|
||||
var Saf_1_3 = []; // массив перекрёстного спектра ускорения каналов 1 и 3
|
||||
for (let i = 0; i < ausp_accel_1_data.length; i++)
|
||||
{
|
||||
Saf_1_3.push(delta_y_aver_ausp_accel_1_data[i] * delta_y_aver_ausp_force_3_data[i]);
|
||||
}
|
||||
var sum_Saf_1_3 = 0; // сумма всех чисел массива перекрёстного спектра Saf_1_3
|
||||
for (let i = 0; i < Saf_1_3.length; i += 1)
|
||||
{
|
||||
sum_Saf_1_3 += Saf_1_3[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
var HaF_1_3 = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_1_3.length; i++)
|
||||
{
|
||||
HaF_1_3.push(Saf_1_3[i] / ausp_force_3_data[i]);
|
||||
}
|
||||
var HaF_1_3_sum = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_1_3.length; i++)
|
||||
{
|
||||
HaF_1_3_sum.push(sum_Saf_1_3 / ausp_force_3_data[i]);
|
||||
}
|
||||
|
||||
// Канал_2 & Канал_3
|
||||
var Saf_2_3 = []; // массив перекрёстного спектра ускорения каналов 2 и 3
|
||||
for (let i = 0; i < ausp_accel_2_data.length; i++)
|
||||
{
|
||||
Saf_2_3.push(delta_y_aver_ausp_accel_2_data[i] * delta_y_aver_ausp_force_3_data[i]);
|
||||
}
|
||||
var sum_Saf_2_3 = 0; // сумма всех чисел массива перекрёстного спектра Saf_2_3
|
||||
for (let i = 0; i < Saf_2_3.length; i += 1)
|
||||
{
|
||||
sum_Saf_2_3 += Saf_2_3[i]; // на каждой итерации прибавляем к сумме значение текущего элемента массива
|
||||
}
|
||||
var HaF_2_3 = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_2_3.length; i++)
|
||||
{
|
||||
HaF_2_3.push(Saf_2_3[i] / ausp_force_3_data[i]);
|
||||
}
|
||||
var HaF_2_3_sum = []; // массив спектра передаточной функции
|
||||
for (let i = 0; i < Saf_2_3.length; i++)
|
||||
{
|
||||
HaF_2_3_sum.push(sum_Saf_2_3 / ausp_force_3_data[i]);
|
||||
}
|
||||
|
||||
|
||||
gtl.log.info("---", "---");
|
||||
gtl.log.info("average ausp_force_3_data", aver_ausp_force_3_data);
|
||||
gtl.log.info("summ ausp_force_3_data", sum_ausp_force_3_data);
|
||||
gtl.log.info("length ausp_force_3_data", ausp_force_3_data.length);
|
||||
gtl.log.info("sum_Saf_0_3", sum_Saf_0_3);
|
||||
gtl.log.info("---", "---");
|
||||
gtl.log.info("average ausp_accel_2_data", aver_ausp_accel_2_data);
|
||||
gtl.log.info("summ ausp_accel_2_data", sum_ausp_accel_2_data);
|
||||
gtl.log.info("length ausp_accel_2_data", ausp_accel_2_data.length);
|
||||
gtl.log.info("---", "---");
|
||||
gtl.log.info("average ausp_accel_1_data", aver_ausp_accel_1_data);
|
||||
gtl.log.info("summ ausp_accel_1_data", sum_ausp_accel_1_data);
|
||||
gtl.log.info("length ausp_accel_1_data", ausp_accel_1_data.length);
|
||||
gtl.log.info("---", "---");
|
||||
gtl.log.info("average ausp_accel_0_data", aver_ausp_accel_0_data);
|
||||
gtl.log.info("summ ausp_accel_0_data", sum_ausp_accel_0_data);
|
||||
gtl.log.info("length ausp_accel_0_data", ausp_accel_0_data.length);
|
||||
|
||||
|
||||
// Построение пользовательских графиков
|
||||
|
||||
plot_0.add(
|
||||
{
|
||||
color: 0x04ff00,
|
||||
name: "Спектр ускорения (канал 0)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_accel_0_data
|
||||
});
|
||||
|
||||
plot_1.add(
|
||||
{
|
||||
color: 0xcad714,
|
||||
name: "Спектр ускорения (канал 1)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_accel_1_data
|
||||
});
|
||||
|
||||
plot_2.add(
|
||||
{
|
||||
color: 0xff8800,
|
||||
name: "Спектр ускорения (канал 2)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_accel_2_data
|
||||
});
|
||||
|
||||
plot_3.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_force_3_data
|
||||
});
|
||||
|
||||
plot_0_3.add(
|
||||
{
|
||||
color: 0xff00ff,
|
||||
name: "Перекрёстный спектр (каналы 0 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: Saf_0_3
|
||||
});
|
||||
|
||||
plot_1_3.add(
|
||||
{
|
||||
color: 0xED3CCA,
|
||||
name: "Перекрёстный спектр (каналы 1 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: Saf_1_3
|
||||
});
|
||||
|
||||
plot_2_3.add(
|
||||
{
|
||||
color: 0x9966CC,
|
||||
name: "Перекрёстный спектр (каналы 2 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: Saf_2_3
|
||||
});
|
||||
|
||||
plotSpecTransfer_0_3.add(
|
||||
{
|
||||
color: 0x78DBE2,
|
||||
name: "Спектр передаточной функции (каналы 0 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_0_3
|
||||
});
|
||||
|
||||
plotSpecTransfer_1_3.add(
|
||||
{
|
||||
color: 0x349a32,
|
||||
name: "Спектр передаточной функции (каналы 1 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_1_3
|
||||
});
|
||||
|
||||
plotSpecTransfer_2_3.add(
|
||||
{
|
||||
color: 0x6dd08c,
|
||||
name: "Спектр передаточной функции (каналы 2 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_2_3
|
||||
});
|
||||
|
||||
plotTransfer_0_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Передаточная функция (каналы 0 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_0_3_sum
|
||||
});
|
||||
|
||||
plotTransfer_1_3.add(
|
||||
{
|
||||
color: 0x99f0b7,
|
||||
name: "Передаточная функция (каналы 1 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_1_3_sum
|
||||
});
|
||||
|
||||
plotTransfer_2_3.add(
|
||||
{
|
||||
color: 0xe8e463,
|
||||
name: "Передаточная функция (каналы 2 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: HaF_2_3_sum
|
||||
});
|
||||
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,397 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
// let signal_force = gtl.options.customOptions.force; // номер канала силы (молотка)
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
let ausp_vibr = []; // массив объектов спектров вибрации
|
||||
let ausp_force = []; // массив объектов спектров силы по диапазонам [k]
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl_avg = []; // усреднение амплитуды частотного отклика по всем ударам
|
||||
let freq_resp_phase_avg = []; // усреднение фазы частотного отклика по всем ударам
|
||||
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
// Фильтр сигнала силы
|
||||
let filter_band_force = gtl.add_filter_iir(gtl.analog_inputs[signals[0].portNumber]);
|
||||
filter_band_force.kind = gtl.filter_iir.butterworth;
|
||||
filter_band_force.type = gtl.filter_iir.bandpass;
|
||||
filter_band_force.order = 4;
|
||||
filter_band_force.frequency = (frequency + 2) / 2; // центральная частота полосового фильтра
|
||||
filter_band_force.width = frequency; // ширина полосы фильтра
|
||||
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
// for (let j = 1; j < 2; j++) {
|
||||
|
||||
// Фильтр сигнала вибрации
|
||||
let filter_band_vibr = gtl.add_filter_iir(gtl.analog_inputs[signals[j].portNumber]);
|
||||
filter_band_vibr.kind = gtl.filter_iir.butterworth;
|
||||
filter_band_vibr.type = gtl.filter_iir.bandpass;
|
||||
filter_band_vibr.order = 4;
|
||||
filter_band_vibr.frequency = (frequency + 2) / 2; // центральная частота полосового фильтра
|
||||
filter_band_vibr.width = frequency; // ширина полосы фильтра
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сырой сигнал вибрации
|
||||
// "src": filter_band_vibr, // фильтрованный сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы, относительно него вычисляем дельту фазы
|
||||
// "src0" : filter_band_force, // фильтрованный сигнал силы, относительно него вычисляем дельту фазы
|
||||
"src1" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
// "src1" : filter_band_vibr, // фильтрованный сигнал вибрации
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
// "src": filter_band_force, // фильтрованный сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let src_force = gtl.analog_inputs[0]; // источник сигнала силы
|
||||
// let src_force = filter_band_force; // источник фильтрованного сигнала силы
|
||||
let time = gtl.options.record.playerTime; // время записи для анализа
|
||||
let time_window = 0.02 // временное окно наблюдения
|
||||
let time_impulse = 0; // длина импульса для функции нарезки сигнала
|
||||
if (time_impulse_ == 0)
|
||||
{
|
||||
// time_impulse = ausp_force_0.acq_time + 0.05; // временное окно для анализа импульса (не менее времени построения спектра)
|
||||
time_impulse = gtl.acq_time + 0.05;
|
||||
}
|
||||
else {time_impulse = time_impulse_};
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Скользящая амплитуда для создания "огибающей" импульса
|
||||
let __max = gtl.create_moving_max({
|
||||
src: src_force,
|
||||
name: "max",
|
||||
time: time_window
|
||||
});
|
||||
__max.history = 2; //история сохраненных данных сигнала
|
||||
|
||||
// Порог для олтслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: __max,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
__thresh.history = 2; // история сохраненных данных сигнала
|
||||
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Функция диагностики.
|
||||
/*
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = time; // интервал запуска функции диагностики
|
||||
let plot = gtl.plots.add("Impulses"); // создаем координатную плоскость
|
||||
|
||||
function diagnose() {
|
||||
if (tries >= ranges.length) gtl.diagnostic.stop();
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
|
||||
plot.add({
|
||||
color: 0x0000ff, // цвет графика
|
||||
name: "max", // наименование графика
|
||||
x: 1 / __max.rate, // частотное разрешение
|
||||
y: __max.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
|
||||
plot.add({
|
||||
color: 0xff00ff, // цвет графика
|
||||
name: "thresh", // наименование графика
|
||||
x: 1 / __thresh.rate, // частотное разрешение
|
||||
y: __thresh.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
}
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
if (tries == 0) { gtl.log.info("Установленный интервал запуска диагностики", time_impulse)
|
||||
gtl.log.info("Необходимая длина сигнала для спектров", ausp_force_0.acq_time)
|
||||
gtl.log.info("acq_time", gtl.acq_time)
|
||||
gtl.log.info("Длина массива спектра", ausp_force_0.data.length);}
|
||||
else { gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`) }
|
||||
|
||||
/*
|
||||
Математика обработки сигнала
|
||||
*/
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналом силы и вибрации
|
||||
for (let k = 0; k < ranges.length; k++) { // цикл по ударам (сначала по ударам, потом по каналам)
|
||||
for (let j = 1; j < ausp_j.length; j++) { // цикл по каналам
|
||||
// for (let j = 1; j < 2; j++) { // цикл по каналам
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1} - удар №${k+1}, g`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
});
|
||||
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[j] & Канал[0]
|
||||
// сигнал силы в комплексно-сопряжённом виде
|
||||
// сигнал вибрации умножвается на сигнал силы, а НЕ наоборот
|
||||
// умножение комплексных чисел по формуле:
|
||||
// (a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
// (a1*a2-b1*b2) - действительная часть
|
||||
// (a1*b2+b1*a2)i - мнимая часть
|
||||
ausp_cross_real[j] = []; // массив действительной части кросс-спектра
|
||||
ausp_cross_imag[j] = []; // массив мнимой части кросс-спектра
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Вычисление частотного отклика
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
// (a*c-b*d) - действительная часть
|
||||
// (a*d+b*c)i - мнимая часть
|
||||
freq_resp_real[j] = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag[j] = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_j[j].real[i] * ausp_force_0.real[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_j[j].imag[i] -
|
||||
ausp_j[j].real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров частотного отклика в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1} - удар №${k+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
// plot_FreqResp_phase_j.add(
|
||||
// {
|
||||
// color: 0xb6306f,
|
||||
// name: `Фаза частотного отклика канала ${j+1} - удар №${k+1}, °`,
|
||||
// x: 1/lines,
|
||||
// y: freq_resp_phase[j],
|
||||
// tags: ["Фаза частотного отклика, °"]
|
||||
// });
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы (канал [0]) - удар №${k+1}, N`,
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: [`Спектр силы (канал [0]) - удар №${k+1}, N`]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
tries++;
|
||||
|
||||
// Усреднение откликов (амплитудных спектров) по всем ударам для каждого канала отдельно
|
||||
// for (let j = 0; j < ausp_j.length; j++) { // цикл по каналам
|
||||
// for (let k = 0; k < ranges.length; k++) { // цикл по ударам
|
||||
// // freq_resp_ampl_avg[j] = freq_resp_ampl[k]
|
||||
// // freq_resp_phase_avg[j] = [];
|
||||
|
||||
// // gtl.log.info("freq_resp_ampl[j][k].length", freq_resp_ampl[j][k].length);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
let plot_ausp_vibr = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
// let signal_force = gtl.options.customOptions.force; // номер канала силы (молотка)
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
let ausp_vibr; // массив объектов спектров вибрации
|
||||
let ausp_force; // массив объектов спектров силы по диапазонам [k]
|
||||
let phase_vibr; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl_avg = []; // усреднение амплитуды частотного отклика по всем ударам
|
||||
let freq_resp_phase_avg = []; // усреднение фазы частотного отклика по всем ударам
|
||||
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
|
||||
let src_force = gtl.analog_inputs[0]; // источник сигнала силы
|
||||
// let src_force = filter_band_force; // источник фильтрованного сигнала силы
|
||||
let time = gtl.options.record.playerTime; // время записи для анализа
|
||||
let time_window = 0.02 // временное окно наблюдения
|
||||
let time_impulse = 0; // длина импульса для функции нарезки сигнала
|
||||
if (time_impulse_ == 0)
|
||||
{
|
||||
// time_impulse = ausp_force_0.acq_time + 0.05; // временное окно для анализа импульса (не менее времени построения спектра)
|
||||
time_impulse = gtl.acq_time + 0.05;
|
||||
}
|
||||
else {time_impulse = time_impulse_};
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Скользящая амплитуда для создания "огибающей" импульса
|
||||
let __max = gtl.create_moving_max({
|
||||
src: src_force,
|
||||
name: "max",
|
||||
time: time_window
|
||||
});
|
||||
__max.history = 2; //история сохраненных данных сигнала
|
||||
|
||||
// Порог для олтслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: __max,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
__thresh.history = 2; // история сохраненных данных сигнала
|
||||
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
gtl.log.info("Количество ударов (ranges)", ranges.length);
|
||||
|
||||
for (let k = 0; k < ranges.length; k++) { // цикл по диапазонам
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
ausp_vibr =
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[1].portNumber], // сырой сигнал вибрации
|
||||
// "src": filter_band_vibr, // фильтрованный сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
phase_vibr =
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы, относительно него вычисляем дельту фазы
|
||||
// "src0" : filter_band_force, // фильтрованный сигнал силы, относительно него вычисляем дельту фазы
|
||||
"src1" : gtl.analog_inputs[signals[1].portNumber], // сигнал вибрации
|
||||
// "src1" : filter_band_vibr, // фильтрованный сигнал вибрации
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
ausp_force =
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
// "src": filter_band_force, // фильтрованный сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// gtl.log.info("Количество спектров вибрации", ausp_vibr.length);
|
||||
// gtl.log.info("Количество спектров силы", ausp_force.length);
|
||||
|
||||
|
||||
|
||||
|
||||
// let src_force = gtl.analog_inputs[0]; // источник сигнала силы
|
||||
// // let src_force = filter_band_force; // источник фильтрованного сигнала силы
|
||||
// let time = gtl.options.record.playerTime; // время записи для анализа
|
||||
// let time_window = 0.02 // временное окно наблюдения
|
||||
// let time_impulse = 0; // длина импульса для функции нарезки сигнала
|
||||
// if (time_impulse_ == 0)
|
||||
// {
|
||||
// // time_impulse = ausp_force_0.acq_time + 0.05; // временное окно для анализа импульса (не менее времени построения спектра)
|
||||
// time_impulse = gtl.acq_time + 0.05;
|
||||
// }
|
||||
// else {time_impulse = time_impulse_};
|
||||
// let time_pre = time_window / 2; // время предыстории
|
||||
// let ranges = []; // массив диапазонов для импульсов
|
||||
// let tries = 0; // циклы диагностки
|
||||
// let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// // Скользящая амплитуда для создания "огибающей" импульса
|
||||
// let __max = gtl.create_moving_max({
|
||||
// src: src_force,
|
||||
// name: "max",
|
||||
// time: time_window
|
||||
// });
|
||||
// __max.history = 2; //история сохраненных данных сигнала
|
||||
|
||||
// // Порог для олтслеживание импульсов
|
||||
// let __thresh = gtl.create_moving_thresh({
|
||||
// src: __max,
|
||||
// name: "thresh",
|
||||
// time: time_window,
|
||||
// level: thresh_level
|
||||
// });
|
||||
// __thresh.history = 2; // история сохраненных данных сигнала
|
||||
|
||||
|
||||
// __thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// // Функция получения диапазонов импульсов
|
||||
// function thresh_triggered_event(flag, sample) {
|
||||
// if (is_ranges) return;
|
||||
// if (flag) {
|
||||
// let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
// gtl.log.info("trigger on time", start);
|
||||
|
||||
// let range = {
|
||||
// min: start,
|
||||
// max: start + time_impulse
|
||||
// };
|
||||
// ranges.push(range); //добавляем диапазон в массив
|
||||
// };
|
||||
// };
|
||||
|
||||
|
||||
// Функция диагностики.
|
||||
/*
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = time; // интервал запуска функции диагностики
|
||||
let plot = gtl.plots.add("Impulses"); // создаем координатную плоскость
|
||||
|
||||
function diagnose() {
|
||||
if (tries >= ranges.length) gtl.diagnostic.stop();
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
|
||||
plot.add({
|
||||
color: 0x0000ff, // цвет графика
|
||||
name: "max", // наименование графика
|
||||
x: 1 / __max.rate, // частотное разрешение
|
||||
y: __max.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
|
||||
plot.add({
|
||||
color: 0xff00ff, // цвет графика
|
||||
name: "thresh", // наименование графика
|
||||
x: 1 / __thresh.rate, // частотное разрешение
|
||||
y: __thresh.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
}
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
if (tries == 0) { gtl.log.info("Установленный интервал запуска диагностики", time_impulse)
|
||||
gtl.log.info("Необходимая длина сигнала для спектров", ausp_force.acq_time)
|
||||
gtl.log.info("acq_time", gtl.acq_time)
|
||||
gtl.log.info("Длина массива спектра", ausp_force.data.length);}
|
||||
else { gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`) }
|
||||
|
||||
/*
|
||||
Математика обработки сигнала
|
||||
*/
|
||||
let n = ausp_force.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
// Канал[0] (ausp_force) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_imag_anti.push(ausp_force.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналом силы и вибрации
|
||||
for (let k = 0; k < ranges.length; k++) { // цикл по ударам (сначала по ударам, потом по каналам)
|
||||
// for (let j = 1; j < ausp_j.length; j++) { // цикл по каналам
|
||||
// for (let j = 1; j < 2; j++) { // цикл по каналам
|
||||
if (counter > 0) {
|
||||
plot_ausp_vibr.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала - удар №${k+1}, g`,
|
||||
x: ausp_vibr.resolution,
|
||||
y: ausp_vibr.data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
});
|
||||
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[j] & Канал[0]
|
||||
// сигнал силы в комплексно-сопряжённом виде
|
||||
// сигнал вибрации умножвается на сигнал силы, а НЕ наоборот
|
||||
// умножение комплексных чисел по формуле:
|
||||
// (a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
// (a1*a2-b1*b2) - действительная часть
|
||||
// (a1*b2+b1*a2)i - мнимая часть
|
||||
ausp_cross_real = []; // массив действительной части кросс-спектра
|
||||
ausp_cross_imag = []; // массив мнимой части кросс-спектра
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real.push(ausp_vibr.real[i] * ausp_force.real[i] -
|
||||
(ausp_vibr.imag[i] * ausp_force_imag_anti[i]));
|
||||
ausp_cross_imag.push(ausp_vibr.real[i] * ausp_force_imag_anti[i] +
|
||||
ausp_vibr.imag[i] * ausp_force.real[i]);
|
||||
}
|
||||
|
||||
// Вычисление частотного отклика
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
// (a*c-b*d) - действительная часть
|
||||
// (a*d+b*c)i - мнимая часть
|
||||
freq_resp_real = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real.push((ausp_cross_real[i] * ausp_force.real[i] +
|
||||
ausp_cross_imag[i] * ausp_force.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[i], 2) + Math.pow(ausp_force.imag[i], 2)));
|
||||
|
||||
freq_resp_imag.push((ausp_force.real[i] * ausp_cross_imag[i] -
|
||||
ausp_cross_real[i] * ausp_force.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[i], 2) + Math.pow(ausp_force.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real.push((ausp_vibr.real[i] * ausp_force.real[i] +
|
||||
ausp_vibr.imag[i] * ausp_force.imag[i]) /
|
||||
(Math.pow(ausp_vibr.real[i], 2) + Math.pow(ausp_force.imag[i], 2)));
|
||||
|
||||
freq_resp_imag.push((ausp_force.real[i] * ausp_vibr.imag[i] -
|
||||
ausp_vibr.real[i] * ausp_force.imag[i]) /
|
||||
(Math.pow(ausp_vibr.real[i], 2) + Math.pow(ausp_force_vibr.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl = [];
|
||||
freq_resp_phase = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров частотного отклика в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl.push(Math.sqrt(Math.pow(freq_resp_real[i],2) + Math.pow(freq_resp_imag[i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl.push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[i],2) + Math.pow(freq_resp_imag[i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[i] > 0 & freq_resp_imag[i] > 0)
|
||||
{freq_resp_phase.push(Math.atan(freq_resp_imag[i] / freq_resp_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[i] < 0 & freq_resp_imag[i] > 0)
|
||||
{freq_resp_phase.push(180 - Math.atan(freq_resp_imag[i] / freq_resp_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[i] < 0 & freq_resp_imag[i] < 0)
|
||||
{freq_resp_phase.push(180 + Math.atan(freq_resp_imag[i] / freq_resp_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[i] > 0 & freq_resp_imag[i] < 0)
|
||||
{freq_resp_phase.push(360 - Math.atan(freq_resp_imag[i] / freq_resp_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[i] >= 360)
|
||||
{freq_resp_phase[i] = freq_resp_phase[i] - 360}
|
||||
else {freq_resp_phase[i] = freq_resp_phase[i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала - удар №${k+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl,
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
// plot_FreqResp_phase.add(
|
||||
// {
|
||||
// color: 0xb6306f,
|
||||
// name: `Фаза частотного отклика канала - удар №${k+1}, °`,
|
||||
// x: 1/lines,
|
||||
// y: freq_resp_phase[j],
|
||||
// tags: ["Фаза частотного отклика, °"]
|
||||
// });
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_vibr.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы (канал [0]) - удар №${k+1}, N`,
|
||||
x: 1/lines,
|
||||
y: ausp_force.data,
|
||||
tags: [`Спектр силы (канал [0]) - удар №${k+1}, N`]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
tries++;
|
||||
|
||||
// Усреднение откликов (амплитудных спектров) по всем ударам для каждого канала отдельно
|
||||
// for (let j = 0; j < ausp_j.length; j++) { // цикл по каналам
|
||||
// for (let k = 0; k < ranges.length; k++) { // цикл по ударам
|
||||
// // freq_resp_ampl_avg[j] = freq_resp_ampl[k]
|
||||
// // freq_resp_phase_avg[j] = [];
|
||||
|
||||
// // gtl.log.info("freq_resp_ampl[j][k].length", freq_resp_ampl[j][k].length);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
// let signal_force = gtl.options.customOptions.force; // номер канала силы (молотка)
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl_avg = []; // усреднение амплитуды частотного отклика по всем ударам
|
||||
let freq_resp_phase_avg = []; // усреднение фазы частотного отклика по всем ударам
|
||||
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сырой сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации (относительно сигнала силы)
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы, относительно него вычисляем дельту фазы
|
||||
"src1" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let src_force = gtl.analog_inputs[0]; // источник сигнала силы
|
||||
let time = gtl.options.record.playerTime; // время записи для анализа
|
||||
let time_window = 0.02 // временное окно наблюдения
|
||||
let time_impulse = 0; // длина импульса для функции нарезки сигнала
|
||||
if (time_impulse_ == 0)
|
||||
{
|
||||
// time_impulse = ausp_force_0.acq_time + 0.05; // временное окно для анализа импульса (не менее времени построения спектра)
|
||||
time_impulse = gtl.acq_time + 0.05;
|
||||
}
|
||||
else {time_impulse = time_impulse_};
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Скользящая амплитуда для создания "огибающей" импульса
|
||||
let __max = gtl.create_moving_max({
|
||||
src: src_force,
|
||||
name: "max",
|
||||
time: time_window
|
||||
});
|
||||
__max.history = 2; //история сохраненных данных сигнала
|
||||
|
||||
// Порог для олтслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: __max,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
__thresh.history = 2; // история сохраненных данных сигнала
|
||||
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Функция диагностики.
|
||||
/*
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = time; // интервал запуска функции диагностики
|
||||
let plot = gtl.plots.add("Impulses"); // создаем координатную плоскость
|
||||
|
||||
function diagnose() {
|
||||
if (tries >= ranges.length) gtl.diagnostic.stop();
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
|
||||
plot.add({
|
||||
color: 0x0000ff, // цвет графика
|
||||
name: "max", // наименование графика
|
||||
x: 1 / __max.rate, // частотное разрешение
|
||||
y: __max.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
|
||||
plot.add({
|
||||
color: 0xff00ff, // цвет графика
|
||||
name: "thresh", // наименование графика
|
||||
x: 1 / __thresh.rate, // частотное разрешение
|
||||
y: __thresh.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
}
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
if (tries == 0) { gtl.log.info("Установленный интервал запуска диагностики", time_impulse)
|
||||
gtl.log.info("Необходимая длина сигнала для спектров", ausp_force_0.acq_time)
|
||||
gtl.log.info("acq_time", gtl.acq_time)
|
||||
gtl.log.info("Длина массива спектра", ausp_force_0.data.length);}
|
||||
else { gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`) }
|
||||
|
||||
/*
|
||||
Математика обработки сигнала
|
||||
*/
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналом силы и вибрации
|
||||
for (let k = 0; k < ranges.length; k++) { // цикл по ударам (сначала по ударам, потом по каналам)
|
||||
for (let j = 1; j < ausp_j.length; j++) { // цикл по каналам
|
||||
// for (let j = 1; j < 2; j++) { // цикл по каналам
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1} - удар №${k+1}, g`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
});
|
||||
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[j] & Канал[0]
|
||||
// сигнал силы в комплексно-сопряжённом виде
|
||||
// сигнал вибрации умножвается на сигнал силы, а НЕ наоборот
|
||||
// умножение комплексных чисел по формуле:
|
||||
// (a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
// (a1*a2-b1*b2) - действительная часть
|
||||
// (a1*b2+b1*a2)i - мнимая часть
|
||||
ausp_cross_real[j] = []; // массив действительной части кросс-спектра
|
||||
ausp_cross_imag[j] = []; // массив мнимой части кросс-спектра
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Вычисление частотного отклика
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c + b*d)/(c^2 + d^2) + (c*b - a*d)/(c^2 + d^2)i
|
||||
// (a*c + b*d)/(c^2 + d^2) - действительная часть
|
||||
// (c*b - a*d)/(c^2 + d^2)i - мнимая часть
|
||||
freq_resp_real[j] = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag[j] = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_j[j].real[i] * ausp_force_0.real[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0[i].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_j[j].imag[i] -
|
||||
ausp_j[j].real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0[i].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров частотного отклика в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1} - удар №${k+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
// plot_FreqResp_phase_j.add(
|
||||
// {
|
||||
// color: 0xb6306f,
|
||||
// name: `Фаза частотного отклика канала ${j+1} - удар №${k+1}, °`,
|
||||
// x: 1/lines,
|
||||
// y: freq_resp_phase[j],
|
||||
// tags: ["Фаза частотного отклика, °"]
|
||||
// });
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы (канал [0]) - удар №${k+1}, N`,
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: [`Спектр силы (канал [0]) - удар №${k+1}, N`]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
tries++;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
"use strict";
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
let getResponse = gtl.import("getResponse.js").getResponse;
|
||||
|
||||
let plot_ausp = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_resp_ampl = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_resp_phase = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра unit/dB (0/1)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let thresh_level = gtl.options.customOptions.thresh_level; // уровень удара для засчитывания импульса
|
||||
let time_impulse_ = gtl.options.customOptions.time_impulse; // задание длины импульса из опций
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
let spec_view = view_ == 0 ? gtl.spec.unit : gtl.spec.db; // условие отображения спектров в дБ или линейном виде
|
||||
let src_force = gtl.analog_inputs[signals[0].portNumber]; // источник сигнала силы
|
||||
let channel = 1; //номер первого канала вибрации
|
||||
|
||||
let force = gtl.create_ausp({
|
||||
src: src_force, // сигнал силы
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.hann,
|
||||
view: view
|
||||
});
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
let ausps = []; //массив объектов спектров вибрации по каналам
|
||||
let phases = []; //массив объектов ФЧХ по каналам
|
||||
for (let i = channel; i < signals.length; i++) { }; //цикл по каналам
|
||||
|
||||
let ausp = gtl.create_ausp({
|
||||
src: gtl.analog_inputs[signals[channel].portNumber], // сырой сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.hann,
|
||||
view: spec_view
|
||||
});
|
||||
|
||||
let phase_delta = gtl.create_pfc({
|
||||
src0: src_force, // сигнал силы, относительно него вычисляем дельту фазы
|
||||
src1: gtl.analog_inputs[signals[channel].portNumber], // сигнал вибрации
|
||||
frequency: frequency,
|
||||
resolution: resolution,
|
||||
average: average,
|
||||
overlap: overlap,
|
||||
window: gtl.spec.hann,
|
||||
view: gtl.phase.deg,
|
||||
range: gtl.phase.positive,
|
||||
is_single: false
|
||||
});
|
||||
|
||||
let time_window = 0.0001 // временное окно наблюдения
|
||||
let time_impulse = time_impulse_ == 0 ? gtl.acq_time + 0.05 : time_impulse_; // условие выбора длительности импульса
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
|
||||
// Порог для отслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: src_force,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: thresh_level
|
||||
});
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - 0; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
/* Функция диагностики.
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = gtl.options.record.playerTime; // первичный интервал запуска функции диагностики
|
||||
gtl.log.info('Время импульса', time_impulse);
|
||||
|
||||
function diagnose() {
|
||||
if (tries >= ranges.length) gtl.diagnostic.stop();
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
}
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
if (tries == 0) {
|
||||
gtl.log.info("Установленный интервал запуска диагностики", time_impulse)
|
||||
gtl.log.info("acq_time", gtl.acq_time)
|
||||
}
|
||||
else { gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`) }
|
||||
|
||||
if (tries > 0) {
|
||||
|
||||
// Отображаем спектр силы
|
||||
plot_ausp.add({
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы - удар №${tries}, N`,
|
||||
x: force.resolution,
|
||||
y: force.data,
|
||||
tags: [`Спектр силы, N`]
|
||||
});
|
||||
|
||||
// Отображаем автоспектр вибрации
|
||||
plot_ausp.add({
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала 1 - удар №${tries}, g`,
|
||||
x: ausp.resolution,
|
||||
y: ausp.data,
|
||||
tags: ["Cпектр вибрации, g"]
|
||||
});
|
||||
|
||||
// Вычисляем спектр отклика
|
||||
let rsp = getResponse({
|
||||
spec_force: force, //спектр силы
|
||||
spec_vibro: ausp, //спектр вибрации
|
||||
type: 0, //способ вычисления отклика
|
||||
view: 0 //способ отображения спектра в линейных единицах или дБ
|
||||
});
|
||||
|
||||
gtl.log.info('Амплитуда отклика', JSON.stringify(rsp.data));
|
||||
|
||||
// Отображаем спектр отклика
|
||||
plot_resp_ampl.add({
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала 1 - удар №${tries}, g/N`,
|
||||
x: resolution,
|
||||
y: rsp.data,
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
}
|
||||
|
||||
tries++;
|
||||
}
|
||||
|
|
@ -0,0 +1,371 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_0 = gtl.plots.add("Спектр ускорения (канал 0)"); // спектр ускорения канала 0
|
||||
let plot_1 = gtl.plots.add("Спектр ускорения (канал 1)"); // спектр ускорения канала 1
|
||||
let plot_2 = gtl.plots.add("Спектр ускорения (канал 2)"); // спектр ускорения канала 2
|
||||
let plot_3 = gtl.plots.add("Спектр силы (канал 3)"); // спектр ускорения канала 3
|
||||
let plot_FreqResp_0_3 = gtl.plots.add("Частотный отклик (каналы 0 и 3)"); // частотный отклик между каналами 0 и 3
|
||||
let plot_FreqResp_1_3 = gtl.plots.add("Частотный отклик (каналы 1 и 3)"); // частотный отклик между каналами 1 и 3
|
||||
let plot_FreqResp_2_3 = gtl.plots.add("Частотный отклик (каналы 2 и 3)"); // частотный отклик между каналами 2 и 3
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
|
||||
// Канал_0
|
||||
let ausp_acсel_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_1
|
||||
let ausp_acсel_1 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[1].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_2
|
||||
let ausp_acсel_2 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[2].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_3
|
||||
let ausp_force_3 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[3].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_acсel_0.acq_time, ausp_acсel_1.acq_time, ausp_acсel_2.acq_time,
|
||||
ausp_force_3.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
let n = ausp_force_3.data.length; // переменная для цикла
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_3.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
|
||||
// Получение массивов для формулы определения частотного отклика
|
||||
|
||||
// Канал_3 (ausp_force_3) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_3_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_3_imag_anti.push(ausp_force_3.imag[i] * (-1));
|
||||
}
|
||||
// Кросс-спектры
|
||||
// Канал_0 & Канал_3
|
||||
let ausp_cross_0_3_real = []; // действительная часть кросс-спектра 0 & 3
|
||||
let ausp_cross_0_3_imag = []; // мнимая часть кросс-спектра 0 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_3_real.push(ausp_acсel_0.real[i] * ausp_force_3.real[i] -
|
||||
(ausp_acсel_0.imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_0_3_imag.push(ausp_acсel_0.real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_acсel_0.imag[i] * ausp_force_3.real[i]);
|
||||
}
|
||||
// Канал_1 & Канал_3
|
||||
var ausp_cross_1_3_real = []; // действительная часть кросс-спектра 1 & 3
|
||||
var ausp_cross_1_3_imag = []; // мнимая часть кросс-спектра 1 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_1_3_real.push(ausp_acсel_1.real[i] * ausp_force_3.real[i] -
|
||||
(ausp_acсel_1.imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_1_3_imag.push(ausp_acсel_1.real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_acсel_1.imag[i] * ausp_force_3.real[i]);
|
||||
}
|
||||
// Канал_2 & Канал_3
|
||||
var ausp_cross_2_3_real = []; // действительная часть кросс-спектра 2 & 3
|
||||
var ausp_cross_2_3_imag = []; // мнимая часть кросс-спектра 2 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_2_3_real.push(ausp_acсel_2.real[i] * ausp_force_3.real[i] -
|
||||
(ausp_acсel_2.imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_2_3_imag.push(ausp_acсel_2.real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_acсel_2.imag[i] * ausp_force_3.real[i]);
|
||||
}
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал_0 & Канал_3) / Канал_3
|
||||
let freq_resp_0_3_real = []; // действительная часть частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_imag = []; // мнимая часть частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_ampl = []; // амплитуда частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_phase = []; // фаза частотного отклика между 0 и 3 (корректировка)
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_real.push((ausp_cross_0_3_real[i] * ausp_force_3.real[i] +
|
||||
ausp_cross_0_3_imag[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
|
||||
freq_resp_0_3_imag.push((ausp_force_3.real[i] * ausp_cross_0_3_imag[i] -
|
||||
ausp_cross_0_3_real[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_ampl.push(Math.sqrt(Math.pow(freq_resp_0_3_real[i],2) + Math.pow(freq_resp_0_3_imag[i],2)));
|
||||
if (freq_resp_0_3_real[i] > 0 & freq_resp_0_3_imag[i] > 0)
|
||||
{freq_resp_0_3_phase.push(Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] < 0 & freq_resp_0_3_imag[i] > 0)
|
||||
{freq_resp_0_3_phase.push(180 - Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] < 0 & freq_resp_0_3_imag[i] < 0)
|
||||
{freq_resp_0_3_phase.push(180 + Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] > 0 & freq_resp_0_3_imag[i] < 0)
|
||||
{freq_resp_0_3_phase.push(360 - Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_0_3_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_0_3_phase[i] >= 360)
|
||||
{freq_resp_0_3_phase[i] = freq_resp_0_3_phase[i] - 360}
|
||||
else {freq_resp_0_3_phase[i] = freq_resp_0_3_phase[i]}
|
||||
}
|
||||
|
||||
// (Канал_1 & Канал_3) / Канал_3
|
||||
let freq_resp_1_3_real = []; // действительная часть частотного отклика между 0 и 3
|
||||
let freq_resp_1_3_imag = []; // мнимая часть частотного отклика между 0 и 3
|
||||
let freq_resp_1_3_ampl = []; // амплитуда частотного отклика между 0 и 3
|
||||
let freq_resp_1_3_phase = []; // фаза частотного отклика между 0 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_1_3_real.push((ausp_cross_1_3_real[i] * ausp_force_3.real[i] +
|
||||
ausp_cross_1_3_imag[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
|
||||
freq_resp_1_3_imag.push((ausp_force_3.real[i] * ausp_cross_1_3_imag[i] -
|
||||
ausp_cross_1_3_real[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_1_3_ampl.push(Math.sqrt(Math.pow(freq_resp_1_3_real[i],2) + Math.pow(freq_resp_1_3_imag[i],2)));
|
||||
if (freq_resp_1_3_real[i] > 0 & freq_resp_1_3_imag[i] > 0)
|
||||
{freq_resp_1_3_phase.push(Math.atan(freq_resp_1_3_imag[i] / freq_resp_1_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_1_3_real[i] < 0 & freq_resp_1_3_imag[i] > 0)
|
||||
{freq_resp_1_3_phase.push(180 - Math.atan(freq_resp_1_3_imag[i] / freq_resp_1_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_1_3_real[i] < 0 & freq_resp_1_3_imag[i] < 0)
|
||||
{freq_resp_1_3_phase.push(180 + Math.atan(freq_resp_1_3_imag[i] / freq_resp_1_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_1_3_real[i] > 0 & freq_resp_1_3_imag[i] < 0)
|
||||
{freq_resp_1_3_phase.push(360 - Math.atan(freq_resp_1_3_imag[i] / freq_resp_1_3_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_1_3_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_1_3_phase[i] >= 360)
|
||||
{freq_resp_1_3_phase[i] = freq_resp_1_3_phase[i] - 360}
|
||||
else {freq_resp_1_3_phase[i] = freq_resp_1_3_phase[i]}
|
||||
}
|
||||
|
||||
// (Канал_2 & Канал_3) / Канал_3
|
||||
let freq_resp_2_3_real = []; // действительная часть частотного отклика между 2 и 3
|
||||
let freq_resp_2_3_imag = []; // мнимая часть частотного отклика между 2 и 3
|
||||
let freq_resp_2_3_ampl = []; // амплитуда частотного отклика между 2 и 3
|
||||
let freq_resp_2_3_phase = []; // фаза частотного отклика между 2 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_2_3_real.push((ausp_cross_2_3_real[i] * ausp_force_3.real[i] +
|
||||
ausp_cross_2_3_imag[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
|
||||
freq_resp_2_3_imag.push((ausp_force_3.real[i] * ausp_cross_2_3_imag[i] -
|
||||
ausp_cross_2_3_real[i] * ausp_force_3.imag[i]) /
|
||||
(Math.pow(ausp_force_3.real[i], 2) + Math.pow(ausp_force_3.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_2_3_ampl.push(Math.sqrt(Math.pow(freq_resp_2_3_real[i],2) + Math.pow(freq_resp_2_3_imag[i],2)));
|
||||
if (freq_resp_2_3_real[i] > 0 & freq_resp_2_3_imag[i] > 0)
|
||||
{freq_resp_2_3_phase.push(Math.atan(freq_resp_2_3_imag[i] / freq_resp_2_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_2_3_real[i] < 0 & freq_resp_2_3_imag[i] > 0)
|
||||
{freq_resp_2_3_phase.push(180 - Math.atan(freq_resp_2_3_imag[i] / freq_resp_2_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_2_3_real[i] < 0 & freq_resp_2_3_imag[i] < 0)
|
||||
{freq_resp_2_3_phase.push(180 + Math.atan(freq_resp_2_3_imag[i] / freq_resp_2_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_2_3_real[i] > 0 & freq_resp_2_3_imag[i] < 0)
|
||||
{freq_resp_2_3_phase.push(360 - Math.atan(freq_resp_2_3_imag[i] / freq_resp_2_3_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_2_3_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_2_3_phase[i] >= 360)
|
||||
{freq_resp_2_3_phase[i] = freq_resp_2_3_phase[i] - 360}
|
||||
else {freq_resp_2_3_phase[i] = freq_resp_2_3_phase[i]}
|
||||
}
|
||||
|
||||
// Построение пользовательских графиков
|
||||
|
||||
plot_0.add(
|
||||
{
|
||||
color: 0x04ff00,
|
||||
name: "Спектр ускорения (канал 0)",
|
||||
x: 1/lines,
|
||||
y: ausp_acсel_0.data
|
||||
});
|
||||
|
||||
plot_1.add(
|
||||
{
|
||||
color: 0xcad714,
|
||||
name: "Спектр ускорения (канал 1)",
|
||||
x: 1/lines,
|
||||
y: ausp_acсel_1.data
|
||||
});
|
||||
|
||||
plot_2.add(
|
||||
{
|
||||
color: 0xff8800,
|
||||
name: "Спектр ускорения (канал 2)",
|
||||
x: 1/lines,
|
||||
y: ausp_acсel_2.data
|
||||
});
|
||||
|
||||
plot_3.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал 3)",
|
||||
x: 1/lines,
|
||||
y: ausp_force_3.data
|
||||
});
|
||||
|
||||
plot_FreqResp_0_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Амплитуда частотный отклик (каналы 0 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_3_ampl
|
||||
});
|
||||
plot_FreqResp_0_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 0 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_3_phase
|
||||
});
|
||||
|
||||
plot_FreqResp_1_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Амплитуда частотный отклик (каналы 1 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_1_3_ampl
|
||||
});
|
||||
plot_FreqResp_1_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 1 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_1_3_phase
|
||||
});
|
||||
|
||||
plot_FreqResp_2_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Амплитуда частотный отклик (каналы 2 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_2_3_ampl
|
||||
});
|
||||
plot_FreqResp_2_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 2 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_2_3_phase
|
||||
});
|
||||
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,696 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp = gtl.plots.add("Спектр"); // спектры
|
||||
let plot_FreqResp = gtl.plots.add("Частотный отклик"); // частотный отклик между каналами 0 и n
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_j = gtl.plots.add("Частотный отклик по каналам"); // спектры по каналам вибрации
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
// Спектр для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_1
|
||||
let ausp_acсel_1 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[1].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_2
|
||||
let ausp_acсel_2 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[2].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_3
|
||||
let ausp_acсel_3 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[3].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_4
|
||||
let ausp_acсel_4 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[4].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_5
|
||||
let ausp_acсel_5 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[5].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_6
|
||||
let ausp_acсel_6 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[6].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_7
|
||||
let ausp_acсel_7 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[7].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_8
|
||||
let ausp_acсel_8 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[8].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_9
|
||||
let ausp_acсel_9 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[9].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_10
|
||||
let ausp_acсel_10 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[10].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_11
|
||||
let ausp_acсel_11 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[11].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
// Канал_12
|
||||
let ausp_acсel_12 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[12].portNumber], // сигнал вибрации сырой
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": gtl.spec.unit
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_acсel_1.acq_time,
|
||||
ausp_force_0.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_0.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
// Канал_0 (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
for (let j = 0; j < ausp_j.length; j++) {
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1}`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data
|
||||
}
|
||||
);
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[0] & Канал[j]
|
||||
ausp_cross_real[j] = [];
|
||||
ausp_cross_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
freq_resp_real[j] = [];
|
||||
freq_resp_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1}`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика"]
|
||||
});
|
||||
plot_FreqResp_j.add(
|
||||
{
|
||||
color: 0xb6306f,
|
||||
name: `Фаза частотного отклика канала ${j+1}`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_phase[j],
|
||||
tags: ["Фаза частотного отклика"]
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// #b6306f - жёлтый
|
||||
|
||||
counter += 1;
|
||||
|
||||
|
||||
// Получение массивов для формулы определения частотного отклика
|
||||
|
||||
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал_0 & Канал_1
|
||||
let ausp_cross_0_1_real = []; // действительная часть кросс-спектра 0 & 1
|
||||
let ausp_cross_0_1_imag = []; // мнимая часть кросс-спектра 0 & 1
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_1_real.push(ausp_acсel_1.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_1.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_1_imag.push(ausp_acсel_1.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_1.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_2
|
||||
let ausp_cross_0_2_real = []; // действительная часть кросс-спектра 0 & 2
|
||||
let ausp_cross_0_2_imag = []; // мнимая часть кросс-спектра 0 & 2
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_2_real.push(ausp_acсel_2.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_2.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_2_imag.push(ausp_acсel_2.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_2.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_3
|
||||
let ausp_cross_0_3_real = []; // действительная часть кросс-спектра 0 & 3
|
||||
let ausp_cross_0_3_imag = []; // мнимая часть кросс-спектра 0 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_3_real.push(ausp_acсel_3.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_3.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_3_imag.push(ausp_acсel_3.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_3.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_4
|
||||
let ausp_cross_0_4_real = []; // действительная часть кросс-спектра 0 & 4
|
||||
let ausp_cross_0_4_imag = []; // мнимая часть кросс-спектра 0 & 4
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_4_real.push(ausp_acсel_4.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_4.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_4_imag.push(ausp_acсel_4.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_4.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_5
|
||||
let ausp_cross_0_5_real = []; // действительная часть кросс-спектра 0 & 5
|
||||
let ausp_cross_0_5_imag = []; // мнимая часть кросс-спектра 0 & 5
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_5_real.push(ausp_acсel_5.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_5.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_5_imag.push(ausp_acсel_5.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_5.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_6
|
||||
let ausp_cross_0_6_real = []; // действительная часть кросс-спектра 0 & 6
|
||||
let ausp_cross_0_6_imag = []; // мнимая часть кросс-спектра 0 & 6
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_6_real.push(ausp_acсel_6.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_6.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_6_imag.push(ausp_acсel_6.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_6.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_7
|
||||
let ausp_cross_0_7_real = []; // действительная часть кросс-спектра 0 & 7
|
||||
let ausp_cross_0_7_imag = []; // мнимая часть кросс-спектра 0 & 7
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_7_real.push(ausp_acсel_7.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_7.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_7_imag.push(ausp_acсel_7.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_7.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_8
|
||||
let ausp_cross_0_8_real = []; // действительная часть кросс-спектра 0 & 8
|
||||
let ausp_cross_0_8_imag = []; // мнимая часть кросс-спектра 0 & 8
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_8_real.push(ausp_acсel_8.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_8.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_8_imag.push(ausp_acсel_8.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_8.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_9
|
||||
let ausp_cross_0_9_real = []; // действительная часть кросс-спектра 0 & 9
|
||||
let ausp_cross_0_9_imag = []; // мнимая часть кросс-спектра 0 & 9
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_9_real.push(ausp_acсel_9.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_9.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_9_imag.push(ausp_acсel_9.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_9.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_10
|
||||
let ausp_cross_0_10_real = []; // действительная часть кросс-спектра 0 & 10
|
||||
let ausp_cross_0_10_imag = []; // мнимая часть кросс-спектра 0 & 10
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_10_real.push(ausp_acсel_10.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_10.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_10_imag.push(ausp_acсel_10.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_10.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_11
|
||||
let ausp_cross_0_11_real = []; // действительная часть кросс-спектра 0 & 11
|
||||
let ausp_cross_0_11_imag = []; // мнимая часть кросс-спектра 0 & 11
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_11_real.push(ausp_acсel_11.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_11.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_11_imag.push(ausp_acсel_11.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_11.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
// Канал_0 & Канал_12
|
||||
let ausp_cross_0_12_real = []; // действительная часть кросс-спектра 0 & 12
|
||||
let ausp_cross_0_12_imag = []; // мнимая часть кросс-спектра 0 & 12
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_12_real.push(ausp_acсel_12.real[i] * ausp_force_0.real[i] -
|
||||
(ausp_acсel_12.imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_0_12_imag.push(ausp_acсel_12.real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_acсel_12.imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал_0 & Канал_1) / Канал_0
|
||||
let freq_resp_0_1_real = []; // действительная часть частотного отклика между 0 и 1
|
||||
let freq_resp_0_1_imag = []; // мнимая часть частотного отклика между 0 и 1
|
||||
let freq_resp_0_1_ampl = []; // амплитуда частотного отклика между 0 и 1
|
||||
let freq_resp_0_1_phase = []; // фаза частотного отклика между 0 и 1
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_1_real.push((ausp_cross_0_1_real[i] * ausp_force_0.real[i] +
|
||||
ausp_cross_0_1_imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_0_1_imag.push((ausp_force_0.real[i] * ausp_cross_0_1_imag[i] -
|
||||
ausp_cross_0_1_real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_1_ampl.push(Math.sqrt(Math.pow(freq_resp_0_1_real[i],2) + Math.pow(freq_resp_0_1_imag[i],2)));
|
||||
if (freq_resp_0_1_real[i] > 0 & freq_resp_0_1_imag[i] > 0)
|
||||
{freq_resp_0_1_phase.push(Math.atan(freq_resp_0_1_imag[i] / freq_resp_0_1_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_1_real[i] < 0 & freq_resp_0_1_imag[i] > 0)
|
||||
{freq_resp_0_1_phase.push(180 - Math.atan(freq_resp_0_1_imag[i] / freq_resp_0_1_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_1_real[i] < 0 & freq_resp_0_1_imag[i] < 0)
|
||||
{freq_resp_0_1_phase.push(180 + Math.atan(freq_resp_0_1_imag[i] / freq_resp_0_1_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_1_real[i] > 0 & freq_resp_0_1_imag[i] < 0)
|
||||
{freq_resp_0_1_phase.push(360 - Math.atan(freq_resp_0_1_imag[i] / freq_resp_0_1_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_0_1_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_0_1_phase[i] >= 360)
|
||||
{freq_resp_0_1_phase[i] = freq_resp_0_1_phase[i] - 360}
|
||||
else {freq_resp_0_1_phase[i] = freq_resp_0_1_phase[i]}
|
||||
}
|
||||
|
||||
// (Канал_0 & Канал_2) / Канал_0
|
||||
let freq_resp_0_2_real = []; // действительная часть частотного отклика между 0 и 2
|
||||
let freq_resp_0_2_imag = []; // мнимая часть частотного отклика между 0 и 2
|
||||
let freq_resp_0_2_ampl = []; // амплитуда частотного отклика между 0 и 2
|
||||
let freq_resp_0_2_phase = []; // фаза частотного отклика между 0 и 2
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_2_real.push((ausp_cross_0_2_real[i] * ausp_force_0.real[i] +
|
||||
ausp_cross_0_2_imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_0_2_imag.push((ausp_force_0.real[i] * ausp_cross_0_2_imag[i] -
|
||||
ausp_cross_0_2_real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_2_ampl.push(Math.sqrt(Math.pow(freq_resp_0_2_real[i],2) + Math.pow(freq_resp_0_2_imag[i],2)));
|
||||
if (freq_resp_0_2_real[i] > 0 & freq_resp_0_2_imag[i] > 0)
|
||||
{freq_resp_0_2_phase.push(Math.atan(freq_resp_0_2_imag[i] / freq_resp_0_2_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_2_real[i] < 0 & freq_resp_0_2_imag[i] > 0)
|
||||
{freq_resp_0_2_phase.push(180 - Math.atan(freq_resp_0_2_imag[i] / freq_resp_0_2_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_2_real[i] < 0 & freq_resp_0_2_imag[i] < 0)
|
||||
{freq_resp_0_2_phase.push(180 + Math.atan(freq_resp_0_2_imag[i] / freq_resp_0_2_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_2_real[i] > 0 & freq_resp_0_2_imag[i] < 0)
|
||||
{freq_resp_0_2_phase.push(360 - Math.atan(freq_resp_0_2_imag[i] / freq_resp_0_2_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_0_2_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_0_2_phase[i] >= 360)
|
||||
{freq_resp_0_2_phase[i] = freq_resp_0_2_phase[i] - 360}
|
||||
else {freq_resp_0_2_phase[i] = freq_resp_0_2_phase[i]}
|
||||
}
|
||||
|
||||
// (Канал_0 & Канал_3) / Канал_0
|
||||
let freq_resp_0_3_real = []; // действительная часть частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_imag = []; // мнимая часть частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_ampl = []; // амплитуда частотного отклика между 0 и 3
|
||||
let freq_resp_0_3_phase = []; // фаза частотного отклика между 0 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_real.push((ausp_cross_0_3_real[i] * ausp_force_0.real[i] +
|
||||
ausp_cross_0_3_imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_0_3_imag.push((ausp_force_0.real[i] * ausp_cross_0_3_imag[i] -
|
||||
ausp_cross_0_3_real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_ampl.push(Math.sqrt(Math.pow(freq_resp_0_3_real[i],2) + Math.pow(freq_resp_0_3_imag[i],2)));
|
||||
if (freq_resp_0_3_real[i] > 0 & freq_resp_0_3_imag[i] > 0)
|
||||
{freq_resp_0_3_phase.push(Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] < 0 & freq_resp_0_3_imag[i] > 0)
|
||||
{freq_resp_0_3_phase.push(180 - Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] < 0 & freq_resp_0_3_imag[i] < 0)
|
||||
{freq_resp_0_3_phase.push(180 + Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_0_3_real[i] > 0 & freq_resp_0_3_imag[i] < 0)
|
||||
{freq_resp_0_3_phase.push(360 - Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_0_3_phase.length; i += 1)
|
||||
{
|
||||
if (freq_resp_0_3_phase[i] >= 360)
|
||||
{freq_resp_0_3_phase[i] = freq_resp_0_3_phase[i] - 360}
|
||||
else {freq_resp_0_3_phase[i] = freq_resp_0_3_phase[i]}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Построение пользовательских графиков
|
||||
|
||||
// plot_ausp.add(
|
||||
// {
|
||||
// color: 0x04ff00,
|
||||
// name: "Спектр ускорения (канал 1)",
|
||||
// x: 1/lines,
|
||||
// y: ausp_acсel_1.data
|
||||
// });
|
||||
|
||||
// plot_ausp.add(
|
||||
// {
|
||||
// color: 0xcad714,
|
||||
// name: "Спектр ускорения (канал 2)",
|
||||
// x: 1/lines,
|
||||
// y: ausp_acсel_2.data
|
||||
// });
|
||||
|
||||
// plot_ausp.add(
|
||||
// {
|
||||
// color: 0xff8800,
|
||||
// name: "Спектр ускорения (канал 3)",
|
||||
// x: 1/lines,
|
||||
// y: ausp_acсel_2.data
|
||||
// });
|
||||
|
||||
plot_ausp.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал 0)",
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data
|
||||
});
|
||||
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0x04ff00,
|
||||
name: "Амплитуда частотного отклика (каналы 0 и 1)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_1_ampl
|
||||
});
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0x04ff00,
|
||||
name: "Фаза частотного отклика (каналы 0 и 1)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_1_phase
|
||||
});
|
||||
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0xcad714,
|
||||
name: "Амплитуда частотного отклика (каналы 0 и 2)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_2_ampl
|
||||
});
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0xcad714,
|
||||
name: "Фаза частотного отклика (каналы 0 и 2)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_2_phase
|
||||
});
|
||||
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0xff8800,
|
||||
name: "Амплитуда частотного отклика (каналы 0 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_3_ampl
|
||||
});
|
||||
plot_FreqResp.add(
|
||||
{
|
||||
color: 0xff8800,
|
||||
name: "Фаза частотного отклика (каналы 0 и 3)",
|
||||
x: 1/lines,
|
||||
y: freq_resp_0_3_phase
|
||||
});
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_j = gtl.plots.add("Частотный отклик по каналам"); // спектры по каналам вибрации
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"src1" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_force_0.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_0.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналами вибрации и силы
|
||||
for (let j = 0; j < ausp_j.length; j++) {
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1}`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации"]
|
||||
}
|
||||
);
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x00ddff,
|
||||
name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
x: phase_delta_j[j].resolution,
|
||||
y: phase_delta_j[j].data,
|
||||
tags: ["Разница фаз вибрации и силы"]
|
||||
}
|
||||
);
|
||||
plot_FreqResp_j.add(
|
||||
{
|
||||
color: 0x00ddff,
|
||||
name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
x: phase_delta_j[j].resolution,
|
||||
y: phase_delta_j[j].data,
|
||||
tags: ["Разница фаз вибрации и силы"]
|
||||
}
|
||||
);
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[0] & Канал[j]
|
||||
ausp_cross_real[j] = [];
|
||||
ausp_cross_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
freq_resp_real[j] = [];
|
||||
freq_resp_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1}`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика"]
|
||||
});
|
||||
plot_FreqResp_j.add(
|
||||
{
|
||||
color: 0xb6306f,
|
||||
name: `Фаза частотного отклика канала ${j+1}`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_phase[j],
|
||||
tags: ["Фаза частотного отклика"]
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// #b6306f - жёлтый
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал [0])",
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: ["Спектр силы (канал [0])"]
|
||||
});
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"src1" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_force_0.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_0.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналами вибрации и силы
|
||||
for (let j = 0; j < ausp_j.length; j++) {
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1}`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации"]
|
||||
}
|
||||
);
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x00ddff,
|
||||
name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
x: phase_delta_j[j].resolution,
|
||||
y: phase_delta_j[j].data,
|
||||
tags: ["Разница фаз вибрации и силы"]
|
||||
}
|
||||
);
|
||||
plot_FreqResp_phase_j.add(
|
||||
{
|
||||
color: 0x00ddff,
|
||||
name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
x: phase_delta_j[j].resolution,
|
||||
y: phase_delta_j[j].data,
|
||||
tags: ["Разница фаз вибрации и силы"]
|
||||
}
|
||||
);
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[0] & Канал[j]
|
||||
ausp_cross_real[j] = [];
|
||||
ausp_cross_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
freq_resp_real[j] = [];
|
||||
freq_resp_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_force_0.real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1}`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика"]
|
||||
});
|
||||
// plot_FreqResp_phase_j.add(
|
||||
// {
|
||||
// color: 0xb6306f,
|
||||
// name: `Фаза частотного отклика канала ${j+1}`,
|
||||
// x: 1/lines,
|
||||
// y: freq_resp_phase[j],
|
||||
// tags: ["Фаза частотного отклика"]
|
||||
// });
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// #b6306f - жёлтый
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал [0])",
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: ["Спектр силы (канал [0])"]
|
||||
});
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"src1" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_force_0.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_0.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналами вибрации и силы
|
||||
for (let j = 0; j < ausp_j.length; j++) {
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1}, g`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
}
|
||||
);
|
||||
// plot_ausp_j.add(
|
||||
// {
|
||||
// color: 0x00ddff,
|
||||
// name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
// x: phase_delta_j[j].resolution,
|
||||
// y: phase_delta_j[j].data,
|
||||
// tags: ["Разница фаз вибрации и силы"]
|
||||
// }
|
||||
// );
|
||||
// plot_FreqResp_phase_j.add(
|
||||
// {
|
||||
// color: 0x00ddff,
|
||||
// name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
// x: phase_delta_j[j].resolution,
|
||||
// y: phase_delta_j[j].data,
|
||||
// tags: ["Разница фаз вибрации и силы"]
|
||||
// }
|
||||
// );
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[0] & Канал[j]
|
||||
ausp_cross_real[j] = [];
|
||||
ausp_cross_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
|
||||
freq_resp_real[j] = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag[j] = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Частотный отклик (деление спектра вибрации на спектр силы)
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_j[j].real[i] * ausp_force_0.real[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_j[j].imag[i] -
|
||||
ausp_j[j].real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
plot_FreqResp_phase_j.add(
|
||||
{
|
||||
color: 0xb6306f,
|
||||
name: `Фаза частотного отклика канала ${j+1}, °`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_phase[j],
|
||||
tags: ["Фаза частотного отклика, °"]
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// #b6306f - жёлтый
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал [0]), N",
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: ["Спектр силы (канал [0]), N"]
|
||||
});
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.custom_ranges;
|
||||
// ranges.custom_ranges = [{min : 0.0172949, max: 0.4528125}, ranges[0]];
|
||||
// gtl.player.custom_ranges = [gtl.player.stored_ranges[1,2,3]];
|
||||
gtl.log.info("Количество выделенных диапазонов", gtl.player.stored_ranges.length);
|
||||
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"src1" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_force_0.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
// gtl.log.info("ranges", JSON.stringify(ranges));
|
||||
// gtl.log.info("ranges", JSON.stringify(gtl.player.stored_ranges));
|
||||
|
||||
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_0.data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналами вибрации и силы
|
||||
for (let j = 0; j < ausp_j.length; j++) {
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1}, g`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
}
|
||||
);
|
||||
// plot_ausp_j.add(
|
||||
// {
|
||||
// color: 0x00ddff,
|
||||
// name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
// x: phase_delta_j[j].resolution,
|
||||
// y: phase_delta_j[j].data,
|
||||
// tags: ["Разница фаз вибрации и силы"]
|
||||
// }
|
||||
// );
|
||||
// plot_FreqResp_phase_j.add(
|
||||
// {
|
||||
// color: 0x00ddff,
|
||||
// name: `Разница фаз канала ${j+1} и канала силы`,
|
||||
// x: phase_delta_j[j].resolution,
|
||||
// y: phase_delta_j[j].data,
|
||||
// tags: ["Разница фаз вибрации и силы"]
|
||||
// }
|
||||
// );
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[0] & Канал[j]
|
||||
ausp_cross_real[j] = [];
|
||||
ausp_cross_imag[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
|
||||
freq_resp_real[j] = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag[j] = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Частотный отклик (деление спектра вибрации на спектр силы)
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_j[j].real[i] * ausp_force_0.real[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_j[j].imag[i] -
|
||||
ausp_j[j].real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
plot_FreqResp_phase_j.add(
|
||||
{
|
||||
color: 0xb6306f,
|
||||
name: `Фаза частотного отклика канала ${j+1}, °`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_phase[j],
|
||||
tags: ["Фаза частотного отклика, °"]
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// #b6306f - жёлтый
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал [0]), N",
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: ["Спектр силы (канал [0]), N"]
|
||||
});
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
// let fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
let plot_ausp_vibr = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let ausp_vibr = []; // массив объектов спектров вибрации
|
||||
let ausp_force = []; // массив объектов спектров силы по диапазонам [k]
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.custom_ranges;
|
||||
// ranges.custom_ranges = [{min : 0.0172949, max: 0.4528125}, ranges[0]];
|
||||
// gtl.player.custom_ranges = [gtl.player.stored_ranges[1,2,3]];
|
||||
gtl.log.info("Количество выделенных диапазонов", gtl.player.stored_ranges.length);
|
||||
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество каналов кроме силы", signals.length - 1);
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
|
||||
for (let k = 0; k < gtl.player.stored_ranges.length; k++) { // цикл по диапазонам
|
||||
ausp_vibr[k] = [];
|
||||
for (let j = 1; j < signals.length; j++) { // цикл по каналам
|
||||
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
ausp_vibr.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (let k = 0; k < gtl.player.stored_ranges.length; k++) { // цикл по диапазонам
|
||||
// Спектр силы (канал сигнала молотка) канал [0]
|
||||
ausp_force.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
gtl.log.info("Количество спектров вибрации", ausp_vibr.length);
|
||||
gtl.log.info("Количество спектров силы", ausp_force.length);
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_force[0].acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
gtl.log.info("acq_time", acq_time);
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
// gtl.log.info("ranges", JSON.stringify(ranges));
|
||||
// gtl.log.info("ranges", JSON.stringify(gtl.player.stored_ranges));
|
||||
|
||||
|
||||
|
||||
// Графики амплитудных спектров вибрации
|
||||
for (let k = 0; k < gtl.player.stored_ranges.length; k++) {
|
||||
if (counter_ranges > 0) {
|
||||
for (let j = 0; j < ausp_vibr.length; j++) {
|
||||
if (counter > 0) {
|
||||
|
||||
// plot_ausp_vibr.add(
|
||||
// {
|
||||
// color: 0x34C924,
|
||||
// name: `Спектр канала ${j+1} диапазона ${k}, g`,
|
||||
// x: ausp_vibr[k][j].resolution,
|
||||
// y: ausp_vibr[k][j].data,
|
||||
// tags: ["Амплитудный спектр вибрации, g"]
|
||||
// }
|
||||
// );
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
counter += 1;
|
||||
gtl.log.info("ausp_force[k].length", ausp_force[0].length);
|
||||
plot_ausp_vibr.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал [0]), N",
|
||||
x: 1/lines,
|
||||
y: ausp_force[k].data,
|
||||
tags: ["Спектр силы (канал [0]), N"]
|
||||
});
|
||||
}
|
||||
};
|
||||
counter_ranges += 1;
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
"use strict";
|
||||
|
||||
let signals = gtl.options.record.signalsModel;
|
||||
let options = gtl.options;
|
||||
let record = gtl.options.record;
|
||||
let point = gtl.options.point;
|
||||
|
||||
let plot_ausp_j = gtl.plots.add("Спектры по каналам"); // спектры по каналам вибрации
|
||||
let plot_FreqResp_ampl_j = gtl.plots.add("Частотный отклик по каналам (амплитуда)"); // амплитудные спектры по каналам вибрации
|
||||
let plot_FreqResp_phase_j = gtl.plots.add("Частотный отклик по каналам (фаза)"); // фазовые спектры по каналам вибрации
|
||||
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// Настройки для спектров и АФЧХ
|
||||
// let signal_force = gtl.options.customOptions.force; // номер канала силы (молотка)
|
||||
let frequency = gtl.options.customOptions.frequency; // граничная частота
|
||||
let resolution = gtl.options.customOptions.resolution; // частотное разрешение
|
||||
let lines = 1 / resolution; // количество линий
|
||||
let average = gtl.options.customOptions.average; // количество усреднений
|
||||
let overlap = gtl.options.customOptions.overlap; // наложение
|
||||
let view_ = gtl.options.customOptions.view; // отображение амплитуды спектра db / unit (1 / 0)
|
||||
let view = gtl.spec.unit; // значение view по умолчанию
|
||||
let view_freq_resp = gtl.options.customOptions.view_freq_resp; // отображение амплитуды спектра частотного отклика db / unit (1 / 0)
|
||||
let variant_freq_resp = gtl.options.customOptions.variant_freq_resp; // вариант вычисления: 0 - через кросс, 1 - через автоспектр
|
||||
let ausp_vibr = []; // массив объектов спектров вибрации
|
||||
let ausp_force = []; // массив объектов спектров силы по диапазонам [k]
|
||||
let ausp_j = []; // массив объектов спектров вибрации
|
||||
let phase_delta_j = []; // массив объектов дельты фазовых спектров вибрации и спектра силы
|
||||
let counter = 1; // счётчик для цикла по каналам вибрации
|
||||
let counter_ranges = 0; // счётчик для цикла по выделенным диапазонам сигналов записи
|
||||
let ausp_cross_real = []; // массив объектов действительной части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let ausp_cross_imag = []; // массив объектов мнимой части кросс-спектров канала силы [0] и канала вибрации [j]
|
||||
let freq_resp_real = []; // действительная часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_imag = []; // мнимая часть частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_ampl = []; // амплитуда частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
let freq_resp_phase = []; // фаза частотного отклика между каналом силы [0] и каналом вибрации [j]
|
||||
|
||||
|
||||
// Задание диапазона сигнала для анализа
|
||||
// let ranges = gtl.player.stored_ranges;
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
gtl.log.info("Количество сигналов", signals.length);
|
||||
|
||||
gtl.log.info("Граничная частота спектров", frequency);
|
||||
gtl.log.info("Частотное разрешение спектров", resolution);
|
||||
|
||||
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_ == 1) {view = gtl.spec.db}
|
||||
else if (view_ == 0) {view = gtl.spec.unit}
|
||||
|
||||
|
||||
for (let j = 1; j < signals.length; j++) {
|
||||
|
||||
// Спектр амплитудный для цикла по всем каналам вибрации
|
||||
ausp_j.push(
|
||||
gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Спектр фазовый для цикла по всем каналам вибрации
|
||||
phase_delta_j.push(
|
||||
gtl.create_pfc(
|
||||
{
|
||||
"src0" : gtl.analog_inputs[signals[0].portNumber], // сигнал силы, относительно него вычисляем дельту фазы
|
||||
"src1" : gtl.analog_inputs[signals[j].portNumber], // сигнал вибрации
|
||||
"frequency" : frequency,
|
||||
"resolution" : resolution,
|
||||
"average" : average,
|
||||
"overlap" : overlap,
|
||||
"window" : gtl.spec.rectangular,
|
||||
"view" : gtl.phase.deg,
|
||||
"range" : gtl.phase.positive,
|
||||
"is_single" : false
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gtl.log.info("Количество спектров", ausp_j.length);
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_0
|
||||
let ausp_force_0 = gtl.create_ausp(
|
||||
{
|
||||
"src": gtl.analog_inputs[signals[0].portNumber], // сигнал силы
|
||||
"frequency": frequency,
|
||||
"resolution": resolution,
|
||||
"average": average,
|
||||
"overlap": overlap,
|
||||
"window": gtl.spec.rectangular,
|
||||
"view": view
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let src_force = gtl.analog_inputs[0]; // источник сигнала силы
|
||||
let time = gtl.options.record.playerTime; // время записи для анализа
|
||||
let time_window = 0.02 // временное окно наблюдения
|
||||
// let time_impulse = ausp_force_0.acq_time + 0.05; // временное окно для анализа импульса (не менее времени построения спектра)
|
||||
let time_impulse = gtl.acq_time + 0.05;
|
||||
let time_pre = time_window / 2; // время предыстории
|
||||
let ranges = []; // массив диапазонов для импульсов
|
||||
let tries = 0; // циклы диагностки
|
||||
let is_ranges = false; // состояние готовности диапазонов
|
||||
gtl.log.info("time_impulse", time_impulse);
|
||||
gtl.log.info("Длина массива спектра", ausp_force_0.data.length);
|
||||
|
||||
// Скользящая амплитуда для создания "огибающей" импульса
|
||||
let __max = gtl.create_moving_max({
|
||||
src: src_force,
|
||||
name: "max",
|
||||
time: time_window
|
||||
});
|
||||
__max.history = 2; //история сохраненных данных сигнала
|
||||
|
||||
// Порог для олтслеживание импульсов
|
||||
let __thresh = gtl.create_moving_thresh({
|
||||
src: __max,
|
||||
name: "thresh",
|
||||
time: time_window,
|
||||
level: 1
|
||||
});
|
||||
__thresh.history = 2; // история сохраненных данных сигнала
|
||||
|
||||
|
||||
__thresh.triggered.connect(thresh_triggered_event); //подключаем функцию
|
||||
// Функция получения диапазонов импульсов
|
||||
function thresh_triggered_event(flag, sample) {
|
||||
if (is_ranges) return;
|
||||
if (flag) {
|
||||
let start = (sample / __thresh.rate) - time_pre; //время срабатывания триггера
|
||||
gtl.log.info("trigger on time", start);
|
||||
|
||||
let range = {
|
||||
min: start,
|
||||
max: start + time_impulse
|
||||
};
|
||||
ranges.push(range); //добавляем диапазон в массив
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Функция диагностики.
|
||||
/*
|
||||
Первый запуск функции диагностики происходит после проигрывания всего сигнала и определения массива диапазонов по срабатыванию триггера
|
||||
После этого происходит добавление массива пользовательских диапазонов в плеер, отрисовка (при необходимости) сигнала триггера
|
||||
Затем устанавливается интервал запуска функции диагностики, равный временному окну для анализа импульса и запускается отсчет циклов (попыток) диагностики
|
||||
Как только количество циклов (попыток) сравнивается с количеством установленных пользовательских диапазонов, диагностика останавливается
|
||||
*/
|
||||
|
||||
gtl.diagnostic.interval = time; // интервал запуска функции диагностики
|
||||
let plot = gtl.plots.add("Impulses"); // создаем координатную плоскость
|
||||
function diagnose() {
|
||||
if (tries >= ranges.length) gtl.diagnostic.stop();
|
||||
if (!is_ranges) {
|
||||
gtl.player.custom_ranges = ranges; // добавляем пользовательские диапазоны в плеер
|
||||
gtl.results = { ranges: ranges }; // добавляем диапазоны в результат
|
||||
gtl.log.info('creating ranges', true);
|
||||
gtl.log.info('ranges', JSON.stringify(ranges));
|
||||
is_ranges = true; // пользовательские диапазоны готовы
|
||||
|
||||
plot.add({
|
||||
color: 0x0000ff, // цвет графика
|
||||
name: "max", // наименование графика
|
||||
x: 1 / __max.rate, // частотное разрешение
|
||||
y: __max.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
|
||||
plot.add({
|
||||
color: 0xff00ff, // цвет графика
|
||||
name: "thresh", // наименование графика
|
||||
x: 1 / __thresh.rate, // частотное разрешение
|
||||
y: __thresh.getHistoryArray() // значения амплитуд
|
||||
}); // рисуем сигнал для контроля
|
||||
}
|
||||
|
||||
gtl.diagnostic.interval = time_impulse; // задаем время запуска функции диагностики, равное длине импульса
|
||||
if (tries == 0) { gtl.log.info("Установленный интервал запуска диагностики", time_impulse) }
|
||||
else { gtl.log.info('diagnostic', `Цикл диагностики ${tries} - ${true}`) }
|
||||
|
||||
/*
|
||||
Математика обработки сигнала
|
||||
*/
|
||||
let n = ausp_force_0.data.length; // переменная для цикла по гармоникам спектра
|
||||
// signals.length - переменная для цикла по каналам
|
||||
|
||||
// Канал[0] (ausp_force_0) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
let ausp_force_0_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_0_imag_anti.push(ausp_force_0.imag[i] * (-1));
|
||||
}
|
||||
|
||||
// Графики амплитудных спектров вибрации и спектров дельты фаз между каналом силы и вибрации
|
||||
for (let k = 0; k < ranges.length; k++) { // цикл по ударам (сначала по ударам, потом по каналам)
|
||||
for (let j = 0; j < ausp_j.length; j++) { // цикл по каналам
|
||||
if (counter > 0) {
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0x34C924,
|
||||
name: `Спектр канала ${j+1} - удар ${k+1}, g`,
|
||||
x: ausp_j[j].resolution,
|
||||
y: ausp_j[j].data,
|
||||
tags: ["Амплитудный спектр вибрации, g"]
|
||||
});
|
||||
|
||||
|
||||
// Кросс-спектры
|
||||
// Канал[j] & Канал[0]
|
||||
// сигнал силы в комплексно-сопряжённом виде
|
||||
// сигнал вибрации умножвается на сигнал силы, а НЕ наоборот
|
||||
// умножение комплексных чисел по формуле:
|
||||
// (a1+b1i)*(a2+b2i)=(a1*a2-b1*b2)*(a1*b2+b1*a2)i
|
||||
// (a1*a2-b1*b2) - действительная часть
|
||||
// (a1*b2+b1*a2)i - мнимая часть
|
||||
ausp_cross_real[j] = []; // массив действительной части кросс-спектра
|
||||
ausp_cross_imag[j] = []; // массив мнимой части кросс-спектра
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_real[j].push(ausp_j[j].real[i] * ausp_force_0.real[i] -
|
||||
(ausp_j[j].imag[i] * ausp_force_0_imag_anti[i]));
|
||||
ausp_cross_imag[j].push(ausp_j[j].real[i] * ausp_force_0_imag_anti[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.real[i]);
|
||||
}
|
||||
|
||||
// Вычисление частотного отклика
|
||||
// деление комплексных чисел по формуле:
|
||||
// (a+bi)/(c+di)=(a*c-b*d)*(a*d+b*c)i
|
||||
// (a*c-b*d) - действительная часть
|
||||
// (a*d+b*c)i - мнимая часть
|
||||
freq_resp_real[j] = []; // массив массивов действительной части отклика
|
||||
freq_resp_imag[j] = []; // массив массивов мнимой части отклика
|
||||
if (variant_freq_resp == 0)
|
||||
{
|
||||
// Вариант 1: Частотный отклик как деление кросс-спектра вибрации и силы на автоспектр силы
|
||||
// (Канал[0] & Канал[j]) / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_cross_real[j][i] * ausp_force_0.real[i] +
|
||||
ausp_cross_imag[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_cross_imag[j][i] -
|
||||
ausp_cross_real[j][i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_cross_real[j][i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
} else {
|
||||
// Вариант 2: Частотный отклик как деление автоспектра вибрации на автоспектр силы
|
||||
// Канал[j] / Канал[0]
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_real[j].push((ausp_j[j].real[i] * ausp_force_0.real[i] +
|
||||
ausp_j[j].imag[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
|
||||
freq_resp_imag[j].push((ausp_force_0.real[i] * ausp_j[j].imag[i] -
|
||||
ausp_j[j].real[i] * ausp_force_0.imag[i]) /
|
||||
(Math.pow(ausp_j[j].real[i], 2) + Math.pow(ausp_force_0.imag[i], 2)));
|
||||
}
|
||||
}
|
||||
|
||||
// запись массива амплитуды и фазы
|
||||
freq_resp_ampl[j] = [];
|
||||
freq_resp_phase[j] = [];
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
// Условие отображения спектров в дБ или линейном виде
|
||||
if (view_freq_resp == 0) {
|
||||
freq_resp_ampl[j].push(Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2)));
|
||||
} else if (view_freq_resp == 1) {
|
||||
freq_resp_ampl[j].push(20 * Math.log10((Math.sqrt(Math.pow(freq_resp_real[j][i],2) + Math.pow(freq_resp_imag[j][i],2))) / Math.pow(10,-6)));
|
||||
}
|
||||
if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] > 0)
|
||||
{freq_resp_phase[j].push(180 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] < 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(180 + Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
else if (freq_resp_real[j][i] > 0 & freq_resp_imag[j][i] < 0)
|
||||
{freq_resp_phase[j].push(360 - Math.atan(freq_resp_imag[j][i] / freq_resp_real[j][i]) * 180 / Math.PI)}
|
||||
}
|
||||
// корректировка угла для предотвращения превышения 360 град
|
||||
for (let i = 0; i < freq_resp_phase[j].length; i += 1)
|
||||
{
|
||||
if (freq_resp_phase[j][i] >= 360)
|
||||
{freq_resp_phase[j][i] = freq_resp_phase[j][i] - 360}
|
||||
else {freq_resp_phase[j][i] = freq_resp_phase[j][i]}
|
||||
}
|
||||
|
||||
plot_FreqResp_ampl_j.add(
|
||||
{
|
||||
color: 0x3b30b6,
|
||||
name: `Амплитуда частотного отклика канала ${j+1} - удар ${k+1}, g/N`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_ampl[j],
|
||||
tags: ["Амплитуда частотного отклика, g/N"]
|
||||
});
|
||||
plot_FreqResp_phase_j.add(
|
||||
{
|
||||
color: 0xb6306f,
|
||||
name: `Фаза частотного отклика канала ${j+1} - удар ${k+1}, °`,
|
||||
x: 1/lines,
|
||||
y: freq_resp_phase[j],
|
||||
tags: ["Фаза частотного отклика, °"]
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
counter += 1;
|
||||
|
||||
plot_ausp_j.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: `Спектр силы (канал [0]) - удар ${k+1}, N`,
|
||||
x: 1/lines,
|
||||
y: ausp_force_0.data,
|
||||
tags: [`Спектр силы (канал [0]) - удар ${k+1}, N`]
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
tries++;
|
||||
}
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
"use strict";
|
||||
|
||||
var signals = gtl.options.record.signalsModel;
|
||||
var options = gtl.options;
|
||||
var record = gtl.options.record;
|
||||
var point = gtl.options.point;
|
||||
|
||||
var fnc = gtl.import("user-functions.js"); // используемые функции
|
||||
|
||||
var plot_0 = gtl.plots.add("Спектр ускорения (канал 0)"); // спектр ускорения канала 0
|
||||
var plot_1 = gtl.plots.add("Спектр ускорения (канал 1)"); // спектр ускорения канала 1
|
||||
var plot_2 = gtl.plots.add("Спектр ускорения (канал 2)"); // спектр ускорения канала 2
|
||||
var plot_3 = gtl.plots.add("Спектр силы (канал 3)"); // спектр ускорения канала 3
|
||||
var plot_FreqResp_ampl_0_3 = gtl.plots.add("Частотный отклик (каналы 0 и 3)"); // частотный отклик между каналами 0 и 3 (действительная часть)
|
||||
var plot_FreqResp_ampl_1_3 = gtl.plots.add("Частотный отклик (каналы 1 и 3)"); // частотный отклик между каналами 1 и 3 (действительная часть)
|
||||
var plot_FreqResp_ampl_2_3 = gtl.plots.add("Частотный отклик (каналы 2 и 3)"); // частотный отклик между каналами 2 и 3 (действительная часть)
|
||||
var plot_FreqResp_phase_0_3 = gtl.plots.add("Фаза частотного отклика (каналы 0 и 3)"); // частотный отклик между каналами 0 и 3 (мнимая часть)
|
||||
var plot_FreqResp_phase_1_3 = gtl.plots.add("Фаза частотного отклика (каналы 1 и 3)"); // частотный отклик между каналами 1 и 3 (мнимая часть)
|
||||
var plot_FreqResp_phase_2_3 = gtl.plots.add("Фаза частотного отклика (каналы 2 и 3)");; // частотный отклик между каналами 2 и 3 (мнимая часть)
|
||||
|
||||
// ***************************************************************
|
||||
// ********** ВЫЧИСЛЕНИЕ ЧАСТОТНОГО ОТКЛИКА (ВНИИЖТ) ***********
|
||||
// ***************************************************************
|
||||
|
||||
// Алгоритм
|
||||
// 1. Получить спектры ускорения и силы в комплексном виде (вибропреобразователь и молоток).
|
||||
// 2. Преобразовать спектр силы (молотка) в комплексно-сопряжённый вид.
|
||||
// 3. Получить кросс-спектр (перекрёстный) между ускорением и силой.
|
||||
// 4. Вычислить деление кросс-спектра на спектр силы.
|
||||
|
||||
|
||||
// ОБРАБОТКА СИГНАЛОВ
|
||||
// ФИЛЬТРЫ
|
||||
// Входной сигнал - виброускорение
|
||||
|
||||
// Файл импорта функций
|
||||
// var imp = gtl.import("...");
|
||||
|
||||
// ПАРАМЕТРЫ и их ПОРОГОВЫЕ ЗНАЧЕНИЯ (уставки)
|
||||
|
||||
// Настройки спектров
|
||||
// Цвета
|
||||
// #ff0000 - красный
|
||||
// #00ff00 - зелёный
|
||||
// #0000ff - синий
|
||||
// #00ddff - голубой
|
||||
// #ff3dcc - фиолетовый
|
||||
// #ffff00 - жёлтый
|
||||
|
||||
// Пороги и прочие изменяемые параметры
|
||||
var ausp_frequency = 1000; // граничная частота спектра
|
||||
var ausp_average = 1; // количество усреднений спектра
|
||||
var ausp_lines = 4; // множитель количества линий спектра (на 1 Гц)
|
||||
var ausp_smoothing_factor = 100; // усреднение средней линии
|
||||
var ausp_peak_level = 0.001 // порог обнаружения гармоник РЕДАКТИРОВАТЬ НА РЕАЛЬНЫХ СИГНАЛАХ
|
||||
var ausp_tolerance = 1; // диапазон поиска гармоники по ширине +/- Гц
|
||||
var average = 6; // количество усреднений объекта АФЧХ (когерентность и разница фаз)
|
||||
// var ausp_unit = gtl.spec.db; // отображение амплитуды в дБ
|
||||
var ausp_unit = gtl.spec.unit; // отображение амплитуды в м/с^2
|
||||
|
||||
|
||||
// *** Формирование спектров сигналов ***
|
||||
|
||||
// Спектры каналов ускорения (каналы датчиков вибрации)
|
||||
|
||||
// Канал_0
|
||||
var ausp_acсel_0 = gtl.add_ausp(gtl.analog_inputs[signals[0].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_0.color = 0x04ff00; // цвет спектра
|
||||
ausp_acсel_0.name = "Спектр ускорения (канал 0)"; // имя спектра
|
||||
ausp_acсel_0.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_0.frequency = ausp_frequency;
|
||||
ausp_acсel_0.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_0.average = ausp_average;
|
||||
ausp_acсel_0.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_0.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_0.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_0.peak_level = ausp_peak_level;
|
||||
ausp_acсel_0.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Канал_1
|
||||
var ausp_acсel_1 = gtl.add_ausp(gtl.analog_inputs[signals[1].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_1.color = 0xcad714; // цвет спектра
|
||||
ausp_acсel_1.name = "Спектр ускорения (канал 1)"; // имя спектра
|
||||
ausp_acсel_1.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_1.frequency = ausp_frequency;
|
||||
ausp_acсel_1.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_1.average = ausp_average;
|
||||
ausp_acсel_1.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_1.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_1.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_1.peak_level = ausp_peak_level;
|
||||
ausp_acсel_1.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Канал_2
|
||||
var ausp_acсel_2 = gtl.add_ausp(gtl.analog_inputs[signals[2].portNumber]); // объявление переменной спектра
|
||||
ausp_acсel_2.color = 0xff8800; // цвет спектра
|
||||
ausp_acсel_2.name = "Спектр ускорения (канал 2)"; // имя спектра
|
||||
ausp_acсel_2.color = 0x000000ff; // синий цвет спектра
|
||||
ausp_acсel_2.frequency = ausp_frequency;
|
||||
ausp_acсel_2.lines = ausp_frequency * ausp_lines;
|
||||
ausp_acсel_2.average = ausp_average;
|
||||
ausp_acсel_2.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_acсel_2.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_acсel_2.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_acсel_2.peak_level = ausp_peak_level;
|
||||
ausp_acсel_2.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
// Спектр силы (канал сигнала молотка)
|
||||
// Канал_3
|
||||
var ausp_force_3 = gtl.add_ausp(gtl.analog_inputs[signals[3].portNumber]); // объявление переменной спектра
|
||||
ausp_force_3.color = 0x000000ff; // цвет спектра
|
||||
ausp_force_3.name = "Спектр силы (канал 3)"; // имя спектра
|
||||
ausp_force_3.color = 0x00ff0000; // красный цвет спектра
|
||||
ausp_force_3.frequency = ausp_frequency;
|
||||
ausp_force_3.lines = ausp_frequency * ausp_lines;
|
||||
ausp_force_3.average = ausp_average;
|
||||
ausp_force_3.unit = ausp_unit; // отображение амплитуды
|
||||
ausp_force_3.smoothing_factor = ausp_smoothing_factor;
|
||||
ausp_force_3.smoothed_line_color = 0xff004dff; // цвет средней линии
|
||||
ausp_force_3.peak_level = ausp_peak_level;
|
||||
ausp_force_3.tolerance = ausp_tolerance; // диапазон поиска гармоник +/-
|
||||
|
||||
|
||||
// Спектры для комплексного представления
|
||||
|
||||
// Канал 0
|
||||
var ausp_0 = gtl.create_ausp(
|
||||
{
|
||||
"src" : gtl.analog_inputs[signals[0].portNumber],
|
||||
"frequency" : 1000,
|
||||
"resolution" : 0.25,
|
||||
"average" : 6,
|
||||
"overlap" : .5,
|
||||
"window" : gtl.spec.rectangular
|
||||
}
|
||||
);
|
||||
|
||||
// Канал 1
|
||||
var ausp_1 = gtl.create_ausp(
|
||||
{
|
||||
"src" : gtl.analog_inputs[signals[1].portNumber],
|
||||
"frequency" : 1000,
|
||||
"resolution" : 0.25,
|
||||
"average" : 6,
|
||||
"overlap" : .5,
|
||||
"window" : gtl.spec.rectangular
|
||||
}
|
||||
);
|
||||
|
||||
// Канал 2
|
||||
var ausp_2 = gtl.create_ausp(
|
||||
{
|
||||
"src" : gtl.analog_inputs[signals[2].portNumber],
|
||||
"frequency" : 1000,
|
||||
"resolution" : 0.25,
|
||||
"average" : 6,
|
||||
"overlap" : .5,
|
||||
"window" : gtl.spec.rectangular
|
||||
}
|
||||
);
|
||||
|
||||
// Канал 3
|
||||
var ausp_3 = gtl.create_ausp(
|
||||
{
|
||||
"src" : gtl.analog_inputs[signals[3].portNumber],
|
||||
"frequency" : 1000,
|
||||
"resolution" : 0.25,
|
||||
"average" : 6,
|
||||
"overlap" : .5,
|
||||
"window" : gtl.spec.rectangular
|
||||
}
|
||||
);
|
||||
|
||||
//*******************ДИАГНОСТИКА*********************
|
||||
//***************************************************
|
||||
|
||||
// Задаем период проведения диагностики в секундах
|
||||
var acq_time = Math.max(ausp_acсel_0.acq_time, ausp_acсel_1.acq_time, ausp_acсel_2.acq_time,
|
||||
ausp_force_3.acq_time, ausp_0.acq_time, ausp_1.acq_time, ausp_2.acq_time, ausp_3.acq_time) + 0.3;
|
||||
gtl.diagnostic.interval = acq_time;
|
||||
// gtl.diagnostic.interval = 10; // время в секундах (константа)
|
||||
// примечание: наблюдается зависимость результатов АФЧХ от времени диагностики
|
||||
|
||||
function diagnose() {
|
||||
|
||||
// Массивы значений
|
||||
var ausp_accel_0_data = ausp_acсel_0.data; // массив уровней спектра ускорения 0
|
||||
var ausp_accel_1_data = ausp_acсel_1.data; // массив уровней спектра ускорения 1
|
||||
var ausp_accel_2_data = ausp_acсel_2.data; // массив уровней спектра ускорения 2
|
||||
var ausp_force_3_data = ausp_force_3.data; // массив уровней спектра силы 3
|
||||
|
||||
// Комплексные числа
|
||||
var ausp_accel_0_real = ausp_0.real; // действительная часть спектра ускорения 0
|
||||
var ausp_accel_0_imag = ausp_0.imag; // мнимая часть спектра ускорения 0
|
||||
var ausp_accel_1_real = ausp_1.real; // действительная часть спектра ускорения 1
|
||||
var ausp_accel_1_imag = ausp_1.imag; // мнимая часть спектра ускорения 1
|
||||
var ausp_accel_2_real = ausp_2.real; // действительная часть спектра ускорения 2
|
||||
var ausp_accel_2_imag = ausp_2.imag; // мнимая часть спектра ускорения 2
|
||||
var ausp_force_3_real = ausp_3.real; // действительная часть спектра силы 3
|
||||
var ausp_force_3_imag = ausp_3.imag; // мнимая часть спектра силы 3
|
||||
|
||||
var n = ausp_force_3_data.length; // переменная для цикла
|
||||
|
||||
gtl.log.info("n (ausp_data.length)", ausp_force_3_data.length);
|
||||
gtl.log.info("Минимально необходимая длительность сигнала", gtl.diagnostic.interval);
|
||||
gtl.log.info("ausp_frequency", ausp_frequency);
|
||||
gtl.log.info("ausp_lines", ausp_lines);
|
||||
gtl.log.info("Math.PI", Math.PI);
|
||||
|
||||
|
||||
// Получение массивов для формулы определения частотного отклика
|
||||
|
||||
// Канал_3 (ausp_force_3) - комплексно-сопряжённый вид
|
||||
// меняется знак мнимой части на противоположный
|
||||
// действительная часть без изменений
|
||||
var ausp_force_3_imag_anti = []; // мнимая часть с противоположным знаком
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_force_3_imag_anti.push(ausp_force_3_imag[i] * (-1));
|
||||
}
|
||||
// Кросс-спектры
|
||||
// Канал_0 & Канал_3
|
||||
var ausp_cross_0_3_real = []; // действительная часть кросс-спектра 0 & 3
|
||||
var ausp_cross_0_3_imag = []; // мнимая часть кросс-спектра 0 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_0_3_real.push(ausp_accel_0_real[i] * ausp_force_3_real[i] -
|
||||
(ausp_accel_0_imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_0_3_imag.push(ausp_accel_0_real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_accel_0_imag[i] * ausp_force_3_real[i]);
|
||||
}
|
||||
// Канал_1 & Канал_3
|
||||
var ausp_cross_1_3_real = []; // действительная часть кросс-спектра 1 & 3
|
||||
var ausp_cross_1_3_imag = []; // мнимая часть кросс-спектра 1 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_1_3_real.push(ausp_accel_1_real[i] * ausp_force_3_real[i] -
|
||||
(ausp_accel_1_imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_1_3_imag.push(ausp_accel_1_real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_accel_1_imag[i] * ausp_force_3_real[i]);
|
||||
}
|
||||
// Канал_2 & Канал_3
|
||||
var ausp_cross_2_3_real = []; // действительная часть кросс-спектра 2 & 3
|
||||
var ausp_cross_2_3_imag = []; // мнимая часть кросс-спектра 2 & 3
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
ausp_cross_2_3_real.push(ausp_accel_2_real[i] * ausp_force_3_real[i] -
|
||||
(ausp_accel_2_imag[i] * ausp_force_3_imag_anti[i]));
|
||||
ausp_cross_2_3_imag.push(ausp_accel_2_real[i] * ausp_force_3_imag_anti[i] +
|
||||
ausp_accel_2_imag[i] * ausp_force_3_real[i]);
|
||||
}
|
||||
|
||||
// Частотный отклик (деление кросс-спектра на спектр силы)
|
||||
// (Канал_0 & Канал_3) / Канал_3
|
||||
var freq_resp_0_3_real = []; // действительная часть частотного отклика между 0 и 3
|
||||
var freq_resp_0_3_imag = []; // мнимая часть частотного отклика между 0 и 3
|
||||
var freq_resp_0_3_ampl = []; // амплитуда частотного отклика между 0 и 3
|
||||
var freq_resp_0_3_phase = []; // фаза частотного отклика между 0 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_real.push((ausp_cross_0_3_real[i] * ausp_force_3_real[i] +
|
||||
ausp_cross_0_3_imag[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
|
||||
freq_resp_0_3_imag.push((ausp_force_3_real[i] * ausp_cross_0_3_imag[i] -
|
||||
ausp_cross_0_3_real[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_0_3_ampl.push(Math.sqrt(Math.pow(freq_resp_0_3_real[i],2) + Math.pow(freq_resp_0_3_imag[i],2)));
|
||||
freq_resp_0_3_phase.push(Math.atan(freq_resp_0_3_imag[i] / freq_resp_0_3_real[i]) * 180 / Math.PI);
|
||||
}
|
||||
|
||||
// (Канал_1 & Канал_3) / Канал_3
|
||||
var freq_resp_1_3_real = []; // действительная часть частотного отклика между 0 и 3
|
||||
var freq_resp_1_3_imag = []; // мнимая часть частотного отклика между 0 и 3
|
||||
var freq_resp_1_3_ampl = []; // амплитуда частотного отклика между 0 и 3
|
||||
var freq_resp_1_3_phase = []; // фаза частотного отклика между 0 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_1_3_real.push((ausp_cross_1_3_real[i] * ausp_force_3_real[i] +
|
||||
ausp_cross_1_3_imag[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
|
||||
freq_resp_1_3_imag.push((ausp_force_3_real[i] * ausp_cross_1_3_imag[i] -
|
||||
ausp_cross_1_3_real[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_1_3_ampl.push(Math.sqrt(Math.pow(freq_resp_1_3_real[i],2) + Math.pow(freq_resp_1_3_imag[i],2)));
|
||||
freq_resp_1_3_phase.push(Math.atan(freq_resp_1_3_imag[i] / freq_resp_1_3_real[i]) * 180 / Math.PI);
|
||||
}
|
||||
|
||||
// (Канал_2 & Канал_3) / Канал_3
|
||||
var freq_resp_2_3_real = []; // действительная часть частотного отклика между 2 и 3
|
||||
var freq_resp_2_3_imag = []; // мнимая часть частотного отклика между 2 и 3
|
||||
var freq_resp_2_3_ampl = []; // амплитуда частотного отклика между 2 и 3
|
||||
var freq_resp_2_3_phase = []; // фаза частотного отклика между 2 и 3
|
||||
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_2_3_real.push((ausp_cross_2_3_real[i] * ausp_force_3_real[i] +
|
||||
ausp_cross_2_3_imag[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
|
||||
freq_resp_2_3_imag.push((ausp_force_3_real[i] * ausp_cross_2_3_imag[i] -
|
||||
ausp_cross_2_3_real[i] * ausp_force_3_imag[i]) /
|
||||
(Math.pow(ausp_force_3_real[i], 2) + Math.pow(ausp_force_3_imag[i], 2)));
|
||||
}
|
||||
// запись массива амплитуды и фазы
|
||||
for (let i = 0; i < n; i += 1)
|
||||
{
|
||||
freq_resp_2_3_ampl.push(Math.sqrt(Math.pow(freq_resp_2_3_real[i],2) + Math.pow(freq_resp_2_3_imag[i],2)));
|
||||
freq_resp_2_3_phase.push(Math.atan(freq_resp_2_3_imag[i] / freq_resp_2_3_real[i]) * 180 / Math.PI);
|
||||
}
|
||||
|
||||
// Построение пользовательских графиков
|
||||
|
||||
plot_0.add(
|
||||
{
|
||||
color: 0x04ff00,
|
||||
name: "Спектр ускорения (канал 0)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_acсel_0.data
|
||||
});
|
||||
|
||||
plot_1.add(
|
||||
{
|
||||
color: 0xcad714,
|
||||
name: "Спектр ускорения (канал 1)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_accel_1_data
|
||||
});
|
||||
|
||||
plot_2.add(
|
||||
{
|
||||
color: 0xff8800,
|
||||
name: "Спектр ускорения (канал 2)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_accel_2_data
|
||||
});
|
||||
|
||||
plot_3.add(
|
||||
{
|
||||
color: 0xff00f7,
|
||||
name: "Спектр силы (канал 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: ausp_force_3_data
|
||||
});
|
||||
|
||||
plot_FreqResp_ampl_0_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Частотный отклик (каналы 0 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_0_3_real
|
||||
});
|
||||
plot_FreqResp_phase_0_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 0 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_0_3_phase
|
||||
});
|
||||
|
||||
plot_FreqResp_ampl_1_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Частотный отклик (каналы 1 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_1_3_real
|
||||
});
|
||||
plot_FreqResp_phase_1_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 1 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_1_3_phase
|
||||
});
|
||||
|
||||
plot_FreqResp_ampl_2_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Частотный отклик (каналы 2 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_2_3_real
|
||||
});
|
||||
plot_FreqResp_phase_2_3.add(
|
||||
{
|
||||
color: 0xedc887,
|
||||
name: "Фаза частотного отклика (каналы 2 и 3)",
|
||||
x: 1/ausp_lines,
|
||||
y: freq_resp_2_3_phase
|
||||
});
|
||||
|
||||
|
||||
|
||||
gtl.diagnostic.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
||||
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"ranges": [
|
||||
{
|
||||
"max": 3.044842578125,
|
||||
"min": 2.935233203125
|
||||
},
|
||||
{
|
||||
"max": 11.92075078125,
|
||||
"min": 11.81114140625
|
||||
},
|
||||
{
|
||||
"max": 14.986971484375,
|
||||
"min": 14.877362109375
|
||||
},
|
||||
{
|
||||
"max": 17.74098515625,
|
||||
"min": 17.63137578125
|
||||
},
|
||||
{
|
||||
"max": 20.595496875,
|
||||
"min": 20.485887499999997
|
||||
},
|
||||
{
|
||||
"max": 23.402166796875,
|
||||
"min": 23.292557421875
|
||||
},
|
||||
{
|
||||
"max": 26.106854296875,
|
||||
"min": 25.997244921874998
|
||||
},
|
||||
{
|
||||
"max": 28.987987109375,
|
||||
"min": 28.878377734374997
|
||||
},
|
||||
{
|
||||
"max": 32.100389453125,
|
||||
"min": 31.990780078125
|
||||
},
|
||||
{
|
||||
"max": 35.2981921875,
|
||||
"min": 35.1885828125
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"ranges": [
|
||||
{
|
||||
"max": 13.4652234375,
|
||||
"min": 13.3556140625
|
||||
},
|
||||
{
|
||||
"max": 17.291522265625,
|
||||
"min": 17.181912890625
|
||||
},
|
||||
{
|
||||
"max": 20.87848515625,
|
||||
"min": 20.76887578125
|
||||
},
|
||||
{
|
||||
"max": 23.86118046875,
|
||||
"min": 23.751571093749998
|
||||
},
|
||||
{
|
||||
"max": 27.403924609375,
|
||||
"min": 27.294315234375
|
||||
},
|
||||
{
|
||||
"max": 31.992782031249998,
|
||||
"min": 31.883172656249997
|
||||
},
|
||||
{
|
||||
"max": 36.845369921875,
|
||||
"min": 36.735760546875
|
||||
},
|
||||
{
|
||||
"max": 40.212791796874995,
|
||||
"min": 40.103182421875
|
||||
},
|
||||
{
|
||||
"max": 43.80007695312499,
|
||||
"min": 43.690467578124995
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"ranges": [
|
||||
{
|
||||
"max": 2.465116015625,
|
||||
"min": 2.3555066406250003
|
||||
},
|
||||
{
|
||||
"max": 4.629354296875,
|
||||
"min": 4.5197449218750005
|
||||
},
|
||||
{
|
||||
"max": 6.63301640625,
|
||||
"min": 6.5234070312500005
|
||||
},
|
||||
{
|
||||
"max": 8.69754765625,
|
||||
"min": 8.58793828125
|
||||
},
|
||||
{
|
||||
"max": 10.96016484375,
|
||||
"min": 10.85055546875
|
||||
},
|
||||
{
|
||||
"max": 13.211873828125,
|
||||
"min": 13.102264453125
|
||||
},
|
||||
{
|
||||
"max": 15.479217578125,
|
||||
"min": 15.369608203125
|
||||
},
|
||||
{
|
||||
"max": 17.78164921875,
|
||||
"min": 17.67203984375
|
||||
},
|
||||
{
|
||||
"max": 19.964393359375,
|
||||
"min": 19.854783984374997
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"ranges": [
|
||||
{
|
||||
"max": 2.710311328125,
|
||||
"min": 2.600701953125
|
||||
},
|
||||
{
|
||||
"max": 4.901658984375,
|
||||
"min": 4.792049609375
|
||||
},
|
||||
{
|
||||
"max": 7.426229296875,
|
||||
"min": 7.3166199218750005
|
||||
},
|
||||
{
|
||||
"max": 9.87832890625,
|
||||
"min": 9.76871953125
|
||||
},
|
||||
{
|
||||
"max": 12.4415125,
|
||||
"min": 12.331903125
|
||||
},
|
||||
{
|
||||
"max": 15.22229375,
|
||||
"min": 15.112684375
|
||||
},
|
||||
{
|
||||
"max": 17.862147265625,
|
||||
"min": 17.752537890625
|
||||
},
|
||||
{
|
||||
"max": 20.8111609375,
|
||||
"min": 20.701551562499997
|
||||
},
|
||||
{
|
||||
"max": 23.64692265625,
|
||||
"min": 23.537313281249997
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue