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