IndoorFusionNav
An open-source project for accurate indoor pedestrian localization using WiFi, PDR, and EKF fusion. It combines WiFi signals, step tracking, and sensor fusion for reliable positioning in GPS-denied environments.
Install / Use
/learn @salmoshu/IndoorFusionNavREADME
IndoorFusionNav

IndoorFusionNav是一个基于Wi-Fi/PDR(行人航位推算)的多源融合定位项目,目前包含了Wi-Fi指纹定位、PDR与EKF融合定位的Python实现,本项目针对的平台为安卓平台,融合使用的数据为Wi-Fi数据与IMU数据。
项目中涉及的Java代码主要用于采集实验数据,而数据分析与定位轨迹生成主要使用Python离线完成。该项目较为久远,在数据采集和融合时没有很好地注意不同数据源之间的时间同步问题(应当进行插值或外推)。不过这并不影响大家通过项目源码来理解Wi-Fi指纹、PDR和EKF等定位领域中的基础概念。
最后,该项目只是一个入门的科研项目,让初次涉猎该领域的同学能够快速上手。doc目录下提供了笔者的大论文,仅供参考。
目录
第三方依赖
- Numpy
- Pandas
- Matplotlib
- Sklearn
实验数据
| data | 实验数据 | |:--|---| | data/count_steps | 正常直线行走数据,包含了安卓或苹果设备采集的数据,用来判断步伐检测的结果是否良好,其中安卓程序为自己开发的程序,苹果数据采集程序为phyphox(使用的时候注意修改属性名,方便后续程序使用)。 | | data/fusion | 小范围融合定位实验,具体数据包含了:Fingerprint(指纹数据)、LeftBorder(左边缘测试点)、RightBorder(右边缘测试点)和LType(L型路线行走数据)。 | | data/linear_08m | 正常直线行走数据,行走步数为10步,每一步为固定步长0.8m。 | | data/rssi_fluctuation | 一组长时间记录Wi-Fi变化的数据,每个文件大约记录2万条样本数据,该数据可以用来分析Wi-Fi数据的波动情况。 | | data/still | 静止数据,用来分析惯性传感器数据的特性。 |
开始使用
IndoorFusionNav的使用前提:操作的文件格式大概为如下所示,其中rssi根据实验过程中AP数量决定,AP为指定的固定路由器,比较适合小范围实验。
| timestamp | rssi1 | rssi2 | rssi3 | rssi4 | linear-x | linear-y | linear-z | gravity-x | gravity-y | gravity-z | rotation-x | rotation-y | rotation-z | rotation-w | | ------------- | ----- | ----- | ----- | ----- | -------- | -------- | -------- | --------- | --------- | --------- | ---------- | ---------- | ---------- | ---------- | | 1591610015190 | -37 | -45 | -66 | -64 | 0.1322 | -0.0105 | 0.5227 | 0.4463 | 2.8838 | 9.3623 | 0.078042 | -0.12869 | -0.75696 | 0.635895 | | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
可以利用pandas读取数据,并获取为numpy.ndarray格式数据,location模块中类的参数均为numpy.ndarray格式。
df = pd.read_csv(file)
rssi = df[[col for col in df.columns if 'rssi' in col]].values
linear = df[[col for col in df.columns if 'linear' in col]].values
gravity = df[[col for col in df.columns if 'gravity' in col]].values
rotation = df[[col for col in df.columns if 'rotation' in col]].values
location模块提供以下功能:
| location | 自定义定位工具包(可以进行数据分析与处理、定位解算与可视化,不同文件可配合使用) | | :----------------- | ------------------------------------------------------------ | | location/fusion.py | 融合定位工具包,包含了EKF融合定位算法。 | | locaiton/pdr.py | PDR定位工具包,包含了步伐检测、航向角推算、步长推算和定位结束输出等常见功能。 | | location/wifi.py | wifi指纹定位工具包,包含了常见的在线匹配算法。 |
Demo1 PDR定位
要进行PDR操作,需要创建一个pdr.Model对象:
import location.pdr as pdr
pdr = pdr.Model(linear, gravity, rotation)
Demo1.1 show_steps函数:显示垂直方向合加速度与步伐波峰分布
show_steps参数使用说明如下:
- frequency - 数据采集频率
- walkType - 行走模式
| walkType | 描述 | | :------- | :----------------------------------------------------------- | | normal | 正常行走模式。 | | abnormal | 小范围实验行走模式。在做Wi-Fi指纹与PDR融合定位的时候,由于安卓设备Wi-Fi扫描有一定的时间间隔(大约为2~3秒),所以在实验的过程中,两步之间的控制时间大于3s,算法部分进行了不同处理。 |
示例1,对data/linear_08m中的数据进行分析。
pdr.show_steps(frequency=70, walkType='normal')
结果如下:

