Compare commits
6 Commits
4658f3d9f5
...
4f7a9d2e70
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f7a9d2e70 | ||
|
|
1c4bf3e340 | ||
|
|
659525cefb | ||
|
|
1bbdac4a2e | ||
|
|
0146fb4db2 | ||
|
|
99ea06bc91 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -174,3 +174,5 @@ poetry.toml
|
|||||||
pyrightconfig.json
|
pyrightconfig.json
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||||
|
|
||||||
|
config.yaml
|
||||||
|
|||||||
29
config.yaml.example
Normal file
29
config.yaml.example
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
receive_hosts:
|
||||||
|
- ["10.0.12.62", 8008]
|
||||||
|
- ["10.0.12.64", 8008]
|
||||||
|
transmit_host: ["10.0.12.63", 8008]
|
||||||
|
antennas:
|
||||||
|
order: [
|
||||||
|
[["10.0.12.62", 8008], 0],
|
||||||
|
[["10.0.12.64", 8008], 1],
|
||||||
|
[["10.0.12.64", 8008], 0],
|
||||||
|
[["10.0.12.62", 8008], 1]]
|
||||||
|
spacing: 0.0285
|
||||||
|
|
||||||
|
sample_rate: 100 # Hz
|
||||||
|
|
||||||
|
central_freq: 6195 # MHz
|
||||||
|
channel_width: 20 # MHz
|
||||||
|
frame_format: HT
|
||||||
|
|
||||||
|
preprocessing:
|
||||||
|
moving_average_alpha: 0.01
|
||||||
|
|
||||||
|
bandpass:
|
||||||
|
lowcut: 2
|
||||||
|
highcut: 40
|
||||||
|
|
||||||
|
music:
|
||||||
|
eigval_threshold: 10
|
||||||
|
window_size: 40
|
||||||
|
|
||||||
@ -5,15 +5,21 @@ description = "Use Wi-Fi Channel State Information to locate human presence"
|
|||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flask",
|
"flask",
|
||||||
"numpy",
|
"numpy>=2.0.0",
|
||||||
"flask-sock",
|
"flask-sock",
|
||||||
"pytest",
|
"pytest",
|
||||||
"matplotlib",
|
"matplotlib",
|
||||||
"scipy",
|
"scipy",
|
||||||
"scipy-stubs",
|
"scipy-stubs",
|
||||||
"typer"
|
"typer",
|
||||||
|
"h5py>=3.12.1",
|
||||||
|
"pyyaml>=6.0.2",
|
||||||
|
"pydantic>=2.10.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
where-fi = "where_fi.cli:app"
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 88
|
line-length = 88
|
||||||
@ -30,3 +36,9 @@ reportMissingTypeStubs = "warning"
|
|||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
python_files = "*.py"
|
python_files = "*.py"
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
package = true
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
packages = ["where_fi"]
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
PREPROCESSING_SHORT_TERM_WINDOW_SIZE = 5
|
|
||||||
PREPROCESSING_LONG_TERM_ALPHA = 0.01
|
|
||||||
|
|
||||||
PREPROCESSING_BANDPASS_LOW_CUTOFF = 2
|
|
||||||
PREPROCESSING_BANDPASS_HIGH_CUTOFF = 40
|
|
||||||
|
|
||||||
AOA_SLIDING_WINDOW_SIZE = 40
|
|
||||||
|
|
||||||
RECEIVE_HOSTS = [("cfalas.com", 10001), ("cfalas.com", 10002)]
|
|
||||||
INJECT_HOST = ("cfalas.com", 10003)
|
|
||||||
|
|
||||||
ANTENNA_ORDER = [
|
|
||||||
(("cfalas.com", 10001), 0),
|
|
||||||
(("cfalas.com", 10002), 1),
|
|
||||||
(("cfalas.com", 10002), 0),
|
|
||||||
(("cfalas.com", 10001), 1),
|
|
||||||
]
|
|
||||||
|
|
||||||
SAMPLE_RATE = 100 # Hz
|
|
||||||
|
|
||||||
EIGVAL_THRESHOLD = 10
|
|
||||||
|
|
||||||
|
|
||||||
# DELTA_F = 78_125 # Spacing between subcarriers in Hz
|
|
||||||
DELTA_F = 312_500 # Spacing between subcarriers in Hz
|
|
||||||
CENTRAL_FREQUENCY_MHZ = 6195
|
|
||||||
ANTENNA_SPACING = 0.0285 # 2.85 cm
|
|
||||||
CHANNEL_WIDTH = 20
|
|
||||||
FRAME_FORMAT = "HT"
|
|
||||||
|
|
||||||
|
|
||||||
CENTRAL_FREQUENCY_HZ = CENTRAL_FREQUENCY_MHZ * 1_000_000
|
|
||||||
C = 299_792_458 # m/s
|
|
||||||
|
|
||||||
VISUALISE_RAW = False
|
|
||||||
HEATMAP_FPS = 10
|
|
||||||
201
uv.lock
201
uv.lock
@ -1,6 +1,15 @@
|
|||||||
version = 1
|
version = 1
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "annotated-types"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blinker"
|
name = "blinker"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -122,35 +131,35 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fonttools"
|
name = "fonttools"
|
||||||
version = "4.55.5"
|
version = "4.55.6"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/8b/d0/6a515b1587f2fe3540429120b20c674687e6f5fdd7dbd114f0fca224294b/fonttools-4.55.5.tar.gz", hash = "sha256:87afe2a1e81a55131bbae66f3f1718b1faee3218b1261abce036d7d189094c36", size = 3499695 }
|
sdist = { url = "https://files.pythonhosted.org/packages/49/2e/0b11e907b90665253dbad425479e874e38a9e81ced397a4e3312b9116935/fonttools-4.55.6.tar.gz", hash = "sha256:1beb4647a0df5ceaea48015656525eb8081af226fe96554089fd3b274d239ef0", size = 3500677 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/de/23dde20ca4de7bb0c307d6a0a9754cf2d81f3a95b7cd97d75404d8189500/fonttools-4.55.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:019ab35daacec241d567174e1e8068191b059a7e171f68483778a91485e8e27b", size = 2775730 },
|
{ url = "https://files.pythonhosted.org/packages/53/42/e6cb653675fcf2bed7814b5d688c95a1b6d136ad26e4ed1523c18d6dbb28/fonttools-4.55.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0879f99eabbf2171dfadd9c8c75cec2b7b3aa9cd1f3955dd799c69d60a5189ef", size = 2776041 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/58/fa/5398f1f6352ac1538d4d8c214bec36ac90c5bee2a0df715ec9dfca33bbe7/fonttools-4.55.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59fbfd348fe3c15b4cb31f0cb81a9fad67c1419596e2f349be0a1e48955775fd", size = 2303942 },
|
{ url = "https://files.pythonhosted.org/packages/58/b6/d54d71a59498def2b58d5ec5f8baad35add4a076edb1968d645b7a95759a/fonttools-4.55.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d77d83ca77a4c3156a2f4cbc7f09f5a8503795da658fa255b987ad433a191266", size = 2304268 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/1a/5fa231ec23b1437955ba5ccc943ad05a08e62a84f6a66dc0a805c9dfacc6/fonttools-4.55.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3686e74b372313495ffbe58b23304772bc2f7c7fb947da382f250bfc1b0417c", size = 4891706 },
|
{ url = "https://files.pythonhosted.org/packages/fe/ed/0743c21126fc3442a710b8c880355e381dd750a18bfe10097d663a1838c5/fonttools-4.55.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07478132407736ee5e54f9f534e73923ae28e9bb6dba17764a35e3caf7d7fea3", size = 4891976 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/35/4e/8e9cb6f0e9c226d555818c43635750bade00773ba0e1d73076bbb5230fef/fonttools-4.55.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f8065f503b2abc9d8d2b241da307c58c80df0e28c5ea8464fe8d2ba3bb76990", size = 4920908 },
|
{ url = "https://files.pythonhosted.org/packages/0d/73/8f7a0084bc0b3591e281fdcef7e704ad3817244d35ca98b444de5acf0f47/fonttools-4.55.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c06fbc2fd76b9bab03eddfd8aa9fb7c0981d314d780e763c80aa76be1c9982", size = 4921223 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9e/45/7916dc6ac9a40a18a593d5232d3058ed15010d179f15c4187942a878fc06/fonttools-4.55.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac1e3139c9776eb3a5119a25da5665fd961f6b39a5307b62bd427afba69b7c5e", size = 4900127 },
|
{ url = "https://files.pythonhosted.org/packages/ad/75/b47d792d4c4f65ff488d9f25d59f8bb6382c74efd6169bd3c0341320ac76/fonttools-4.55.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:09ed667c4753e1270994e5398cce8703e6423c41702a55b08f843b2907b1be65", size = 4900418 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/32/e7/b79257a994b8234b8dc3cee1eb4c15ad9d34fe4256f4a7a43f2adfd507d1/fonttools-4.55.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1bf14bcec231408581ee3cafcb23a0ef1821a974a6ff5031ccbc1aad65192de9", size = 5068214 },
|
{ url = "https://files.pythonhosted.org/packages/88/70/f821dce8121b6c4bccd10ca28499df2e0e9811e2a711deeb270b9065fcd9/fonttools-4.55.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0ee6ed68af8d57764d69da099db163aaf37d62ba246cfd42f27590e3e6724b55", size = 5068531 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/df/0760283000cf9f6c33f9b5b229c3a576229d88a29519022fd0618b5e7a30/fonttools-4.55.5-cp311-cp311-win32.whl", hash = "sha256:aa7868dd7d42992ccd722d70a3bd413d875ca51633b094b5867ab09ed8e78bbe", size = 2176959 },
|
{ url = "https://files.pythonhosted.org/packages/76/6e/6b7c919c4f985042fe02fe9cbd3d956e2e85a6db8575737ff600aa24c42c/fonttools-4.55.6-cp311-cp311-win32.whl", hash = "sha256:9f99e7876518b2d059a9cc67c506168aebf9c71ac8d81006d75e684222f291d2", size = 2177287 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/f0/280d44cc18ba8c3cce26ba7c591a4644560664af5696b3ceaa895a672dbb/fonttools-4.55.5-cp311-cp311-win_amd64.whl", hash = "sha256:d895f363e03697f7941c278fb7a42fca63d52de5416180ef1892dfd67a136698", size = 2223480 },
|
{ url = "https://files.pythonhosted.org/packages/1e/10/26a4123227fa1ab9fa8ec062f4f2b980f43483d58ec261d502bfe49af6c2/fonttools-4.55.6-cp311-cp311-win_amd64.whl", hash = "sha256:3aa6c684007723895aade9b2fe76d07008c9dc90fd1ef6c310b3ca9c8566729f", size = 2223807 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/d7/27b1a46e6322aa7d47baa988748e32791edf8a68f077eb39324beb6674a3/fonttools-4.55.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:5ad2b4a8bfd94ae6792c2f00e585fcdaa5c7803d87eedaeaa30e81616283e712", size = 2770149 },
|
{ url = "https://files.pythonhosted.org/packages/f7/c0/b9c7308f925545702a2ecc696bb59ed0cab544aa53b3abd6c0f3ab1186e2/fonttools-4.55.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:51120695ee13001533e50abd40eec32c01b9c6f44c5567db38a7acd3eedcd19d", size = 2770475 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/bf/8228556457e8a3f2f8c67ad7e648001ef2d7e9e364e9350757ae106c5c82/fonttools-4.55.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:928d0a093eaab9bde8b295f01859b0463384b86ba800eb959370734588347444", size = 2301405 },
|
{ url = "https://files.pythonhosted.org/packages/9c/ec/bc7baa296dbbfb58fee00458285006a00deeedbbdeae2b88ca477d662170/fonttools-4.55.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:76ac5a595f86892b49ba86ba2e46185adc76328ce6eff0583b30e5c3ab02a914", size = 2301727 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/72/7933a3986c415d7917569c0c67cba1b65b8a9e72b6da3c9d58726dab2300/fonttools-4.55.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b10b408a68f5c1ecb927ad11860bf534312a236c61f3b20cb6e22bb55265b9", size = 4806426 },
|
{ url = "https://files.pythonhosted.org/packages/dd/73/75e0c47f5bc8805419499a016691e388d92ab4dc607ef5e9ace86c466829/fonttools-4.55.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7535a5ac386e549e2b00b34c59b53f805e2423000676723b6867df3c10df04", size = 4806704 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/8a/e3c99a9aa1f9153fddf98c020449acc98140cd492d6264f8800fbd189c40/fonttools-4.55.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a06e77f956a5857a4444f689f0ca4a1c4bdbcb38c812805f54a1b21380cc24", size = 4877508 },
|
{ url = "https://files.pythonhosted.org/packages/ff/de/932d68e198dc386c7fb055416822834b1b3a21cd376eeb7cc2d6fdc5ad14/fonttools-4.55.6-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c42009177d3690894288082d5e3dac6bdc9f5d38e25054535e341a19cf5183a4", size = 4877824 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/3b/b446becf4a8a057a54dd06ee5f0b018fdf81bacb233ea7694612e32c542e/fonttools-4.55.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:85dc010bb9dc0fc9cfdb050ace4fb810ff5d5edb6a34045bce83dd4307b1a27c", size = 4784922 },
|
{ url = "https://files.pythonhosted.org/packages/01/cd/e6249ce95a0fa7d2950524400a524fb6860c688776b53a3635f3d3c2d3f4/fonttools-4.55.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:88f74bc19dbab3dee6a00ca67ca54bb4793e44ff0c4dcf1fa61d68651ae3fa0a", size = 4785213 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/91/29e384f0d8141a64c03a7efec118f4e09eba84123b627b458f6d71c1a91e/fonttools-4.55.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:546b195de57360e52b6f94bf126b1400004643fc2754705b6ae659293c34e449", size = 5012492 },
|
{ url = "https://files.pythonhosted.org/packages/67/85/db2ac44e066043451542d9845969e2e9a3545b8a77e9d0e35484ebe95227/fonttools-4.55.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bc6f58976ffc19fe1630119a2736153b66151d023c6f30065f31c9e8baed1303", size = 5012806 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c3/31/2ee42e91a0975e8f5093c41aeb8fc172de0a133c3e841cc61f876c379dd8/fonttools-4.55.5-cp312-cp312-win32.whl", hash = "sha256:8c9061a4027bfc62b22c55885e561d6eb36d3f6d058f7894e4d84eb778580e3f", size = 2165431 },
|
{ url = "https://files.pythonhosted.org/packages/66/ec/6dca43eb8d6555503b6e454edf42688464d0e744b089a757afc7c513f8a9/fonttools-4.55.6-cp312-cp312-win32.whl", hash = "sha256:4259159715142c10b0f4d121ef14da3fa6eafc719289d9efa4b20c15e57fef82", size = 2165760 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cc/46/8491a74940fa1cfa62b66308ac5268fbdc1003fa93503a87ba671e93c3c2/fonttools-4.55.5-cp312-cp312-win_amd64.whl", hash = "sha256:742c63ba8e2888dc6cf4cce98d16fe77d79a6c283f5c6d1a8e17d128ecde45fc", size = 2212275 },
|
{ url = "https://files.pythonhosted.org/packages/39/5d/99a164057dd1fc345027113909022877e5fd1b649b2357d18a2a03c50d8b/fonttools-4.55.6-cp312-cp312-win_amd64.whl", hash = "sha256:d91fce2e9a87cc0db9f8042281b6458f99854df810cfefab2baf6ab2acc0f4b4", size = 2212601 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/3c/f6c02e0322033f4e537d16d86d0d4b01ac7723f55b16d183261c5e93f658/fonttools-4.55.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a853ee8ac47c2e2e68d5a0f07f7f38eb616d60c4438bcff5c0312322451f15c6", size = 2757519 },
|
{ url = "https://files.pythonhosted.org/packages/da/ce/65ea137cdc6d7682c8133931944dec81d2cf9f0276665e4a8292efeb262a/fonttools-4.55.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9394813cc73fa22c5413ec1c5745c0a16f68dd2b890f7c55eaba5cb40187ed55", size = 2757836 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/f1/bb73cd6b13a9dba570d7003c6eb07163e1c97ced01b97f1508b514bb4d9f/fonttools-4.55.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:444e84d8158ed40427827e5ff8db4d05d89560e19f2a6baf90565880d1c7c08f", size = 2294919 },
|
{ url = "https://files.pythonhosted.org/packages/d1/39/671f6e5af29235bf598a14eb060bfa2a1dd5010cafefe39fc9648ace3a3c/fonttools-4.55.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ac817559a7d245454231374e194b4e457dca6fefa5b52af466ab0516e9a09c6e", size = 2295238 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a3/4e/7a22f5fb504b99a5b4a3c331d40db8db0d662735b16da0b046905ff6a89b/fonttools-4.55.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8eb7ca7b3ef580114edd6f9ce9424e534b9cb1a98c918a42930f196b1ac59e", size = 4784860 },
|
{ url = "https://files.pythonhosted.org/packages/31/68/c41d6fe8c3132db492d054c39e043672d1739055f1aa531e4141541e1a4a/fonttools-4.55.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34405f1314f1e88b1877a9f9e497fe45190e8c4b29a6c7cd85ed7f666a57d702", size = 4785136 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4d/c6/20c8e07361ad1337b2c7daf226356dcd33c56bb0ddae09b7ab74e66f80b1/fonttools-4.55.5-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c27b2084eb715bce93b4c3cc2080a8b3fb6aff5a105c221f150df42e79120a", size = 4856843 },
|
{ url = "https://files.pythonhosted.org/packages/1a/85/591b8f36af1f36d78a9d3f24a95912a70ca899d037e43bb41dba19088d05/fonttools-4.55.6-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af5469bbf555047efd8752d85faeb2a3510916ddc6c50dd6fb168edf1677408f", size = 4857158 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bf/94/07dba160780be53b75dc888d9d8bde6e09c786ba3856fe55333b29618cc2/fonttools-4.55.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bb11588c41c9e867cebbf72485963252b2d782e97514845aa3fd372b31f63afe", size = 4765232 },
|
{ url = "https://files.pythonhosted.org/packages/27/1b/a8bccde7c0f88e6ccd8b2c80b112f7b363a2d1f600fb29f8654bf14bdf5f/fonttools-4.55.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8a8004a19195eb8a8a13de69e26ec9ed60a5bc1fde336d0021b47995b368fac9", size = 4765517 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/38/1f/695ceb66a691f3ace1c21f61065ddd28b8aaef57099e0f372bbf5b075f06/fonttools-4.55.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a65d4407ca31ec582d1a7105ee08986f6ef964ddcbe0a2878881926bc23cfba3", size = 4986145 },
|
{ url = "https://files.pythonhosted.org/packages/1c/d4/9b24f3563325e396810191240ed8efa0b093ea7a3e5971cc97515da42ceb/fonttools-4.55.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:73a4aaf672e7b2265c6354a69cbbadf71b7f3133ecb74e98fec4c67c366698a3", size = 4986460 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/0a/3466ce7c0db620c314c534aa242abe7fe2176a3f049f71bd0da1679917fa/fonttools-4.55.5-cp313-cp313-win32.whl", hash = "sha256:7cf3dc8051c0b37034c2661934e8795a1e95ac5cf4f97ce9935cf6f10ba481f0", size = 2163461 },
|
{ url = "https://files.pythonhosted.org/packages/30/01/874a26eaad82ab5e469766cb4532a3a7d65262d443023507bd5cd6247cce/fonttools-4.55.6-cp313-cp313-win32.whl", hash = "sha256:73bdff9c44d36c57ea84766afc20517eda0c9bb1571b4a09876646264bd5ff3b", size = 2163789 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/eb/f1/a599c8fbe74a7735789ad98c4eaa2982d6e613ef72c35b5bfbe7b1c16b9f/fonttools-4.55.5-cp313-cp313-win_amd64.whl", hash = "sha256:b5e6868d8952a31cb3643080ea1594adde971bf2a05aae5bc47bf0ac91e79575", size = 2209257 },
|
{ url = "https://files.pythonhosted.org/packages/59/94/f1b35883172676e71c259dfdf5dddab9cffa650b503f4dd2535dce726a06/fonttools-4.55.6-cp313-cp313-win_amd64.whl", hash = "sha256:132fa22be8a99784de8cb171b30425a581f04a40ec1c05183777fb2b1fe3bac9", size = 2209586 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/09/4bb71d2cf825a368bc7f44805a198d9980541944b0a400becaa05703c72d/fonttools-4.55.5-py3-none-any.whl", hash = "sha256:6261deeaa54a720405fc4a21dc92f722d1b2c5a977910d464029534b9475f716", size = 1112207 },
|
{ url = "https://files.pythonhosted.org/packages/1e/6a/6afc55d75036b8d3fe5ceaea2e8da2c04e8f3b298325de73a35f098cb9a8/fonttools-4.55.6-py3-none-any.whl", hash = "sha256:d20ab5a78d0536c26628eaadba661e7ae2427b1e5c748a0a510a44d914e1b155", size = 1112524 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -162,6 +171,32 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h5py"
|
||||||
|
version = "3.12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "numpy" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cc/0c/5c2b0a88158682aeafb10c1c2b735df5bc31f165bfe192f2ee9f2a23b5f1/h5py-3.12.1.tar.gz", hash = "sha256:326d70b53d31baa61f00b8aa5f95c2fcb9621a3ee8365d770c551a13dbbcbfdf", size = 411457 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/61/c463dc5fc02fbe019566d067a9d18746cd3c664f29c9b8b3c3f9ed025365/h5py-3.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ccd9006d92232727d23f784795191bfd02294a4f2ba68708825cb1da39511a93", size = 3410828 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/9d/eb91a9076aa998bb2179d6b1788055ea09cdf9d6619cd967f1d3321ed056/h5py-3.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ad8a76557880aed5234cfe7279805f4ab5ce16b17954606cca90d578d3e713ef", size = 2872586 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/62/e2b1f9723ff713e3bd3c16dfeceec7017eadc21ef063d8b7080c0fcdc58a/h5py-3.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1473348139b885393125126258ae2d70753ef7e9cec8e7848434f385ae72069e", size = 5273038 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/89/118c3255d6ff2db33b062ec996a762d99ae50c21f54a8a6047ae8eda1b9f/h5py-3.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:018a4597f35092ae3fb28ee851fdc756d2b88c96336b8480e124ce1ac6fb9166", size = 5452688 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/4d/cbd3014eb78d1e449b29beba1f3293a841aa8086c6f7968c383c2c7ff076/h5py-3.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:3fdf95092d60e8130ba6ae0ef7a9bd4ade8edbe3569c13ebbaf39baefffc5ba4", size = 3006095 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/e1/ea9bfe18a3075cdc873f0588ff26ce394726047653557876d7101bf0c74e/h5py-3.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:06a903a4e4e9e3ebbc8b548959c3c2552ca2d70dac14fcfa650d9261c66939ed", size = 3372538 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/74/1009b663387c025e8fa5f3ee3cf3cd0d99b1ad5c72eeb70e75366b1ce878/h5py-3.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b3b8f3b48717e46c6a790e3128d39c61ab595ae0a7237f06dfad6a3b51d5351", size = 2868104 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/52/c604adc06280c15a29037d4aa79a24fe54d8d0b51085e81ed24b2fa995f7/h5py-3.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:050a4f2c9126054515169c49cb900949814987f0c7ae74c341b0c9f9b5056834", size = 5194606 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/63/eeaacff417b393491beebabb8a3dc5342950409eb6d7b39d437289abdbae/h5py-3.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c4b41d1019322a5afc5082864dfd6359f8935ecd37c11ac0029be78c5d112c9", size = 5413256 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/f7/bb465dcb92ca3521a15cbe1031f6d18234dbf1fb52a6796a00bfaa846ebf/h5py-3.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4d51919110a030913201422fb07987db4338eba5ec8c5a15d6fab8e03d443fc", size = 2993055 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/1c/ecdd0efab52c24f2a9bf2324289828b860e8dd1e3c5ada3cf0889e14fdc1/h5py-3.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:513171e90ed92236fc2ca363ce7a2fc6f2827375efcbb0cc7fbdd7fe11fecafc", size = 3346239 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/cd/5b6f574bf3e318bbe305bc93ba45181676550eb44ba35e006d2e98004eaa/h5py-3.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59400f88343b79655a242068a9c900001a34b63e3afb040bd7cdf717e440f653", size = 2843416 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/4f/b74332f313bfbe94ba03fff784219b9db385e6139708e55b11490149f90a/h5py-3.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e465aee0ec353949f0f46bf6c6f9790a2006af896cee7c178a8c3e5090aa32", size = 5154390 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/57/93ea9e10a6457ea8d3b867207deb29a527e966a08a84c57ffd954e32152a/h5py-3.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba51c0c5e029bb5420a343586ff79d56e7455d496d18a30309616fdbeed1068f", size = 5378244 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/51/0bbf3663062b2eeee78aa51da71e065f8a0a6e3cb950cc7020b4444999e6/h5py-3.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:52ab036c6c97055b85b2a242cb540ff9590bacfda0c03dd0cf0661b311f522f8", size = 2979760 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iniconfig"
|
name = "iniconfig"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -497,6 +532,73 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "2.10.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "annotated-types" },
|
||||||
|
{ name = "pydantic-core" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-core"
|
||||||
|
version = "2.27.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.19.1"
|
version = "2.19.1"
|
||||||
@ -542,6 +644,41 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "13.9.4"
|
version = "13.9.4"
|
||||||
@ -678,13 +815,16 @@ wheels = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "where-fi"
|
name = "where-fi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "flask" },
|
{ name = "flask" },
|
||||||
{ name = "flask-sock" },
|
{ name = "flask-sock" },
|
||||||
|
{ name = "h5py" },
|
||||||
{ name = "matplotlib" },
|
{ name = "matplotlib" },
|
||||||
{ name = "numpy" },
|
{ name = "numpy" },
|
||||||
|
{ name = "pydantic" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
{ name = "scipy" },
|
{ name = "scipy" },
|
||||||
{ name = "scipy-stubs" },
|
{ name = "scipy-stubs" },
|
||||||
{ name = "typer" },
|
{ name = "typer" },
|
||||||
@ -694,9 +834,12 @@ dependencies = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "flask" },
|
{ name = "flask" },
|
||||||
{ name = "flask-sock" },
|
{ name = "flask-sock" },
|
||||||
|
{ name = "h5py", specifier = ">=3.12.1" },
|
||||||
{ name = "matplotlib" },
|
{ name = "matplotlib" },
|
||||||
{ name = "numpy" },
|
{ name = "numpy", specifier = ">=2.0.0" },
|
||||||
|
{ name = "pydantic", specifier = ">=2.10.6" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
|
{ name = "pyyaml", specifier = ">=6.0.2" },
|
||||||
{ name = "scipy" },
|
{ name = "scipy" },
|
||||||
{ name = "scipy-stubs" },
|
{ name = "scipy-stubs" },
|
||||||
{ name = "typer" },
|
{ name = "typer" },
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from . import cli
|
|||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s %(name)-40s %(levelname)-8s %(message)s",
|
format="%(asctime)s %(name)-50s %(levelname)-8s %(message)s",
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -5,12 +5,13 @@ import numpy as np
|
|||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from . import config, visualise
|
from .. import visualise
|
||||||
from .collection import ingest
|
from ..config import config
|
||||||
from .processing.aoa import AoA
|
from ..processing.aoa import AoA
|
||||||
from .processing.preprocess import Preprocessor
|
from ..processing.preprocess import Preprocessor
|
||||||
|
from . import file, globals
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer(callback=globals.main)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +24,10 @@ def antennas() -> None:
|
|||||||
print the antenna identifier. When you are done, press Ctrl+C to stop the script and
|
print the antenna identifier. When you are done, press Ctrl+C to stop the script and
|
||||||
get the final order.
|
get the final order.
|
||||||
"""
|
"""
|
||||||
from .utils import antenna_order
|
from ..utils import antenna_order
|
||||||
|
|
||||||
|
if not globals.is_live:
|
||||||
|
raise ValueError("This command only works with live data")
|
||||||
|
|
||||||
antenna_order.main()
|
antenna_order.main()
|
||||||
|
|
||||||
@ -32,7 +36,8 @@ def antennas() -> None:
|
|||||||
def heatmap() -> None:
|
def heatmap() -> None:
|
||||||
preprocessor = Preprocessor()
|
preprocessor = Preprocessor()
|
||||||
aoa = AoA()
|
aoa = AoA()
|
||||||
webapp_queue: "mp.Queue[AoA]" = mp.Queue(config.SAMPLE_RATE)
|
manager = mp.Manager()
|
||||||
|
webapp_queue: "mp.Queue[AoA]" = manager.Queue(config.sample_rate)
|
||||||
# Start webapp in background process
|
# Start webapp in background process
|
||||||
webapp = mp.Process(target=visualise.start, args=(webapp_queue,))
|
webapp = mp.Process(target=visualise.start, args=(webapp_queue,))
|
||||||
webapp.start()
|
webapp.start()
|
||||||
@ -45,4 +50,8 @@ def heatmap() -> None:
|
|||||||
if not webapp_queue.full():
|
if not webapp_queue.full():
|
||||||
webapp_queue.put(aoa)
|
webapp_queue.put(aoa)
|
||||||
|
|
||||||
ingest.start_processing(callback)
|
globals.csi_producer(csi_callback=callback)
|
||||||
|
logger.info("Finished processing CSI data")
|
||||||
|
|
||||||
|
|
||||||
|
app.add_typer(file.app, name="file", help="Commands for working with CSI files")
|
||||||
28
where_fi/cli/file.py
Normal file
28
where_fi/cli/file.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import h5py
|
||||||
|
import numpy as np
|
||||||
|
import numpy.typing as npt
|
||||||
|
import typer
|
||||||
|
|
||||||
|
from . import globals
|
||||||
|
|
||||||
|
|
||||||
|
app = typer.Typer()
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def capture(output_path: Path) -> None:
|
||||||
|
"""Capture CSI data to a file"""
|
||||||
|
logger.info(f"Capturing data to {output_path}")
|
||||||
|
|
||||||
|
with h5py.File(output_path, "w") as file:
|
||||||
|
|
||||||
|
def callback(antenna_data: npt.NDArray[np.complex128]) -> None:
|
||||||
|
logger.info(f"Got final CSI data with shape {antenna_data.shape}")
|
||||||
|
file.create_dataset(datetime.now().isoformat(), data=antenna_data)
|
||||||
|
|
||||||
|
globals.csi_producer(csi_callback=callback)
|
||||||
18
where_fi/cli/globals.py
Normal file
18
where_fi/cli/globals.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from functools import partial
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .. import collection
|
||||||
|
from ..collection import file, ingest
|
||||||
|
|
||||||
|
csi_producer: collection.CSIProducer = collection.noop
|
||||||
|
is_live = True
|
||||||
|
|
||||||
|
|
||||||
|
def main(from_file: Path | None = None) -> None:
|
||||||
|
global csi_producer, is_live
|
||||||
|
if from_file:
|
||||||
|
csi_producer = partial(file.start_processing, file_path=from_file)
|
||||||
|
is_live = False
|
||||||
|
else:
|
||||||
|
csi_producer = ingest.start_processing
|
||||||
|
is_live = True
|
||||||
9
where_fi/collection/__init__.py
Normal file
9
where_fi/collection/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from . import file, ingest
|
||||||
|
from .protocols import CSICallback, CSIProducer
|
||||||
|
|
||||||
|
|
||||||
|
def noop(csi_callback: CSICallback | None = None) -> None:
|
||||||
|
del csi_callback
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["file", "ingest", "noop", "CSIProducer", "CSICallback"]
|
||||||
39
where_fi/collection/file.py
Normal file
39
where_fi/collection/file.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import h5py
|
||||||
|
|
||||||
|
from . import protocols
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def start_processing(
|
||||||
|
file_path: Path,
|
||||||
|
csi_callback: protocols.CSICallback | None = None,
|
||||||
|
) -> None:
|
||||||
|
logger.info(f"Replaying CSI data from {file_path}")
|
||||||
|
with h5py.File(file_path, "r") as file:
|
||||||
|
try:
|
||||||
|
for key in file:
|
||||||
|
datetime.fromisoformat(key)
|
||||||
|
except ValueError as e:
|
||||||
|
logger.exception(
|
||||||
|
"The file provided was not generated using this software", e
|
||||||
|
)
|
||||||
|
|
||||||
|
start_time = datetime.fromisoformat(list(file.keys())[0])
|
||||||
|
target_offset = datetime.now() - start_time
|
||||||
|
for key in file:
|
||||||
|
logger.debug(f"Sending data from {key} at {datetime.now().isoformat()}")
|
||||||
|
csi_callback(file[key][:])
|
||||||
|
curr_time_virtual = datetime.fromisoformat(key)
|
||||||
|
new_offset = datetime.now() - curr_time_virtual
|
||||||
|
logger.debug(f"New offset {new_offset}, target is {target_offset}")
|
||||||
|
if new_offset > target_offset + timedelta(seconds=1):
|
||||||
|
logger.warning(
|
||||||
|
f"Data is {new_offset - target_offset} behind, lagging behind..."
|
||||||
|
)
|
||||||
|
time.sleep(max(0, (target_offset - new_offset).total_seconds()))
|
||||||
@ -6,16 +6,15 @@ import subprocess
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Callable, NamedTuple, NoReturn
|
from typing import Callable, NamedTuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
|
||||||
|
|
||||||
from .. import config
|
from ..config import config
|
||||||
from .csi_frame import CSI
|
from .csi_frame import CSI
|
||||||
|
from .protocols import CSICallback
|
||||||
|
|
||||||
Host = tuple[str, int]
|
Host = tuple[str, int]
|
||||||
CSICallback = Callable[[npt.NDArray[np.complex128]], None]
|
|
||||||
|
|
||||||
|
|
||||||
class FeitHost:
|
class FeitHost:
|
||||||
@ -25,6 +24,7 @@ class FeitHost:
|
|||||||
self.logger = logging.getLogger(
|
self.logger = logging.getLogger(
|
||||||
f"{__name__}.{self.__class__.__name__}-{self.host[0]}"
|
f"{__name__}.{self.__class__.__name__}-{self.host[0]}"
|
||||||
)
|
)
|
||||||
|
self.active = True
|
||||||
self.checker = threading.Thread(target=self.check_continuous)
|
self.checker = threading.Thread(target=self.check_continuous)
|
||||||
self.checker.start()
|
self.checker.start()
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class FeitHost:
|
|||||||
self.server.send(self.command.encode())
|
self.server.send(self.command.encode())
|
||||||
self.logger.info(f"Connected to {self.host}")
|
self.logger.info(f"Connected to {self.host}")
|
||||||
|
|
||||||
def check_continuous(self) -> NoReturn:
|
def check_continuous(self) -> None:
|
||||||
"""
|
"""
|
||||||
Repeatedly check if the FeitCSI service is running
|
Repeatedly check if the FeitCSI service is running
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class FeitHost:
|
|||||||
and logs continuously if the service is running.
|
and logs continuously if the service is running.
|
||||||
"""
|
"""
|
||||||
last_status = False
|
last_status = False
|
||||||
while True:
|
while self.active:
|
||||||
if not self.check_connection():
|
if not self.check_connection():
|
||||||
self.logger.error(f"FeitCSI is not running on {self.host[0]}")
|
self.logger.error(f"FeitCSI is not running on {self.host[0]}")
|
||||||
last_status = False
|
last_status = False
|
||||||
@ -62,34 +62,35 @@ class FeitHost:
|
|||||||
self.connect()
|
self.connect()
|
||||||
last_status = True
|
last_status = True
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
self.logger.info("Stopping host checker")
|
||||||
|
|
||||||
|
|
||||||
class FeitTransmitter(FeitHost):
|
class FeitTransmitter(FeitHost):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
command = (
|
command = (
|
||||||
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
|
f"feitcsi --frequency {config.central_freq} "
|
||||||
f"--channel-width {config.CHANNEL_WIDTH} "
|
f"--channel-width {config.channel_width} "
|
||||||
f"--format {config.FRAME_FORMAT} "
|
f"--format {config.frame_format} "
|
||||||
f"--mode inject -s 1 --verbose "
|
f"--mode inject -s 1 --verbose "
|
||||||
f"--inject-delay {1_000_000 // config.SAMPLE_RATE}"
|
f"--inject-delay {1_000_000 // config.sample_rate}"
|
||||||
)
|
)
|
||||||
super().__init__(config.INJECT_HOST, command)
|
super().__init__(config.transmit_host, command)
|
||||||
|
|
||||||
|
|
||||||
class FeitReceiver(FeitHost):
|
class FeitReceiver(FeitHost):
|
||||||
def __init__(self, host: Host) -> None:
|
def __init__(self, host: Host) -> None:
|
||||||
command = (
|
command = (
|
||||||
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
|
f"feitcsi --frequency {config.central_freq} "
|
||||||
f"--channel-width {config.CHANNEL_WIDTH} "
|
f"--channel-width {config.channel_width} "
|
||||||
f"--format {config.FRAME_FORMAT} "
|
f"--format {config.frame_format} "
|
||||||
f"--mode measure"
|
f"--mode measure"
|
||||||
)
|
)
|
||||||
super().__init__(host, command)
|
super().__init__(host, command)
|
||||||
|
|
||||||
def listen(self, queue: "mp.Queue[CSI]") -> NoReturn:
|
def listen(self, queue: "mp.Queue[CSI]") -> None:
|
||||||
prev_time = datetime.now()
|
prev_time = datetime.now()
|
||||||
self.logger.info("Listening for CSI data")
|
self.logger.info("Listening for CSI data")
|
||||||
while True:
|
while self.active:
|
||||||
while not hasattr(self, "server"):
|
while not hasattr(self, "server"):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
# This is the max size of a UDP packet. The size of the actual CSI
|
# This is the max size of a UDP packet. The size of the actual CSI
|
||||||
@ -105,6 +106,7 @@ class FeitReceiver(FeitHost):
|
|||||||
queue.put(csidata)
|
queue.put(csidata)
|
||||||
except struct.error:
|
except struct.error:
|
||||||
self.logger.error("Failed to parse CSI data")
|
self.logger.error("Failed to parse CSI data")
|
||||||
|
self.logger.info("Stopping CSI receiver")
|
||||||
|
|
||||||
|
|
||||||
class CSIProcessor:
|
class CSIProcessor:
|
||||||
@ -117,6 +119,7 @@ class CSIProcessor:
|
|||||||
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
||||||
self.last_processed = datetime.now()
|
self.last_processed = datetime.now()
|
||||||
self.connections = receiver_connections
|
self.connections = receiver_connections
|
||||||
|
self.active = True
|
||||||
|
|
||||||
def add_data(self, host: Host, data: CSI) -> None:
|
def add_data(self, host: Host, data: CSI) -> None:
|
||||||
if (
|
if (
|
||||||
@ -131,7 +134,7 @@ class CSIProcessor:
|
|||||||
self.pending_data[host] = (datetime.now(), data)
|
self.pending_data[host] = (datetime.now(), data)
|
||||||
|
|
||||||
def is_ready(self) -> bool:
|
def is_ready(self) -> bool:
|
||||||
for host in config.RECEIVE_HOSTS:
|
for host in config.receive_hosts:
|
||||||
if (
|
if (
|
||||||
host not in self.pending_data
|
host not in self.pending_data
|
||||||
or self.pending_data[host][0] <= self.last_processed
|
or self.pending_data[host][0] <= self.last_processed
|
||||||
@ -151,7 +154,7 @@ class CSIProcessor:
|
|||||||
)
|
)
|
||||||
antenna_data = [
|
antenna_data = [
|
||||||
np.expand_dims(self.pending_data[ip][1].matrix[:, antenna], axis=2)
|
np.expand_dims(self.pending_data[ip][1].matrix[:, antenna], axis=2)
|
||||||
for ip, antenna in config.ANTENNA_ORDER
|
for ip, antenna in config.antennas.order
|
||||||
]
|
]
|
||||||
|
|
||||||
# We have data from all servers
|
# We have data from all servers
|
||||||
@ -164,16 +167,19 @@ class CSIProcessor:
|
|||||||
self,
|
self,
|
||||||
callback: CSICallback | None = None,
|
callback: CSICallback | None = None,
|
||||||
pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None,
|
pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None,
|
||||||
) -> NoReturn:
|
) -> None:
|
||||||
while True:
|
try:
|
||||||
for ip, queue in self.connections.items():
|
while self.active:
|
||||||
while not queue.empty():
|
for ip, queue in self.connections.items():
|
||||||
self.add_data(ip, queue.get())
|
while not queue.empty():
|
||||||
if self.is_ready():
|
self.add_data(ip, queue.get())
|
||||||
self.process_data(callback, pre_merge_callback=pre_merge_callback)
|
if self.is_ready():
|
||||||
else:
|
self.process_data(callback, pre_merge_callback=pre_merge_callback)
|
||||||
self.logger.debug("Not all data is ready")
|
else:
|
||||||
time.sleep(0.0005)
|
self.logger.debug("Not all data is ready")
|
||||||
|
time.sleep(0.0005)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.logger.info("Exiting CSI processing")
|
||||||
|
|
||||||
|
|
||||||
class Receiver(NamedTuple):
|
class Receiver(NamedTuple):
|
||||||
@ -187,11 +193,11 @@ def start_processing(
|
|||||||
pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None,
|
pre_merge_callback: Callable[[dict[Host, CSI]], None] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
receivers = [
|
receivers = [
|
||||||
Receiver(ip, FeitReceiver(ip), mp.Queue(config.SAMPLE_RATE))
|
Receiver(ip, FeitReceiver(ip), mp.Queue(config.sample_rate))
|
||||||
for ip in config.RECEIVE_HOSTS
|
for ip in config.receive_hosts
|
||||||
]
|
]
|
||||||
|
|
||||||
FeitTransmitter()
|
transmitter = FeitTransmitter()
|
||||||
|
|
||||||
# Start injecting CSI frames
|
# Start injecting CSI frames
|
||||||
processor = CSIProcessor({r.ip: r.queue for r in receivers})
|
processor = CSIProcessor({r.ip: r.queue for r in receivers})
|
||||||
@ -208,6 +214,11 @@ def start_processing(
|
|||||||
)
|
)
|
||||||
processing_thread.start()
|
processing_thread.start()
|
||||||
try:
|
try:
|
||||||
processing_thread.join()
|
while True:
|
||||||
|
time.sleep(100)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
for r in receivers:
|
||||||
|
r.receiver.active = False
|
||||||
|
transmitter.active = False
|
||||||
|
processor.active = False
|
||||||
return
|
return
|
||||||
10
where_fi/collection/protocols.py
Normal file
10
where_fi/collection/protocols.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from typing import Callable, Protocol
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import numpy.typing as npt
|
||||||
|
|
||||||
|
CSICallback = Callable[[npt.NDArray[np.complex128]], None]
|
||||||
|
|
||||||
|
|
||||||
|
class CSIProducer(Protocol):
|
||||||
|
def __call__(self, csi_callback: CSICallback | None = None) -> None: ...
|
||||||
24
where_fi/config/__init__.py
Normal file
24
where_fi/config/__init__.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pydantic
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = yaml.safe_load(open("config.yaml"))
|
||||||
|
except FileNotFoundError:
|
||||||
|
logger.error(
|
||||||
|
"No config.yaml file found. Make sure to copy the "
|
||||||
|
"config.example.yaml file to config.yaml"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = models.Config(**config)
|
||||||
|
except pydantic.ValidationError as e:
|
||||||
|
logger.error(f"Invalid config.yaml file: {e}")
|
||||||
|
sys.exit(1)
|
||||||
82
where_fi/config/models.py
Normal file
82
where_fi/config/models.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
from typing import Literal, Self
|
||||||
|
|
||||||
|
from pydantic import BaseModel, model_validator
|
||||||
|
|
||||||
|
Host = tuple[str, int]
|
||||||
|
|
||||||
|
|
||||||
|
class Preprocessing(BaseModel):
|
||||||
|
moving_average_alpha: float
|
||||||
|
|
||||||
|
class Bandpass(BaseModel):
|
||||||
|
lowcut: int
|
||||||
|
highcut: int
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bounds(self) -> tuple[int, int]:
|
||||||
|
return (self.lowcut, self.highcut)
|
||||||
|
|
||||||
|
bandpass: Bandpass
|
||||||
|
|
||||||
|
|
||||||
|
class MUSIC(BaseModel):
|
||||||
|
eigval_threshold: int
|
||||||
|
window_size: int
|
||||||
|
|
||||||
|
|
||||||
|
class Antennas(BaseModel):
|
||||||
|
spacing: float
|
||||||
|
order: list[tuple[Host, int]]
|
||||||
|
|
||||||
|
|
||||||
|
class Config(BaseModel):
|
||||||
|
receive_hosts: list[Host]
|
||||||
|
transmit_host: Host
|
||||||
|
|
||||||
|
antennas: Antennas
|
||||||
|
|
||||||
|
sample_rate: int
|
||||||
|
central_freq: int
|
||||||
|
channel_width: Literal[20, 40, 80, 160]
|
||||||
|
frame_format: Literal["NOHT", "HT", "VHT", "HESU"]
|
||||||
|
|
||||||
|
preprocessing: Preprocessing
|
||||||
|
music: MUSIC
|
||||||
|
|
||||||
|
@property
|
||||||
|
def central_freq_hz(self) -> int:
|
||||||
|
return self.central_freq * 1_000_000
|
||||||
|
|
||||||
|
@property
|
||||||
|
def band(self) -> Literal["2.4", "5", "6"]:
|
||||||
|
if self.central_freq in range(2412, 2484):
|
||||||
|
return "2.4"
|
||||||
|
if self.central_freq in range(5180, 5320):
|
||||||
|
return "5"
|
||||||
|
if self.central_freq in range(5955, 7115):
|
||||||
|
return "6"
|
||||||
|
raise ValueError(f"{self.central_freq} is not a valid Wi-Fi channel")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delta_f(self) -> int:
|
||||||
|
if self.frame_format == "HESU":
|
||||||
|
return 78_125
|
||||||
|
return 312_500
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def channels(self) -> Self:
|
||||||
|
band_start = 2412 if self.band == "2.4" else 5180 if self.band == "5" else 5955
|
||||||
|
if self.band == "2.4" and self.channel_width not in [20, 40]:
|
||||||
|
raise ValueError(
|
||||||
|
f"2.4GHz channel {self.central_freq} must "
|
||||||
|
"have a channel width of 20 or 40 MHz"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (self.band == "2.4" and (self.central_freq - band_start) % 5 != 0) or (
|
||||||
|
self.band in ["5", "6"]
|
||||||
|
and ((self.central_freq - band_start) % self.channel_width != 0)
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
f"Central frequency {self.central_freq} must be a channel as in https://en.wikipedia.org/wiki/List_of_WLAN_channels"
|
||||||
|
)
|
||||||
|
return self
|
||||||
@ -4,7 +4,7 @@ from datetime import datetime
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
|
|
||||||
from .. import config
|
from ..config import config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class AoA:
|
|||||||
self.historical_autocorr, np.expand_dims(auto_corr, 0), axis=0
|
self.historical_autocorr, np.expand_dims(auto_corr, 0), axis=0
|
||||||
)
|
)
|
||||||
|
|
||||||
WINDOW_SIZE = config.AOA_SLIDING_WINDOW_SIZE
|
WINDOW_SIZE = config.music.window_size
|
||||||
if self.historical_autocorr.shape[0] > WINDOW_SIZE:
|
if self.historical_autocorr.shape[0] > WINDOW_SIZE:
|
||||||
self.historical_autocorr = self.historical_autocorr[-WINDOW_SIZE:]
|
self.historical_autocorr = self.historical_autocorr[-WINDOW_SIZE:]
|
||||||
|
|
||||||
@ -70,24 +70,19 @@ class AoA:
|
|||||||
# The smallest eigenvectors span the noise subspace,
|
# The smallest eigenvectors span the noise subspace,
|
||||||
# and the largest span the signal subspace.
|
# and the largest span the signal subspace.
|
||||||
eigvals, eigvecs = np.linalg.eigh(R)
|
eigvals, eigvecs = np.linalg.eigh(R)
|
||||||
self.E_n = eigvecs[:, np.abs(eigvals) < config.EIGVAL_THRESHOLD]
|
self.E_n = eigvecs[:, np.abs(eigvals) < config.music.eigval_threshold]
|
||||||
|
|
||||||
omega_base = np.exp(-2j * np.pi * config.DELTA_F)
|
|
||||||
phi_base = np.exp(
|
|
||||||
2j * np.pi * config.CENTRAL_FREQUENCY_HZ * config.ANTENNA_SPACING / config.C
|
|
||||||
)
|
|
||||||
|
|
||||||
def steering_vector(
|
def steering_vector(
|
||||||
self, theta: float, tof: float
|
self, theta: float, tof: float
|
||||||
) -> npt.NDArray[np.complexfloating]:
|
) -> npt.NDArray[np.complexfloating]:
|
||||||
omega_t: npt.NDArray[np.complex128] = np.exp(-2j * np.pi * config.DELTA_F * tof)
|
omega_t: npt.NDArray[np.complex128] = np.exp(-2j * np.pi * config.delta_f * tof)
|
||||||
phi_theta: npt.NDArray[np.complex128] = np.exp(
|
phi_theta: npt.NDArray[np.complex128] = np.exp(
|
||||||
2j
|
2j
|
||||||
* np.pi
|
* np.pi
|
||||||
* config.CENTRAL_FREQUENCY_HZ
|
* config.central_freq_hz
|
||||||
* config.ANTENNA_SPACING
|
* config.antennas.spacing
|
||||||
* (1 - np.cos(theta))
|
* (1 - np.cos(theta))
|
||||||
/ config.C
|
/ 299_792_458
|
||||||
)
|
)
|
||||||
|
|
||||||
omega_t = np.expand_dims(omega_t, axis=-1)
|
omega_t = np.expand_dims(omega_t, axis=-1)
|
||||||
@ -129,8 +124,6 @@ def test_steering_vector() -> None:
|
|||||||
aoa = AoA()
|
aoa = AoA()
|
||||||
aoa.N_subcarriers = 10
|
aoa.N_subcarriers = 10
|
||||||
aoa.N_rx = 2
|
aoa.N_rx = 2
|
||||||
print(aoa.omega_base)
|
|
||||||
print(aoa.phi_base)
|
|
||||||
tau = 1
|
tau = 1
|
||||||
theta = 0
|
theta = 0
|
||||||
print(aoa.steering_vector(theta, tau))
|
print(aoa.steering_vector(theta, tau))
|
||||||
@ -5,7 +5,7 @@ import numpy as np
|
|||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
from scipy.signal import butter, correlate, sosfilt, sosfilt_zi
|
from scipy.signal import butter, correlate, sosfilt, sosfilt_zi
|
||||||
|
|
||||||
from .. import config
|
from ..config import config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
@ -20,11 +20,8 @@ class Preprocessor:
|
|||||||
self.long_term_avg = np.zeros((1,), dtype=np.complex128)
|
self.long_term_avg = np.zeros((1,), dtype=np.complex128)
|
||||||
self.filter = butter(
|
self.filter = butter(
|
||||||
5,
|
5,
|
||||||
[
|
config.preprocessing.bandpass.bounds,
|
||||||
config.PREPROCESSING_BANDPASS_LOW_CUTOFF,
|
fs=config.sample_rate,
|
||||||
config.PREPROCESSING_BANDPASS_HIGH_CUTOFF,
|
|
||||||
],
|
|
||||||
fs=config.SAMPLE_RATE,
|
|
||||||
btype="band",
|
btype="band",
|
||||||
output="sos",
|
output="sos",
|
||||||
)
|
)
|
||||||
@ -52,8 +49,8 @@ class Preprocessor:
|
|||||||
self.long_term_avg = np.zeros(h_hat.shape, dtype=np.complex128)
|
self.long_term_avg = np.zeros(h_hat.shape, dtype=np.complex128)
|
||||||
|
|
||||||
self.long_term_avg = (
|
self.long_term_avg = (
|
||||||
self.long_term_avg * (1 - config.PREPROCESSING_LONG_TERM_ALPHA)
|
self.long_term_avg * (1 - config.preprocessing.moving_average_alpha)
|
||||||
+ h_hat * config.PREPROCESSING_LONG_TERM_ALPHA
|
+ h_hat * config.preprocessing.moving_average_alpha
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove long term average, to remove static paths
|
# Remove long term average, to remove static paths
|
||||||
@ -28,12 +28,12 @@ def callback(antenna_data: dict[ingest.Host, ingest.CSI]) -> None:
|
|||||||
)
|
)
|
||||||
for host, csi in antenna_data.items():
|
for host, csi in antenna_data.items():
|
||||||
antenna_average[(host, 0)] = (
|
antenna_average[(host, 0)] = (
|
||||||
antenna_average.get((host, 0), csi.header.rssi1) * 0.9
|
antenna_average.get((host, 0), csi.header.rssi1) * 0.99
|
||||||
+ csi.header.rssi1 * 0.1
|
+ csi.header.rssi1 * 0.01
|
||||||
)
|
)
|
||||||
antenna_average[(host, 1)] = (
|
antenna_average[(host, 1)] = (
|
||||||
antenna_average.get((host, 1), csi.header.rssi2) * 0.9
|
antenna_average.get((host, 1), csi.header.rssi2) * 0.99
|
||||||
+ csi.header.rssi2 * 0.1
|
+ csi.header.rssi2 * 0.01
|
||||||
)
|
)
|
||||||
if csi.header.rssi1 > antenna_average[(host, 0)] + RSSI_THRESHOLD:
|
if csi.header.rssi1 > antenna_average[(host, 0)] + RSSI_THRESHOLD:
|
||||||
unplugged.add((host, 0))
|
unplugged.add((host, 0))
|
||||||
@ -1,20 +1,20 @@
|
|||||||
from flask import Flask, render_template, Response, request
|
|
||||||
from flask_sock import Sock
|
|
||||||
import numpy as np
|
|
||||||
import numpy.typing as npt
|
|
||||||
from simple_websocket import Server
|
|
||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
import multiprocessing as mp
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
|
import multiprocessing as mp
|
||||||
from ..processing.aoa import AoA
|
import time
|
||||||
from .. import config
|
from datetime import datetime
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
import numpy.typing as npt
|
||||||
|
from flask import Flask, Response, render_template, request
|
||||||
|
from flask_sock import Sock
|
||||||
|
from simple_websocket import Server
|
||||||
|
|
||||||
|
from .. import config
|
||||||
|
from ..processing.aoa import AoA
|
||||||
|
|
||||||
matplotlib.use("agg")
|
matplotlib.use("agg")
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ aoa: AoA = AoA()
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/preprocessed")
|
@app.route("/preprocessed")
|
||||||
def preprocessed():
|
def preprocessed() -> str:
|
||||||
return render_template("preprocessed.html")
|
return render_template("preprocessed.html")
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ subscriber_settings: dict[Subscriber, tuple[int, int, int]] = {}
|
|||||||
|
|
||||||
|
|
||||||
@sock.route("/data")
|
@sock.route("/data")
|
||||||
def get_data(sock: Subscriber):
|
def get_data(sock: Subscriber) -> None:
|
||||||
while True:
|
while True:
|
||||||
msg = sock.receive()
|
msg = sock.receive()
|
||||||
if len(msg.split()) != 3:
|
if len(msg.split()) != 3:
|
||||||
@ -50,7 +50,7 @@ def get_data(sock: Subscriber):
|
|||||||
|
|
||||||
def add_data(
|
def add_data(
|
||||||
raw_data: npt.NDArray[np.complex128], new_data: npt.NDArray[np.complex128]
|
raw_data: npt.NDArray[np.complex128], new_data: npt.NDArray[np.complex128]
|
||||||
):
|
) -> None:
|
||||||
if config.VISUALISE_RAW:
|
if config.VISUALISE_RAW:
|
||||||
magn = np.abs(raw_data)
|
magn = np.abs(raw_data)
|
||||||
phase = np.angle(raw_data)
|
phase = np.angle(raw_data)
|
||||||
@ -92,7 +92,7 @@ def add_data(
|
|||||||
del subscriber_settings[subscriber]
|
del subscriber_settings[subscriber]
|
||||||
|
|
||||||
|
|
||||||
def make_heatmap(aoa: AoA, max_tof: float):
|
def make_heatmap(aoa: AoA, max_tof: float) -> io.BytesIO:
|
||||||
logger.info(f"Making heatmap with aoa of {aoa.timestamp}")
|
logger.info(f"Making heatmap with aoa of {aoa.timestamp}")
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
ax = fig.add_axes([0, 0, 1, 1], polar=True)
|
ax = fig.add_axes([0, 0, 1, 1], polar=True)
|
||||||
@ -112,7 +112,7 @@ def make_heatmap(aoa: AoA, max_tof: float):
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
def gather_aoa(max_tof: float):
|
def gather_aoa(max_tof: float) -> Generator[bytes, None, None]:
|
||||||
assert aoa_queue is not None
|
assert aoa_queue is not None
|
||||||
|
|
||||||
prev_frame = datetime.now()
|
prev_frame = datetime.now()
|
||||||
@ -130,7 +130,7 @@ def gather_aoa(max_tof: float):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/aoa_tof")
|
@app.route("/aoa_tof")
|
||||||
def aoa_tof():
|
def aoa_tof() -> Response:
|
||||||
max_tof_str = request.args.get("max_tof")
|
max_tof_str = request.args.get("max_tof")
|
||||||
try:
|
try:
|
||||||
max_tof = float(max_tof_str)
|
max_tof = float(max_tof_str)
|
||||||
@ -141,8 +141,9 @@ def aoa_tof():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def start(conn: "mp.Queue[AoA]"):
|
def start(conn: "mp.Queue[AoA]") -> None:
|
||||||
global aoa_queue
|
global app, aoa_queue
|
||||||
|
|
||||||
aoa_queue = conn
|
aoa_queue = conn
|
||||||
app.run(debug=True, use_reloader=False, host="0.0.0.0")
|
app.run(debug=True, use_reloader=False, host="0.0.0.0")
|
||||||
|
logger.info("Visualisation server shut down")
|
||||||
Loading…
Reference in New Issue
Block a user