Wideband autonomous SDR analysis engine forked from sdr-visual-suite
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
1.9KB

  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. scored := make([]ScheduledCandidate, 0, len(candidates))
  24. for _, c := range candidates {
  25. if c.SNRDb < policy.MinCandidateSNRDb {
  26. plan.DroppedBySNR++
  27. continue
  28. }
  29. priority := c.SNRDb + CandidatePriorityBoost(policy, c.Hint)
  30. if c.BandwidthHz > 0 {
  31. priority += minFloat64(c.BandwidthHz/25000.0, 6)
  32. }
  33. if c.PeakDb > 0 {
  34. priority += c.PeakDb / 20.0
  35. }
  36. scored = append(scored, ScheduledCandidate{Candidate: c, Priority: priority})
  37. }
  38. sort.Slice(scored, func(i, j int) bool {
  39. if scored[i].Priority == scored[j].Priority {
  40. return scored[i].Candidate.CenterHz < scored[j].Candidate.CenterHz
  41. }
  42. return scored[i].Priority > scored[j].Priority
  43. })
  44. limit := plan.Budget
  45. if limit <= 0 || limit > len(scored) {
  46. limit = len(scored)
  47. }
  48. plan.Selected = scored[:limit]
  49. plan.DroppedByBudget = len(scored) - len(plan.Selected)
  50. return plan
  51. }
  52. func ScheduleCandidates(candidates []Candidate, policy Policy) []ScheduledCandidate {
  53. return BuildRefinementPlan(candidates, policy).Selected
  54. }
  55. func minFloat64(a, b float64) float64 {
  56. if a < b {
  57. return a
  58. }
  59. return b
  60. }