ソースを参照

feat: add auto-span rules for refinement windows

master
Jan Svabenik 9時間前
コミット
dc5916bb75
7個のファイルの変更63行の追加1行の削除
  1. +1
    -0
      README.md
  2. +12
    -1
      cmd/sdrd/pipeline_runtime.go
  3. +1
    -0
      config.yaml
  4. +2
    -0
      internal/config/config.go
  5. +2
    -0
      internal/pipeline/policy.go
  6. +15
    -0
      internal/pipeline/scheduler_test.go
  7. +30
    -0
      internal/pipeline/window_rules.go

+ 1
- 0
README.md ファイルの表示

@@ -71,6 +71,7 @@ Edit `config.yaml` (autosave goes to `config.autosave.yaml`).
- `refinement.max_concurrent` — refinement budget hint
- `refinement.min_candidate_snr_db` — floor for future scheduling decisions
- `refinement.min_span_hz` / `refinement.max_span_hz` — clamp refinement window span (0 = no clamp)
- `refinement.auto_span` — use mod-type heuristics when candidate bandwidth is missing/odd
- `resources.prefer_gpu` — GPU preference hint
- `resources.max_refinement_jobs` — processing budget hint
- `resources.max_recording_streams` — recording/streaming budget hint


+ 12
- 1
cmd/sdrd/pipeline_runtime.go ファイルの表示

@@ -239,16 +239,27 @@ func (rt *dspRuntime) buildRefinementInput(surv pipeline.SurveillanceResult) pip
windows := make([]pipeline.RefinementWindow, 0, len(scheduled))
for _, sc := range scheduled {
span := sc.Candidate.BandwidthHz
windowSource := "candidate"
if policy.RefinementAutoSpan && (span <= 0 || span < 2000 || span > 400000) {
autoSpan, autoSource := pipeline.AutoSpanForHint(sc.Candidate.Hint)
if autoSpan > 0 {
span = autoSpan
windowSource = autoSource
}
}
if policy.RefinementMinSpanHz > 0 && span < policy.RefinementMinSpanHz {
span = policy.RefinementMinSpanHz
}
if policy.RefinementMaxSpanHz > 0 && span > policy.RefinementMaxSpanHz {
span = policy.RefinementMaxSpanHz
}
if span <= 0 {
span = 12000
}
windows = append(windows, pipeline.RefinementWindow{
CenterHz: sc.Candidate.CenterHz,
SpanHz: span,
Source: "candidate",
Source: windowSource,
})
}
input := pipeline.RefinementInput{


+ 1
- 0
config.yaml ファイルの表示

@@ -33,6 +33,7 @@ refinement:
min_candidate_snr_db: 0
min_span_hz: 0
max_span_hz: 0
auto_span: true
resources:
prefer_gpu: true
max_refinement_jobs: 8


+ 2
- 0
internal/config/config.go ファイルの表示

@@ -99,6 +99,7 @@ type RefinementConfig struct {
MinCandidateSNRDb float64 `yaml:"min_candidate_snr_db" json:"min_candidate_snr_db"`
MinSpanHz float64 `yaml:"min_span_hz" json:"min_span_hz"`
MaxSpanHz float64 `yaml:"max_span_hz" json:"max_span_hz"`
AutoSpan bool `yaml:"auto_span" json:"auto_span"`
}

type ResourceConfig struct {
@@ -177,6 +178,7 @@ func Default() Config {
MinCandidateSNRDb: 0,
MinSpanHz: 0,
MaxSpanHz: 0,
AutoSpan: true,
},
Resources: ResourceConfig{
PreferGPU: true,


+ 2
- 0
internal/pipeline/policy.go ファイルの表示

@@ -20,6 +20,7 @@ type Policy struct {
MinCandidateSNRDb float64 `json:"min_candidate_snr_db"`
RefinementMinSpanHz float64 `json:"refinement_min_span_hz"`
RefinementMaxSpanHz float64 `json:"refinement_max_span_hz"`
RefinementAutoSpan bool `json:"refinement_auto_span"`
PreferGPU bool `json:"prefer_gpu"`
}

@@ -42,6 +43,7 @@ func PolicyFromConfig(cfg config.Config) Policy {
MinCandidateSNRDb: cfg.Refinement.MinCandidateSNRDb,
RefinementMinSpanHz: cfg.Refinement.MinSpanHz,
RefinementMaxSpanHz: cfg.Refinement.MaxSpanHz,
RefinementAutoSpan: cfg.Refinement.AutoSpan,
PreferGPU: cfg.Resources.PreferGPU,
}
}


+ 15
- 0
internal/pipeline/scheduler_test.go ファイルの表示

@@ -44,6 +44,21 @@ func TestBuildRefinementPlanTracksDrops(t *testing.T) {
}
}

func TestAutoSpanForHint(t *testing.T) {
span, source := AutoSpanForHint("WFM_STEREO")
if span < 150000 || source == "" {
t.Fatalf("expected WFM span, got %.0f (%s)", span, source)
}
span, source = AutoSpanForHint("CW")
if span != 500 || source == "" {
t.Fatalf("expected CW span, got %.0f (%s)", span, source)
}
span, source = AutoSpanForHint("")
if span != 0 || source != "" {
t.Fatalf("expected empty span for unknown hint, got %.0f (%s)", span, source)
}
}

func TestScheduleCandidatesPriorityBoost(t *testing.T) {
policy := Policy{MaxRefinementJobs: 1, MinCandidateSNRDb: 0, SignalPriorities: []string{"digital"}}
got := ScheduleCandidates([]Candidate{


+ 30
- 0
internal/pipeline/window_rules.go ファイルの表示

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

import "strings"

// AutoSpanForHint returns a suggested refinement span based on the candidate hint.
// It is intentionally conservative: spans are wide enough for robust demod/classify,
// but not so wide that refinement becomes wasteful.
func AutoSpanForHint(hint string) (float64, string) {
h := strings.ToLower(hint)
switch {
case strings.Contains(h, "wfm"):
return 200000, "auto:wfm"
case strings.Contains(h, "nfm"):
return 18000, "auto:nfm"
case strings.Contains(h, "usb") || strings.Contains(h, "lsb") || strings.Contains(h, "ssb"):
return 6000, "auto:ssb"
case strings.Contains(h, "cw"):
return 500, "auto:cw"
case strings.Contains(h, "dmr") || strings.Contains(h, "d-star") || strings.Contains(h, "dstar"):
return 15000, "auto:dig_voice"
case strings.Contains(h, "ft8") || strings.Contains(h, "wspr"):
return 4000, "auto:dig_weak"
case strings.Contains(h, "fsk") || strings.Contains(h, "psk"):
return 6000, "auto:dig"
case strings.Contains(h, "am"):
return 12000, "auto:am"
default:
return 0, ""
}
}

読み込み中…
キャンセル
保存