Note

This notebook can be downloaded here: 04_Derivation_of_data_with_noise.ipynb

Derivation of data with noise

Code author: Emile Roux emile.roux@univ-smb.fr

RISE Slideshow

Scope

  • Finite number \(N\) of data points \((x,y)\) are available, this data include noise: compute the derivative \(\dfrac{dx}{dy}\)
# Setup
%load_ext autoreload
%matplotlib nbagg
%autoreload 2
import numpy as np
import pandas as pd
import matplotlib as mpl
from PIL import Image # On charge Python Image Library
from matplotlib import pyplot as plt # On charge pyplot (un sous module de Matplotlib) et on le renomme plt
from matplotlib import cm
from scipy import ndimage
from scipy import interpolate
from scipy import signal

import gpxpy
import gpxpy.gpx
from geopy.distance import great_circle, vincenty

Introduction

To adress the problem of derivative comptatio of noisy data we proposed to analysed GPS data of hiking in the alpen.

Gps postion are subject to noise, this noise is due to the accuracy of the GPS.

A class to read data form Earthexplorer

This class manipulates elavation map comming from Earthexplorer (login requiered). The supported format is : digital elevation /aster global dem, in geotiff format 1pix = 1 arc second

class ElevMap:
    """
    This class manipulates elavation map comming from https://earthexplorer.usgs.gov/.
    The supported format is : digital  elevation / SRMT 1 arc-seconde global
    Where 1pix = 1 arc second
    """
    def __init__(self, file_name):
        self.file_name = file_name
        self.read_elevation_from_file()


    #https://librenepal.com/article/reading-srtm-data-with-python/
    def read_elevation_from_file(self):
        SAMPLES = 3601 # Change this to 3601 for SRTM1
        with open(self.file_name, 'rb') as hgt_data:
            # Each data is 16bit signed integer(i2) - big endian(>)
            elevations = np.fromfile(hgt_data, np.dtype('i2'), SAMPLES*SAMPLES).reshape((SAMPLES, SAMPLES))

        self.elevations = elevations[4:,4:].astype(np.float64)

        # Creat the grid of coordonee associated with the elevation map
        Nx,Ny = self.elevations.shape
        cor=self.file_name.split("_")[-2]
        N=float(cor[1:3])
        E=float(cor[4:])
        x = np.linspace(E, E + 1, Nx)
        y = np.linspace(N + 1, N, Ny)
        self.Xg, self.Yg = np.meshgrid(x, y)

        self.aspect = great_circle((self.Yg[0,0] ,self.Xg[0,0]) , (self.Yg[-1,0] ,self.Xg[-1,0])).km / great_circle((self.Yg[0,0] ,self.Xg[0,0]) , (self.Yg[0,-1] ,self.Xg[0,-1])).km


    def plot(self,ax):
        cs = ax.contourf(self.Xg, self.Yg, self.elevations , vmin=0, vmax=4808)
        ax.set_aspect(aspect=self.aspect)
        return cs


    def plot_track(self,ax, df):
        mask = np.ones(self.Xg.shape)

        large = .03
        mask[np.where(self.Xg  < df.long.min() - large  )]=np.nan
        mask[np.where(self.Xg  > df.long.max() + large )]=np.nan

        mask[np.where(self.Yg < df.lat.min() - large )]=np.nan
        mask[np.where(self.Yg > df.lat.max() + large )]=np.nan

        cs = ax.contourf(self.Xg , self.Yg , self.elevations*mask )
        plt.plot(df.long,df.lat,'r',label = "path")
        ax.set_aspect(aspect=self.aspect)

        ax.set_xlim(df.long.min() - large  , df.long.max() + large )
        ax.set_ylim(df.lat.min()  - large  , df.lat.max()  + large )

        return cs

Some cities to plot on top of the map

site_coord=np.array([[6.865133,45.832634],[ 6.157845,45.919490],[6.389560,45.663787], [6.864840,45.916684],[6.633973,45.935047],[6.672323,45.200746],[ 6.425097, 45.904318]])
site_name = ["Mont Blanc", "Polytech", "Albertville","Chamonix",'Sallanches', "Modane","La Cluzas"]

Read a map elevation

M1 = ElevMap('.\_DATA\ASTGTM2_N45E006_dem.tif')
#M2 = ElevMap('.\_DATA\ASTGTM2_N46E007_dem.tif')
#M3 = ElevMap('.\_DATA\ASTGTM2_N45E007_dem.tif')
#M4 = ElevMap('.\_DATA\ASTGTM2_N46E006_dem.tif')

Plot the data

fig = plt.figure()
ax = fig.gca()
#M2.plot(ax)
#M3.plot(ax)
#M4.plot(ax)
cs=M1.plot(ax)

cbar = fig.colorbar(cs)
cbar.set_label('Altitude $m$')   # On specifie le label en z

ax.plot(site_coord[:,0],site_coord[:,1],'r+',markersize=3)
for i, txt in enumerate(site_name):
    ax.annotate(txt, (site_coord[i,0]+.01,site_coord[i,1]-0.01))

plt.show()
<IPython.core.display.Javascript object>

GPS point data set

The gpx format is a standar format.

