commit 97034c21cb2a4627aeaed3cf199d84b01575a629 Author: s.savelievrem Date: Wed Jun 10 14:51:53 2026 +0300 comment diff --git a/Frequency_responce.gtld b/Frequency_responce.gtld new file mode 100644 index 0000000..9bc496d --- /dev/null +++ b/Frequency_responce.gtld @@ -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 +} diff --git a/Frequency_responce_devices_model.json b/Frequency_responce_devices_model.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/Frequency_responce_devices_model.json @@ -0,0 +1,2 @@ +[ +] diff --git a/Frequency_responce_local_storage.sqlite b/Frequency_responce_local_storage.sqlite new file mode 100644 index 0000000..00a4383 Binary files /dev/null and b/Frequency_responce_local_storage.sqlite differ diff --git a/Frequency_responce_model.json b/Frequency_responce_model.json new file mode 100644 index 0000000..f16b7ea --- /dev/null +++ b/Frequency_responce_model.json @@ -0,0 +1,1136 @@ +[ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n\"ranges\": [\n{\n\"max\": 13.766053515625,\n\"min\": 13.355623828125\n},\n{\n\"max\": 17.592342578125,\n\"min\": 17.181912892625\n},\n{\n\"max\": 21.179315234374997,\n\"min\": 20.768885546874998\n},\n{\n\"max\": 24.162000781249997,\n\"min\": 23.751571093749998\n},\n{\n\"max\": 27.704744921874997,\n\"min\": 27.294315234375\n},\n{\n\"max\": 32.293602343749995,\n\"min\": 31.883172656249997\n},\n{\n\"max\": 37.146190234375,\n\"min\": 36.735760546875\n},\n{\n\"max\": 40.513612109374996,\n\"min\": 40.103182421875\n},\n{\n\"max\": 44.100897265624994,\n\"min\": 43.690467578124995\n}\n],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 1000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 10\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "Частотный_отклик v12.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{1ee51458-2b67-4738-8832-24a883abe26a}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{da645bbe-04b5-4d5e-86de-3b5ba633addc}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{5aba8185-bd6d-4469-a877-366899f020e9}" + } + ], + "masterScriptName": "", + "name": "Частотный отклик по размеченным сигналам", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{4309f187-2cb5-463c-a4cd-520050c00401}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 40000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 100\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{1ee51458-2b67-4738-8832-24a883abe26a}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{da645bbe-04b5-4d5e-86de-3b5ba633addc}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{5aba8185-bd6d-4469-a877-366899f020e9}" + } + ], + "masterScriptName": "", + "name": "Разметка сигналов", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{081ecf92-3246-49e8-b653-1e2c6b3af435}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n \"ranges\": [\n {\n \"max\": 13.3756140625,\n \"min\": 13.3556140625\n },\n {\n \"max\": 17.201912890625,\n \"min\": 17.181912890625\n },\n {\n \"max\": 20.78887578125,\n \"min\": 20.76887578125\n },\n {\n \"max\": 23.771571093749998,\n \"min\": 23.751571093749998\n },\n {\n \"max\": 27.314315234374998,\n \"min\": 27.294315234375\n },\n {\n \"max\": 31.903172656249996,\n \"min\": 31.883172656249997\n },\n {\n \"max\": 36.755760546875,\n \"min\": 36.735760546875\n },\n {\n \"max\": 40.123182421875,\n \"min\": 40.103182421875\n },\n {\n \"max\": 43.710467578125,\n \"min\": 43.690467578124995\n }\n ],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 40000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 100\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{1ee51458-2b67-4738-8832-24a883abe26a}" + } + ], + "masterScriptName": "", + "name": "Частотный отклик \"верх горизонталь\"", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{e8e5cda3-5278-4fe8-96c8-76b7a552314c}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n \"ranges\": [\n {\n \"max\": 2.955233203125,\n \"min\": 2.935233203125\n },\n {\n \"max\": 11.83114140625,\n \"min\": 11.81114140625\n },\n {\n \"max\": 14.897362109374999,\n \"min\": 14.877362109375\n },\n {\n \"max\": 17.65137578125,\n \"min\": 17.63137578125\n },\n {\n \"max\": 20.505887499999996,\n \"min\": 20.485887499999997\n },\n {\n \"max\": 23.312557421875,\n \"min\": 23.292557421875\n },\n {\n \"max\": 26.017244921874997,\n \"min\": 25.997244921874998\n },\n {\n \"max\": 28.8983777343374996,\n \"min\": 28.878377734374997\n },\n {\n \"max\": 32.010780078125,\n \"min\": 31.990780078125\n },\n {\n \"max\": 35.208582812500005,\n \"min\": 35.1885828125\n }\n ],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 40000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 100\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}" + } + ], + "masterScriptName": "", + "name": "Частотный отклик \"верх вертикаль\"", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{7aa073d4-0afa-4b81-9857-30cb171715a9}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n \"ranges\": [\n {\n \"max\": 2.620701953125,\n \"min\": 2.600701953125\n },\n {\n \"max\": 4.812049609374999,\n \"min\": 4.792049609375\n },\n {\n \"max\": 7.336619921875,\n \"min\": 7.3166199218750005\n },\n {\n \"max\": 9.788719531249999,\n \"min\": 9.76871953125\n },\n {\n \"max\": 12.351903125,\n \"min\": 12.331903125\n },\n {\n \"max\": 15.132684375,\n \"min\": 15.112684375\n },\n {\n \"max\": 17.772537890625,\n \"min\": 17.752537890625\n },\n {\n \"max\": 20.721551562499997,\n \"min\": 20.701551562499997\n },\n {\n \"max\": 23.557313281249996,\n \"min\": 23.537313281249997\n }\n ],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 40000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 100\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{da645bbe-04b5-4d5e-86de-3b5ba633addc}" + } + ], + "masterScriptName": "", + "name": "Частотный отклик \"низ горизонталь\"", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{0af47988-b437-4304-a1fd-d8e4d06f9c7f}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n \"ranges\": [\n {\n \"max\": 2.3754675781250003,\n \"min\": 2.3555066406250003\n },\n {\n \"max\": 4.539705859375,\n \"min\": 4.5197449218750005\n },\n {\n \"max\": 6.54336796875,\n \"min\": 6.5234070312500005\n },\n {\n \"max\": 8.607899218750001,\n \"min\": 8.58793828125\n },\n {\n \"max\": 10.870516406250001,\n \"min\": 10.85055546875\n },\n {\n \"max\": 13.122225390625001,\n \"min\": 13.102264453125\n },\n {\n \"max\": 15.389569140625001,\n \"min\": 15.369608203125\n },\n {\n \"max\": 17.692000781249998,\n \"min\": 17.67203984375\n },\n {\n \"max\": 19.874744921874996,\n \"min\": 19.854783984374997\n }\n ],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 40000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 100\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ низ вертикаль", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{5aba8185-bd6d-4469-a877-366899f020e9}" + } + ], + "masterScriptName": "", + "name": "Частотный отклик \"низ вертикаль\"", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{6582210f-9c71-4c3f-93dd-f656d2d8948e}" + }, + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{\n\"ranges\": [\n{\n\"max\": 13.766053515625,\n\"min\": 13.355623828125\n},\n{\n\"max\": 17.592342578125,\n\"min\": 17.181912892625\n},\n{\n\"max\": 21.179315234374997,\n\"min\": 20.768885546874998\n},\n{\n\"max\": 24.162000781249997,\n\"min\": 23.751571093749998\n},\n{\n\"max\": 27.704744921874997,\n\"min\": 27.294315234375\n},\n{\n\"max\": 32.293602343749995,\n\"min\": 31.883172656249997\n},\n{\n\"max\": 37.146190234375,\n\"min\": 36.735760546875\n},\n{\n\"max\": 40.513612109374996,\n\"min\": 40.103182421875\n},\n{\n\"max\": 44.100897265624994,\n\"min\": 43.690467578124995\n}\n],\n\n\"frequency_comment\": \"граничная частота спектра\",\n\"frequency\": 10000,\n\n\"view_comment\": \"отображение амплитуды спектра в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view\": 0,\n\n\"view_freq_resp_comment\": \"отображение амплитуды частотного отклика в дБ или линейных единицах: 1 - db, 0 - unit\",\n\"view_freq_resp\": 0,\n\n\"average_comment\": \"усреднение спектра\",\n\"average\": 1,\n\n\"overlap_comment\": \"наложение сигнала для спектра\",\n\"overlap\": 0,\n\n\"variant_freq_resp_comment\": \"вариант вычисления частотного отклика: 0 - через кросс, 1 - через автоспектр\",\n\"variant_freq_resp\": 0,\n\n\"thresh_level_comment\": \"уровень удара для засчитывания импульса\",\n\"thresh_level\": 500,\n\n\"time_impulse_comment\": \"длина импульса, если не задано вручную, то вычисляется в скрипте\",\n\"time_impulse\": 0,\n\n\"resolution_comment\": \"разрешение спектра\",\n\"resolution\": 10\n}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + { + "U_freq": 50, + "async_N_rotor": 0, + "bdD1": 0, + "bdD2": 0, + "bdL": 0, + "bsAngle": 0, + "bsInnerD": 0, + "bsModelName": "", + "bsOuterD": 0, + "bsRollerCount": 0, + "bsRollerD": 0, + "bsVendor": "", + "cbdZ1": 0, + "cbdZ2": 0, + "cbdZ3": 0, + "customOptionsString": "{}", + "dpt_K": 0, + "dpt_M": 0, + "dpt_N": 0, + "dpt_freq": 50, + "elType": 0, + "groupType": 0, + "gtZ1": 0, + "gtZ2": 0, + "isQMLViewActive": false, + "isRouteStarter": false, + "items": [ + ], + "masterScriptName": "", + "name": "СТ верх горизонталь", + "nodeType": 2, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_point.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "freq_response 2.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{1ee51458-2b67-4738-8832-24a883abe26a}" + } + ], + "masterScriptName": "", + "name": "Новый объект", + "nodeType": 1, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{a5e1df73-9f23-451b-83f1-719a5ec4bb7e}" + } + ], + "masterScriptName": "master_script.js", + "name": "Новая группа", + "nodeType": 0, + "objectType": 0, + "pgN": 0, + "pgZ1": 0, + "pgZ2": 0, + "pgZ3": 0, + "pmBlades": 0, + "pointComment": "", + "qmlScriptName": "default_object.qml", + "rbAngle": 0, + "rbInnerD": 0, + "rbModelName": "", + "rbOuterD": 0, + "rbRollerCount": 0, + "rbRollerD": 0, + "rbVendor": "", + "scriptName": "debug.js", + "sync_M_rotor": 0, + "sync_M_stator": 0, + "tachoRatio": 1, + "trBlades": 0, + "uuid": "{8b5d7a2a-225c-47e5-aa36-fb17cc2c7d33}" + } +] diff --git a/Frequency_responce_points_model.json b/Frequency_responce_points_model.json new file mode 100644 index 0000000..34f44d7 --- /dev/null +++ b/Frequency_responce_points_model.json @@ -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}" + } +] diff --git a/modules/getResponse.js b/modules/getResponse.js new file mode 100644 index 0000000..f80ade6 --- /dev/null +++ b/modules/getResponse.js @@ -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 }; +} diff --git a/modules/getResponse_old.js b/modules/getResponse_old.js new file mode 100644 index 0000000..4b3cce5 --- /dev/null +++ b/modules/getResponse_old.js @@ -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 + } +}; //рассчет перекрестного спектра \ No newline at end of file diff --git a/qml/default_object.qml b/qml/default_object.qml new file mode 100644 index 0000000..d7bd47c --- /dev/null +++ b/qml/default_object.qml @@ -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 + } + } + } + } + } +} diff --git a/qml/default_point.qml b/qml/default_point.qml new file mode 100644 index 0000000..16ad47b --- /dev/null +++ b/qml/default_point.qml @@ -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 + } + } + } + } + } +} + diff --git a/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav b/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav new file mode 100644 index 0000000..223dab5 Binary files /dev/null and b/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav differ diff --git a/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav.info b/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav.info new file mode 100644 index 0000000..a8bff7d --- /dev/null +++ b/records/{1ee51458-2b67-4738-8832-24a883abe26a}/верх горизонт 2026-02-18 09_56_55.wav.info @@ -0,0 +1,35 @@ +{ + "comment": "", + "hw": { + "channels": [ + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + } + ] + }, + "ranges": [ + ] +} diff --git a/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav b/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav new file mode 100644 index 0000000..3b94901 Binary files /dev/null and b/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav differ diff --git a/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav.info b/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav.info new file mode 100644 index 0000000..a8bff7d --- /dev/null +++ b/records/{5aba8185-bd6d-4469-a877-366899f020e9}/низ вертикаль 2026-02-18 09_56_40.wav.info @@ -0,0 +1,35 @@ +{ + "comment": "", + "hw": { + "channels": [ + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + } + ] + }, + "ranges": [ + ] +} diff --git a/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav b/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav new file mode 100644 index 0000000..97e8400 Binary files /dev/null and b/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav differ diff --git a/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav.info b/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav.info new file mode 100644 index 0000000..a8bff7d --- /dev/null +++ b/records/{d5f70fb9-1e58-4e23-b3e8-5270c02d0904}/верх вертикаль 2026-02-18 09_57_09.wav.info @@ -0,0 +1,35 @@ +{ + "comment": "", + "hw": { + "channels": [ + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + } + ] + }, + "ranges": [ + ] +} diff --git a/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav b/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav new file mode 100644 index 0000000..71ac608 Binary files /dev/null and b/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav differ diff --git a/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav.info b/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav.info new file mode 100644 index 0000000..a8bff7d --- /dev/null +++ b/records/{da645bbe-04b5-4d5e-86de-3b5ba633addc}/низ горизонт 2026-02-18 11_02_47.wav.info @@ -0,0 +1,35 @@ +{ + "comment": "", + "hw": { + "channels": [ + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + }, + { + } + ] + }, + "ranges": [ + ] +} diff --git a/scripts/default/analizer_sample.js b/scripts/default/analizer_sample.js new file mode 100644 index 0000000..e26d219 --- /dev/null +++ b/scripts/default/analizer_sample.js @@ -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; +} diff --git a/scripts/default/ballscrew.js b/scripts/default/ballscrew.js new file mode 100644 index 0000000..01197d9 --- /dev/null +++ b/scripts/default/ballscrew.js @@ -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; + } +} \ No newline at end of file diff --git a/scripts/default/belt_drive.js b/scripts/default/belt_drive.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/bs_defs.js b/scripts/default/bs_defs.js new file mode 100644 index 0000000..9de300b --- /dev/null +++ b/scripts/default/bs_defs.js @@ -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; +}; + + + diff --git a/scripts/default/bs_mtx.js b/scripts/default/bs_mtx.js new file mode 100644 index 0000000..e09bb4a --- /dev/null +++ b/scripts/default/bs_mtx.js @@ -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; +}; + diff --git a/scripts/default/chain_belt_drive.js b/scripts/default/chain_belt_drive.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/debug.js b/scripts/default/debug.js new file mode 100644 index 0000000..4f7d457 --- /dev/null +++ b/scripts/default/debug.js @@ -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(); +} diff --git a/scripts/default/electrical_engine.js b/scripts/default/electrical_engine.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/gear_transmission.js b/scripts/default/gear_transmission.js new file mode 100644 index 0000000..44e2665 --- /dev/null +++ b/scripts/default/gear_transmission.js @@ -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; + } +} \ No newline at end of file diff --git a/scripts/default/gt_defs.js b/scripts/default/gt_defs.js new file mode 100644 index 0000000..9635e2f --- /dev/null +++ b/scripts/default/gt_defs.js @@ -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; +}; + + + diff --git a/scripts/default/gt_mtx.js b/scripts/default/gt_mtx.js new file mode 100644 index 0000000..bef24c7 --- /dev/null +++ b/scripts/default/gt_mtx.js @@ -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; +}; + diff --git a/scripts/default/kNN.js b/scripts/default/kNN.js new file mode 100644 index 0000000..a201fe1 --- /dev/null +++ b/scripts/default/kNN.js @@ -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; + } +} \ No newline at end of file diff --git a/scripts/default/kn_defs.js b/scripts/default/kn_defs.js new file mode 100644 index 0000000..54b4484 --- /dev/null +++ b/scripts/default/kn_defs.js @@ -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; +}; + + + diff --git a/scripts/default/kn_mtx.js b/scripts/default/kn_mtx.js new file mode 100644 index 0000000..1ae29ba --- /dev/null +++ b/scripts/default/kn_mtx.js @@ -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; +}; + diff --git a/scripts/default/master_script.js b/scripts/default/master_script.js new file mode 100644 index 0000000..5720b78 --- /dev/null +++ b/scripts/default/master_script.js @@ -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 }; diff --git a/scripts/default/planetary_gear.js b/scripts/default/planetary_gear.js new file mode 100644 index 0000000..35dec9d --- /dev/null +++ b/scripts/default/planetary_gear.js @@ -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; + } +} \ No newline at end of file diff --git a/scripts/default/pump.js b/scripts/default/pump.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/rb_defs.js b/scripts/default/rb_defs.js new file mode 100644 index 0000000..3706d8d --- /dev/null +++ b/scripts/default/rb_defs.js @@ -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; +}; + + + diff --git a/scripts/default/rb_mtx.js b/scripts/default/rb_mtx.js new file mode 100644 index 0000000..1018eb1 --- /dev/null +++ b/scripts/default/rb_mtx.js @@ -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; +}; + diff --git a/scripts/default/rolling_bearing.js b/scripts/default/rolling_bearing.js new file mode 100644 index 0000000..d30029d --- /dev/null +++ b/scripts/default/rolling_bearing.js @@ -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; + } +} \ No newline at end of file diff --git a/scripts/default/sample_excel_export.js b/scripts/default/sample_excel_export.js new file mode 100644 index 0000000..c204696 --- /dev/null +++ b/scripts/default/sample_excel_export.js @@ -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(); \ No newline at end of file diff --git a/scripts/default/sliding_bearing.js b/scripts/default/sliding_bearing.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/turbine.js b/scripts/default/turbine.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/default/user-functions.js b/scripts/default/user-functions.js new file mode 100644 index 0000000..0debafc --- /dev/null +++ b/scripts/default/user-functions.js @@ -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; +}; //определение амплитудного коэффициента diff --git a/scripts/freq_response 2.js b/scripts/freq_response 2.js new file mode 100644 index 0000000..d4f9858 --- /dev/null +++ b/scripts/freq_response 2.js @@ -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(); + + }; // останавливаем диагностику после окончания диапазонов +} diff --git a/scripts/freq_response.js b/scripts/freq_response.js new file mode 100644 index 0000000..590ba02 --- /dev/null +++ b/scripts/freq_response.js @@ -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(); + + }; // останавливаем диагностику после окончания диапазонов +} \ No newline at end of file diff --git a/scripts/freq_response_multichannel.js b/scripts/freq_response_multichannel.js new file mode 100644 index 0000000..75ceb3a --- /dev/null +++ b/scripts/freq_response_multichannel.js @@ -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(); // останавливаем диагностику после окончания диапазонов +} diff --git a/scripts/getResponse.js b/scripts/getResponse.js new file mode 100644 index 0000000..f80ade6 --- /dev/null +++ b/scripts/getResponse.js @@ -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 }; +} diff --git a/scripts/getResponse_old.js b/scripts/getResponse_old.js new file mode 100644 index 0000000..4b3cce5 --- /dev/null +++ b/scripts/getResponse_old.js @@ -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 + } +}; //рассчет перекрестного спектра \ No newline at end of file diff --git a/scripts/Передаточная_функция_(older_ver).js b/scripts/Передаточная_функция_(older_ver).js new file mode 100644 index 0000000..beecffd --- /dev/null +++ b/scripts/Передаточная_функция_(older_ver).js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v10.js b/scripts/Частотный_отклик v10.js new file mode 100644 index 0000000..b1ae2ef --- /dev/null +++ b/scripts/Частотный_отклик v10.js @@ -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); + // } + // } + +} \ No newline at end of file diff --git a/scripts/Частотный_отклик v11.js b/scripts/Частотный_отклик v11.js new file mode 100644 index 0000000..e553cdd --- /dev/null +++ b/scripts/Частотный_отклик v11.js @@ -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); + // } + // } + +// } \ No newline at end of file diff --git a/scripts/Частотный_отклик v12.js b/scripts/Частотный_отклик v12.js new file mode 100644 index 0000000..47bbf17 --- /dev/null +++ b/scripts/Частотный_отклик v12.js @@ -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++; + +} \ No newline at end of file diff --git a/scripts/Частотный_отклик v13.js b/scripts/Частотный_отклик v13.js new file mode 100644 index 0000000..2b11780 --- /dev/null +++ b/scripts/Частотный_отклик v13.js @@ -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++; +} diff --git a/scripts/Частотный_отклик v2.js b/scripts/Частотный_отклик v2.js new file mode 100644 index 0000000..1e7de20 --- /dev/null +++ b/scripts/Частотный_отклик v2.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v3.js b/scripts/Частотный_отклик v3.js new file mode 100644 index 0000000..fdbf416 --- /dev/null +++ b/scripts/Частотный_отклик v3.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v4.js b/scripts/Частотный_отклик v4.js new file mode 100644 index 0000000..e207c95 --- /dev/null +++ b/scripts/Частотный_отклик v4.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v5.js b/scripts/Частотный_отклик v5.js new file mode 100644 index 0000000..d2ed6cd --- /dev/null +++ b/scripts/Частотный_отклик v5.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v6.js b/scripts/Частотный_отклик v6.js new file mode 100644 index 0000000..3c955d3 --- /dev/null +++ b/scripts/Частотный_отклик v6.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v7.js b/scripts/Частотный_отклик v7.js new file mode 100644 index 0000000..64ea6ce --- /dev/null +++ b/scripts/Частотный_отклик v7.js @@ -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(); + } \ No newline at end of file diff --git a/scripts/Частотный_отклик v8.js b/scripts/Частотный_отклик v8.js new file mode 100644 index 0000000..47b61c2 --- /dev/null +++ b/scripts/Частотный_отклик v8.js @@ -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(); + +} + diff --git a/scripts/Частотный_отклик v9.js b/scripts/Частотный_отклик v9.js new file mode 100644 index 0000000..9ea88dd --- /dev/null +++ b/scripts/Частотный_отклик v9.js @@ -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++; +} \ No newline at end of file diff --git a/scripts/Частотный_отклик.js b/scripts/Частотный_отклик.js new file mode 100644 index 0000000..dbde345 --- /dev/null +++ b/scripts/Частотный_отклик.js @@ -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(); + } \ No newline at end of file diff --git a/transfer_function_devices_model.json b/transfer_function_devices_model.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/transfer_function_devices_model.json @@ -0,0 +1,2 @@ +[ +] diff --git a/transfer_function_local_storage.sqlite b/transfer_function_local_storage.sqlite new file mode 100644 index 0000000..0f97524 Binary files /dev/null and b/transfer_function_local_storage.sqlite differ diff --git a/transfer_function_model.json b/transfer_function_model.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/transfer_function_model.json @@ -0,0 +1,2 @@ +[ +] diff --git a/transfer_function_points_model.json b/transfer_function_points_model.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/transfer_function_points_model.json @@ -0,0 +1,2 @@ +[ +] diff --git a/верх вертикаль.json b/верх вертикаль.json new file mode 100644 index 0000000..b05ac55 --- /dev/null +++ b/верх вертикаль.json @@ -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 + } + ] +} diff --git a/верх горизонталь.json b/верх горизонталь.json new file mode 100644 index 0000000..17f6811 --- /dev/null +++ b/верх горизонталь.json @@ -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 + } + ] +} diff --git a/низ вертикаль.json b/низ вертикаль.json new file mode 100644 index 0000000..f0e15ff --- /dev/null +++ b/низ вертикаль.json @@ -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 + } + ] +} diff --git a/низ горизонталь.json b/низ горизонталь.json new file mode 100644 index 0000000..cee932b --- /dev/null +++ b/низ горизонталь.json @@ -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 + } + ] +}