python - 如果未给出速度标签本身,如何从 gpx 文件计算速度?

标签 python algorithm pandas gpx

例如,我可能有这样一些信息:

<trkpt lat="-33.8161780" lon="150.8710320">
 <ele>73.0</ele>
 <time>2017-07-08T22:05:45Z</time>
 <extensions>
  <power>0</power>
  <gpxtpx:TrackPointExtension>
    <gpxtpx:atemp>7</gpxtpx:atemp>
    <gpxtpx:hr>115</gpxtpx:hr>
    <gpxtpx:cad>27</gpxtpx:cad>
  </gpxtpx:TrackPointExtension>
 </extensions>
</trkpt>

我如何根据这些信息计算速度?我使用 python etree 模块解析文件,并将所有信息保存在 pandas 数据库中。

有人提到我可能应该改为显示 pandas 数据框。它看起来像这样:

                     longitude   latitude   ele   temp
time                
2017-07-08 22:05:45 150.8710320 -33.8161780 73.0    7
2017-07-08 22:05:46 150.8710350 -33.8161500 73.0    7
2017-07-08 22:05:47 150.8710440 -33.8161170 73.0    7
2017-07-08 22:05:48 150.8710540 -33.8160820 73.0    7
2017-07-08 22:05:49 150.8710690 -33.8160430 73.0    7

等等。

最佳答案

速度等于距离/时间longitudelatitude 大概代表地球表面的位置。如果我们接受半径为 6371 公里的球体作为地球的近似值,那么我们可以轻松地将 longitudelatitude 转换为 xyz 坐标:

r = 6371000 # meters
df['theta'] = np.deg2rad(df['longitude'])
df['phi'] = np.deg2rad(df['latitude'])
df['x'] = r*np.cos(df['theta'])*np.sin(df['phi'])
df['y'] = r*np.sin(df['theta'])*np.sin(df['phi'])
df['z'] = r*np.cos(df['phi'])

现在计算连续点之间的距离并不难:

df['x2'] = df['x'].shift()
df['y2'] = df['y'].shift()
df['z2'] = df['z'].shift()
df['distance'] = np.sqrt((df['x2']-df['x'])**2 + (df['y2']-df['y'])**2 + (df['z2']-df['z'])**2)

但是,这是弦长——球体表面两点之间的直线距离。如果这些点相距很远,弦就会穿过地球表面。据推测,运动发生在地球表面。因此,更准确的距离计算将使用 arclength :

df['central angle'] = np.arccos((df['x']*df['x2'] + df['y']*df['y2'] + df['z']*df['z2'])/r**2)
df['arclength'] = df['central angle']*r

中心角使用dot product formula .

计算弧长(距离)后,我们现在还必须计算连续观察(即 DataFrame 的行)之间的时间间隔:

df['time'] = (df.index.to_series().diff() / pd.Timedelta(seconds=1))

所以使用speed = distance/time:

df['speed'] = df['arclength'] / df['time']  # in meters/second

import numpy as np
import pandas as pd

df = pd.DataFrame({'ele': [73.0, 73.0, 73.0, 73.0, 73.0], 'latitude': [-33.816178, -33.81615, -33.816117, -33.816082, -33.816043], 'longitude': [150.871032, 150.871035, 150.87104399999998, 150.87105400000002, 150.871069], 'temp': [7, 7, 7, 7, 7], 'time': ['2017-07-08 22:05:45', '2017-07-08 22:05:46', '2017-07-08 22:05:47', '2017-07-08 22:05:48', '2017-07-08 22:05:49']})
df['time'] = pd.to_datetime(df['time'])
df = df.set_index('time')
columns = df.columns.tolist()

r = 6371000 # radius of the Earth in meters
df['theta'] = np.deg2rad(df['longitude'])
df['phi'] = np.deg2rad(df['latitude'])
df['x'] = r*np.cos(df['theta'])*np.sin(df['phi'])
df['y'] = r*np.sin(df['theta'])*np.sin(df['phi'])
df['z'] = r*np.cos(df['phi'])
df['x2'] = df['x'].shift()
df['y2'] = df['y'].shift()
df['z2'] = df['z'].shift()
df['distance'] = np.sqrt((df['x2']-df['x'])**2 + (df['y2']-df['y'])**2 + (df['z2']-df['z'])**2)

df['central angle'] = np.arccos((df['x']*df['x2'] + df['y']*df['y2'] + df['z']*df['z2'])/r**2)
df['arclength'] = df['central angle']*r

df['time'] = (df.index.to_series().diff() / pd.Timedelta(seconds=1))
df['speed'] = df['arclength'] / df['time']  # in meters/second
df = df[columns + ['speed']]
print(df)

产量

                      ele   latitude   longitude  temp     speed
time                                                            
2017-07-08 22:05:45  73.0 -33.816178  150.871032     7       NaN
2017-07-08 22:05:46  73.0 -33.816150  150.871035     7  3.119892
2017-07-08 22:05:47  73.0 -33.816117  150.871044     7  3.712201
2017-07-08 22:05:48  73.0 -33.816082  150.871054     7  3.940673
2017-07-08 22:05:49  73.0 -33.816043  150.871069     7  4.433590

如果你注释掉

df = df[columns + ['speed']]

然后重新运行脚本,您将看到所有的中间计算。你会 请注意 df['distance'] 非常接近 df['arclength']。自从 地球表面上的点相距不是很远,弦长是 弧长的良好近似。所以对于你发布的数据

df['speed'] = df['distance'] / df['time'] 

也可以。不过,arclength的计算有点 更健壮,因为如果点很远,它会给出更准确的值 分开。

关于python - 如果未给出速度标签本身,如何从 gpx 文件计算速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45840118/

相关文章:

python - 使用 xml.etree 或 Dom API 在 Python 中解析 XML 问题

c++ - 为什么没有 std::copy_if 算法?

algorithm - Aho-Corasick 和真子串

python - 如何在不写入磁盘的情况下将 AWS S3 上的文本文件导入 pandas

python - 如何用 NaN 替换 python 数据框中的破折号?

Python:TypeError:最多输入 1 个参数,得到 5 个

python - Python 中的正则表达式 : Referring to characters at start of text

python - 如何将列中的值更改为二进制?

python - 打开 Python 串行端口时出错

algorithm - 排列游戏 - 第二个输入案例 - 解释