Oznaczanie sygnału z fotodiody

Odpowiedz Nowy wątek
2015-02-09 17:15
0

Poszukuję dokładnej i wydajnej metody do automatycznego oznaczania sygnału pochodzącego z fotodiody, na podstawie wartości amplitudy zebranego sygnału. Powiedzmy, że rejestruję z monitora zmiany jasności, które wynikają z wyświetlania na nim czarnych i białych pól o różnym kontraście. Sygnał, który rejestruje fotodioda dla częstotliwości rejestracji 1024 Hz wygląda tak (oś x w sekundach):

3s.jpg

Teraz zależy mi, aby dokładnie w czasie osadzić na sygnale "markery", które będą wskazywać, w którym momencie nastąpiła zmiana jasności monitora. Nie chodzi mi bynajmniej o rysowanie czerwonej kreski na wykresie :) Bardziej zależy mi, aby na podstawie posiadanego sygnału "znaleźć" miejsca w czasie, w których nastąpiła zmiana wyświetlanego obrazu.

2s.jpg

Przykładowy set danych:
data.txt

Eny ajdijas? :)

  • data.txt (0,72 MB) - ściągnięć: 55
  • 2s.jpg (0,04 MB) - ściągnięć: 74
  • 3s.jpg (0,03 MB) - ściągnięć: 84

The quieter you become, the more you are able to hear.
edytowany 1x, ostatnio: Gjorni, 2015-02-09 17:16

Pozostało 580 znaków

2015-02-09 19:43
2

Licz sobie pochodną / przyrost wartości funkcji dla kolejnych par punktów i tam gdzie nagle będzie wyraźny skok tam masz skok ;]
Czyli po prostu abs(f(t)-f(t+h)/h) i jak nagle będzie to duża liczba to masz skok.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
edytowany 1x, ostatnio: Shalom, 2015-02-09 19:44

Pozostało 580 znaków

2015-02-10 12:13
0

Dzięki @Shalom za odpowiedź, ale obawiam się, że to nie takie proste. Sygnał z fotodiody nie utrzymuje się na stosunkowo stałym poziomie przy określonej luminancji monitora, ale oscyluje non-stop. Wygląda to tak:

s3.jpg

...czerwonym kwadracikiem jest zaznaczony obszar, który został po powiększeniu przedstawiony poniżej:

s2.png

Siedzę teraz nad metodą wykorzystującą średnie kroczące, ale też mi to nie leży...

  • s2.png (0,06 MB) - ściągnięć: 72
  • s3.jpg (0,04 MB) - ściągnięć: 60

The quieter you become, the more you are able to hear.

Pozostało 580 znaków

2015-02-10 12:31
0

No dobra, ale z tego wynika że amplituda w pewnej chwili mocno skacze. Tzn masz przez pewien czas np. 60-2000 a nagle robi się z tego 60-3000. Może wystarczy w takim razie pamiętać ostatnią amplitudę (z dokładnościa do pewnej delty) i w ten sposób wykrywać skok? :)


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
Wyzerowałem teraz jeszcze wartości poniżej danego progu, żeby ustabilizować "spód" sygnału. Powinno być teraz łatwiej :) - Gjorni 2015-02-10 12:34

Pozostało 580 znaków

2015-02-10 12:48
1

1) zrób filtr dolnoprzepustowy (odrzucasz drobne drgania)
http://www.ufxmarkets.com/lea[...]advanced/calculating-the-macd
https://autotradingstrategy.w[...]g-exponential-moving-average/
http://en.wikipedia.org/wiki/Filter_%28signal_processing%29

2) zamień sygnał amplitudowy na skokowy
Np:
jeśli abs(dy/dx) > próg -> wynik = wartość sygnału lub "1".
inaczej -> 0

Wynik z (2) to właśnie sygnał którego szukasz.
Co do (1) to linki są wg stopnia trudności (najprostszy na początku).


Szacuje się, że w Polsce brakuje 50 tys. programistów
edytowany 4x, ostatnio: vpiotr, 2015-02-10 14:00

Pozostało 580 znaków

2015-02-10 15:07
1