示例2,对fusion01/SType中的数据进行分析。
pdr.show_steps(frequency=70, walkType='abnormal')
结果如下:

可以发现,对比示例1中的结果,该图峰值之间的间隔比较大。
Demo1.2 show_gaussian函数:查看数据在一定范围内的分布情况
用来判断数据的分布情况,同时可利用高斯函数拟合(可选),可以用来分析静止惯性数据。
show_gaussian参数使用说明如下:
- data - 某一轴加速度数据
- fit - 布尔值,是否进行高斯拟合
示例1,对data/still中的静止数据进行分析。
acc_z = linear[:,2]
pdr.show_gaussian(acc_z, True)
结果如下:

示例2,对data/linear_08m中的数据及进行分析:
acc_z = linear[:,2]
pdr.show_gaussian(acc_z, False)
结果如下:

Demo1.3 show_data函数:查看三轴加速度的分布情况
show_data参数使用说明如下:
| dataType | 描述 | | :------- | :--------------------------- | | linear | 查看三轴线性加速度的分布情况 | | gravity | 查看三轴重力加速度的分布情况 | | rotation | 查看旋转四元数的数据分布情况 |
示例1,对data/linear_08m中的数据及行分析:
pdr.show_data("linear")
结果如下:

示例2,对data/linear_08m中的数据及行分析:
pdr.show_data("gravity")
结果如下:

示例3,对data/linear_08m中的数据及行分析:
pdr.show_data("rotation")
结果如下:

