Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

67 řádky
2.0KB

  1. package pipeline
  2. import "sort"
  3. type ScheduledCandidate struct {
  4. Candidate Candidate `json:"candidate"`
  5. Priority float64 `json:"priority"`
  6. }
  7. // BuildRefinementPlan scores and budgets candidates for costly local refinement.
  8. // Current heuristic is intentionally simple and deterministic; later phases can add
  9. // richer scoring (novelty, persistence, profile-aware band priorities, decoder value).
  10. func BuildRefinementPlan(candidates []Candidate, policy Policy) RefinementPlan {
  11. budget := policy.MaxRefinementJobs
  12. if policy.RefinementMaxConcurrent > 0 && (budget <= 0 || policy.RefinementMaxConcurrent < budget) {
  13. budget = policy.RefinementMaxConcurrent
  14. }
  15. plan := RefinementPlan{
  16. TotalCandidates: len(candidates),
  17. MinCandidateSNRDb: policy.MinCandidateSNRDb,
  18. Budget: budget,
  19. }
  20. if len(candidates) == 0 {
  21. return plan
  22. }
  23. snrWeight, bwWeight, peakWeight := refinementIntentWeights(policy.Intent)
  24. scored := make([]ScheduledCandidate, 0, len(candidates))
  25. for _, c := range candidates {
  26. if c.SNRDb < policy.MinCandidateSNRDb {
  27. plan.DroppedBySNR++
  28. continue
  29. }
  30. priority := c.SNRDb*snrWeight + CandidatePriorityBoost(policy, c.Hint)
  31. if c.BandwidthHz > 0 {
  32. priority += minFloat64(c.BandwidthHz/25000.0, 6) * bwWeight
  33. }
  34. if c.PeakDb > 0 {
  35. priority += (c.PeakDb / 20.0) * peakWeight
  36. }
  37. scored = append(scored, ScheduledCandidate{Candidate: c, Priority: priority})
  38. }
  39. sort.Slice(scored, func(i, j int) bool {
  40. if scored[i].Priority == scored[j].Priority {
  41. return scored[i].Candidate.CenterHz < scored[j].Candidate.CenterHz
  42. }
  43. return scored[i].Priority > scored[j].Priority
  44. })
  45. limit := plan.Budget
  46. if limit <= 0 || limit > len(scored) {
  47. limit = len(scored)
  48. }
  49. plan.Selected = scored[:limit]
  50. plan.DroppedByBudget = len(scored) - len(plan.Selected)
  51. return plan
  52. }
  53. func ScheduleCandidates(candidates []Candidate, policy Policy) []ScheduledCandidate {
  54. return BuildRefinementPlan(candidates, policy).Selected
  55. }
  56. func minFloat64(a, b float64) float64 {
  57. if a < b {
  58. return a
  59. }
  60. return b
  61. }