Archiwum: September, 2016

Ostatni dzień września z drona: nowy budynek IGF

Udało mi się zrobić dziś kilka ładnych zdjęć z drona. Najpierw widok na Warszawę z okolic Mostu Północnego:


003_sm004_sm

Następnie widok na nowy budynek Instytutu Geofizyki Wydziału Fizyki UW:


001_sm002_sm

Wokół powyższego budynku nagrałem również kilka ujęć wideo. Moje ujęcia nie są niestety gładkie jaku u @CaseyNeistat, ale ćwiczę. Zapraszam, to tylko 54 sekundy:

| Komentarze

27 wyjazdów na pomorze, 31000 km zapisane w GPS

O eksperymencie sejsmicznym “13 BB Start” już wspominałem (obiecuję napisać więcej). W ramach eksperymentu przez 3 lata w 13 miejscach na pomorzu umieszczone były szerokopasmowe stacje sejsmiczne. Ponieważ nasza siedziba jest w Warszawie trzeba było trochę na pomorze jeździć: zaplanować, zainstalować, serwisować i zdemontować. Ostatni wyjazd był w zeszłym tygodniu. Ponieważ od początku jeździłem prywatnym samochodem potrzebowałem rejestrować za pomocą GPS przebytą trasę, żeby mieć podkładkę do rozliczenia kosztów. Wykorzystałem do tego dwa bliźnicze odbiorniki: starszy Garmin GPSmap 60CSx i młodszy GPSmap 62sc. Podczas wyjazdów odbiornik zawsze był w samochodzie, uruchamiał się po uruchomianiu silnika i zapisywał pozycję do pliku co 1 sekundę.

W sumie wyjazdów było 27, a całkowita odległość przekroczyła 31 tysięcy kilometrów. Zapis tras obejmuje ponad półtora miliona punktów, co daje ponad 400 godzin jazdy (średnio 16 godzin na wyjazd). Jest to piękny zbiór danych, który wymaga wizualizacji na mapie. Oczywiście nie byłbym sobą, gdybym najpierw nie wczytał wszystkich danych do Matlaba (zawsze po wyjeździe wczytywałem zapis do Matlaba i skryptem generowałem raport wszystkich odcinków tras: skąd – dokąd i od kiedy – do kiedy). Goła wizualizacja danych jest bardzo ładna, ale dopiero naniesienie tras na mapę daje pełny obraz sytuacji. Wykorzystałem do tego oczywiście mapy google. Z Matlaba zapisałem moje ścieżki do pliku KML (pamiętając o wpisaniu NaN na końcu każdego odcinka, żeby podczas rysowania była przerwa pomiędzy odcinkami) i ten wgrałem na mapę Google (po zalogowaniu idziemy w moje miejsca i moje mapy, gdzie można wgrać plik KML). Plik ze wszystkimi moimi danymi miał rozmiar ponad 40 mega, więc żeby zaspokoić ograniczenia google (max 5mb) podczas zapisu brałem co 10 punkt. Efekty wyglądają tak:

screencapture-google-maps-d-u-2-edit-1474983786479

Zbliżenie na obszar startowy i docelowy:

screencapture-google-maps-d-u-2-edit-1474983297187

screencapture-google-maps-d-u-2-edit-1474983254545

Trzeba zaznaczyć, że podczas pierwszych naszych wyjazdów (pierwszy był w 2012), autostrada A1 była jeszcze w budowie na odcinku z Łodzi do Torunia. W tym miejscu przyszedł mi do głowy pewien pomysł. Ponieważ ponad połowa moich wyjazdów była właśnie przez autostradę A2 i A1 zrobiłem prostą analizę. Dla każdego wyjazdu tą drogą brałem czas przejechania przez punkt wspólny (zaraz za połączeniem S8 i A2 pod Warszawą, pomarańczowy znacznik na mapie) i zaznaczyłem położenie po 30 (zielone), 60 (brązowe), 120 (żółte), 180 (fioletowe) i 240 minutach (jasno zielone). Oczywiście jeździłem o różnych porach, czasem z tankowaniem, w różnych warunkach, itp., natomiast ładnie widać, że im dalej tym większy rozrzut:

