| @@ -62,7 +62,7 @@ func runDSP(ctx context.Context, srcMgr *sourceManager, cfg config.Config, det * | |||||
| noiseFloor := state.surveillance.NoiseFloor | noiseFloor := state.surveillance.NoiseFloor | ||||
| var displaySignals []detector.Signal | var displaySignals []detector.Signal | ||||
| if len(art.iq) > 0 { | if len(art.iq) > 0 { | ||||
| state.refinement = rt.refineSignals(art, extractMgr, rec) | |||||
| state.refinement = rt.refineSignals(art, state.surveillance.Scheduled, extractMgr, rec) | |||||
| displaySignals = state.refinement.Signals | displaySignals = state.refinement.Signals | ||||
| if rec != nil && len(displaySignals) > 0 && len(art.allIQ) > 0 { | if rec != nil && len(displaySignals) > 0 && len(art.allIQ) > 0 { | ||||
| aqCfg := extractionConfig{firTaps: rt.cfg.Recorder.ExtractionTaps, bwMult: rt.cfg.Recorder.ExtractionBwMult} | aqCfg := extractionConfig{firTaps: rt.cfg.Recorder.ExtractionTaps, bwMult: rt.cfg.Recorder.ExtractionBwMult} | ||||
| @@ -8,13 +8,13 @@ import ( | |||||
| func TestPhaseStateCarriesPhaseResults(t *testing.T) { | func TestPhaseStateCarriesPhaseResults(t *testing.T) { | ||||
| ps := &phaseState{ | ps := &phaseState{ | ||||
| surveillance: pipeline.SurveillanceResult{NoiseFloor: -90}, | |||||
| refinement: pipeline.RefinementResult{Decisions: []pipeline.SignalDecision{{ShouldRecord: true}}}, | |||||
| surveillance: pipeline.SurveillanceResult{NoiseFloor: -90, Scheduled: []pipeline.ScheduledCandidate{{Candidate: pipeline.Candidate{ID: 1}, Priority: 5}}}, | |||||
| refinement: pipeline.RefinementResult{Decisions: []pipeline.SignalDecision{{ShouldRecord: true}}, Candidates: []pipeline.Candidate{{ID: 1}}}, | |||||
| } | } | ||||
| if ps.surveillance.NoiseFloor != -90 { | |||||
| if ps.surveillance.NoiseFloor != -90 || len(ps.surveillance.Scheduled) != 1 { | |||||
| t.Fatalf("unexpected surveillance state: %+v", ps.surveillance) | t.Fatalf("unexpected surveillance state: %+v", ps.surveillance) | ||||
| } | } | ||||
| if len(ps.refinement.Decisions) != 1 || !ps.refinement.Decisions[0].ShouldRecord { | |||||
| if len(ps.refinement.Decisions) != 1 || !ps.refinement.Decisions[0].ShouldRecord || len(ps.refinement.Candidates) != 1 { | |||||
| t.Fatalf("unexpected refinement state: %+v", ps.refinement) | t.Fatalf("unexpected refinement state: %+v", ps.refinement) | ||||
| } | } | ||||
| } | } | ||||
| @@ -216,8 +216,12 @@ func (rt *dspRuntime) buildSurveillanceResult(art *spectrumArtifacts) pipeline.S | |||||
| if art == nil { | if art == nil { | ||||
| return pipeline.SurveillanceResult{} | return pipeline.SurveillanceResult{} | ||||
| } | } | ||||
| policy := pipeline.PolicyFromConfig(rt.cfg) | |||||
| candidates := pipeline.CandidatesFromSignals(art.detected, "surveillance-detector") | |||||
| scheduled := pipeline.ScheduleCandidates(candidates, policy) | |||||
| return pipeline.SurveillanceResult{ | return pipeline.SurveillanceResult{ | ||||
| Candidates: pipeline.CandidatesFromSignals(art.detected, "surveillance-detector"), | |||||
| Candidates: candidates, | |||||
| Scheduled: scheduled, | |||||
| Finished: art.finished, | Finished: art.finished, | ||||
| Signals: art.detected, | Signals: art.detected, | ||||
| NoiseFloor: art.noiseFloor, | NoiseFloor: art.noiseFloor, | ||||
| @@ -225,13 +229,11 @@ func (rt *dspRuntime) buildSurveillanceResult(art *spectrumArtifacts) pipeline.S | |||||
| } | } | ||||
| } | } | ||||
| func (rt *dspRuntime) refineSignals(art *spectrumArtifacts, extractMgr *extractionManager, rec *recorder.Manager) pipeline.RefinementResult { | |||||
| func (rt *dspRuntime) refineSignals(art *spectrumArtifacts, scheduled []pipeline.ScheduledCandidate, extractMgr *extractionManager, rec *recorder.Manager) pipeline.RefinementResult { | |||||
| if art == nil || len(art.iq) == 0 { | if art == nil || len(art.iq) == 0 { | ||||
| return pipeline.RefinementResult{} | return pipeline.RefinementResult{} | ||||
| } | } | ||||
| policy := pipeline.PolicyFromConfig(rt.cfg) | policy := pipeline.PolicyFromConfig(rt.cfg) | ||||
| candidates := pipeline.CandidatesFromSignals(art.detected, "surveillance-detector") | |||||
| scheduled := pipeline.ScheduleCandidates(candidates, policy) | |||||
| selectedCandidates := make([]pipeline.Candidate, 0, len(scheduled)) | selectedCandidates := make([]pipeline.Candidate, 0, len(scheduled)) | ||||
| selectedSignals := make([]detector.Signal, 0, len(scheduled)) | selectedSignals := make([]detector.Signal, 0, len(scheduled)) | ||||
| for _, sc := range scheduled { | for _, sc := range scheduled { | ||||
| @@ -280,7 +282,7 @@ func (rt *dspRuntime) refineSignals(art *spectrumArtifacts, extractMgr *extracti | |||||
| } | } | ||||
| } | } | ||||
| rt.det.UpdateClasses(signals) | rt.det.UpdateClasses(signals) | ||||
| return pipeline.RefinementResult{Signals: signals, Decisions: decisions} | |||||
| return pipeline.RefinementResult{Signals: signals, Decisions: decisions, Candidates: selectedCandidates} | |||||
| } | } | ||||
| func (rt *dspRuntime) updateRDS(now time.Time, rec *recorder.Manager, sig *detector.Signal, cls *classifier.Classification) { | func (rt *dspRuntime) updateRDS(now time.Time, rec *recorder.Manager, sig *detector.Signal, cls *classifier.Classification) { | ||||
| @@ -3,14 +3,16 @@ package pipeline | |||||
| import "sdr-wideband-suite/internal/detector" | import "sdr-wideband-suite/internal/detector" | ||||
| type SurveillanceResult struct { | type SurveillanceResult struct { | ||||
| Candidates []Candidate `json:"candidates"` | |||||
| Finished []detector.Event `json:"finished"` | |||||
| Signals []detector.Signal `json:"signals"` | |||||
| NoiseFloor float64 `json:"noise_floor"` | |||||
| Thresholds []float64 `json:"thresholds,omitempty"` | |||||
| Candidates []Candidate `json:"candidates"` | |||||
| Scheduled []ScheduledCandidate `json:"scheduled,omitempty"` | |||||
| Finished []detector.Event `json:"finished"` | |||||
| Signals []detector.Signal `json:"signals"` | |||||
| NoiseFloor float64 `json:"noise_floor"` | |||||
| Thresholds []float64 `json:"thresholds,omitempty"` | |||||
| } | } | ||||
| type RefinementResult struct { | type RefinementResult struct { | ||||
| Signals []detector.Signal `json:"signals"` | |||||
| Decisions []SignalDecision `json:"decisions,omitempty"` | |||||
| Signals []detector.Signal `json:"signals"` | |||||
| Decisions []SignalDecision `json:"decisions,omitempty"` | |||||
| Candidates []Candidate `json:"candidates,omitempty"` | |||||
| } | } | ||||
| @@ -8,10 +8,21 @@ import ( | |||||
| func TestRefinementResultCarriesDecisions(t *testing.T) { | func TestRefinementResultCarriesDecisions(t *testing.T) { | ||||
| res := RefinementResult{ | res := RefinementResult{ | ||||
| Signals: []detector.Signal{{ID: 1}}, | |||||
| Decisions: []SignalDecision{{ShouldRecord: true}}, | |||||
| Signals: []detector.Signal{{ID: 1}}, | |||||
| Decisions: []SignalDecision{{ShouldRecord: true}}, | |||||
| Candidates: []Candidate{{ID: 1}}, | |||||
| } | } | ||||
| if len(res.Signals) != 1 || len(res.Decisions) != 1 { | |||||
| if len(res.Signals) != 1 || len(res.Decisions) != 1 || len(res.Candidates) != 1 { | |||||
| t.Fatalf("unexpected refinement result: %+v", res) | t.Fatalf("unexpected refinement result: %+v", res) | ||||
| } | } | ||||
| } | } | ||||
| func TestSurveillanceResultCarriesScheduledCandidates(t *testing.T) { | |||||
| res := SurveillanceResult{ | |||||
| Candidates: []Candidate{{ID: 1}}, | |||||
| Scheduled: []ScheduledCandidate{{Candidate: Candidate{ID: 1}, Priority: 10}}, | |||||
| } | |||||
| if len(res.Candidates) != 1 || len(res.Scheduled) != 1 { | |||||
| t.Fatalf("unexpected surveillance result: %+v", res) | |||||
| } | |||||
| } | |||||