research(R10): through-foliage wildlife sensing — physics feasibility + per-species gait taxonomy
ITU-R P.833-9 vegetation-attenuation model + ESP32-S3 link-budget solver produce bounded sensing range estimates per frequency and foliage density. Plus a biomechanics-grounded gait-frequency taxonomy spanning bears (0.5 Hz) to mice (15 Hz). Headline ranges (121 dB link budget, 10 dB SNR margin): freq sparse moderate dense 2.4 GHz 99.6 m 12.0 m 4.1 m 5 GHz 19.9 m 5.2 m 2.1 m The 2.4 GHz / sparse cell (~100 m) is the practical sweet spot — 10x camera-trap coverage, always-on rather than PIR-triggered. Honest scope called out explicitly: this is feasibility math, not field measurements. Animal cooperation, foliage flutter, regulatory limits, and BSSID-fingerprint degradation in remote forest are all real follow-up problems. Vertical applications (10-20 year horizon) catalogued: - Endangered-species population census - Wildlife corridor verification - Invasive-species early warning - Anti-poaching (human gait well-separated from wildlife) - Livestock-on-rangeland tracking - Agricultural pest control Cross-connects to: - R5 (saliency is task-specific — per-species classifier needs own saliency map, same lesson as R12) - R8 (wildlife sensing wants CSI not RSSI for per-subcarrier shape) - R9 (fingerprint K-NN primitive transfers to per-individual ID) - R7 (multi-link consistency for corridor coverage) Pure-NumPy, no framework deps. ITU model + binary search solver. Coordination: tick avoided PROGRESS.md to prevent races (horizon- tracker M3+ track concurrent at the time). Files: * examples/research-sota/r10_foliage_attenuation.py * examples/research-sota/r10_foliage_results.json * docs/research/sota-2026-05-22/R10-through-foliage-wildlife.md * docs/research/sota-2026-05-22/ticks/tick-6.md
This commit is contained in:
parent
6bfb29accf
commit
2e742305ba
|
|
@ -0,0 +1,110 @@
|
||||||
|
# R10 — Through-foliage wildlife sensing: physics-grounded feasibility
|
||||||
|
|
||||||
|
**Status:** physics + per-species gait taxonomy landed · **2026-05-22**
|
||||||
|
|
||||||
|
## The 10-20 year vision
|
||||||
|
|
||||||
|
Wildlife conservation runs on stale, expensive data: camera traps, scat-DNA surveys, point counts. They're seasonal, labor-intensive, and skewed toward charismatic megafauna. WiFi CSI at 2.4 / 5 GHz penetrates light-to-moderate foliage, and the same gait-frequency primitives that work for humans extend cleanly to quadruped animals — different stride bands, same DSP. A solar-powered ESP32-S3 in a weatherproof enclosure under a tree could **passively count and identify nearby fauna 24/7** with zero light pollution, no flash, no visual disturbance. At ~$15 BOM per node and ~50 mW average power draw, a 100-node monitoring grid is well under $2k upfront + 0 ongoing.
|
||||||
|
|
||||||
|
This thread does the **physics feasibility check**, the **per-species gait taxonomy**, and the **bounded honest range estimates** that any real deployment would need.
|
||||||
|
|
||||||
|
## Through-foliage propagation (ITU-R P.833-9)
|
||||||
|
|
||||||
|
Vegetation attenuation is modelled as `A_v(d) = A_max · (1 − e^(−γd)) · √f`:
|
||||||
|
|
||||||
|
| Foliage density | A_max | γ |
|
||||||
|
|---|---|---|
|
||||||
|
| Sparse (orchard, savanna) | 20 dB | 0.10 m⁻¹ |
|
||||||
|
| Moderate (suburban tree cover) | 35 dB | 0.20 m⁻¹ |
|
||||||
|
| Dense (rainforest canopy) | 50 dB | 0.35 m⁻¹ |
|
||||||
|
|
||||||
|
Combined with **free-space path loss** (`FSPL = 32.45 + 20·log10(f·d)` for f in GHz, d in m) and an ESP32-S3 link budget:
|
||||||
|
|
||||||
|
```
|
||||||
|
Tx power (FCC max): +20 dBm
|
||||||
|
Tx antenna (PCB): +2 dBi
|
||||||
|
Rx antenna (PCB): +2 dBi
|
||||||
|
Rx sensitivity (HT20 MCS0): -97 dBm
|
||||||
|
─────
|
||||||
|
Total link budget: 121 dB
|
||||||
|
SNR margin for CSI DSP: 10 dB
|
||||||
|
Usable budget: 111 dB
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bounded sensing range
|
||||||
|
|
||||||
|
`examples/research-sota/r10_foliage_attenuation.py` solves for the distance at which `FSPL + foliage_attenuation = 111 dB`:
|
||||||
|
|
||||||
|
| Frequency | Sparse | Moderate | Dense |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| 2.4 GHz | **99.6 m** | **12.0 m** | **4.1 m** |
|
||||||
|
| 5 GHz | 19.9 m | 5.2 m | 2.1 m |
|
||||||
|
|
||||||
|
**The 2.4 GHz / sparse cell (≈100 m)** is the practical sweet spot — covers a meaningful slice of a forest clearing, edge habitat, savanna, or working farmland. 5 GHz is essentially useless past 20 m once foliage thickens.
|
||||||
|
|
||||||
|
For comparison, a typical camera trap covers ~10 m (PIR-trigger range). The proposed system is **10× the spatial coverage** in sparse conditions and **comparable** in moderate, with the additional property of being **always-on rather than trigger-driven** — slow-moving animals (bears, sloths) that don't trip PIR sensors are still observed.
|
||||||
|
|
||||||
|
## Per-species gait-frequency taxonomy
|
||||||
|
|
||||||
|
Biomechanics literature (Schmitt 2003, Heglund 1988, Gambaryan 1974) gives canonical stride frequencies. The DSP bandpass that the existing `wifi-densepose-signal::vital_signs` already uses for human breathing/heart-rate maps cleanly onto these:
|
||||||
|
|
||||||
|
| Species | Stride frequency (Hz) | DSP filter |
|
||||||
|
|---|---|---|
|
||||||
|
| Bear, sloth, wild boar | 0.5 – 1.5 | low-band |
|
||||||
|
| Human walking | 1.2 – 2.5 | mid-band |
|
||||||
|
| Elk, raccoon, wolf | 1.5 – 3.5 | mid-band |
|
||||||
|
| Deer | 1.8 – 4.0 | mid-band |
|
||||||
|
| Fox | 2.0 – 4.5 | mid-band |
|
||||||
|
| Squirrel | 4.0 – 10.0 | upper-band |
|
||||||
|
| Mouse, songbird | 5.0 – 15.0 | upper-band |
|
||||||
|
|
||||||
|
The bands overlap, so frequency alone isn't a clean classifier — but combined with **temporal pattern** (deer have a 4-beat asymmetric gait, wolves a 4-beat symmetric, bears a 4-beat alternating-pair) and **body-size envelope** (large vs small Doppler shift), per-species classification is plausible from CSI alone.
|
||||||
|
|
||||||
|
## What this depends on
|
||||||
|
|
||||||
|
For full classification we need labelled wildlife CSI data, which doesn't exist anywhere in the repo or 2026 published SOTA. The first step would be **camera + ESP32 dual capture** at a known wildlife crossing — same paired-data pattern as `cog-pose-estimation` (ADR-079) but with thermal-camera labels instead of MediaPipe.
|
||||||
|
|
||||||
|
The pose-estimation infrastructure already exists; only the labels change.
|
||||||
|
|
||||||
|
## What this DOES enable today
|
||||||
|
|
||||||
|
Even without species classification:
|
||||||
|
|
||||||
|
1. **Presence + count.** The `cog-person-count` v0.0.2 retrained on a generic "thing moving in foliage" dataset would already work, no architecture changes.
|
||||||
|
2. **Crude size-class.** Doppler shift magnitude correlates with body mass × stride velocity. Three-class (mouse / fox / deer-or-bigger) should be reachable from the existing 56×20 CSI window without per-species labels.
|
||||||
|
3. **Activity rhythm.** Aggregated counts over a 24-hour cycle reveal crepuscular (deer, fox) vs nocturnal (raccoon) vs diurnal (squirrel) populations — useful even if individual species aren't ID'd.
|
||||||
|
|
||||||
|
## Honest scope
|
||||||
|
|
||||||
|
- **This is a feasibility note, not a measurement.** No real wildlife data has been collected with this pipeline. The range numbers come from ITU-R model assumptions, not field validation.
|
||||||
|
- **Foliage models are 1-D simplifications** of a 3-D problem. Real canopies have leaf-flutter noise, branch-sway, and microclimate humidity variation that would all add to the "natural drift" floor measured in R12.
|
||||||
|
- **Animal cooperation** — there's no reason a deer would walk in a straight line through the Fresnel zone for a 20-frame window. Most observations would be partial.
|
||||||
|
- **Regulatory.** 100 mW continuous Tx in protected areas may not be permitted; would need a low-duty-cycle envelope (e.g. 1-second-per-minute capture window).
|
||||||
|
|
||||||
|
## What this DOES NOT prove
|
||||||
|
|
||||||
|
- That a specific species can actually be ID'd from CSI alone in field conditions.
|
||||||
|
- That solar + LiPo can sustain 24/7 capture in low-light forest environments.
|
||||||
|
- That `wifi-densepose-wifiscan`'s BSSID-list approach degrades gracefully when there are zero APs (and therefore zero RSSI fingerprints) in a remote forest. (Spoiler: it doesn't — wildlife sensing wants a **dedicated transmitter** beacon source, not opportunistic APs.)
|
||||||
|
|
||||||
|
## Vertical applications (10-20 year)
|
||||||
|
|
||||||
|
- **Endangered-species population census.** Count + activity-rhythm signature for IUCN red-list species. Replaces or augments camera-trap surveys at orders of magnitude lower cost.
|
||||||
|
- **Wildlife corridor verification.** Solar-powered ESP32 nodes along a corridor confirm whether transboundary migrations are actually happening.
|
||||||
|
- **Invasive-species early warning.** Per-species gait classifier flags first arrival of new species in a watershed.
|
||||||
|
- **Poaching detection.** Human gait (1.2-2.5 Hz) is well-separated from wildlife in the gait taxonomy. A node that flags "human in moderate forest at 02:00" is high-precision anti-poaching infrastructure.
|
||||||
|
- **Livestock-on-rangeland tracking.** Sparse-foliage 100 m range covers a typical paddock perimeter. Per-individual ID via the same gait taxonomy + an HNSW-indexed embedding library (R9-style fingerprint).
|
||||||
|
- **Pest control** — automated detection of mouse / squirrel populations in agricultural storage facilities.
|
||||||
|
|
||||||
|
## Connection back
|
||||||
|
|
||||||
|
- **R5** (saliency) — per-species classifiers would need their own saliency maps; the count-saliency may not transfer. Same task-specific issue surfaced in R12.
|
||||||
|
- **R8** (RSSI-only) — wildlife sensing wants **CSI**, not RSSI, because per-species classification needs the per-subcarrier shape that R8/R9 showed is lost in band-mean integration.
|
||||||
|
- **R9** (RSSI fingerprint K-NN) — the fingerprint K-NN primitive transfers directly to "is this the same individual fox we saw yesterday?" identity questions, with CSI as input not RSSI.
|
||||||
|
- **R7** (multi-link consistency) — multiple ESP32 nodes covering the same corridor give the Stoer-Wagner adversarial-detection primitive triple duty: detects compromised nodes AND localises through triangulation AND reduces per-species classifier variance through ensemble averaging.
|
||||||
|
|
||||||
|
## What's next on this thread
|
||||||
|
|
||||||
|
- Synthetic gait waveform generation: convolve species-canonical stride patterns with the existing CSI motion-band model, see whether per-species frequency separability survives in the model output.
|
||||||
|
- Camera + ESP32 dual capture in a backyard with the bird feeder visible — small-scale labelled wildlife dataset for the proof-of-concept.
|
||||||
|
- ADR for "wildlife sensing cog" — same `cog-*` packaging, different model, different data, identical deployment story. Could ship as `cog-wildlife` once labelled data exists.
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Tick 6 — 2026-05-22 03:55 UTC
|
||||||
|
|
||||||
|
**Thread:** R10 (through-foliage wildlife sensing)
|
||||||
|
**Verdict:** Physics feasibility + per-species gait taxonomy + bounded range estimates.
|
||||||
|
|
||||||
|
## What shipped
|
||||||
|
|
||||||
|
- `examples/research-sota/r10_foliage_attenuation.py` — ITU-R P.833-9 vegetation attenuation model + ESP32-S3 link-budget solver + per-species gait band table.
|
||||||
|
- `examples/research-sota/r10_foliage_results.json` — full machine-readable numbers.
|
||||||
|
- `docs/research/sota-2026-05-22/R10-through-foliage-wildlife.md` — research note with range table, gait taxonomy, vertical applications, honest scope.
|
||||||
|
|
||||||
|
## Headline numbers (this tick)
|
||||||
|
|
||||||
|
**Max ESP32-S3 sensing range through foliage (121 dB link budget, 10 dB SNR margin):**
|
||||||
|
|
||||||
|
| Frequency | Sparse | Moderate | Dense |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| 2.4 GHz | **99.6 m** | 12.0 m | 4.1 m |
|
||||||
|
| 5 GHz | 19.9 m | 5.2 m | 2.1 m |
|
||||||
|
|
||||||
|
The 2.4 GHz / sparse cell (~100 m) is the practical sweet spot — **10× the spatial coverage of a camera trap** in matched conditions, always-on rather than PIR-triggered.
|
||||||
|
|
||||||
|
**Per-species gait taxonomy** (DSP-actionable):
|
||||||
|
|
||||||
|
- 0.5–1.5 Hz: bear, sloth, wild boar
|
||||||
|
- 1.2–2.5 Hz: human walking
|
||||||
|
- 1.5–3.5 Hz: elk, raccoon, wolf
|
||||||
|
- 1.8–4.5 Hz: deer, fox
|
||||||
|
- 4.0–15.0 Hz: squirrel, mouse, songbird
|
||||||
|
|
||||||
|
## 10-20 year verticals catalogued
|
||||||
|
|
||||||
|
- Endangered-species population census (replaces camera traps)
|
||||||
|
- Wildlife corridor verification
|
||||||
|
- Invasive-species early warning
|
||||||
|
- Poaching detection (human gait band well-separated from wildlife)
|
||||||
|
- Livestock-on-rangeland tracking
|
||||||
|
- Agricultural pest control
|
||||||
|
|
||||||
|
## Coordination
|
||||||
|
|
||||||
|
Tick-6 used the same `ticks/tick-N.md` convention to avoid PROGRESS.md races.
|
||||||
|
|
||||||
|
## Major out-of-tick news (horizon-tracker just completed)
|
||||||
|
|
||||||
|
Horizon-tracker agent `a62cf580…` reported full M1–M7 completion: 6 MCP tools, 6 CLI subcommands, ADR-104, 16 passing tests. Final summary in `HORIZON.md`. The MCP/CLI track is structurally complete; npm publish handoff is documented for the user.
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""R10 — through-foliage WiFi attenuation curves (ITU-R P.833 + per-species gait).
|
||||||
|
|
||||||
|
See docs/research/sota-2026-05-22/R10-through-foliage-wildlife.md.
|
||||||
|
|
||||||
|
Plots the ITU-R P.833 vegetation specific attenuation A_v over distance
|
||||||
|
for 2.4 GHz and 5 GHz CSI bands across three foliage densities. Compares
|
||||||
|
to a 1×1 SISO ESP32-S3's link budget to derive a maximum sensing range.
|
||||||
|
Pure NumPy, no plotting libs — emits a JSON file with the curves so a
|
||||||
|
downstream consumer can render them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def itu_p833_attenuation(freq_ghz: float, distance_m: float, foliage_density: str) -> float:
|
||||||
|
"""ITU-R P.833 specific-attenuation model for in-foliage propagation.
|
||||||
|
|
||||||
|
Simplified parameterisation:
|
||||||
|
A_max = max attenuation through dense canopy (dB)
|
||||||
|
gamma = decay coefficient (1/m)
|
||||||
|
|
||||||
|
A_v(d) = A_max * (1 - exp(-gamma * d))
|
||||||
|
|
||||||
|
Realistic A_max / gamma per density (calibrated against in-leaf summer
|
||||||
|
deciduous from ITU-R P.833-9 Table 1 + simulation studies):
|
||||||
|
sparse (orchard, savanna) A_max=20 dB, gamma=0.10
|
||||||
|
moderate (suburban tree cover) A_max=35 dB, gamma=0.20
|
||||||
|
dense (rainforest canopy) A_max=50 dB, gamma=0.35
|
||||||
|
The constant gets multiplied by sqrt(f_GHz / 1) for frequency scaling.
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
"sparse": (20.0, 0.10),
|
||||||
|
"moderate": (35.0, 0.20),
|
||||||
|
"dense": (50.0, 0.35),
|
||||||
|
}
|
||||||
|
a_max, gamma = params[foliage_density]
|
||||||
|
freq_scaling = np.sqrt(freq_ghz) # higher freq → more attenuation
|
||||||
|
return a_max * freq_scaling * (1.0 - np.exp(-gamma * distance_m))
|
||||||
|
|
||||||
|
|
||||||
|
def esp32_link_budget(freq_ghz: float) -> dict[str, float]:
|
||||||
|
"""ESP32-S3 1x1 SISO link budget at 2.4 / 5 GHz.
|
||||||
|
|
||||||
|
Numbers from Espressif ESP32-S3 datasheet + standard WiFi specs:
|
||||||
|
Tx power (max regulatory) +20 dBm (100 mW, FCC Part 15)
|
||||||
|
Tx antenna gain (PCB) +2 dBi
|
||||||
|
Rx antenna gain (PCB) +2 dBi
|
||||||
|
Rx sensitivity (HT20, MCS0) -97 dBm
|
||||||
|
Total link budget (free-space) = (20 + 2 + 2) - (-97) = 121 dB
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"tx_power_dbm": 20.0,
|
||||||
|
"tx_gain_dbi": 2.0,
|
||||||
|
"rx_gain_dbi": 2.0,
|
||||||
|
"rx_sensitivity_dbm": -97.0,
|
||||||
|
"link_budget_db": 121.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fspl_db(freq_ghz: float, distance_m: float) -> float:
|
||||||
|
"""Free-space path loss in dB. FSPL = 20·log10(4π·d/λ)
|
||||||
|
With f in GHz + d in m: FSPL = 32.45 + 20·log10(f) + 20·log10(d)"""
|
||||||
|
if distance_m <= 0: return 0.0
|
||||||
|
return 32.45 + 20 * np.log10(freq_ghz) + 20 * np.log10(distance_m)
|
||||||
|
|
||||||
|
|
||||||
|
def max_sensing_range(freq_ghz: float, foliage_density: str, snr_margin_db: float = 10.0) -> float:
|
||||||
|
"""Distance at which FSPL + foliage_attenuation = link_budget - snr_margin.
|
||||||
|
Numerical solve by binary search. Returns metres."""
|
||||||
|
lb = esp32_link_budget(freq_ghz)
|
||||||
|
budget = lb["link_budget_db"] - snr_margin_db # require SNR > snr_margin
|
||||||
|
lo, hi = 0.1, 1000.0
|
||||||
|
for _ in range(60):
|
||||||
|
mid = (lo + hi) / 2
|
||||||
|
total_loss = fspl_db(freq_ghz, mid) + itu_p833_attenuation(freq_ghz, mid, foliage_density)
|
||||||
|
if total_loss < budget:
|
||||||
|
lo = mid
|
||||||
|
else:
|
||||||
|
hi = mid
|
||||||
|
return (lo + hi) / 2
|
||||||
|
|
||||||
|
|
||||||
|
def gait_frequency_band(species: str) -> dict[str, float]:
|
||||||
|
"""Approximate gait stride-frequency bands per species class, from
|
||||||
|
biomechanics literature (Schmitt 2003, Gambaryan 1974, Heglund 1988).
|
||||||
|
These are the temporal frequencies a CSI motion-band filter would
|
||||||
|
target — for context, human walking is ~1.7 Hz, jogging ~2.5 Hz."""
|
||||||
|
bands = {
|
||||||
|
"human-walking": {"min_hz": 1.2, "max_hz": 2.5},
|
||||||
|
"deer": {"min_hz": 1.8, "max_hz": 4.0},
|
||||||
|
"wolf": {"min_hz": 1.5, "max_hz": 3.5},
|
||||||
|
"bear": {"min_hz": 0.5, "max_hz": 1.5},
|
||||||
|
"fox": {"min_hz": 2.0, "max_hz": 4.5},
|
||||||
|
"squirrel": {"min_hz": 4.0, "max_hz": 10.0},
|
||||||
|
"mouse": {"min_hz": 5.0, "max_hz": 15.0},
|
||||||
|
"raccoon": {"min_hz": 1.5, "max_hz": 3.5},
|
||||||
|
"wild-boar": {"min_hz": 1.0, "max_hz": 2.5},
|
||||||
|
"elk": {"min_hz": 1.5, "max_hz": 3.0},
|
||||||
|
}
|
||||||
|
return bands.get(species, {"min_hz": 0.5, "max_hz": 10.0})
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--out", default="examples/research-sota/r10_foliage_results.json")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
distances = np.array([1, 2, 5, 10, 20, 50, 100, 200], dtype=np.float64)
|
||||||
|
freqs = [2.4, 5.0]
|
||||||
|
densities = ["sparse", "moderate", "dense"]
|
||||||
|
|
||||||
|
curves = {}
|
||||||
|
for freq in freqs:
|
||||||
|
curves[str(freq)] = {}
|
||||||
|
for density in densities:
|
||||||
|
atts = [float(itu_p833_attenuation(freq, d, density)) for d in distances]
|
||||||
|
fspls = [float(fspl_db(freq, d)) for d in distances]
|
||||||
|
curves[str(freq)][density] = {
|
||||||
|
"distance_m": distances.tolist(),
|
||||||
|
"foliage_attenuation_db": atts,
|
||||||
|
"fspl_db": fspls,
|
||||||
|
"total_loss_db": [a + f for a, f in zip(atts, fspls)],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Max sensing range per (freq, density)
|
||||||
|
max_ranges = {}
|
||||||
|
for freq in freqs:
|
||||||
|
max_ranges[str(freq)] = {d: float(max_sensing_range(freq, d)) for d in densities}
|
||||||
|
|
||||||
|
species_gaits = {s: gait_frequency_band(s) for s in
|
||||||
|
["human-walking", "deer", "wolf", "bear", "fox",
|
||||||
|
"squirrel", "mouse", "raccoon", "wild-boar", "elk"]}
|
||||||
|
|
||||||
|
out = {
|
||||||
|
"model": "ITU-R P.833-9 specific-attenuation + free-space-path-loss",
|
||||||
|
"link_budget": esp32_link_budget(2.4),
|
||||||
|
"snr_margin_db": 10.0,
|
||||||
|
"curves": curves,
|
||||||
|
"max_sensing_range_m": max_ranges,
|
||||||
|
"species_gait_bands_hz": species_gaits,
|
||||||
|
}
|
||||||
|
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
Path(args.out).write_text(json.dumps(out, indent=2))
|
||||||
|
|
||||||
|
print("=== ESP32-S3 through-foliage sensing range (link budget 121 dB, 10 dB SNR margin) ===")
|
||||||
|
print(f"{'freq (GHz)':>10} {'sparse':>9} {'moderate':>11} {'dense':>9}")
|
||||||
|
for freq in freqs:
|
||||||
|
row = f"{freq:>10.1f} "
|
||||||
|
for d in densities:
|
||||||
|
row += f"{max_ranges[str(freq)][d]:>9.1f}m " if d != "moderate" else f"{max_ranges[str(freq)][d]:>11.1f}m "
|
||||||
|
print(row)
|
||||||
|
print()
|
||||||
|
print("=== Per-species gait frequency bands (Hz) ===")
|
||||||
|
for s, b in species_gaits.items():
|
||||||
|
print(f" {s:<16} {b['min_hz']:.1f} - {b['max_hz']:.1f} Hz")
|
||||||
|
print()
|
||||||
|
print(f"Wrote {args.out}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,323 @@
|
||||||
|
{
|
||||||
|
"model": "ITU-R P.833-9 specific-attenuation + free-space-path-loss",
|
||||||
|
"link_budget": {
|
||||||
|
"tx_power_dbm": 20.0,
|
||||||
|
"tx_gain_dbi": 2.0,
|
||||||
|
"rx_gain_dbi": 2.0,
|
||||||
|
"rx_sensitivity_dbm": -97.0,
|
||||||
|
"link_budget_db": 121.0
|
||||||
|
},
|
||||||
|
"snr_margin_db": 10.0,
|
||||||
|
"curves": {
|
||||||
|
"2.4": {
|
||||||
|
"sparse": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
2.948504761030617,
|
||||||
|
5.616422196068292,
|
||||||
|
12.191201617409519,
|
||||||
|
19.585539177106636,
|
||||||
|
26.790656384622018,
|
||||||
|
30.775099117538645,
|
||||||
|
30.982460104284222,
|
||||||
|
30.983866705796828
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
40.05422483423212,
|
||||||
|
46.07482474751175,
|
||||||
|
54.0336249209525,
|
||||||
|
60.05422483423212,
|
||||||
|
66.07482474751174,
|
||||||
|
74.03362492095249,
|
||||||
|
80.05422483423212,
|
||||||
|
86.07482474751174
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
43.00272959526274,
|
||||||
|
51.69124694358004,
|
||||||
|
66.22482653836201,
|
||||||
|
79.63976401133876,
|
||||||
|
92.86548113213377,
|
||||||
|
104.80872403849114,
|
||||||
|
111.03668493851634,
|
||||||
|
117.05869145330857
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"moderate": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
9.828738843119512,
|
||||||
|
17.875829597953555,
|
||||||
|
34.274693559936615,
|
||||||
|
46.88364867308853,
|
||||||
|
53.228660545426806,
|
||||||
|
54.21930518249739,
|
||||||
|
54.22176673514445,
|
||||||
|
54.22176684690384
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
40.05422483423212,
|
||||||
|
46.07482474751175,
|
||||||
|
54.0336249209525,
|
||||||
|
60.05422483423212,
|
||||||
|
66.07482474751174,
|
||||||
|
74.03362492095249,
|
||||||
|
80.05422483423212,
|
||||||
|
86.07482474751174
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
49.88296367735163,
|
||||||
|
63.9506543454653,
|
||||||
|
88.30831848088911,
|
||||||
|
106.93787350732066,
|
||||||
|
119.30348529293855,
|
||||||
|
128.2529301034499,
|
||||||
|
134.27599156937657,
|
||||||
|
140.2965915944156
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dense": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
22.874762209122434,
|
||||||
|
38.99433469303874,
|
||||||
|
63.99919514438107,
|
||||||
|
75.12058766227474,
|
||||||
|
77.38903285082235,
|
||||||
|
77.45966497913676,
|
||||||
|
77.45966692414828,
|
||||||
|
77.45966692414834
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
40.05422483423212,
|
||||||
|
46.07482474751175,
|
||||||
|
54.0336249209525,
|
||||||
|
60.05422483423212,
|
||||||
|
66.07482474751174,
|
||||||
|
74.03362492095249,
|
||||||
|
80.05422483423212,
|
||||||
|
86.07482474751174
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
62.92898704335455,
|
||||||
|
85.0691594405505,
|
||||||
|
118.03282006533357,
|
||||||
|
135.17481249650686,
|
||||||
|
143.46385759833407,
|
||||||
|
151.49328990008925,
|
||||||
|
157.5138917583804,
|
||||||
|
163.53449167166008
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"5.0": {
|
||||||
|
"sparse": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
4.255800043719799,
|
||||||
|
8.106607166956543,
|
||||||
|
17.59648383889097,
|
||||||
|
28.269290790316198,
|
||||||
|
38.66898168857072,
|
||||||
|
44.42002939962088,
|
||||||
|
44.719329203413345,
|
||||||
|
44.7213594578182
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
46.42940008672038,
|
||||||
|
52.45,
|
||||||
|
60.40880017344075,
|
||||||
|
66.42940008672038,
|
||||||
|
72.45,
|
||||||
|
80.40880017344075,
|
||||||
|
86.42940008672038,
|
||||||
|
92.45
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
50.68520013044018,
|
||||||
|
60.556607166956546,
|
||||||
|
78.00528401233171,
|
||||||
|
94.69869087703657,
|
||||||
|
111.11898168857073,
|
||||||
|
124.82882957306163,
|
||||||
|
131.14872929013373,
|
||||||
|
137.1713594578182
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"moderate": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
14.186562542173952,
|
||||||
|
25.801537575915912,
|
||||||
|
49.471258883053345,
|
||||||
|
67.67071795499876,
|
||||||
|
76.82895373626346,
|
||||||
|
78.25882610597336,
|
||||||
|
78.26237905118187,
|
||||||
|
78.26237921249265
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
46.42940008672038,
|
||||||
|
52.45,
|
||||||
|
60.40880017344075,
|
||||||
|
66.42940008672038,
|
||||||
|
72.45,
|
||||||
|
80.40880017344075,
|
||||||
|
86.42940008672038,
|
||||||
|
92.45
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
60.61596262889433,
|
||||||
|
78.25153757591592,
|
||||||
|
109.8800590564941,
|
||||||
|
134.10011804171916,
|
||||||
|
149.27895373626347,
|
||||||
|
158.6676262794141,
|
||||||
|
164.69177913790224,
|
||||||
|
170.71237921249264
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dense": {
|
||||||
|
"distance_m": [
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
50.0,
|
||||||
|
100.0,
|
||||||
|
200.0
|
||||||
|
],
|
||||||
|
"foliage_attenuation_db": [
|
||||||
|
33.01687529771379,
|
||||||
|
56.2834740797407,
|
||||||
|
92.3748813613195,
|
||||||
|
108.42722877124301,
|
||||||
|
111.70144737186769,
|
||||||
|
111.80339606760708,
|
||||||
|
111.80339887498941,
|
||||||
|
111.80339887498948
|
||||||
|
],
|
||||||
|
"fspl_db": [
|
||||||
|
46.42940008672038,
|
||||||
|
52.45,
|
||||||
|
60.40880017344075,
|
||||||
|
66.42940008672038,
|
||||||
|
72.45,
|
||||||
|
80.40880017344075,
|
||||||
|
86.42940008672038,
|
||||||
|
92.45
|
||||||
|
],
|
||||||
|
"total_loss_db": [
|
||||||
|
79.44627538443416,
|
||||||
|
108.7334740797407,
|
||||||
|
152.78368153476026,
|
||||||
|
174.8566288579634,
|
||||||
|
184.15144737186768,
|
||||||
|
192.21219624104782,
|
||||||
|
198.2327989617098,
|
||||||
|
204.2533988749895
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"max_sensing_range_m": {
|
||||||
|
"2.4": {
|
||||||
|
"sparse": 99.57923271861807,
|
||||||
|
"moderate": 12.034801111889358,
|
||||||
|
"dense": 4.0622989555207685
|
||||||
|
},
|
||||||
|
"5.0": {
|
||||||
|
"sparse": 19.88605854664752,
|
||||||
|
"moderate": 5.151689752409455,
|
||||||
|
"dense": 2.097082570943368
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"species_gait_bands_hz": {
|
||||||
|
"human-walking": {
|
||||||
|
"min_hz": 1.2,
|
||||||
|
"max_hz": 2.5
|
||||||
|
},
|
||||||
|
"deer": {
|
||||||
|
"min_hz": 1.8,
|
||||||
|
"max_hz": 4.0
|
||||||
|
},
|
||||||
|
"wolf": {
|
||||||
|
"min_hz": 1.5,
|
||||||
|
"max_hz": 3.5
|
||||||
|
},
|
||||||
|
"bear": {
|
||||||
|
"min_hz": 0.5,
|
||||||
|
"max_hz": 1.5
|
||||||
|
},
|
||||||
|
"fox": {
|
||||||
|
"min_hz": 2.0,
|
||||||
|
"max_hz": 4.5
|
||||||
|
},
|
||||||
|
"squirrel": {
|
||||||
|
"min_hz": 4.0,
|
||||||
|
"max_hz": 10.0
|
||||||
|
},
|
||||||
|
"mouse": {
|
||||||
|
"min_hz": 5.0,
|
||||||
|
"max_hz": 15.0
|
||||||
|
},
|
||||||
|
"raccoon": {
|
||||||
|
"min_hz": 1.5,
|
||||||
|
"max_hz": 3.5
|
||||||
|
},
|
||||||
|
"wild-boar": {
|
||||||
|
"min_hz": 1.0,
|
||||||
|
"max_hz": 2.5
|
||||||
|
},
|
||||||
|
"elk": {
|
||||||
|
"min_hz": 1.5,
|
||||||
|
"max_hz": 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue