Geomagnetic + IMU fusion experiments with PF/DDTW on UJIIndoorLoc-Mag.
Project description
Lego-like Geomagnetic Positioning
First of All
This is the package I am using for testing my own geomagnetic positioning project using Particle filter, and I am trying to make the project more lego-like such as pytorch , and you can see some of the characteristics are from pytorch, actually. I am going to make this a acedemic-directed tool, everyone who come up with an idea of, whatever the filter problem is, can immediately turn on the mac, quickly have a simulation, and feel free to build anything you like. World of Machine Learning can do it, I hope we will do it.
Although the algorithm I've written in the main.py is still dumb and I am still seeking the reason why it is performing below my expectation, however, like someone said on Youtube, I am the guy interested in building shovels, and I hope there will be more contributers can participate in it.
The project per se is just in testing right now, with so many functional issues yet to be finished, but I hope this project, conversely, will never be an end, with firm cooperation of the intelligence of the community. A project with continuous maintainence and contributers is a healthy project.
For anyone who is interested, email kudoumakoto6523@gmail.com (same as the github account).
Below are the content.
Lego-style geomagnetic indoor positioning for fast academic prototyping.
This repository is a testing package for geomagnetic positioning with particle filtering, IMU-based PDR, and DDTW-oriented magnetic matching. The current algorithm in main.py is still experimental and its performance is not yet where I want it to be, but the goal of the project is already clear:
- make geomagnetic positioning experiments easy to assemble
- expose reusable building blocks instead of one hard-coded pipeline
- let researchers quickly try a new filter idea, run a simulation, and inspect results
The project is closer to "building shovels" than claiming a finished localization system. If PyTorch can give machine learning researchers a flexible toolbox, this project aims to do something similar for geomagnetic and filter-oriented indoor positioning research.
Status
This project is under active restructuring.
- The package layout is already modular and usable for experiments.
- The particle-filter pipeline is configurable and reorderable.
- UJI map building and visualization are implemented.
- Some algorithm hooks are still placeholders or baseline implementations.
- End-to-end accuracy is still being improved.
If you are interested in contributing ideas, code, experiments, or criticism, contributions are welcome.
What The Repository Currently Covers
The current pipeline combines:
- IMU-based PDR for step and heading estimation
- geomagnetic matching
- particle filtering with DDTW-oriented weighting design
- UJIIndoorLoc-Mag map building
- direct user-defined magnetic map input
Installation
Python >= 3.11 is required.
python -m venv .venv
source .venv/bin/activate
pip install -e .
Current package dependencies from pyproject.toml:
numpypykrigematplotlib
Quick Start
Run the default experiment:
python main.py
Test UJI map building plus user-map visualization:
python main_get_map_temp.py
Plot true route overlays:
python main_get_true_route.py
Inspect sensor streams and visualization outputs:
python main_get_sensor_and_len.py
Design Goal: Lego-Style Pipeline
The package is intentionally structured in a PyTorch-like style. Instead of forcing one giant script, it separates:
- orchestration
- state models
- block registries
- configurable PDR modules
- configurable PF modules
The default flow is:
Initializer -> RunContext -> Experiment -> GeomagPipeline
Basic example:
from Geomag import Experiment, Initializer, PDRConfig, PFConfig
ctx = Initializer(
num_runs=1,
window_size=400,
route_source="uji",
sensor_source="uji",
uji_test_file="tt01.txt",
).create_context()
pdr = PDRConfig(
step_judge="peak_dynamic",
step_judge_params={"peak_sigma": 0.40, "peak_prominence": 0.16},
step_length="weinberg",
step_length_params={"weinberg_k": 0.45},
heading="gyro",
heading_params={"dt": 0.02},
mag="norm_mean",
)
pf = PFConfig(
state_params={"num_particles": 500, "min_particles": 120, "max_particles": 5000},
motion="gaussian",
motion_params={"heading_noise_std": 0.10, "step_noise_std": 0.20},
weight="ddtw",
weight_params={"sigma": 6.0, "max_hist": 80},
particle_size="kld",
particle_size_params={"epsilon": 0.10},
resample_trigger="ess_or_target",
resample_trigger_params={"ess_ratio_threshold": 0.45},
resample="cso",
)
result = Experiment(ctx, pdr_config=pdr, pf_config=pf).run(show=True)
Reordering The Particle Filter
The PF side is built from composable stages, so you can rearrange them when needed.
from Geomag import (
ParticleSizeStage,
PredictStage,
ResampleDecisionStage,
ResampleStage,
UpdateStage,
build_pf_sequential,
)
pf = build_pf_sequential(
("predict", PredictStage(motion="gaussian")),
("particle_size", ParticleSizeStage(particle_size="kld")),
("update", UpdateStage(weight="ddtw")),
("resample_decision", ResampleDecisionStage(trigger="ess_or_target")),
("resample", ResampleStage(resample="cso")),
)
You can inspect the registered blocks at runtime:
from Geomag import Experiment, GeomagPipeline
print(GeomagPipeline.available_blocks())
print(Experiment.describe_api())
Current block families include:
step_judge:autocorr,frequency_fft,peak_dynamic,peak_fixed,valley_peak,zero_crossingstep_length:fixed,weinbergheading:gyro,q_fused,tilt_compassmag:norm_last,norm_meanmotion:gaussianweight:ddtwparticle_size:kldresample_trigger:always,ess_or_targetresample:cso
Map API
Geomag/algorithms.py exposes the public map entrypoint:
from Geomag.algorithms import get_map
Two branches are currently supported:
source="uji": build a continuous map from UJIIndoorLoc-Magsource="own": use a user-defined magnetic map, with direct matrix input preferred
UJI Branch
from Geomag.algorithms import get_map
uji_map = get_map(source="uji")
print(uji_map)
Behavior:
- downloads the UJI zip if missing
- extracts the dataset if missing
- parses
lines/andcurves/ - reconstructs sample positions
- fits an Ordinary Kriging model
- writes processed artifacts
- returns a metadata dictionary
Configuration lives in pyproject.toml under [tool.map_builder].
Relevant keys:
preview_resolutionmax_kriging_pointsseedvariogram_modeloutput_model_npzoutput_preview_npzoutput_jsonoutput_png
Typical returned fields include:
sourcecontinuous_mapoutput_model_npzoutput_preview_npzoutput_jsonoutput_pngzip_pathextract_dir
Own Branch
Preferred input is a directly editable 2D matrix:
from Geomag.algorithms import get_map
own_map = get_map(
source="own",
own_grid_array=[
[45.10, 45.22, 45.31],
[44.97, 45.05, 45.27],
[44.83, 44.96, 45.14],
],
own_grid_meta={
"cell_size_m": 0.5,
"origin_xy_m": [0.0, 0.0],
"variogram_model": "spherical",
},
)
print(own_map)
Important metadata:
cell_size_m: distance between neighboring cells in metersorigin_xy_m: physical origin for mapping matrix indices to world coordinates- optional
variogram_model: interpolation choice for visualization
Matrix convention:
matrix[row][col]stores magnetic magnitudex = origin_x + col * cell_sizey = origin_y + row * cell_size
Visualization
Use visualize(...) with mode selection:
from Geomag.algorithms import visualize
UJI map preview:
visualize(geomag_map=uji_map, mode="ujimap")
User map preview:
visualize(geomag_map=own_map, mode="usermap")
The visualization API also supports route and sensor overlays, as shown in:
Repository Layout
main.py: thin runtime entrypointGeomag/initiation.py: initialization orchestrationGeomag/experiment.py: experiment loop wrapperGeomag/pipeline.py: composable PDR and PF pipelineGeomag/models.py: shared state classes such asPFState,Particle, andRunContextGeomag/blocks.py: block interfaces and registriesGeomag/algorithms.py: map building, visualization, and algorithm implementations/placeholdersGeomag/nn.py: lightweightModuleandSequentialabstractionsGeomag/utils.py: helper utilities for sensor collection and map loading
Notes
- If
pykrigeis missing, continuous interpolation will fail with an explicit installation message. - If
matplotlibis missing, visualization will fail with an explicit installation message. - The initializer tries to build the UJI map first and can fall back to existing processed artifacts if rebuilding is unavailable.
- The first
get_map(source="uji")call may download the dataset automatically.
Roadmap
Near-term goals:
- improve particle-filter performance and diagnostics
- replace baseline or placeholder parts with stronger research-grade implementations
- make more blocks plug-and-play
- add more examples, tests, and benchmark scripts
- make the package easier for outside contributors to extend
Contributing
This project is meant to keep evolving. If you have:
- a new filter idea
- a better weighting method
- a stronger step detector
- a new dataset adapter
- a cleaner interface design
then this repository is intended to be a place where that idea can be tested quickly.
Pull requests, issue reports, design suggestions, and academic collaboration are all welcome.
Contact
For collaboration or questions, email:
kudoumakoto6523@gmail.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lego_like_positioning-0.1.1.tar.gz.
File metadata
- Download URL: lego_like_positioning-0.1.1.tar.gz
- Upload date:
- Size: 31.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b6a0026ab7449634ae6c28faffe4a7eb5db8f0d5bc76c6d42acc9248515d3d5
|
|
| MD5 |
893df8dc2a1d98d23bf4090da3a7bdc5
|
|
| BLAKE2b-256 |
72769825d5996b04cfc2c2086f633ff9e7d2d3ebe02da44b830a120506055441
|
File details
Details for the file lego_like_positioning-0.1.1-py3-none-any.whl.
File metadata
- Download URL: lego_like_positioning-0.1.1-py3-none-any.whl
- Upload date:
- Size: 34.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e55403755c6ab7918e5fdd6c59c5de33a237fac01739b44afa8aae5ffb5f98dd
|
|
| MD5 |
2d15ebb6cee4d1066e3e09b199cb8e44
|
|
| BLAKE2b-256 |
2f4627094e800a4017cb95daeb504c97a81afb9c2cd434e07118285b134d3fef
|