No więc tak. Do sygnału z fotodiody zastosowałem filtr dolnoprzepustowy, tj.:

# File name "Filters.py"

import scipy.signal as ss

def filt(sig, sf, cf, btype='higphass'):
    """
    :param sig: signal.
    :param sf: sampling frequency.
    :param cf: cut frequencies - array.
    :param btype: bandpass type.
    :return: bandpassed signal.
    """
    if btype == 'higphass' or btype == 'lowpass':
        b, a = ss.butter(3, Wn=cf/(0.5*sf), btype=btype, analog=0, output='ba')
        return ss.filtfilt(b, a, sig)
    elif btype == 'bandstop' or btype == 'bandpass':
        b, a = ss.butter(3, Wn=(cf[0]/(0.5*sf), cf[1]/(0.5*sf)), btype=btype, analog=0, output='ba')
        return ss.filtfilt(b, a, sig)

I jego użycie dla 40 Hz:

import IBD.ElectricalStimulation.Filters as filt

filtered = filt.filt(signal, 1024, 40, btype='lowpass')
py.plot(time_scale, filtered)

Co dało mi:

f1.png

Po czym wyliczyłem pochodną dla całego sygnału, dla kroku = 1, a całość podniosłem do kwadratu, żeby uwypuklić wartości.

# Derivate signal.
step = 1
accuracy_range = 9
derivative = np.diff(filtered, n=step)
derivative = np.append(derivative, np.zeros(step)) ** 2
derivative[derivative > accuracy_range] = np.max(filtered)
derivative[derivative < accuracy_range] = 0
py.plot(time_scale, derivative)

Otrzymałem w rezultacie coś takiego:

f2.png

Prawie jestem w domu, ale niestety nie udaje mi się "uwzględnić" wszystkich "eventów", tj. wszystkich "istotnych" załamków.

UPDATE
Udało mi się jeszcze zwiększyć dokładność oznaczania, manipulując wartością obcinanej częstotliwości i zmienną accuracy_range. Jednak tak, czy siak niektóre eventy pozostają nieoznaczone :/

# Bandpass signal.
import IBD.ElectricalStimulation.Filters as filt

filtered = filt.filt(signal, 1024, 33, btype='lowpass')
py.plot(time_scale, filtered)

# Derivate signal.
step = 1
accuracy_range = 1
derivative = np.diff(filtered, n=step)
derivative = np.append(derivative, np.zeros(step)) ** 2
derivative[derivative > accuracy_range] = np.max(filtered)
derivative[derivative < accuracy_range] = 0
py.plot(time_scale, derivative)

f3.png

UPDATE 2

Wymyśliłem jeszcze coś takiego:

def walk_on_the_bitch(sig, t, interval=1000):
    """
    :param sig:         Pre-processed signal, ie. filtered.
    :param t:           Threshold.
    :param interval:    Interval between next value check (ms);
                        should be a predictive interval between each event.
    """
    last_value = 0
    interval_flag = True
    interval_iterator = 0
    markers = np.zeros(np.size(sig))
    for i in np.arange(np.size(sig)):
        absolute = np.abs(last_value - sig[i])
        last_value = sig[i]
        if interval_flag:
            if absolute > t:
                markers[i] = np.max(sig)
                interval_flag = False
        else:
            if interval_iterator == interval:
                interval_flag = True
                interval_iterator = 0
            else:
                interval_iterator += 1

    return markers

py.plot(time_scale, walk_on_the_bitch(filtered, 0.02))

z4.png

Działa niby idealnie. Nie podoba mi się jednak ta drabinka ifów. Będę musiał jeszcze jednak nad tym pomyśleć. Dzięki chłopaki za pobudzenie kory :)

  • z4.png (0,04 MB) - ściągnięć: 91
  • f1.png (0,02 MB) - ściągnięć: 64
  • f3.png (0,02 MB) - ściągnięć: 61
  • f2.png (0,02 MB) - ściągnięć: 70

The quieter you become, the more you are able to hear.
edytowany 7x, ostatnio: Gjorni, 2015-02-10 18:13

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0