fix(pskr): an opening has to be an opening HERE
A PSK Reporter message says "X was heard BY Y". The watcher measured the distance and bearing from the operator to X and stopped there, never asking who had actually heard it — so a station 1400 km away, decoded by somebody in Japan, counted as evidence. That proves the path from X to JAPAN and says nothing about whether anything reaches this station. It is how a "2 m opening" came to be announced out of a KX9X in the United States, and the operator was right to find the callsign list absurd. Reports are now kept only when the RECEIVING station is within 300 km. Far enough to borrow the ears of a whole region — an opening reaches an area, not a postcode, and waiting for a decode at one's own antenna is just working the band — and close enough that the ionosphere doing something there is it doing the same thing here. The transmitter still supplies the direction and the path length, which is what was always wanted from it. Also drops 12 m from the watched bands, at the operator's request: at this point in the cycle it is open often enough that announcing it is a notification rather than news, and a band that cries wolf costs the ones that do not. One fewer subscription is also less traffic on a PC that pays for every message.
This commit is contained in:
+42
-8
@@ -36,10 +36,17 @@ import (
|
||||
// DefaultBroker is PSK Reporter's public MQTT endpoint, TLS.
|
||||
const DefaultBroker = "tls://mqtt.pskreporter.info:1884"
|
||||
|
||||
// Bands offered. HF below 12 m is deliberately absent: an "opening" on 20 m is
|
||||
// the normal state of the band and announcing it says nothing. These are the
|
||||
// bands where an opening is an event worth interrupting an operator for.
|
||||
var Bands = []string{"12m", "10m", "6m", "4m", "2m"}
|
||||
// DefaultNearKm is the radius that counts as "around here" for a receiver.
|
||||
const DefaultNearKm = 300
|
||||
|
||||
// Bands offered. Anything below 10 m is deliberately absent, 12 m included: an
|
||||
// "opening" on 20 m is the normal state of the band and announcing it says
|
||||
// nothing, and 12 m is close enough to that at this point in the cycle to be the
|
||||
// same problem. These are the bands where an opening is an event.
|
||||
//
|
||||
// Fewer subscriptions is also less traffic, which matters here: the operator's
|
||||
// PC pays for every message the broker sends, whether or not anything comes of it.
|
||||
var Bands = []string{"10m", "6m", "4m", "2m"}
|
||||
|
||||
// Spot is one decode, already reduced to what a detector needs.
|
||||
type Spot struct {
|
||||
@@ -59,6 +66,14 @@ type Config struct {
|
||||
// OpLat/OpLon are the operator's position: every spot is measured from it,
|
||||
// so with no position there is nothing to measure and the watcher stays down.
|
||||
OpLat, OpLon float64
|
||||
// NearKm is how close a RECEIVER must be to count as "around here". A report
|
||||
// collected further away proves a path that is not the operator's.
|
||||
//
|
||||
// 300 km by default: far enough to borrow the ears of a whole region, which
|
||||
// is the point — an opening reaches an area, not a postcode, and waiting for
|
||||
// a decode at one's own station is just working the band. Close enough that
|
||||
// the ionosphere doing something there is the ionosphere doing it here.
|
||||
NearKm int
|
||||
// Geo turns two grids into distance and bearing. Injected rather than
|
||||
// implemented here so it stays the SAME arithmetic the cluster path uses —
|
||||
// two answers for one question is how a bearing quietly becomes wrong.
|
||||
@@ -91,6 +106,9 @@ func New(cfg Config) *Watcher {
|
||||
if len(cfg.Bands) == 0 {
|
||||
cfg.Bands = Bands
|
||||
}
|
||||
if cfg.NearKm <= 0 {
|
||||
cfg.NearKm = DefaultNearKm
|
||||
}
|
||||
if cfg.Logf == nil {
|
||||
cfg.Logf = func(string, ...any) {}
|
||||
}
|
||||
@@ -183,12 +201,28 @@ func (w *Watcher) handle(_ mqtt.Client, m mqtt.Message) {
|
||||
}
|
||||
call := strings.ToUpper(strings.TrimSpace(p.TxCall))
|
||||
grid := strings.ToUpper(strings.TrimSpace(p.TxGrid))
|
||||
if call == "" || len(grid) < 4 {
|
||||
rxGrid := strings.ToUpper(strings.TrimSpace(p.RxGrid))
|
||||
if call == "" || len(grid) < 4 || len(rxGrid) < 4 {
|
||||
return
|
||||
}
|
||||
// The TRANSMITTER is the station on the air; the receiver is whoever
|
||||
// happened to be listening. An opening is described by where the signals are
|
||||
// coming from, so it is the transmitter's grid that is measured.
|
||||
|
||||
// THE RECEIVER HAS TO BE NEAR THE OPERATOR. This is the whole difference
|
||||
// between a useful feed and a world map.
|
||||
//
|
||||
// A PSK Reporter message says "X was heard BY Y". Without this check, a
|
||||
// station 1400 km from here heard by somebody in Japan counted as evidence
|
||||
// of an opening — it proves the path from X to JAPAN, and says nothing at all
|
||||
// about whether anything reaches this station. That is how a "2 m opening"
|
||||
// came to be announced from a KX9X in the United States.
|
||||
//
|
||||
// Only reports collected by a receiver in the operator's own region show that
|
||||
// signals are actually arriving HERE, which is the only question worth asking.
|
||||
if rxDist, _, ok := w.cfg.Geo(rxGrid[:4]); !ok || rxDist > w.cfg.NearKm {
|
||||
return
|
||||
}
|
||||
|
||||
// The TRANSMITTER is the station on the air, so it is the transmitter's grid
|
||||
// that gives the direction and length of the path that just proved itself.
|
||||
dist, brg, ok := w.cfg.Geo(grid[:4])
|
||||
if !ok {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user