screencapture-google-maps-d-u-2-edit-1475009898800

Zupełnie przy okazji pisania tego wpisu zakochałem się ponownie w mapach google. Dodatkowym, ważnym atutem takiej mapy google, jest możliwość wczytania mapy z nałożonymi trasami w aplikacji w telefonie, co znacząco ułatwia nawigację np. powtórzenie trasy po lesie. Postaram się kiedyś więcej na ten temat napisać.

Bonus! Jeden z przejazdów nagrałem w całości kamerą sportową (takie GoPro, ale od Sony):

| Komentarze

Wyjazd pomorze z lotu ptaka [4k]

Nie zapomnijcie subskrybować mojego kanału na YouTube:

| Komentarze

Wpływ sezonowych zmian w jonosferze na pomiary GPS

Od czterech lat biorę udział w pasywnym eksperymencie sejsmicznym “13BB star”. Będę na ten temat pisał jeszcze wiele razy, ale muszę tutaj zrobić dwa zdania wstępu. Celem eksperymentu jest rejestracja naturalnych zjawisk sejsmicznych, co pozwala na określanie głębokich struktur w Ziemi. W ramach eksperymentu na pomorzu pracowało 13 samodzielnych stacji poukrywanych głęboko w lasach. Każda ze stacji wyposażona była w odbiornik GPS, których celem było dostarczanie bardzo precyzyjnych informacji o czasie. Gdzieś na boku i przy okazji raz na godzinę każda stacja zapisywała pozycję według gps: długość i szerokość geograficzną oraz wysokość n.p.m.

Któregoś dnia postanowiłem wczytać do matlaba te dane dla jednej ze stacji. Gdy narysowałem wykres zależności mierzonej wysokości n.p.m. od czasu zainteresowała mnie mało widoczna zmiana sezonowa. Zupełnie nie dziwi rozrzut pomiarów o +- 10 metrów, bo pomiary “cywilnym” (jako przeciwieństwo do geodezyjnego) GPS są obarczone mniej więcej takim błędem. Zaciekawiło mnie sezonowe przesunięcie pomiarów, które jest bardzo dobrze widoczne po narysowaniu tygodniowej średniej kroczącej:

out_13bb_gps_001

Sprawdziłem od razu czy podobny efekt widać na pozostałych stacjach:

out_13bb_gps_002

Jeszcze ciekawej sprawa wygląda gdy porówna się średnie kroczące dla wszystkich stacji poprzez odjęcie średniej z całego okresu. Poniżej średnie 7-dniowe:

out_13bb_gps_003_7

30-dniowe:

out_13bb_gps_003_30

i 60-dniowe:

out_13bb_gps_003_60

Na powyższych wykresach widać wyraźną sezonowość zmian. Poprosiłem o komentarz specjalistę od pomiarów referencyjnych GPS: “jonosfera, standard, nuda”. Natomiast dla mnie ciekawe jest, że skoro efekt jest tak dobrze znany i tak powtarzalny, czemu nie została wprowadzona na to poprawka. To właśnie dynamika zmian jonosfery powoduje, że cywilne GPS mają ograniczoną dokładność. Sprzęt geodezyjny wykorzystuje stacje permanentne, dzięki którym można określi wpływ jonosfery na pomiar w danym momencie (stacja permanentna się nie rusza, więc odchylenie pomiaru wynika właśnie ze zmian w jonosferze). Takich szybkich lokalnych zmian nie da się przewidzieć, ale zmiany między latem a zimą wydają się całkowicie powtarzalne i oczywiste.

Gdyby ktoś był zainteresowany kodem użytym do wygenerowania 3 dolnych rysunków:

%% 7 dni
clf; hold on
files = dir('*.gps');

colors = lines(length(files));

