正弦波的零交叉


9

我正在尝试找到正弦波的零交叉点,以将正弦波转换为方波。唯一的问题是正弦波很嘈杂,所以我会遇到很多抖动和错误的零交叉。

谁能推荐任何简单的伪代码或相关材料?到目前为止,我有这样的事情:

if (sample[i]>0 && sample[i+1]<0) || (sample[i]<0 && sample[i+1]>0)

谁能推荐一种更强大的方法?


您试图使其成为方波的目的是什么?您是否要找出信号在哪里开始和结束?如果您是我可以推荐一种方法。
Spacey 2012年

if((sample [i] * sample [i + 1])<0)zero_crossing ++;
Marius Hrisca,

Answers:


8

您可以尝试对输入信号进行低通滤波以获得更平滑的零交叉(如果您对正弦波的频率位置有所了解,甚至可以进行带通滤波)。风险是,如果样品准确的相位信息对于您的应用至关重要,那么来自滤波器的额外滞后可能会成为问题。

另一种方法:与其尝试将正弦波转换为方波,不如让一个独立的方波振荡器将其自身在相位/频率上与正弦波对齐?这可以通过锁相环来完成。


6

您所展示的肯定是一个过零检测器。有几件事可能会改善您的状况:

  • 如果您的噪声超出信号频带(由于输入是纯音,这几乎可以肯定是这种情况),那么可以通过在感兴趣的信号周围应用带通滤波器来提高信噪比。 。滤波器的通带宽度应根据您先验地知道正弦频率精确度来选择。通过减少正弦波上的噪声量,将减少错误的零交叉次数及其在正确的交叉时间附近的抖动。

    • 附带说明一下,如果您事先没有足够的信息,则可以使用更先进的技术,称为自适应线路增强器,顾名思义,它是一种自适应滤波器,可以增强周期性输入信号。但是,这是一个比较高级的主题,通常您对信号的频率已经有了足够的了解,因此不需要这种方法。
  • 关于过零检测器本身,您可能会在过程中添加一些滞后现象。这将防止在正确的穿越时刻周围产生额外的虚假测量穿越。向检测器添加磁滞可能看起来像这样:

    if ((state == POSITIVE) && (sample[i - 1] > -T) && (sample[i] < -T))
    {
        // handle negative zero-crossing
        state = NEGATIVE;
    }
    else if ((state == NEGATIVE) && (sample[i - 1] < T) && (sample[i] > T))
    {
        // handle positive zero-crossing
        state = POSITIVE;
    }
    

    实际上,您可以向过零检测器添加一些状态。如果您认为输入信号具有正值,则要求信号下降到选定的阈值以下-T才能声明真正的过零。同样,您要求信号回升到阈值以上T才能声明信号再次振荡回正。

    您可以选择任意阈值,但是对于正弦曲线之类的平衡信号,有意义的是使它们对称于零。这种方法可以帮助您获得更清晰的输出,但是由于您实际上是在测量非零阈值交叉点而不是零交叉点,因此会增加一些时间延迟。

正如皮肯特在他的回答中所暗示的那样,锁相环很可能是最好的选择,因为PLL几乎可以完全满足您的要求。简而言之,您将运行与输入正弦波并联运行的方波发生器。PLL在正弦波上进行周期性的相位测量,然后对测量流进行滤波,以控制方波发生器的瞬时频率。在某个时候,环路将(希望)锁定,在这一点上,方波应该在频率和相位上与输入的正弦波锁定(当然会有一些误差;工程上没有什么是完美的)。


那是施密特触发器吗?
达沃林

确实,您可以说这是施密特触发器的软件版本。施密特触发器的主要特征是它是具有滞后的比较器
Jason R

为了避免未检测到过渡,在两个条件中的任何一个条件中也都包括阈值T。代替意思&& (sample[i - 1] > -T) && (sample[i] < -T)),使用&& (sample[i - 1] >= -T) && (sample[i] < -T))。这需要同时应用于ifelse if语句。
马克·

2

我对使用非常简单的方法有时会发现信号的符号变化有很好的经验:

  1. a = diff(sign(signal))!= 0#这会检测符号变化
  2. 候选人=时间[a]#这些都是所有候选点,包括虚假穿越
  3. 在候选人中找到点簇
  4. 每个群集的平均值/中位数,这是您的符号变化

  5. 在4预测的点上与阶跃函数相关

  6. 将曲线拟合到相关结果并找到峰

在我的情况下5和6不会增加方法的精度。您可以用噪声来抖动信号,看看是否有帮助。


2

我知道这个问题比较老,但是最近我不得不实施零交叉。我执行了Dan建议的方式,并对结果感到满意。如果有人感兴趣,这是我的python代码。我不是一个优雅的程序员,请忍受我。

import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle

fig = plt.figure()
ax = fig.add_subplot(111)

sample_time = 0.01
sample_freq = 1/sample_time

# a-priori knowledge of frequency, in this case 1Hz, make target_voltage variable to use as trigger?
target_freq = 1
target_voltage = 0

time = np.arange(0.0, 5.0, 0.01)
data = np.cos(2*np.pi*time)
noise = np.random.normal(0,0.2, len(data))
data = data + noise


line, = ax.plot(time, data, lw=2)

candidates = [] #indizes of candidates (values better?)
for i in range(0, len(data)-1):
    if data[i] < target_voltage and data[i+1] > target_voltage:
        #positive crossing
        candidates.append(time[i])
    elif data[i] > target_voltage and data[i+1] < target_voltage:
        #negative crossing
        candidates.append(time[i])

ax.plot(candidates, np.ones(len(candidates)) * target_voltage, 'rx')
print('candidates: ' + str(candidates))

#group candidates by threshhold
groups = [[]]
time_thresh = target_freq / 8;
group_idx = 0;

for i in range(0, len(candidates)-1):
    if(candidates[i+1] - candidates[i] < time_thresh):
        groups[group_idx].append(candidates[i])
        if i == (len(candidates) - 2):
            # special case for last candidate
            # in this case last candidate belongs to the present group
            groups[group_idx].append(candidates[i+1])
    else:
        groups[group_idx].append(candidates[i])
        groups.append([])
        group_idx = group_idx + 1
        if i == (len(candidates) - 2):
            # special case for last candidate
            # in this case last candidate belongs to the next group
            groups[group_idx].append(candidates[i+1])



cycol = cycle('bgcmk')
for i in range(0, len(groups)):
    for j in range(0, len(groups[i])):
        print('group' + str(i) + ' candidate nr ' + str(j) + ' value: ' + str(groups[i][j]))
    ax.plot(groups[i], np.ones(len(groups[i])) * target_voltage, color=next(cycol), marker='o',  markersize=4)


#determine zero_crosses from groups
zero_crosses = []

for i in range(0, len(groups)):
    group_median = groups[i][0] + ((groups[i][-1] - groups [i][0])/2)
    print('group median: ' + str(group_median))
    #find index that best matches time-vector
    idx = np.argmin(np.abs(time - group_median))
    print('index of timestamp: ' + str(idx))
    zero_crosses.append(time[idx])


#plot zero crosses
ax.plot(zero_crosses, np.ones(len(zero_crosses)) * target_voltage, 'bx', markersize=10) 
plt.show()

请注意:我的代码无法检测到信号,并且使用了对目标频率的先验知识来确定时间阈值。此阈值用于对多个交叉点(图片中的不同色点)进行分组,从中选择最接近组中位数的那个(图片中的蓝色叉号)。

带有零交叉标记的正弦波

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.