2013-02-27 17 views
8

Mam tablicę wartości CSV reprezentujących cyfrowe wyjście. Został on zebrany przy użyciu oscyloskopu analogowego, więc nie jest to idealny sygnał cyfrowy. Próbuję odfiltrować dane, aby uzyskać doskonały sygnał cyfrowy do obliczania okresów (które mogą się różnić). Chciałbym również zdefiniować maksymalny błąd jaki dostaję z tej filtracji.Digitalizacja sygnału analogowego

coś takiego:

enter image description here

Idea

Nałożyć Próg od danych. Oto pseudokod:

for data_point_raw in data_array: 
    if data_point_raw < 0.8: data_point_perfect = LOW 
    if data_point_raw > 2 : data_point_perfect = HIGH 

else: 
    #area between thresholds 
    if previous_data_point_perfect == Low : data_point_perfect = LOW 
    if previous_data_point_perfect == HIGH: data_point_perfect = HIGH 

Dotykają mnie dwa problemy.

  1. Wydaje się, że jest to powszechny problem w cyfrowym przetwarzaniu sygnału, jednak nie znalazłem dla niego predefiniowanej funkcji standardowej. Czy jest to dobry sposób na filtrowanie?
  2. Jak uzyskać maksymalny błąd?
+0

Całkowicie styczny, ale oscyloskop analogowy jest znacznie lepszy na stole niż cyfrowy zakres. Zakresy cyfrowe mają minimalną ziarnistość (zarówno na wyjściu wejściowym, jak i wyjściowym) i mają tendencję do połysku w zakresie wartości odstających. – L0j1k

+0

Czy brałeś pod uwagę [Matlab?] (Http://www.mathworks.com/products/matlab/) w połączeniu z Pythonem, zobacz [This] (https://sites.google.com/site/pythonforscientists/python- vs-matlab). i [This] (http://matplotlib.org/) –

+0

@ L0j1k Cóż, w rzeczywistości jest cyfrowy, używamy tylko sond analogowych, więc sami możemy dokonać konwersji :) – TheMeaningfulEngineer

Odpowiedz

6

Oto kawałek kodu, który może pomóc.

from __future__ import division 

import numpy as np 


def find_transition_times(t, y, threshold): 
    """ 
    Given the input signal `y` with samples at times `t`, 
    find the times where `y` increases through the value `threshold`. 

    `t` and `y` must be 1-D numpy arrays. 

    Linear interpolation is used to estimate the time `t` between 
    samples at which the transitions occur. 
    """ 
    # Find where y crosses the threshold (increasing). 
    lower = y < threshold 
    higher = y >= threshold 
    transition_indices = np.where(lower[:-1] & higher[1:])[0] 

    # Linearly interpolate the time values where the transition occurs. 
    t0 = t[transition_indices] 
    t1 = t[transition_indices + 1] 
    y0 = y[transition_indices] 
    y1 = y[transition_indices + 1] 
    slope = (y1 - y0)/(t1 - t0) 
    transition_times = t0 + (threshold - y0)/slope 

    return transition_times 


def periods(t, y, threshold): 
    """ 
    Given the input signal `y` with samples at times `t`, 
    find the time periods between the times at which the 
    signal `y` increases through the value `threshold`. 

    `t` and `y` must be 1-D numpy arrays. 
    """ 
    transition_times = find_transition_times(t, y, threshold) 
    deltas = np.diff(transition_times) 
    return deltas 


if __name__ == "__main__": 
    import matplotlib.pyplot as plt 

    # Time samples 
    t = np.linspace(0, 50, 501) 
    # Use a noisy time to generate a noisy y. 
    tn = t + 0.05 * np.random.rand(t.size) 
    y = 0.6 * (1 + np.sin(tn) + (1./3) * np.sin(3*tn) + (1./5) * np.sin(5*tn) + 
       (1./7) * np.sin(7*tn) + (1./9) * np.sin(9*tn)) 

    threshold = 0.5 
    deltas = periods(t, y, threshold) 
    print "Measured periods at threshold %g:" % threshold 
    print deltas 
    print "Min: %.5g" % deltas.min() 
    print "Max: %.5g" % deltas.max() 
    print "Mean: %.5g" % deltas.mean() 
    print "Std dev: %.5g" % deltas.std() 

    trans_times = find_transition_times(t, y, threshold) 

    plt.plot(t, y) 
    plt.plot(trans_times, threshold * np.ones_like(trans_times), 'ro-') 
    plt.show() 

Wyjście:

Measured periods at threshold 0.5: 
[ 6.29283207 6.29118893 6.27425846 6.29580066 6.28310224 6.30335003] 
Min: 6.2743 
Max: 6.3034 
Mean: 6.2901 
Std dev: 0.0092793 

Plot

Można użyć numpy.histogram i/lub matplotlib.pyplot.hist do dalszej analizy tablicy zwróconej przez periods(t, y, threshold).

1

Jeśli naprawdę interesujesz się tylko okresem, możesz wykreślić transformację Fouriera, będziesz miał szczyt, w którym występuje częstotliwość sygnałów (a więc masz okres). Szerszy szczyt w domenie Fouriera, tym większy błąd w pomiarze okresu

import numpy as np 

data = np.asarray(my_data) 

np.fft.fft(data) 
+0

Fajny pomysł, jednak staramy się uzyskać histogram okresów, abyśmy mogli stwierdzić, w jakim procencie odpowiada naszym potrzebom. Jest to eksperyment w dziedzinie implementacji różnych PWM oprogramowania na Malina py. – TheMeaningfulEngineer

1

Twój filtrowanie jest w porządku, to jest w zasadzie taki sam jak przerzutnik Schmitta, ale główny problem może mieć z niego jest szybkość. Zaletą korzystania z Numpy jest to, że może być tak szybki jak C, podczas gdy musisz powtórzyć jeden raz nad każdym elementem.

Możesz osiągnąć coś podobnego za pomocą filtru medianowego z SciPy. Poniższy powinna osiągnąć podobny wynik (i nie jest uzależnione od jakichkolwiek wielkości):

filtered = scipy.signal.medfilt(raw) 
filtered = numpy.where(filtered > numpy.mean(filtered), 1, 0) 

Można dostroić siła mediany filtrowanie medfilt(raw, n_samples), n_samples domyślnie 3.

Co do błędu, to będzie bardzo subiektywne. Jednym ze sposobów byłoby dyskretyzowanie sygnału bez filtrowania, a następnie porównywanie różnic. Na przykład:

discrete = numpy.where(raw > numpy.mean(raw), 1, 0) 
errors = np.count_nonzero(filtered != discrete) 
error_rate = errors/len(discrete) 
2

To nie jest odpowiedź na twoje pytanie, tylko sugestia, która może pomóc. Piszę to tutaj, ponieważ nie mogę umieścić obrazu w komentarzu.

Myślę, że należy jakoś normalizować dane przed jakimkolwiek przetwarzaniem.

Po normalizacji do zakresu 0 ... 1 należy zastosować filtr.

enter image description here

+1

Dzięki za cynk. Jednak w tym konkretnym przykładzie konwertuję sygnał na wartości boolowskie, więc nie widzę korzyści w normalizacji. – TheMeaningfulEngineer