The pygpx module is used to imoprt the data (https://pypi.python.org/pypi/gpxpy)

gpx_file = open( './_DATA/activity_Raquette.gpx', 'r' )

Parse the gpx data to make a pandas dataframe of it

Parse the gpx file

gpx = gpxpy.parse(gpx_file)

Initiate the pandas dataframe

df = pd.DataFrame([] , index = [], columns = ['time','seconde', 'lat', 'long','elevation','dist'])

Fullfill the dataframe with the gpx data

i=0
t0 = gpx.tracks[0].segments[0].points[0].time
for track in gpx.tracks:
    for segment in track.segments:
        for point in segment.points:
            if i==0:
                df.loc[i]=[(point.time-t0),(point.time-t0).seconds,point.latitude, point.longitude, point.elevation,0.]
            else:
                dist = df.dist[i-1] + great_circle((point.latitude,point.longitude) , (df.lat[i-1],df.long[i-1])).km*1000.
                df.loc[i]=[(point.time-t0),(point.time-t0).seconds,point.latitude, point.longitude, point.elevation,dist]
            i=i+1

Display the dataframe

df.head(30)
time seconde lat long elevation dist
0 00:00:00 0 45.889134 6.451944 1761.599976 0.000000
1 00:00:01 1 45.889134 6.451944 1761.599976 0.055937
2 00:00:03 3 45.889138 6.451947 1761.199951 0.561099
3 00:00:06 6 45.889148 6.451971 1761.400024 2.746140
4 00:00:07 7 45.889151 6.451982 1761.800049 3.594090
5 00:00:08 8 45.889153 6.451989 1762.199951 4.204322
6 00:00:09 9 45.889156 6.451997 1762.599976 4.936265
7 00:00:10 10 45.889159 6.452006 1763.199951 5.693639
8 00:00:11 11 45.889161 6.452014 1763.400024 6.337976
9 00:00:17 17 45.889176 6.452063 1763.400024 10.514476
10 00:00:22 22 45.889187 6.452107 1763.400024 14.115267
11 00:00:28 28 45.889204 6.452154 1763.599976 18.182346
12 00:00:29 29 45.889206 6.452160 1764.000000 18.697474
13 00:00:30 30 45.889208 6.452169 1764.400024 19.448647
14 00:00:31 31 45.889210 6.452177 1764.800049 20.132073
15 00:00:32 32 45.889212 6.452189 1765.199951 21.071081
16 00:00:33 33 45.889212 6.452194 1765.400024 21.495445
17 00:00:36 36 45.889214 6.452223 1765.400024 23.698945
18 00:00:42 42 45.889233 6.452275 1765.400024 28.232220
19 00:00:44 44 45.889238 6.452297 1765.800049 30.061939
20 00:00:45 45 45.889239 6.452298 1766.199951 30.203330
21 00:00:46 46 45.889245 6.452316 1766.599976 31.733769
22 00:00:47 47 45.889242 6.452318 1767.000000 32.014060
23 00:00:48 48 45.889249 6.452334 1767.400024 33.435011
24 00:00:49 49 45.889252 6.452340 1767.400024 34.015566
25 00:00:55 55 45.889263 6.452388 1767.400024 37.907578
26 00:00:58 58 45.889272 6.452408 1767.800049 39.750404
27 00:00:59 59 45.889274 6.452418 1768.199951 40.580836
28 00:01:00 60 45.889276 6.452420 1768.599976 40.820970
29 00:01:01 61 45.889278 6.452433 1769.000000 41.842973

Plot the track

fig = plt.figure()
ax = fig.gca()
cs = M1.plot_track(ax,df)
cbar = fig.colorbar(cs)
cbar.set_label('Altitude $m$')   # On specifie le label en z

ax.plot(site_coord[:,0],site_coord[:,1],'r+',markersize=3)
for i, txt in enumerate(site_name):
    ax.annotate(txt, (site_coord[i,0]+.002,site_coord[i,1]-0.002))
<IPython.core.display.Javascript object>

Plot the elevation vs. distance

fig = plt.figure()
plt.plot(df.dist,df.elevation,'b',label = "Elevation")
plt.ylabel("Distance [$m$]")
plt.xlabel("Elevation [$m$]")
plt.grid()
plt.legend()
plt.show()
<IPython.core.display.Javascript object>

Plot the distance vs. time

fig = plt.figure()
plt.plot(df.seconde/60,df.dist,'b',label = "path")
plt.xlabel("temps [$min$]")
plt.ylabel("Distance [$m$]")
plt.grid()
plt.legend()
plt.show()
<IPython.core.display.Javascript object>

How to compute the velocity during the snow shoes hicking ?

We know that to get the velocity, we just have to compute the derivative of the distance respect to time.

To performe this derivative the reader can refer to the notebook “Derivation of numerical data”

vit = np.diff(df.dist)/np.diff(df.seconde)
vit = vit * 3.6 # m/s to km/h

Plot the velocity vs. time

fig = plt.figure()
plt.plot(df.seconde[:-1]/60,vit,'+b')
plt.xlabel("temps [$min$]")
plt.ylabel("Velocity [$km/h$]")
plt.grid()
plt.show()
<IPython.core.display.Javascript object>

The obtained results is no readable and give no valuable information !

skip = 5
vit = np.diff(signal.savgol_filter(df.dist[::skip] , 41, 2))/np.diff(df.seconde[::skip])
vit = signal.savgol_filter(df.dist , 101, 1, deriv=1, delta = 1)
vit = vit * 3.6 # m/s to km/h
fig = plt.figure()
plt.plot(df.seconde/60,vit,'b')
plt.xlabel("temps [$min$]")
plt.ylabel("Velocity [$km/h$]")
plt.grid()
plt.show()
<IPython.core.display.Javascript object>