Classifies every contact's likely non-LOS propagation mechanism and persists the result on contacts.propagation_mechanism. Mechanism is determined in priority order: 1. user_declared_prop_mode (ADIF PROP_MODE from the operator log) 2. EME — moon-ephemeris check, ≥2m band, >1800 km path 3. aurora — Kp≥5 + high-lat path, 50-432 MHz 4. sporadic-E — foEs × 5 ≥ band_mhz, 400-2500 km path 5. meteor_scatter — ±3 days of a shower peak, VHF/UHF 6. rain_scatter — common-volume radar heavy rain, 5-11 GHz ≤800 km 7. tropo_duct — HRRR native_best_duct ≥ band or ducting_detected 8. line_of_sight — ≤50 km path 9. troposcatter — default Persisted via MechanismClassifyWorker (queue: :mechanism, unique on contact_id). Submit-time enqueue path includes :mechanism by default; BackfillEnqueueWorker cron now handles :mechanism alongside existing types so prod continuously backfills any contact with propagation_mechanism_status in (:pending, :queued, :failed). Also added :radar to the cron's type list so common-volume radar backfill runs automatically rather than only via `mix radar_backfill`. New modules: - Microwaveprop.Propagation.MoonEphemeris — Meeus low-precision moon position, accuracy ±1° — enough for the mutual-visibility EME test - Microwaveprop.Propagation.MechanismClassifier — plug-in priority chain over the evidence map - Microwaveprop.Workers.MechanismClassifyWorker — assembles inputs from HRRR / native profiles / common-volume radar / solar_indices / ionosonde + calls the classifier ADIF importer now reads PROP_MODE into user_declared_prop_mode so operator-tagged mechanisms (EME/ES/MS/RS/AS/AUR) become ground truth.
30 lines
1.3 KiB
Elixir
30 lines
1.3 KiB
Elixir
defmodule Microwaveprop.Repo.Migrations.AddPropagationMechanismToContacts do
|
|
use Ecto.Migration
|
|
|
|
def change do
|
|
alter table(:contacts) do
|
|
# Classifier output. `user_declared_prop_mode` is the raw ADIF
|
|
# PROP_MODE string the operator submitted (if any); it's trusted
|
|
# as ground truth by the classifier when present. The two
|
|
# `propagation_mechanism*` columns are the classifier's output
|
|
# and its enrichment status, following the same pattern as
|
|
# hrrr_status / weather_status / terrain_status / radar_status.
|
|
add :user_declared_prop_mode, :string
|
|
add :propagation_mechanism, :string
|
|
add :propagation_mechanism_confidence, :string
|
|
add :propagation_mechanism_status, :string, null: false, default: "pending"
|
|
end
|
|
|
|
# Partial index for the backfill cron to scan only contacts that
|
|
# still need classification. Matches the pattern on other *_status
|
|
# columns.
|
|
create index(:contacts, [:propagation_mechanism_status],
|
|
where: "propagation_mechanism_status <> 'complete'",
|
|
name: :contacts_propagation_mechanism_status_pending_index
|
|
)
|
|
|
|
# Lets algo.md / map / analysis queries filter by mechanism without
|
|
# a full table scan.
|
|
create index(:contacts, [:propagation_mechanism])
|
|
end
|
|
end
|