Sfoglia il codice sorgente

feat: derive signal actions from pipeline goals

master
Jan Svabenik 9 ore fa
parent
commit
8a9b90b9cc
4 ha cambiato i file con 89 aggiunte e 4 eliminazioni
  1. +25
    -0
      cmd/sdrd/pipeline_decision_test.go
  2. +13
    -4
      cmd/sdrd/pipeline_runtime.go
  3. +32
    -0
      internal/pipeline/decisions.go
  4. +19
    -0
      internal/pipeline/decisions_test.go

+ 25
- 0
cmd/sdrd/pipeline_decision_test.go Vedi File

@@ -0,0 +1,25 @@
package main

import (
"testing"

"sdr-wideband-suite/internal/classifier"
"sdr-wideband-suite/internal/pipeline"
)

func TestDecisionCanEnableRecorderFlags(t *testing.T) {
rt := &dspRuntime{}
rt.cfg.Recorder.Enabled = false
rt.cfg.Recorder.AutoDecode = false
policy := pipeline.Policy{AutoRecordClasses: []string{"WFM"}, AutoDecodeClasses: []string{"WFM"}}
decision := pipeline.DecideSignalAction(policy, pipeline.Candidate{ID: 1, Hint: "WFM"}, &classifier.Classification{ModType: classifier.ClassWFM})
if decision.ShouldRecord {
rt.cfg.Recorder.Enabled = true
}
if decision.ShouldAutoDecode {
rt.cfg.Recorder.AutoDecode = true
}
if !rt.cfg.Recorder.Enabled || !rt.cfg.Recorder.AutoDecode {
t.Fatalf("expected recorder flags to be enabled")
}
}

+ 13
- 4
cmd/sdrd/pipeline_runtime.go Vedi File

@@ -219,9 +219,11 @@ func (rt *dspRuntime) refineSignals(art *spectrumArtifacts, extractMgr *extracti
policy := pipeline.PolicyFromConfig(rt.cfg)
candidates := pipeline.CandidatesFromSignals(art.detected, "surveillance-detector")
scheduled := pipeline.ScheduleCandidates(candidates, policy)
selected := make([]detector.Signal, 0, len(scheduled))
selectedCandidates := make([]pipeline.Candidate, 0, len(scheduled))
selectedSignals := make([]detector.Signal, 0, len(scheduled))
for _, sc := range scheduled {
selected = append(selected, detector.Signal{
selectedCandidates = append(selectedCandidates, sc.Candidate)
selectedSignals = append(selectedSignals, detector.Signal{
ID: sc.Candidate.ID,
FirstBin: sc.Candidate.FirstBin,
LastBin: sc.Candidate.LastBin,
@@ -232,14 +234,21 @@ func (rt *dspRuntime) refineSignals(art *spectrumArtifacts, extractMgr *extracti
NoiseDb: sc.Candidate.NoiseDb,
})
}
snips, snipRates := extractSignalIQBatch(extractMgr, art.iq, rt.cfg.SampleRate, rt.cfg.CenterHz, selected)
refined := pipeline.RefineCandidates(pipeline.CandidatesFromSignals(selected, "scheduled-candidate"), art.spectrum, rt.cfg.SampleRate, rt.cfg.FFTSize, snips, snipRates, classifier.ClassifierMode(rt.cfg.ClassifierMode))
snips, snipRates := extractSignalIQBatch(extractMgr, art.iq, rt.cfg.SampleRate, rt.cfg.CenterHz, selectedSignals)
refined := pipeline.RefineCandidates(selectedCandidates, art.spectrum, rt.cfg.SampleRate, rt.cfg.FFTSize, snips, snipRates, classifier.ClassifierMode(rt.cfg.ClassifierMode))
signals := make([]detector.Signal, 0, len(refined))
for i, ref := range refined {
sig := ref.Signal
signals = append(signals, sig)
cls := sig.Class
snipRate := ref.SnippetRate
decision := pipeline.DecideSignalAction(policy, ref.Candidate, cls)
if decision.ShouldAutoDecode && rec != nil {
rt.cfg.Recorder.AutoDecode = true
}
if decision.ShouldRecord && rec != nil {
rt.cfg.Recorder.Enabled = true
}
if cls != nil {
pll := classifier.PLLResult{}
if i < len(snips) && snips[i] != nil && len(snips[i]) > 256 {


+ 32
- 0
internal/pipeline/decisions.go Vedi File

@@ -0,0 +1,32 @@
package pipeline

import "sdr-wideband-suite/internal/classifier"

type SignalDecision struct {
Candidate Candidate `json:"candidate"`
Class string `json:"class,omitempty"`
ShouldRecord bool `json:"should_record"`
ShouldAutoDecode bool `json:"should_auto_decode"`
Reason string `json:"reason,omitempty"`
}

func DecideSignalAction(policy Policy, candidate Candidate, cls *classifier.Classification) SignalDecision {
decision := SignalDecision{Candidate: candidate}
if cls != nil {
decision.Class = string(cls.ModType)
}
if cls != nil && WantsClass(policy.AutoRecordClasses, string(cls.ModType)) {
decision.ShouldRecord = true
decision.Reason = "matched auto_record_classes"
}
if cls != nil && WantsClass(policy.AutoDecodeClasses, string(cls.ModType)) {
decision.ShouldAutoDecode = true
if decision.Reason == "" {
decision.Reason = "matched auto_decode_classes"
}
}
if decision.Reason == "" && candidate.Hint != "" {
decision.Reason = "policy evaluated candidate hint"
}
return decision
}

+ 19
- 0
internal/pipeline/decisions_test.go Vedi File

@@ -0,0 +1,19 @@
package pipeline

import (
"testing"

"sdr-wideband-suite/internal/classifier"
)

func TestDecideSignalAction(t *testing.T) {
policy := Policy{AutoRecordClasses: []string{"WFM"}, AutoDecodeClasses: []string{"RDS", "WFM"}}
cls := &classifier.Classification{ModType: classifier.ClassWFM}
decision := DecideSignalAction(policy, Candidate{ID: 1, Hint: "WFM"}, cls)
if !decision.ShouldRecord {
t.Fatalf("expected record decision")
}
if !decision.ShouldAutoDecode {
t.Fatalf("expected auto decode decision")
}
}

Loading…
Annulla
Salva