Я пытаюсь реализовать функцию, подобную atan2, для сопоставления двух входных синусоидальных сигналов произвольного относительного фазового сдвига с одним выходным сигналом, который линейно идет от 0
до 2π
. atan2
обычно предполагает наличие двух сигналов со сдвигом фазы на 90 градусов.
atan2 для двух синусоид произвольного фазового сдвига?
Учитывая
Ответы (2)
atan2
возвращает угол двумерного вектора. Ваш код не обрабатывает такое масштабирование должным образом. Но не беспокойтесь, на самом деле очень легко свести вашу проблему к atan2
, которая прекрасно со всем справится.
Обратите внимание, что вычисление sin(x)
и sin(x + phase)
аналогично проецированию точки (cos(x), sin(x))
на оси (0, 1)
и (sin(phase), cos(phase))
. Это то же самое, что скалярное произведение по этим осям или преобразование системы координат из стандартной ортогональной в асимметричную. Это предлагает простое решение: инвертировать преобразование, чтобы получить координаты в ортогональном базисе, а затем использовать atan2
.
Вот код, который делает это:
double super_atan2(double x0, double x1, double a0, double a1) {
double det = sin(a0 - a1);
double u = (x1*sin(a0) - x0*sin(a1))/det;
double v = (x0*cos(a1) - x1*cos(a0))/det;
return atan2(v, u);
}
double duper_atan2(double y0, double y1, double phase) {
const double tau = 6.28318530717958647692; // https://tauday.com/
return super_atan2(y0, y1, tau/4, tau/4 - phase);
}
super_atan2
получает углы двух осей проекции, duper_atan2
решает задачу именно так, как вы указали.
Также обратите внимание, что вычисление det
не является строго обязательным. Его можно заменить на fmod
и copysign
(нам еще нужен правильный знак u
и v
).
Происхождение:
В коде:
// assume phase != k * pi, for any integer k
double f (double y0, double y1, double phase)
{
double u = (- y0 * cos(phase) + y1) / sin(phase);
double v = y0;
double x = atan2 (v, u);
return (x < 0) ? (x + 2 * M_PI) : x;
}
-π <= atan2() <= +π
, а не тот же диапазон, что и [0...2π), иfmod(a, 2*M_PI)
. - person chux - Reinstate Monica   schedule 09.05.2019