So che questa domanda è piuttosto vecchia, ma di recente ho dovuto implementare lo zero crossing. Ho implementato il modo suggerito da Dan e sono piuttosto soddisfatto del risultato. Ecco il mio codice Python, se qualcuno è interessato. Non sono davvero un programmatore elegante, ti prego.
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()
Nota Pls: il mio codice non rileva i segni e usa una piccola conoscenza a priori di una frequenza target per determinare la soglia temporale. Questa soglia viene utilizzata per raggruppare l'attraversamento multiplo (diversi punti di colore nell'immagine) da cui viene selezionato quello più vicino alla mediana dei gruppi (croci blu nell'immagine).