시끄러운 사인파의 제로 크로싱


9

사인파를 사각 파로 변환하기 위해 사인파의 교차점을 찾으려고합니다. 유일한 문제는 사인파가 시끄러워서 많은 지터와 잘못된 제로 크로싱을 얻는다는 것입니다.

누구나 간단한 유사 코드 또는 관련 자료를 추천 할 수 있습니까? 지금까지 나는 이와 같은 것을 가지고있다 :

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

누구나 더 강력한 방법을 추천 할 수 있습니까?


그것을 사각 파로 만들려는 목적은 무엇입니까? 신호가 시작하고 끝나는 위치를 찾으려고합니까? 당신이 있다면 나는 방법을 추천 할 수 있습니다.
Spacey

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

답변:


8

입력 신호를 저역 통과 필터링하여보다 부드러운 제로 크로싱 (또는 사인파의 주파수 위치를 잘 알고있는 경우 대역 통과 필터링)을 시도 할 수 있습니다. 샘플 정확도의 위상 정보가 애플리케이션에 필수적인 경우 필터의 추가 지연이 문제가 될 위험이 있습니다.

또 다른 접근법 : 사인파를 구형파로 변환하는 대신 사인파와 위상 / 주파수를 맞추기 위해 독립 구형파 발진기를 얻는 것은 어떻습니까? 이것은 위상 고정 루프 로 수행 할 수 있습니다 .


6

당신이 확실히 보여준 것은 제로 크로싱 검출기입니다. 상황을 개선 할 수있는 몇 가지 사항이 있습니다.

  • 신호 대역 외부에 노이즈가있는 경우 (입력이 순수한 톤이므로 거의 모든 경우에 해당) 관심 신호 주위에 대역 통과 필터를 적용하여 신호 대 잡음비를 개선 할 수 있습니다. . 필터의 통과 대역 폭이 선택 당신이 정현파 주파수 방법을 알고 정확하게에 기초해야 선험적 . 정현파에 존재하는 노이즈의 양을 줄임으로써 잘못된 제로 크로싱 횟수와 올바른 크로싱 시간에 대한 지터가 감소합니다.

    • 참고로, 사전에 좋은 정보가 없다면, 적응 형 라인 인핸서 (adaptive line enhancer) 라고하는보다 정교한 기술을 사용할 수 있는데, 이는 이름에서 알 수 있듯이주기적인 입력 신호를 향상시키는 적응 형 필터입니다. 그러나 이것은 다소 고급 주제이며 일반적으로 이러한 종류의 접근 방식이 필요하지 않은 신호의 주파수에 대한 충분한 아이디어가 있습니다.
  • 제로 크로싱 검출기 자체와 관련 하여 공정에 약간의 히스테리시스 가 추가 될 수 있습니다 . 이것은 정확한 교차점을 중심으로 여분의 스퓨리어스 측정 교차점이 생성되는 것을 방지합니다. 검출기에 히스테리시스를 추가하면 다음과 같이 보일 수 있습니다.

    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신호가 다시 포지티브로 다시 진동했음을 선언하기 위해 신호가 임계 값 위로 다시 상승해야 합니다.

    원하는 값으로 임계 값을 선택할 수 있지만 정현파와 같은 균형 잡힌 신호의 경우 임계 값을 0으로 대칭하는 것이 좋습니다. 이 접근 방식은보다 깔끔한 출력을 제공하는 데 도움이 될 수 있지만 실제로는 제로 크로싱 대신 0이 아닌 임계 값 크로싱을 측정한다는 사실로 인해 약간의 시간 지연이 발생합니다.

Pchen이 당신이하려는 일을 거의 정확하게 수행하기 때문에 pichenettes가 그의 대답에서 제안했듯이 위상 고정 루프가 가장 좋은 방법 일 것입니다. 요컨대, 입력 정현파와 병렬로 작동하는 구형파 발생기를 실행합니다. PLL은 정현파에 대해 주기적 위상 측정을 한 다음, 구형파 발생기의 순간 주파수를 조정하기 위해 측정 스트림을 필터링합니다. 어떤 시점에서 루프는 (희망적으로) 잠기 며,이 지점에서 구형파는 입력의 정현파로 주파수와 위상으로 고정되어야합니다 (물론 약간의 오차가 있습니다. 엔지니어링에는 완벽하지 않습니다).


슈미트 트리거입니까?
Davorin

실제로 슈미트 트리거 의 소프트웨어 버전이라고 말할 수 있습니다 . 슈미트 트리거의 특징은 히스테리시스가있는 비교기라는 것입니다.
Jason R

전이를 감지하지 않으려면 두 조건 중 하나에 임계 값도 포함하십시오 T. 대신에을 && (sample[i - 1] > -T) && (sample[i] < -T))사용하십시오 && (sample[i - 1] >= -T) && (sample[i] < -T)). 이것은 진술 ifelse if진술 에 모두 적용되어야합니다 .
marc

2

나는 때때로 신호의 부호 변화를 찾는 매우 간단한 방법에 대한 좋은 경험이 있습니다.

  1. a = diff (sign (signal))! = 0 # 부호 변화를 감지합니다
  2. votes = times [a] # 이들은 허위 교차점을 포함하여 모든 후보 지점입니다
  3. 후보에서 포인트의 클러스터를 찾습니다
  4. 각 군집의 평균 / 중앙값, 부호 변경입니다

  5. 4에 의해 예측 된 지점에서 스텝 함수와 상관 관계

  6. 상관 관계 결과에 곡선 맞추기 및 피크 찾기

필자의 경우 5와 6은 방법의 정밀도를 높이 지 않습니다. 노이즈로 신호를 디더링하고 도움이되는지 확인할 수 있습니다.


2

나는이 질문이 다소 오래되었다는 것을 알고 있지만 최근에는 제로 크로싱을 구현해야했습니다. Dan이 제안한 방식을 구현했으며 결과에 만족합니다. 누군가 관심이 있다면 여기에 파이썬 코드가 있습니다. 정말 우아한 프로그래머가 아니에요, pls 나와 함께 곰.

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()

Pls 참고 : 내 코드는 부호를 감지하지 못하고 목표 임계 값에 대한 약간의 사전 지식을 사용하여 시간 임계 값을 결정합니다. 이 임계 값은 그룹 중간 값에 가장 가까운 것을 선택하는 다중 교차 (그림의 다른 색상 점)를 그룹화하는 데 사용됩니다 (그림의 파란색 십자가).

십자 표시가없는 잡음이있는 사인파

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.