相位 unwrap 与 wrap 算法详解(附代码)
最近接手了一个项目,光通信方面的,我负责编写初测结果的数据处理算法,其中有一个算法叫做 unwrap 与 wrap,之前没有听说过。通过询问同事与搜索引擎,原来,所谓的 unwrap 是将在 +180 度到 -180 度之间跳变的相位信号,也就是函数值,变为不跳变的形态。而 wrap 则是其逆运算,即将信号恢复成跳变状态。
通过分析与几次尝试后,成功完成了业务需求,所以在这里总结归纳一些技巧,分享出来(博主不是通信专业的,只是站在程序员的角度看,如有不妥,欢迎指出)
我们用数据与图象来详细说明。
基本概念与数学关系
假设有一组相位数据(在后续说明中,为方便起见,我们只粗略地用整数部分来进行说明,比如第一个值我们就当作 -59 度):
-59.634834
-92.078697
-126.824913
-158.910297
166.959301
133.708772
96.759715
61.819861
26.786247
-7.944068
…(后面还有很多数据)
如图,这些数据呈现一种类似周期性的循环,当然这并不是真的周期函数,只是因为当它的数值跨越正负 180 度时,就会根据其变化趋势,跳变到边界重新计算。这种状态我们称为相位的卷绕/折叠(网上说法不一),用 wrap 这个单词表示,所以相位的解卷绕/展开被称为 unwrap。
具体到这个示例数据,我们可以得到以下信息:
- 数据本身是递减趋势,从 -59 度不断递减,如 -59、-92、-126、-158。
- 数据中有一个跳变点,即 -158 度到 166 度,也就是图像中第一个正的峰值,跳变后继续下降,直到下次跳变。
unwrap 要做的事情,就是消除这个跳变,让 wrap 函数中 166 度这个点,恢复为 -158 - n 度(n 是正值,为两者之间的间隔)。那么 n 是多少呢,其实很简单,-158 度距离 -180 度为 22 度,达到 -180 度后溢出,起点跳变为 180 度,溢出的值从 180 度继续计算,直到 166 度,距离为 14 度,所以合起来,n 为 22 + 14 = 36 度。
根据这样的规则,wrap 中 166 度这个点,对应的其实是 unwrap 下的 -158 - 36 = -194 度。同时你会发现,166 + 194 恰好是 360 度,而从 -180 跳到 180,也是将函数值增加了 360 度。所以 wrap 的本质,就是当相位超出边界时,补偿 360 度并继续计算,而 unwrap 就是去除这个补偿。所以,wrap 状态下的 166 度对应 unwrap 状态下的 -194 度,之后的 133 度对应 133 - 360 = -227 度,后面每个 wrap 值也都减去 360 度,直到遇见下一个跳变点。
显而易见,第二个 -180 度跳变点,对应的 unwrap 度数为 -180 - 360 = -540 度,其后的值由于跳变,将再次被补偿 360 度,合起来就是 720 度。所以,第二次跳变后的 166 度值,对应的 unwrap 值其实是 -554 度。如此循环,每跳变一次,就要让 wrap 值在之前的基础上,再减去一次 360 度,才能变为正确的 unwrap 值。
由于这里的例子是递减的,wrap 从 -180 跳变到 +180,增加了 360 度,因此 unwrap 计算时需要反向减去 360 度。若是递增函数,那么每次 wrap 自然是从 +180 跳变到 -180,减少 360 度,那么每次 unwrap 就需要重新加上 360 度。你可以将示例数据全部取反,就可以很直观的理解。
因此 unwrap 与 wrap 之间的关系,可以表示为:
u n w r a p ( x ) = w r a p ( x ) − 360 ∗ w r a p N u m ( x ) unwrap(x) = wrap(x) -360 * wrapNum(x) unwrap(x)=wrap(x)−360∗wrapNum(x)
或
u