for fi = 1:length(files)
	X = load(files(fi).name);
	D = X(:,1) - circshift(X(:,1),[1 0]); 
	idx = [1; find(D>1); length(X(:,1))]; % Szukanie przerw w danych większych niż 1 dzień
	X(X(:,4)>500,4)=NaN; 
	X(X(:,4)<50,4)=NaN; % Usuwanie pomiarów "od czapy"
	for a = 1:length(idx)-1
		i = idx(a):idx(a+1)-1;
		i(isnan(X(i,4)))=[];
		f = nanmean(X(:,4)); % Średnia dla całego okresu
		if length(i) > 7*24 % Badamy tylko fragmenty o długości > 7 dni
			% Obliczenie i narysowanie średniej kroczącej przesuniętej o średnią globalną
			plot(X(i,1), tsmovavg(X(i,4),'s',7*24,1)-f, 'Color', colors(fi,:), 'LineWidth',3)
		end
	end
end


% Rysowanie i podział rysunku na pory roku

axis([datenum(2013,09,01) datenum(2016,07,31), -6 4])
pory = [datenum(2013,09,22) datenum(2013,12,21) datenum(2014,03,20) datenum(2014,06,21) datenum(2014,09,23)  datenum(2014,12,21) datenum(2015,03,20) datenum(2015,06,21) datenum(2015,09,23) datenum(2015,12,22)  datenum(2016,03,20) datenum(2016,06,20) datenum(2016,09,22)];

names = {'Wiosna', 'Lato', 'Jesien', 'Zima'};
for a = 1:length(pory)-1
	text(mean(pory(a:a+1)),3.5,names{rem(a+1,4)+1},'HorizontalAlignment', 'Center', 'FontSize', 15);
	plot([pory(a) pory(a)], [-10 10],'k--')
end

set(gca,'xTick', pory)

datetick('x','YYYY-mm-dd','keepticks')

hgexport(gcf, '13BB_GPS_003_7.png', hgexport('factorystyle'), 'Format', 'png', 'resolution', 300, 'Width', 40, 'Height', 10);

| Komentarze

Burze w Polsce, edycja 2014

Pod koniec 2013 roku wpadłem na pomysł, aby regularnie zapisywać sobie obrazek (mapę) przedstawiający aktualne lokalizacje wyładowań atmosferycznych. Korzystałem wtedy ze strony blide.de. Oczywiście nie miałem na myśli robienia tego ręcznie, więc uruchomiłem na serwerze skrypt, który równo co 15 minut zapisywał aktualny obrazek. Skrypt działa do dziś i cały czas zapisuje aktualne mapy. Przypomniałem sobie o nim, gdy na serwerze zaczęło brakować miejsca na dane. Pobrałem obrazki na swój komputer i zacząłem zabawę. Na pierwszy ogień poszedł pierwszy pełny rok – 2014.

Teoretycznie w ciągu 365 dni powinienem zapisać 365*24*4 = 35040 obrazków. Faktycznie zapisałem 34999, czyli całkiem nieźle. Pierwsza, oczywista myśl to animacja. Połączyłem wszystkie obrazki w filmik:

W kolejnym korku chciałem podejść do tematu bardziej kompleksowo. Jak oszacować ilość wyładowań dla każdej z map. Oczywiście ilości się nie da, ale da się oszacować obszar objęty burzą. Na mapach kolorem czerwonym oznaczone są miejsca, gdzie wystąpiło co najmniej jedno wyładowanie w przeciągu ostatnich 15 minut. Niestety pliki są zapisane w mocno skompresowanym jpg, ale wyraźnie widać co czerwone a co nie. Napisałem na kolanie szybki skrypt w Matlabie:

clear;clc
files=dir('2014/blids/*.png');
S = zeros(length(files), 2);
for a = 1:length(files)
	name = ['2014/blids/' files(a).name];
	C = strsplit(name, '/');
	C2 = strsplit(C{end},'.');
	date = C2{1};
	time = C2{2};
	I = imread(name);
	idx = (I(:,:,1)>100 & I(:,:,2)<100 & I(:,:,3)<100);
	S(a,1) = sum(sum(idx));
	S(a,2) = datenum(str2double(date(1:4)), str2double(date(5:6)), str2double(date(7:8)), str2double(time(1:2)), str2double(time(3:4)), 0);
	
	fprintf('%d\t%d\n',a,S(a,1));
end

Dla każdej mapy skrypt obliczył i zapisał ilość pikseli, w których miały miejsca wyładowania. Teraz wystarczy to ładnie nanieść na wykres: np. sumarycznie dla każdego dnia.

