atan2对于任意相移的两个正弦曲线?

时间:2019-05-08 20:41:40

标签: c algorithm math atan2

我正在尝试实现一个类似于atan2的函数,以将任意相对相移的两个输入正弦信号映射到一个从0线性变化的单个输出信号。 atan2通常假设两个信号相移90度。

给出y0(x) = sin(x)y1 = sin(x + phase),其中phase是一个固定的非零值,我如何实现一种以x取模的方式返回的方法?

2 个答案:

答案 0 :(得分:8)

atan2返回2d向量的角度。您的代码无法正确处理此类缩放。但不用担心,将问题简化为可以很好地处理所有问题的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的计算并非严格必要。可以用fmodcopysign替换它(我们仍然需要uv的正确符号)。

答案 1 :(得分:1)

派生:

[y0; y1] = [sin(x); sin(x+phase)]  
         = [sin(x); sin(x) * cos(phase) + cos(x) * sin(phase)]
         = [0, 1; sin(phase), cos(phase)] * [cos(x); sin(x)]

Let M := inv([0, 1; sin(phase), cos(phase)]) 
       = [-cos(phase)/sin(phase), 1/sin(phase); 1, 0].

Let [u; v] := M * [y0; y1]
            = [(-y0 * cos(phase) + y1)/sin(phase); y0].  

Then [u; v] = [cos(x); sin(x)] and x = atan2 (v, u).

在代码中:

// assume phase != 0
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;
}