Przeglądaj źródła

Add surveillance level set and evidence plumbing

master
Jan Svabenik 11 godzin temu
rodzic
commit
e29508ec8e
3 zmienionych plików z 57 dodań i 12 usunięć
  1. +19
    -2
      cmd/sdrd/pipeline_runtime.go
  2. +8
    -0
      internal/pipeline/phases.go
  3. +30
    -10
      internal/pipeline/types.go

+ 19
- 2
cmd/sdrd/pipeline_runtime.go Wyświetl plik

@@ -74,6 +74,7 @@ type surveillanceLevelSpec struct {
type surveillancePlan struct {
Primary pipeline.AnalysisLevel
Levels []pipeline.AnalysisLevel
LevelSet pipeline.SurveillanceLevelSet
Presentation pipeline.AnalysisLevel
Context pipeline.AnalysisContext
Specs []surveillanceLevelSpec
@@ -414,15 +415,16 @@ func (rt *dspRuntime) buildSurveillanceResult(art *spectrumArtifacts) pipeline.S
return pipeline.SurveillanceResult{}
}
policy := pipeline.PolicyFromConfig(rt.cfg)
candidates := pipeline.CandidatesFromSignals(art.detected, "surveillance-detector")
scheduled := pipeline.ScheduleCandidates(candidates, policy)
plan := art.surveillancePlan
if plan.Primary.Name == "" {
plan = rt.buildSurveillancePlan(policy)
}
candidates := pipeline.CandidatesFromSignalsWithLevel(art.detected, "surveillance-detector", plan.Primary)
scheduled := pipeline.ScheduleCandidates(candidates, policy)
return pipeline.SurveillanceResult{
Level: plan.Primary,
Levels: plan.Levels,
LevelSet: plan.LevelSet,
DisplayLevel: plan.Presentation,
Context: plan.Context,
Spectra: art.surveillanceSpectra,
@@ -766,6 +768,7 @@ func (rt *dspRuntime) buildSurveillancePlan(policy pipeline.Policy) surveillance
levels := []pipeline.AnalysisLevel{primary}
specs := []surveillanceLevelSpec{{Level: primary, Decim: 1, AllowGPU: true}}
context := pipeline.AnalysisContext{Surveillance: primary}
derivedLevels := make([]pipeline.AnalysisLevel, 0, 2)

strategy := strings.ToLower(strings.TrimSpace(policy.SurveillanceStrategy))
switch strategy {
@@ -779,15 +782,29 @@ func (rt *dspRuntime) buildSurveillancePlan(policy pipeline.Policy) surveillance
levels = append(levels, derived)
specs = append(specs, surveillanceLevelSpec{Level: derived, Decim: decim, AllowGPU: false})
context.Derived = append(context.Derived, derived)
derivedLevels = append(derivedLevels, derived)
}
}

presentation := analysisLevel("presentation", "presentation", "presentation", baseRate, rt.cfg.Surveillance.DisplayBins, rt.cfg.CenterHz, span, "display", 1, baseRate)
context.Presentation = presentation
levelSet := pipeline.SurveillanceLevelSet{
Primary: primary,
Derived: append([]pipeline.AnalysisLevel(nil), derivedLevels...),
Presentation: presentation,
}
allLevels := make([]pipeline.AnalysisLevel, 0, 1+len(derivedLevels)+1)
allLevels = append(allLevels, primary)
allLevels = append(allLevels, derivedLevels...)
if presentation.Name != "" {
allLevels = append(allLevels, presentation)
}
levelSet.All = allLevels

return surveillancePlan{
Primary: primary,
Levels: levels,
LevelSet: levelSet,
Presentation: presentation,
Context: context,
Specs: specs,


+ 8
- 0
internal/pipeline/phases.go Wyświetl plik

@@ -28,9 +28,17 @@ type AnalysisContext struct {
Derived []AnalysisLevel `json:"derived,omitempty"`
}

type SurveillanceLevelSet struct {
Primary AnalysisLevel `json:"primary"`
Derived []AnalysisLevel `json:"derived,omitempty"`
Presentation AnalysisLevel `json:"presentation,omitempty"`
All []AnalysisLevel `json:"all,omitempty"`
}

type SurveillanceResult struct {
Level AnalysisLevel `json:"level"`
Levels []AnalysisLevel `json:"levels,omitempty"`
LevelSet SurveillanceLevelSet `json:"level_set,omitempty"`
Candidates []Candidate `json:"candidates"`
Scheduled []ScheduledCandidate `json:"scheduled,omitempty"`
Finished []detector.Event `json:"finished"`


+ 30
- 10
internal/pipeline/types.go Wyświetl plik

@@ -8,16 +8,24 @@ import (
// Candidate is the coarse output of the surveillance detector.
// It intentionally stays lightweight and cheap to produce.
type Candidate struct {
ID int64 `json:"id"`
CenterHz float64 `json:"center_hz"`
BandwidthHz float64 `json:"bandwidth_hz"`
PeakDb float64 `json:"peak_db"`
SNRDb float64 `json:"snr_db"`
FirstBin int `json:"first_bin"`
LastBin int `json:"last_bin"`
NoiseDb float64 `json:"noise_db,omitempty"`
Source string `json:"source,omitempty"`
Hint string `json:"hint,omitempty"`
ID int64 `json:"id"`
CenterHz float64 `json:"center_hz"`
BandwidthHz float64 `json:"bandwidth_hz"`
PeakDb float64 `json:"peak_db"`
SNRDb float64 `json:"snr_db"`
FirstBin int `json:"first_bin"`
LastBin int `json:"last_bin"`
NoiseDb float64 `json:"noise_db,omitempty"`
Source string `json:"source,omitempty"`
Hint string `json:"hint,omitempty"`
Evidence []LevelEvidence `json:"evidence,omitempty"`
}

// LevelEvidence captures which analysis level produced a candidate.
// This is intentionally lightweight for later multi-level fusion.
type LevelEvidence struct {
Level AnalysisLevel `json:"level"`
Provenance string `json:"provenance,omitempty"`
}

// RefinementWindow describes the local analysis span that refinement should use.
@@ -59,3 +67,15 @@ func CandidatesFromSignals(signals []detector.Signal, source string) []Candidate
}
return out
}

func CandidatesFromSignalsWithLevel(signals []detector.Signal, source string, level AnalysisLevel) []Candidate {
out := CandidatesFromSignals(signals, source)
if level.Name == "" && level.FFTSize == 0 && level.SampleRate == 0 {
return out
}
evidence := LevelEvidence{Level: level, Provenance: source}
for i := range out {
out[i].Evidence = append(out[i].Evidence, evidence)
}
return out
}

Ładowanie…
Anuluj
Zapisz