Нульове перетинання галасливої ​​синусоїди


9

Я намагаюся знайти нульові перетини синусоїди для перетворення синусоїди в квадратну хвилю. Єдина проблема полягає в тому, що синусова хвиля шумна, тому я отримую багато тремтіння та помилкових нульових перетинів.

Хто-небудь може порекомендувати будь-який простий psuedocode або відповідні матеріали? Поки що у мене є щось подібне:

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

Хтось може порекомендувати більш надійний метод?


Яка мета ви намагаєтеся зробити це квадратною хвилею? Ви намагаєтесь з’ясувати, де починається і закінчується сигнал? Якщо ви є, я можу порекомендувати метод.
Спейсі

if ((зразок [i] * зразок [i + 1]) <0) zero_crossing ++;
Маріус Хріска

Відповіді:


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 робить саме те, що ви намагаєтесь зробити. Коротше кажучи, ви запускаєте генератор квадратних хвиль, який працює паралельно вхідному синусоїду. ПЛЛ проводить періодичні вимірювання фаз на синусоїді, потім фільтрує цей потік вимірювань, щоб керувати миттєвою частотою генератора квадратних хвиль. У якийсь момент цикл (сподіваємось) блокується, і в цей момент квадратну хвилю слід замикати за частотою та фазою з синусоїдою входу (звичайно, з деякою кількістю помилок, звичайно, нічого в техніці не ідеально).


Це Шміт-тригер?
Даворин

Дійсно, можна сказати, що це програмна версія тригера Schmitt . Визначальною характеристикою тригера Шмітта є те, що це порівняльник з гістерезисом
Jason R

Щоб уникнути не виявлення переходу, включіть в будь-якому з обох умов також поріг T. Значення замість && (sample[i - 1] > -T) && (sample[i] < -T)), вживати && (sample[i - 1] >= -T) && (sample[i] < -T)). Це потрібно застосувати і до тверджень, ifі до else ifтверджень.
marc

2

Я маю хороший досвід роботи з дуже простим методом пошуку знакових змін сигналу часом:

  1. a = diff (знак (сигнал))! = 0 # це виявляє зміни знаку
  2. Кандидати = раз [a] # це всі кандидатні бали, включаючи помилкові перекреслення
  3. знайти скупчення балів у кандидатів
  4. середня / медіана кожного кластера, це ваша зміна знаку

  5. зробити кореляцію з кроковою функцією в точці, передбачуваній 4

  6. підходить крива до результатів кореляції та знайти пік

У моєму випадку 5 і 6 не підвищують точність методу. Ви можете заглушити свій сигнал шумом і побачити, чи допомагає він.


2

Я знаю, що це питання досить давнє, але мені довелося впроваджувати нульове перетинання останнім часом. Я реалізував те, як запропонував Ден, і досить задоволений результатом. Ось мій код пітона, якщо когось цікавить. Я не дуже елегантний програміст, будьте зі мною.

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

Зверніть увагу: мій код не виявляє ознак і використовує трохи априорі знання про цільову частоту для визначення порогового часу. Цей поріг використовується для групування множинних схрещувань (різних кольорових крапок на малюнку), з яких вибирається найближча до медіани груп (сині хрести на малюнку).

Шумна синусова хвиля з помітними нульовими хрестами

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.