clf
days = datenum(2014,01,01):datenum(2014,12,31);
storm = zeros(size(days));

for d = 1:length(days)
	storm(d) = sum(S(S(:,2)>=days(d)&S(:,2)0)=log10(storm(storm>0));
stairs(days-datenum(2014,01,01),storm, 'LineWidth',2)
axis([0 365 0 2.5e5])
hold on
for month = 1:12
	plot(ones(1,2)*datenum(2014,month,1)-datenum(2014,01,01),[0 2.5e5], 'k--')
end

A oto efekt:

001

Pionowe linie oddzielają kolejne miesiące. Widać wzmożoną aktywność burzową od kwietnia do września. Maksimum przypada na początku sierpnia, co widać na filmie.

Jak wykorzystalibyście takie dane? W wolnej chwili zrobię animację i wykres dla 2015 roku.

| Komentarze

Instalacja iOS 10 psuje iPhone!

Dziś o 19 naszego czasu Apple udostępniło nową, rewolucyjną wersję swojego systemu mobilnego oznaczoną jako iOS10. Cały świat razem ze mną rzucił się do instalacji. Zostawiłem na godzinę podłączony telefon do ładowarki, żeby pobrał i zainstalował uaktualnienie. Po powrocie zobaczyłem to:

img_0002

Dziwna sprawa, pierwszy raz zarządał podłączenia do komputera kablem, ale ok – chce to ma. Niestety po podłączeniu do komputera pojawił się komunikat, że telefon jest w trybie awaryjnym i trzeba od nowa przeprowadzić pobieranie i instalację system. Ok, jestem w stanie to przeboleć. Nie spodziewałem się jednak tego:

dsc02109

Jak żyć!?

Podobno problem dotyczył jedynie osób, które pobierały uaktualnienie zaraz po jego udostępnieniu. Żadne pocieszenie – mój telefon nie działa i nie zanosi się, żeby zadziałał w najbliższym czasie. Zawiodłem się na tobie Apple :(.

Edit (2016-09-14 03:15): Chyba się udało…

| Komentarze

Mapa Google w dużym formacie

Bardzo lubię mapy. Pewnego dnia wcześniej w tym roku wpadłem na pomysł, aby ozdobić ścianę drogową mapą Polski. W pomyśle był jeden mały haczyk: nie chciałem byle jakiej mapy, chciałem mapę Google. Szybki przegląd internetu nie przyniósł żadnych konkretnych rozwiązań – super, będę pierwszy!

Mapy Google wyświetlają różną ilość szczegółów w zależności od stopnia przybliżenia. Gdy na ekranie mieści się cała Polska, szczegółów nie ma wcale. Moja mapa ścienna miała być duża (planowałem coś w okolicach metr na metr), więc potrzebowałem szczegółów. Zdecydowałem się na napisanie aplikacji w C#, której zadaniem było wyświetlanie kolejnych fragmentów mapy i robienie screenshota. Rozwój aplikacji zakończył się w momencie, gdy zadziałała, więc nawet guziki nie były podpisane:

Dla średniej szczegółowości wystarczyło pokrycie Polski za pomocą ~120 screenów, a dla wysokiej zrobiłem ich ponad 1200.

Samo robienie screenów to łatwy fragment. Trudniej było skleić je w całość. Pamiętajmy, że ziemia jest kulą, więc samo sklejenie obrazków spowoduje powstanie dziur, ponieważ relacja pomiędzy stopniami długości geograficznej a kilometrami zależy od szerokości geograficznej. W sieci łatwo znalazłem relację pomiędzy pixelami mapy a fizycznymi odległościami w zależności od szerokości geograficznej:

Meters per pixel = 156543.03392 * Math.cos(latLng.lat() * Math.PI / 180) / Math.pow(2, zoom)

W kolejnym kroku wycinałem z moich screenów fragment mapy bez elementów interfejsu – dla ułatwienia zawsze taki sam prostokąt na środku ekranu. Robiłem to oczywiście automatycznie za pomocą polecenia convert. Przy okazji przycinania konwertowałem wycięty fragment na format tiff. Mając obliczone z wcześniejszego wzoru współrzędne geograficzne rogów fragmentu mapy konwertowałem plik graficzny tiff do formatu geotiff za pomocą polecenia gdal_translate. Geotiff to nic innego jak zwykły tiff z dodatkowymi informacjami dotyczącymi jego orientacji w przestrzeni. Ten proces był sterowany skryptem w MATLABie:

lat_min = 48.7;
lat_max = 55;
lon_min = 13.8;
lon_max = 24.6;

lat_step = .6;
lon_step = 1.2;


xof = 100;
yof = 100;
x = 1920 - 2*xof;
y = 982 - 2*yof;

for lat = lat_min:lat_step:lat_max
	for lon = lon_min:lon_step:lon_max
		im_width = 1720;
		im_height = 782;
		zoom = 10;

		meters_vertical = (156543.03392 * cos(deg2rad(lat))  / (2^zoom));

		[lat_tm, lon_tm] = reckon(lat, lon, km2deg(meters_vertical*(im_height/2)/1000), 0); 
		[lat_bm, lon_bm] = reckon(lat, lon, km2deg(meters_vertical*(im_height/2)/1000), 180); 

		meters_horizontal_top = 156543.03392 * cos(deg2rad(lat_tm)) / (2^zoom);
		meters_horizontal_bottom = 156543.03392 * cos(deg2rad(lat_bm)) / (2^zoom);

		[lat_tr, lon_tr] = reckon(lat_tm, lon_tm, km2deg(meters_horizontal_top*(im_width/2 - .5)/1000), 90); 
		[lat_tl, lon_tl] = reckon(lat_tm, lon_tm, km2deg(meters_horizontal_top*(im_width/2 - .5)/1000), 270); 

		[lat_br, lon_br] = reckon(lat_bm, lon_bm, km2deg(meters_horizontal_bottom*(im_width/2 - .5)/1000), 90); 
		[lat_bl, lon_bl] = reckon(lat_bm, lon_bm, km2deg(meters_horizontal_bottom*(im_width/2 - .5)/1000), 270); 

		system(sprintf('convert source/mapa_%8.5f_%8.5f.png -crop %dx%d+%d+%d -resize %dx%d -transparent white crop/mapa_%8.5f_%8.5f.tiff', lat, lon, x, y, xof, yof, 2*x, 2*y, lat, lon));
		system(sprintf('gdal_translate -of GTiff -a_srs WGS84 -a_ullr  %8.5f %8.5f %8.5f %8.5f crop/mapa_%8.5f_%8.5f.tiff crop/geomapa_%8.5f_%8.5f.tiff', lon_tl, lat_tl, lon_br, lat_br, lat, lon, lat, lon));
	end
end

Następnie za pomocą skryptu gdal_merge.py połączyłem wszystkie geotiffy w jednego wielkiego geotiffa. Tutaj praca mogłaby się zakończyć, ale chciałem, żeby moja mapa miała jakieś fajne odwzorowanie, ramkę itp. Najlepszym znanym mi programem do rysowania map jest pakiet GMT (http://gmt.soest.hawaii.edu/). Za pomocą prostego skryptu przygotowałem pdf (ps to prawie pdf) z mapą do wydruku:

gmt gmtset PS_MEDIA=Custom_60ix80i
gmt gmtset MAP_FRAME_WIDTH=.25i
gmt gmtset FONT_ANNOT_PRIMARY=32p,Helvetica,black
gmt gmtset COLOR_NAN=white
gmt psbasemap -R13.8/24.5/48.7/55 -Jl19.20/19.30/52/60/1:600000 -B1g.5:."": -K -P > mapa_all.ps
gmt grdimage ALL.tiff -D -R13.8/24.5/48.7/55 -Jl19.20/19.30/52/60/1:600000 -Gf -Q -P -O -K >> mapa_all.ps
gmt pscoast -R -Df -J -N1/3p,- -A0/0/1  -O -P >> mapa_all.ps

Tak wyglądał efekt końcowy po wydrukowaniu:

Nie dzielę się plikiem z mapą, bo jest bardzo duży i nie jestem pewnie czy google nie chciałoby mi urwać za to głowy.

| Komentarze (1)