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