♬ ☘ Moja muzyka do majstrowania ♬ ♬ ♬ ☘
♫ ♩ ♪ Monolith ⚡ ☘ ⚡ Voyager ♪ ♩ ♫
https://youtu.be/nDrjtx6Fhq8
No proszę, jak to liczący sobie latek czterdzieści neonowy mierniczek potrafi zaabsorbować, tematów wymyślać można sobie w bród. A mając już podrutowany interface do komputera PC nie sposób pominąć tematyki prostej akwizycji danych oraz późniejszej obróbki tego, co pracowicie udało się zebrać. Instalacja moja wprawdzie zabawowo zorientowana, niemniej jednak problemy już bardziej na serio, choćby obróbka zabrudzonych danych i ich w miarę sensowna prezentacja, no to zapraszam!
Girls go code
Ardu
No to troszkę oprogramowania najpierw, ponieważ bez stosownego wsparcia softwarowego zabawy nie będzie. Aplikacja na Arduino została nieco zmodyfikowana, pracuje teraz w trybie konwersacyjnym (request-response), czyli jeżeli dostanie polecenie to wtedy odsyła wynik przetwarzania, to proste. Ramka danych zawiera licznik inkrementowany w każdym przerwaniu od miernika, to pozwala stwierdzić, czy kolejno odsyłane komunikaty są świeżymi danymi, czy sucharami z cache. Ramka zawiera znacznik przekroczenia zakresu flagowany jako O (over), gdy nie występuje i odbywają się normalne pomiary - Ardu wysyła tam M (measure). Potem lecą cztery nibble zawartości wyświetlacza, poprzedzone polaryzacją +/-.
I w sumie to tyle.
Pętla główna, interpretująca póki co jedno polecenie:
v628link.ino pisze:Kod: Zaznacz cały
void loop() {
char c = 0x00;
String rxBuff = "";
while ( 1 ) {
if ( Serial.available() > 0 ) {
c = Serial.read();
if ( c == '\n' ) { // process on enter
rxBuff.trim();
processCommand ( rxBuff );
rxBuff = "";
}
else {
rxBuff += c;
if ( rxBuff.length() > 8 ) {
rxBuff = ""; // bad way :-(
}
}
}//if
}//while
}
Obsługa polecenia READ:
v628link.ino pisze:Kod: Zaznacz cały
void processCommand ( String cmd ) {
char t[ 32 ];
unsigned short cntr, value;
if ( cmd == "READ" ) {
noInterrupts();
value = ushLastMeterState;
cntr = ushMeasureCounter;
interrupts();
// response frame
// nnnn|N/O|+abcd\n
sprintf ( t, "%04x|%c|%c%04x",
cntr,
value & (1 << 14) ? 'O' : 'M',
value & (1 << 15) ? '-' : '+',
value & 0x2FFF
);
Serial.println( t );
}
}
Cały projekt w v628daq.zip/v628link/v628link.ino
Pececik
Oprogramowanie V628daq powstało jakiś czas temu na potrzeby artykułu o V543, pod tę prezentację przerobiłam tylko parę detali, ponieważ i wyświetlacz małego Meratronika uboższy i funkcji V628 ma jakby mniej. Programik jest tragicznie wręcz prosty - wysyła co kilkaset milisekund polecenie READ do Ardu w odpowiedzi dostając zachomikowane w nim dane o stanie miernika. Odebrana ramka danych służy do odświeżenia zawartości wyświetlacza. Z interwałem zdefiniowanym via combo `save period` programik zapisuje nowe rekordy oraz ich znacznik czasu do pliku-logu, który zakładany jest na nowo przy każdym uruchomieniu aplikacji. Nowe rekordy dodawane są w trybie append, więc ewentualny pad programiku nie zniszczy nam zgromadzonych danych. Całość została napisana w FPC/Lazarus, tak mi było najwygodniej, do zbudowania projektu potrzeba industrialnych kontrolek i komponentu do portu szeregowego, instalacja tu: industrialne kontrolki a projekt dla Lazarus IDE w v628daq.zip/v628daq
Archiwum z kodami (a także z próbkami danych i skryptami): v628daq.zip
Akwizytorom mówimy...
... udanych wieczornych pomiarów i aby do rana! A instalacja testowa, czyli melanż interfejsu na CD4021, Ardu oraz odejmowaczki napięć na AD708 przedstawia fotografia poniżej.
Programik w działaniu trudno jest uchwycić wespół ze zgodnym odczytem z V628, najmniej kłopotliwy jest tu V640 z racji wrodzonego spokoju - oto odczyty zaokiennego chłodu, no cóż, coraz zimniej jakby:
No i tak sobie to wszystko ładnie działało, dane zrzucały sie do plików, w folderze /data jest ich kilka, ponieważ aplikacja była uruchamiana parę razy. Jeden z plików jest logiem z prawie całej nocy i sporej części poranka, dobry materiał do dalszych zabaw i testów.
Dane, dużo, mnóstwo danych
Przyjęte podejście do magazynowania danych (periodyczny append na logu o unikalnej nazwie per uruchomienie) ma kilka konsekwencji. Po pierwsze, w przypadku wykrycia, że coś idzie nie tak - przerywając program kończymy aktualny zestaw danych. Po drugie - edycja zawartości logu poza plecami programu v628daq choć teoretycznie możliwa jest raczej ryzykowna. Ale za to pliczek z coraz to nowszą zawartością możemy sobie oglądać i przetwarzać różnymi narzędziami i pozyskiwać interesujące nas dane, choć zbiór na dysku ciągle żyje.
awk
Przedstawię może próbkę z logu robioną przez V628daq, będzie łatwiej opowiadać, poniżej pierwsze testy z LM35:
20180222_185815_v628_readings.txt pisze:Kod: Zaznacz cały
2018-02-22 18:58:20|0011|M|+2208
2018-02-22 18:58:25|002a|M|+2209
2018-02-22 18:58:30|0043|M|+2208
2018-02-22 18:58:35|005b|M|+2207
2018-02-22 18:58:40|0074|M|+2206
2018-02-22 18:58:45|008d|M|+2207
A to fragment poranny z największego zrzutu, no prawie minus sześć, brrrr.
20180222_220211_v628_readings.txt pisze:Kod: Zaznacz cały
2018-02-23 05:05:15|e15e|M|-0580
2018-02-23 05:05:20|e176|M|-0579
2018-02-23 05:05:25|e18e|M|-0580
2018-02-23 05:05:30|e1a7|M|-0580
2018-02-23 05:05:35|e1bf|M|-0581
2018-02-23 05:05:40|e1d7|M|-0580
2018-02-23 05:05:45|e1f0|M|-0580
No, wygląda to strasznie technicznie, spróbujemy zatem pozyskać z takich danych informacje w ludzkim formacie, pomocne będzie arcysprytne narządko o nazwie `awk`. Tutoriali do awk jest cała masa, to przecież jeden z podstawowych programików w Unix/Linux, ja akurat zerkałam w te materiały (no i oczywiście radosne pytania do Google typu `awk previous next row`):
http://www.grymoire.com/Unix/Awk.html
https://www.tutorialspoint.com/awk/awk_ ... rators.htm
Najpierw selekcja kolumn z logu, interesuje nas znacznik czasu, zamiast w napięcie trafiłam w znacznik przekroczenia, no każdemu się może zdarzyć:
Kod: Zaznacz cały
awk -F '|' '{ print $1, $3}' 20180222_192400_v628_readings.txt
Stanowczo jednak kolumna $4 będzie lepszym wyborem, przy okazji spróbujemy przerobić prostymi operacjami matematycznymi surową wartość na coś, co przypomina temperaturę:
Kod: Zaznacz cały
awk -F '|' '{ print $1, $4/100}' 20180222_192400_v628_readings.txt
Warto potrenować formatowanie wyników czyli znana i lubiana funkcja printf()
Kod: Zaznacz cały
awk -F '|' '{ printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt
Tu w zasadzie wszystko byłoby fajnie, ale zostawienie tylko jednego miejsca po przecinku zabrało całą dynamikę dalszemu przetwarzaniu, no za mało się dzieje na ekranie po prostu, więc choć sens w tym średni, do rysowanek później będę korzystała z `%2.2f`
To była selekcja danych w pionie, kolumnami, zabieramy sobie to co nam aktualnie z rekordu potrzeba. Jak wspominałam log rozszerzany jest o ustawiony w pascalowej aplikacji interwał czasowy. No ale przecież możemy chcieć dane z określonych momentów, powybieramy sobie zatem pomiary ze wskazanych periodycznych punktów na osi czasu bazując na analizie znacznika w kolumnie $1, to selekcja pozioma.
Przykładowo co 30sek:
Kod: Zaznacz cały
awk -F '|' '(index($0,":00|") !=0)||(index($0,":30|") !=0) { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt
Pełne minuty:
Kod: Zaznacz cały
awk -F '|' ' index($0,":00|") !=0 { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt
A może co 5 minut, w końcu temperatura tak wolnozmienna jest, że niewiele stracimy:
Kod: Zaznacz cały
awk -F '|' ' (index($0,"0:00|") !=0) || (index($0,"5:00|")) !=0 { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt
A za oknem zrobiła się z tego wszystkiego nocka i jej mroźne -4, log z pomiarów powoli aczkolwiek uparcie przyrasta.
gnuplot
Jak to było z tym obrazkiem? Że wart tysiąca słów?
No może i tak, szczególnie gdy potrzebujemy przedstawić zmiany jakiejś wielkości w dziedzinie innej, najczęściej na osi czasu. W Linux jest genialny wręcz programik `gnuplot`, z poziomu konsoli możemy sobie rysować ze zgromadzonych danych naprawdę cudne wykresiki. Ja gnuplot dopiero poznaje, zerkam w te strony i linki dookoła:
https://www.techrepublic.com/blog/linux ... h-gnuplot/
http://gnuplot.sourceforge.net/docs_4.2/node76.html
https://alvinalexander.com/technology/g ... s-examples
http://www.gnuplotting.org/plotting-data/
Póki co to szkice niezbyt urodziwe, ale nawet takie pozwalają zauważyć sprawy, których w kolejnych linijkach cyferek jakoś na pierwszy rzut oka nie widać, o na przykład:
To trwały ślad po próbach doregulowania offsetu -500mV przy działającej instalacji, coś przez chwilę nie stykło, ale Ardu jednak nie zawisło i nie zerwało połączenia z PC - stąd ładnie widać jakie były wartości przez regulacją, potem bhhrrr, potem już po regulacji i przepraszamy za usterki.
Jak się robi wykresiki? Ano podajemy programikowi gnuplot skrypt do wykonania, tam zawarte sa wszelkie informacje o ustawieniach rysowania, osiach skalach i sposobie analizy danych źródłowych. Ja to sobie pozamykałam w małe skrypty, wszystko w folderze /data, a teraz tylko taki nieco ogólny przykład:
live.sh pisze:Kod: Zaznacz cały
gnuplot live.gnu
live.gnu pisze:Kod: Zaznacz cały
set grid
set timefmt '%Y-%m-%d %H:%M:%S'
set xdata time
set xtics 3600
set ytics 1
set yrange [-10:10]
plot "<./prepareDataCorr.sh" using 1:3 with lines
pause 2
reread
I w skrócie co do czego:
- włączamy siatkę
- ustawiamy format znacznika czasu, ponieważ jego wartości będą na osi odciętych
- mówimy że na osi odciętych jest czas
- podziałkę co jedną godzinę na przykład (wartości w sekundach)
- podziałkę dla osi rzędnych
- zakres osi rzędnych
- wskazujemy źródło wartości i które kolumny z niego nas interesują, łączymy liniami
- czekamy dwie sekundy
- odmalowujemy rysowankę
A z tym odmalowywaniem po pause sztuczka jest taka, że jeżeli dane do rysowania wykresu są generowane przez skrypt wskazany przez 'plot <', to skrypt zostanie ponownie wykonany, dostarczając na przykład odświeżonych wartości.
Poniżej prosty przebieg zmian temperatury z autoskalowaniem i różnymi wartościami xtics oraz różną długością serii danych, widać że ma ADHD
Ustawiamy zakres na osi Y:
Zmieniamy znaczniki osi Y na nieco gęstsze:
I tak się można bawić do woli czytając dokumentację i fora, ale zrobił poranek ze swoimi prawie -6°C
potem coraz cieplej
Dirty dancing data
Jeżeli zadamy sobie trud przejrzenia logu z pliku 20180222_220211_v628_readings.txt to znajdziemy tam na przykład takie dziwadła:
20180222_220211_v628_readings.txt pisze:Kod: Zaznacz cały
2018-02-23 05:22:40|f537|M|-0592
2018-02-23 05:22:45|f54f|M|-0592
2018-02-23 05:22:50|f568|M|+0592
2018-02-23 05:22:55|f580|M|-0593
2018-02-23 05:23:00|f599|M|+0593
2018-02-23 05:23:05|f5b1|M|-0594
2018-02-23 05:23:10|f5c9|M|-0596
Niektóre rekordy mają odwróconą polaryzację! Takie szpilki, w zupełnie przypadkowych momentach. Co do wartości bezwzględnej pomiar jest w porządku, dostał tylko niewłaściwy znak. Na wyświetlaczu V628 nie udało mi się tego zaobserwować, obstawiam zatem jakiś problem natury kontaktowej w interfejsie, w końcu był dwa razy lutowany. Cokolwiek jednak tam się nie stało, fakt jest taki, że mamy w pliku nie do końca właściwe rekordy i one nam skutecznie psuja malowanki:
No i tu dochodzimy do zagadnienia - jak oczyścić strumień danych z takich śmiećków. Pierwsza myśl, nieco naiwna w sumie to: skoro mamy ciągle na minusie, to może w skrypcie wybierającym dane po prostu odrzucać te dodatnie szpilki? O tak przykładowo:
prepareData.sh pisze:Kod: Zaznacz cały
awk -F '|' '((index($0,":00|") !=0)||(index($0,":30|") !=0) && ($4 < 0)) { printf "%s %2.2f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt
I zasadniczo wszystko byłoby dobrze, ale do chwili gdy zaczęło grzać słonko, które zawitawszy na parapet z MCP9700 zrobiło mi tam ostrowieckie Hawaje, a skrypt konsekwentnie odrzucił całość pomiarów powyżej zera. Czyli, że słońce szkodzi nie tylko wampirom.
W ramach walki z tymi szpilkami powstała kolejna wersja skryptu wybierającego dane:
prepareData.sh pisze:Kod: Zaznacz cały
awk '\
function abs(v) {return v < 0 ? -v : v} \
BEGIN{ FS="|"; s1=1; s2=1; } \
((index($0,":00|") !=0)||(index($0,":30|") !=0) ) { \
val=$4/100; \
if (( s1 != $4/abs($4) ) && ( s1 == s2 ) ) { \
val = val * s2; \
} \
printf "%s %2.2f\n", $1, val; \
s2=s1; \
s1=$4/abs($4); \
} ' 20180222_220211_v628_readings.txt
Wymyśliłam sobie tak, że zapamiętuje dwie ostatnie polaryzacje przebiegu, co pozwala mi skorygować tę niby błedną na podstawie poprzednich w przypadku pojawienia się takiej właśnie szpilki. Wynik działania jest tak na 3+, jednak algorytm nie jest stuprocentowo szczelny i jednego śmiećka mi przepuścił.
Tak ogólnie, to myślę, że takie surowe dane z pomiarów trzeba przed rysowaniem przepuścić przez jakieś dedykowane narzędzie, które porządnie matematycznie obrobi cały towar, wyeliminuje przypadkowe wpisy, pouśrednia i dostawi brakujące sample (o ile potrzeba) etc. Bo samoróbkami jak powyżej można łatać ad-hoc, a i tak pewnie znajdzie się przypadek, który nas zaskoczy...
Na koniec nocne kino - DAQ bardzej na żywo:
https://youtu.be/cHODKVLV3bE
oraz pomiary w przyspieszonym tempie (z pomijaniem klatek)
https://youtu.be/9boMKd_0xlk
A po całonocnej galopadzie mierniczkowi tak ogólnie to jeden z driverów 74141 zaniemógł i teraz mam na pozycji setek 9 w tle, no takie życie. To jest sprawa uszkodzenia wyjścia kostki, daje czterysta mV spadku napięcia przy pomiarze ciągłości obwodu i to w obie strony, inne wyjścia - są przerwą. Kostki '141 akurat mam, w wolnej chwili trzeba będzie przelutować układ, bo mi śmiesznie na zdjęciach wygląda, ale to kiedyś.