[AD2][Pascal] discoveroskop - cykliczna akwizycja danych i histereza triggera | Port Waveforms SDK na Free Pascal | cz.2

Tutaj umieszczamy tematy związane z językami programowania niepasującymi do innych działów.
Regulamin forum
Temat prosimy poprzedzić nazwą języka umieszczonego w nawiasach kwadratowych np. [Pascal].
Awatar użytkownika
tasza
Expert
Expert
Posty: 901
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

[AD2][Pascal] discoveroskop - cykliczna akwizycja danych i histereza triggera | Port Waveforms SDK na Free Pascal | cz.2

Postautor: tasza » piątek 07 gru 2018, 22:34

♬ ☘ Moja muzyka do kodowania ♬ ♬ ♬ ☘
♫ ♩ ♪ KAUAN ⚡ ☘ ⚡ Sorni Nai ♪ ♩ ♫
https://youtu.be/dO02VJEYYEk



dla ustalenia uwagi

Wielbiciele Analog Discovery 2 pewnikiem te stronki na pamięć znają, niemniej jednak profilaktycznie zaparkuję tu dwa arcyważne moim zdaniem linki - do schematów i opisu SDK:

:arrow: Analog Discovery 2 Reference Manual
:arrow: WaveForms SDK Reference Manual

Tematem dzisiejszej wieczorynki będzie cykliczna akwizycja danych wyzwalana ustalonymi programowo parametrami badanego przebiegu. Czyli to, co robi pierwszy z brzegu sensowny oscyloskop. Przykładowe programiki od Digilent dla języków C/C++ oraz Python poruszają ten temat, ale co innego jest wyrzucić strumień liczb na konsolę tekstową, a co inne - jakoś te próbki pokazać w formie oscylogramu. Jest tu kilka drobiazgów do omówienia, a zatem po kolei...

Zaczniemy od prezentacji instalacji - pudełeczko AD2 w roli oscyloskopu, cukierkowy Rigol do weryfikacji co się dzieje na biurku, generator pracowicie produkuje testowe przebiegi.

00_IMG_4742.jpg


czarcia zapadka

Prezentacja stabilnego przebiegu na ekranie, oprócz ustawienia parametrów czasowych i napięciowych akwizycji danych, wymaga jednej ważnej rzeczy - określenia miejsca przebiegu, które potraktujemy jako punkt zero na osi czasu, dzielący zestaw próbek na dwa zbiory - przed i po wyzwoleniu pomiaru. I to właśnie rola triggera, jego poprawne ustawianie to tak naprawdę clue obsługi oscyloskopu, ponieważ zapewnia w miarę stabilny obraz na ekranie, pozwala dowolnie długo kontemplować oscylogram a jednocześnie będzie to przebieg "żywy", nadążający kształtem za mierzonym sygnałem. Jak to robią profesjonalne rozwiązania to wszyscy wiemy, ale może dla przypomnienia krótki filmik:

https://youtu.be/B2pNbQ4Vdao

Na rysunku poniżej jeszcze jedna migawka - czerwoną kropą zaznaczyłam punkt, w którym pracuje trigger - na poziomie 1V, w tym miejscu przyrządy centrują przebieg na ekranie.

01_trig1.png


Spróbujmy mniej więcej to samo zrobić, ale własnym sumptem przy pomocy Lazarusa i świeżo wyklutego modułku dwf.pas. Cała aplikacja simplescope1 dostępna jest w git, o tutaj:

:arrow: https://github.com/bienata/AnalogDiscov ... mplescope1

Kluczowe dla sukcesu całej zabawy jest poprawne zainicjowanie procesu zbierania danych przez AD2. Warto też mieć świadomość jak postępuje nasze pudełeczko z chomikowanymi próbkami, bo to akurat nie jest już takie intuicyjne. Zerknijmy na fragment kodu, przygotowujący AD2 do cyklicznej akwizycji przebiegu:

main.pas pisze:

Kod: Zaznacz cały

procedure TMainForm.PrepareSimpleScope;
begin
  // kanal 0 on
  FDwfAnalogInChannelEnableSet ( hAd2, 0, true );
  // offset na 0
  FDwfAnalogInChannelOffsetSet( hAd2, -1, 0 );
  // zakres 5Vpp
  FDwfAnalogInChannelRangeSet( hAd2, -1, 5.0 );
  // 100kHz, 100pt/div ->  1ms/div
  FDwfAnalogInFrequencySet( hAd2, 100E+3 );
  // buforek np 512 sampli
  FDwfAnalogInBufferSizeSet( hAd2, MAX_SAMPLES );
  // autotrigger na off
  FDwfAnalogInTriggerAutoTimeoutSet( hAd2, 0.0 );
  // wyzwalaj sygnalem analogowym
  FDwfAnalogInTriggerSourceSet( hAd2, trigsrcDetectorAnalogIn );
  // z kanalu 0
  FDwfAnalogInTriggerChannelSet( hAd2, 0 );
  // wyzwalanie zboczem
  FDwfAnalogInTriggerTypeSet( hAd2, trigtypeEdge );
  // poziom 1V
  FDwfAnalogInTriggerLevelSet( hAd2, 1.0 );
  // histereza 100mV
  FDwfAnalogInTriggerHysteresisSet ( hAd2, 0.1 );
  // narastajaco
  FDwfAnalogInTriggerConditionSet( hAd2, trigcondRisingPositive );
