This commit is contained in:
s.savelievrem 2026-06-10 14:51:53 +03:00
commit 97034c21cb
68 changed files with 9826 additions and 0 deletions

11
Frequency_responce.gtld Normal file
View File

@ -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
}

View File

@ -0,0 +1,2 @@
[
]

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -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}"
}
]

213
modules/getResponse.js Normal file
View File

@ -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 };
}

110
modules/getResponse_old.js Normal file
View File

@ -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
}
}; //рассчет перекрестного спектра

103
qml/default_object.qml Normal file
View File

@ -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
}
}
}
}
}
}

104
qml/default_point.qml Normal file
View File

@ -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
}
}
}
}
}
}

View File

@ -0,0 +1,35 @@
{
"comment": "",
"hw": {
"channels": [
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}
]
},
"ranges": [
]
}

View File

@ -0,0 +1,35 @@
{
"comment": "",
"hw": {
"channels": [
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}
]
},
"ranges": [
]
}

View File

@ -0,0 +1,35 @@
{
"comment": "",
"hw": {
"channels": [
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}
]
},
"ranges": [
]
}

View File

@ -0,0 +1,35 @@
{
"comment": "",
"hw": {
"channels": [
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}
]
},
"ranges": [
]
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

View File

@ -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;
};

61
scripts/default/bs_mtx.js Normal file
View File

@ -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;
};

View File

158
scripts/default/debug.js Normal file
View File

@ -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();
}

View File

View File

@ -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;
}
}

View File

@ -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;
};

60
scripts/default/gt_mtx.js Normal file
View File

@ -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;
};

166
scripts/default/kNN.js Normal file
View File

@ -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;
}
}

View File

@ -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;
};

61
scripts/default/kn_mtx.js Normal file
View File

@ -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;
};

View File

@ -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 };

View File

@ -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
scripts/default/pump.js Normal file
View File

View File

@ -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;
};

61
scripts/default/rb_mtx.js Normal file
View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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();

View File

View File

View File

@ -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;
}; //определение амплитудного коэффициента

182
scripts/freq_response 2.js Normal file
View File

@ -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();
}; // останавливаем диагностику после окончания диапазонов
}

208
scripts/freq_response.js Normal file
View File

@ -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();
}; // останавливаем диагностику после окончания диапазонов
}

View File

@ -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(); // останавливаем диагностику после окончания диапазонов
}

213
scripts/getResponse.js Normal file
View File

@ -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 };
}

110
scripts/getResponse_old.js Normal file
View File

@ -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
}
}; //рассчет перекрестного спектра

View File

@ -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();
}

View File

@ -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);
// }
// }
}

View File

@ -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);
// }
// }
// }

View File

@ -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++;
}

View File

@ -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++;
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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++;
}

View File

@ -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();
}

View File

@ -0,0 +1,2 @@
[
]

Binary file not shown.

View File

@ -0,0 +1,2 @@
[
]

View File

@ -0,0 +1,2 @@
[
]

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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
}
]
}