计算超过360度旋转的情况

3
我正在解决一个有关角度的问题。我有一组以标准度数表示的角度数据,例如26度。
通常处理角度时,如果角度超过360度,则角度会继续增加并有效地“重置”——即角度“重新开始”,例如357度、358度、359度、0度、1度等。但我希望度数继续增加,即357度、358度、359度、360度、361度等。我想修改我的数据,使其包含这些转换后的数据。
当数字接近0度限制时,我希望它们变为负数——即3度、2度、1度、0度、-1度、-2度等。
对于360度的倍数(正负都可以),我希望度数继续增加,例如720度等。
你有什么建议?毫无疑问,有一种非常简单的方法来解决这个问题,但我目前的解决方案很笨拙!到目前为止,我最好的尝试是查看角度n和角度n-1之间的百分比差异。如果这是一个很大的差异——例如>60%——那么需要进行修改,通过向当前值添加或减去360度来进行修改,具体取决于先前的角度值。也就是说,如果前一个角度是负数,则减去360,如果前一个角度是正数,则加上360。
你有什么改进的建议吗?

2
我认为我理解了你的问题,但提供一些输入和期望输出的简短示例将有助于极大地澄清事情。 - Judge Maygarden
你能提供更多关于数据的信息吗?你能提供一些样本数据吗?每个数据是一个旋转还是一个新的度数,其中旋转是暗示的?我可以看出这可能会产生歧义,除非在每个数据之间的度数差异方面有约束条件。编辑:+1 @ Judge,因为他比我先回答了 :) - Cam
1
关于角度变化率,可以做出什么假设?换句话说,你正在测量什么物理角度? - Judge Maygarden
6个回答

2

你所说的是一个“unwrap”算法,它是一种泛化算法(不仅适用于360这个特定的数字...你可以使用m=2*pi来表示弧度)。以下是一个javascript实现的例子:

/*  symmetric modulo: 
 *  y = smod(x,m) = x+k*m where k is an integer,
 *  and y is always in the range [-0.5,0.5)*m
 */
function smod(x, m)
{
  return x-((Math.floor(x/m + 0.5))*m);
}

/*  unwrap:
 *  for all i, y[i] = x[i] + k*m where k is an integer,
 *  and for i > 0, the increment y[i]-y[i-1] is in the
 *  range [-0.5,0.5)*m as in smod().
 *
 *  the "init" parameter is optional (default to 0)
 *  and specifies the starting value for the unwrap state.
 */ 

function unwrap(x, m, init)
{
  var yi = init || 0;
  var y = [];
  for (i = 0; i < x.length; ++i)
  {
     yi += smod(x[i]-yi, m);
     y[i] = yi;
  }    
  return y;
}

以下是示例输出:

js>unwrap([100, 200, 348, 359, 23, 37, 46, 10, 350, 190], 360)
100,200,348,359,383,397,406,370,350,190

另一个m=100的示例:

js>unwrap([99,1,7,60,80,22,30,20,90,88,61,23,2,87,50,12], 100, 1000)
999,1001,1007,960,980,1022,1030,1020,990,988,961,923,902,887,850,812

FYI:在C/Java等编程语言中,也存在类似的位扩展算法,其中输入为16位,输出为32位,并且环绕模数m = 65536 = 输入值的跨度。您不需要"smod"函数,只需使用有符号数学即可:
typedef short int16_t;
typedef long  int32_t;
// do typedefs as appropriate on your CPU

int32_t unwrap_extend(int32_t prev, int16_t input)
{
  int16_t delta = input - prev;
  return prev + delta;
}

很棒的答案,当直接使用弧度时,smod非常有用。对我来说解决了问题!谢谢。 - Oliver

1
你可以将所有度数相加/相减,然后使用模运算符对最终结果除以360。这将给出剩余的度数。

这个问题比较模糊,我认为这不是提问者想要的。 - Jason S

1

使用某种方法获取每个角度与前一个角度的差异,确保在两个方向上越过0/360时得到正确的符号。然后将此差异添加到不会翻转的累加总数中。


0
如果我正确理解了问题,这个方法可能有效:
int prev=[first data piece in data set]
int total=prev
foreach data in [the rest of the data set]
    total+=data-prev
    prev=data
    data=total

然后在循环结束时,数据集将包含所有按照您指定的方式添加的数据。

因此,基本上是通过数据集进行循环,并将差异添加到运行总数中。随着迭代,运行总数变为每个数据片段。


data-prev 从359到2时无法工作。解决方案是正确的,除了没有考虑这个区别。 - phkahler

0

这个 C 程序从标准输入中获取一系列 0 到 359 度之间的角度,并通过累积角度变化将无限值打印到标准输出。假定每个输入角度的最大可能变化来检测包装。

#include <stdio.h>
#include <stdlib.h>

int
main()
{
    const float MAX_DELTA = 180.f;          /* highest expected change */
    float previous, next, delta, output;

    /* set the initial value */
    if (EOF == scanf("%f", &next))
        exit(0);   
    previous = next;
    output = previous;

    do {
        /* calculate the change in angle and adjust if too big */
        delta = next - previous;
        if (MAX_DELTA < delta)
            delta -= 360.f;
        else if (-MAX_DELTA > delta)
            delta += 360.f;

        /* accumlate the changes without wrap-around */
        output += delta;
        printf("%f\n", output);

        /* store the value for calculating the next delta */
        previous = next;

        /* read angle values until end of file is reached */
    } while (EOF != scanf("%f", &next));

    exit(0);
}

0
使用取模函数。
static inline float GetAbsoluteModulous(float input ,float devisor )
{
    double output = (devisor==0)?input:fmod(input, devisor);
    return (output>0)?output:devisor+output;
} 

angle = GetAbsoluteModulous(angle,360);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接