Demo1.4 step_stride函数:步长推算函数
step_stride传入的是某一时刻的函数值,往往是垂直方向合加速度的峰值点,从而推算出步长值。
stride_length = pdr.step_stride(acc)
Demo1.5 step_counter函数:获取数据中的步伐信息
step_counter会返回一个包含每一个步伐信息的字典类型数组,其中index为样本序号,acceleration为步伐加速度峰值,函数参数使用说明如下:
- frequency - 数据采集频率
- walkType - 行走模式
| walkType | 描述 | | :------- | :----------------------------------------------------------- | | normal | 正常行走模式。 | | abnormal | 实验行走模式。在做Wi-Fi指纹与PDR融合定位的时候,由于安卓设备Wi-Fi扫描有一定的时间间隔,所以在实验的过程中,两步之间的控制时间大于3s,所以算法部分进行了不同处理。 |
示例1,对data/linear_08m中的数据进行分析。
pdr.show_steps(frequency=70, walkType='normal')
print(steps)
结果如下:
[
{
'index': 298,
'acceleration': 3.88391844277864
},
{
'index': 354,
'acceleration': 6.163800299609754
},
......
]
示例2,利用data/linear_08m中的数据分析步长推算算法的准确度:
steps = pdr.step_counter(frequency=70, walkType='normal')
print('steps:', len(steps))
stride = pdr.step_stride
accuracy = []
for v in steps:
a = v['acceleration']
print(stride(a))
accuracy.append(
np.abs(stride(a)-0.8)
)
square_sum = 0
for v in accuracy:
square_sum += v*v
acc_mean = (square_sum/len(steps))**(1/2)
print("mean: %f" % acc_mean) # 平均误差
print("min: %f" % np.min(accuracy)) # 最小误差
print("max: %f" % np.max(accuracy)) # 最大误差
print("sum: %f" % np.sum(accuracy)) # 累积误差
结果如下:
steps: 10
0.7019198589090117
0.7878293284920566
0.8188530449804803
0.7910022847592212
0.7700272110821945
0.7766284915404985
0.8636455533175651
0.7555013698705025
0.8041832313898543
0.8379454829417488
mean: 0.043746
min: 0.004183
max: 0.098080
sum: 0.341719
Demo1.6 step_heading函数:步长推算函数
实验过程中手机采用HOLDING模式,即手握手机放在胸前,并且x轴与地面平行,step_heading直接返回每一时刻的偏航角yaw值,初始值默认设为0,这里的都是相对值。
yaw = pdr.step_heading()
Demo1.7 pdr_position函数:获取数据中的步伐信息
pdr_position会返回每一步的x、y坐标值,以及每一步的步长和航向角:
- frequency - 数据采集频率
- walkType - 行走模式
- offset - 初始航向角大小
- initPosition - 初始位置,格式为两个元素的元组形式,分别表示x与y
| walkType | 描述 | | :------- | :----------------------------------------------------------- | | normal | 正常行走模式。 | | fusion | 实验行走模式。在做Wi-Fi指纹与PDR融合定位的时候,由于安卓设备Wi-Fi扫描有一定的时间间隔,所以在实验的过程中,两步之间的控制时间大于3s,所以算法部分进行了不同处理。 |
示例:
position_x, position_y, strides, angle = pdr.show_steps(frequency=70, walkType='abnormal', offset=np.pi/2, initPosition=(0,0))
Demo1.8 show_trace函数:输出行走轨迹图
show_trace内部使用了pdr_position,可以输出轨迹图像。
- frequency - 数据采集频率
- walkType - 行走模式
- offset - 轨迹偏差角度(指上北下南地图中的轨迹旋转到输出轨迹的角度值,实验过程使用了安卓的旋转矢量软件传感器,它集成了加速度计、陀螺仪和磁力计的数据,最终输出了一个以地球坐标系为基础的绝对信息,但实验输出图有时候会分析一个相对定位的情景,所以可以用该偏差值进行修正)
- initPosition - 初始位置,格式为两个元素的元组形式,分别表示x与y
- realTrace - 两列的numpy.ndarray格式数据,表示真实轨迹坐标,主要是为了方便轨迹的对比(可选)
| walkType | 描述 | | :------- | :----------------------------------------------------------- | | normal | 正常行走模式。 | | abnormal | 小范围实验行走模式。在做Wi-Fi指纹与PDR融合定位的时候,由于安卓设备Wi-Fi扫描有一定的时间间隔,所以在实验的过程中,两步之间的控制时间大于3s,所以算法部分进行了不同处理。 |
示例1,显示data/fusion/LType数据的预测轨迹图:
pdr.show_trace(frequency=70, walkType='abnormal', initPosition=(2,1))
结果如下:

示例2,显示data/fusion/LType数据的预测轨迹图:
pdr.show_trace(frequency=70, walkType='abnormal', offset=0, real_trace=real_trace, initPosition=(2,1))
结果如下:

Demo2 Wi-Fi指纹定位
要进行wifi操作,需要创建一个wifi.Model对象,由于实验数据中是以每一步作为一个定位状态,因此这里pdr与wifi配合使用。从代码层面而言这不是必要的,也可以更换成其他业务。
import location.wifi as wifi
wifi = wifi.Model(rssi)
Demo2.1 rssi_fluctuation函数:查看wifi数据的波动情况
rssi_fluctuation需要传入一个布尔值merge作为参数。
| merge | 描述 | | :---- | :----------------------------------------------------------- | | True | 以Wi-Fi扫描次数作为x轴 | | False | 以样本点数目作为x轴,事实上样本点数目合并一个Wi-Fi扫描间隔数据从而得到了合并的效果。 |
示例1,显示data/rssi_fluctuation数据:
wifi.rssi_fluctuation(False)
结果如下:

示例2,显示data/rssi_fluctuation数据:
wifi.rssi_fluctuation(True)
结果如下:

Demo2.2 determineGaussian函数:查看wifi数据的高斯拟合情况
determineGaussian的参数如下所示:
- data- numpy.ndarray格式数据,源自一个AP的wifi信号强度数据
- merge- 是否合并为每一个扫描次数
- interval- 划分间隔,默认值为1
- wipeRange- 剔除样本点数目
示例1,显示data/rssi_fluctuation数据:
wifi.determineGaussian(rssi[:, 0], True, wipeRange=170*100)
结果如下:

Demo2.3 create_fingerpirnt函数:构建一个指纹
Related Skills
node-connect
339.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.8kCommit, push, and open a PR