end;


Komentarze tłumaczą wszystko, a MAX_SAMPLES to stała określająca ile próbek będziemy sobie życzyć od naszego pudełeczka w każdym cyklu odczytu. No i tak na logikę - skoro dane składowane są w bufor w pamięci, to wydawałoby się naturalne, że zerowa próbka to wartość z chwili uruchomienia akwizycji, kolejne - to nasz przebieg magazynowany w RAM aż do wysycenia bufora. A tu zrobione jest inaczej, sprytniej. Jak zerkniemy sobie do dokumentacji SDK, do części "Analog In (Oscilloscope)" to na obrazku wyraźnie widać fazę Prefill, przed wyzwoleniem triggera. Ona zaczyna się zaraz po skonfigurowaniu parametrów i zapewnia dostęp do historycznych próbek względem momentu zadziałania triggera. A chytrość budowy AD2 polega na tym, że Prefill ustawia się na połowę rozmiaru zadanego bufora danych, inaczej mówiąc - na połowę widocznego fragmentu odciętych, określającą dziedzinę czasu, czy to w sekundach czy w próbkach. Zerknijmy na rysunek dla kilku wartości MAX_SAMPLES - jak widać, po zadziałaniu triggera na poziomie 1V przebieg jest ładnie "zaczepiony" w zadanym przez nas miejscu.

02_buff-1.png


Oczywiście taka prezentacja bufora 0...N próbek wymaga drobnego zabiegu podczas ładowania danych do wykresu, a mianowicie oś X inicjujemy wartościami -N/2...N/2.
main.pas pisze:

Kod: Zaznacz cały

self.WaveLineSeries1.Clear;
for n := 0 to MAX_SAMPLES - 1 do
begin
   self.WaveLineSeries1.AddXY( n - round ( MAX_SAMPLES/2 ), waveform [ n ] );
end;


Finalny efekt będzie do złudzenia przypominał to, co pokazuje na ekranie Rigol czy aplikacja WaveForms. Filmik z działającym "discoveroskopem" poniżej:

https://youtu.be/nmFM4WMQd28


Może dwa słowa o cyklicznym uruchamianiu zbiórki darów z przetwornika A/C, a mianowicie: po skonfigurowaniu parametrów uzbrajamy trigger wydając polecenie rozpoczęcia akwizycji:

main.pas pisze:

Kod: Zaznacz cały

FDwfAnalogInConfigure ( hAd2, false, true );
repeat
   FDwfAnalogInStatus( hAd2, true, @status );
   Delay (1);
until status = stsDone;
FDwfAnalogInStatusData( hAd2, 0, @waveform, MAX_SAMPLES );


AD2 zaczai się na zadany przez nas punkt w przebiegu, wykona serię pomiarów składując próbki w pamięci, gdy osiągnie koniec buforka - zwróci stsDone co będzie dla nas sygnałem, że można sobie zabrać dane funkcją FDwfAnalogInStatusData(). No i trzeba to biegiem zrobić, ponieważ musimy zdążyć przed następnym cyklem - armed/triggered/read/done. Ten fragment kodu wywoływany jest w handlerze obsługi aplikacyjnego czasomierza (obiekt Timer), szybkość jego pracy określa częstotliwość odświeżania przebiegu na wykresie TChart.

histeria i histereza

No, z histerią to koloryzuję deko, ja nie z takich, ale przyznam - wnerw mnie w pewnej chwili złapał, bo pracowicie wydziubana aplikacyjka nijak nie chciała pokazywać stabilnego przebiegu, tak jak to robił Rigol obok. Pomimo ustawienia triggera na narastające dodatnie zbocze, on łapał raz narastające, jak mu się chciało - to opadające, bez żadnej konsekwencji. A przecież wszystko zrobiłam tak jak w digilentowych przykładach, a tu lipa. Filmik z tej jazdy taki i od razu pokazuje w czym była rzecz:

https://youtu.be/ROhjGd47ShA

Sztuczka polega na dodatkowym ustawieniu jednego drobnego parametru - faktycznych poziomów zadziałania triggera uwzględniających pewną histerezę wartości, to na okazję eliminacji szumów czy innych zakłóceń, mogących skutkować chybionymi wyzwoleniami. Histerezę ustawia się funkcją FDwfAnalogInTriggerHysteresisSet(), eksperymentalnie wybrałam sobie 100mV, dla triggera 1V to w miarę dobra wartość i voilà - przebieg trzyma się ekranu jak przyklejony, no super! Nie zmienia to faktu, że tu zadziałałam zupełnie intuicyjnie, przykłady nie wyjaśniają tej funkcji dokładnie, jest użyta jeno raz (/usr/share/digilent/waveforms/samples/py/AnalogIn_Record_Trigger.py) i bez żadnego komentarza. Jak widać, nie ma łatwo, ale tym przedniejsza ta cała zabawa.

#slowanawiatr
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
___________________________________________ ____ ___ __ _ _ _ _
J​eżeli dadzą ci papier w linie, pisz w poprzek. Juan Ramón Jiménez

Wróć do „Inne języki programowania”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość