|
|
|
@@ -3,8 +3,16 @@ package pipeline |
|
|
|
import "sort" |
|
|
|
|
|
|
|
type ScheduledCandidate struct { |
|
|
|
Candidate Candidate `json:"candidate"` |
|
|
|
Priority float64 `json:"priority"` |
|
|
|
Candidate Candidate `json:"candidate"` |
|
|
|
Priority float64 `json:"priority"` |
|
|
|
Breakdown *PriorityBreakdown `json:"breakdown,omitempty"` |
|
|
|
} |
|
|
|
|
|
|
|
type PriorityBreakdown struct { |
|
|
|
SNRScore float64 `json:"snr_score"` |
|
|
|
BandwidthScore float64 `json:"bandwidth_score"` |
|
|
|
PeakScore float64 `json:"peak_score"` |
|
|
|
PolicyBoost float64 `json:"policy_boost"` |
|
|
|
} |
|
|
|
|
|
|
|
// BuildRefinementPlan scores and budgets candidates for costly local refinement. |
|
|
|
@@ -20,6 +28,13 @@ func BuildRefinementPlan(candidates []Candidate, policy Policy) RefinementPlan { |
|
|
|
MinCandidateSNRDb: policy.MinCandidateSNRDb, |
|
|
|
Budget: budget, |
|
|
|
} |
|
|
|
if start, end, ok := monitorBounds(policy); ok { |
|
|
|
plan.MonitorStartHz = start |
|
|
|
plan.MonitorEndHz = end |
|
|
|
if end > start { |
|
|
|
plan.MonitorSpanHz = end - start |
|
|
|
} |
|
|
|
} |
|
|
|
if len(candidates) == 0 { |
|
|
|
return plan |
|
|
|
} |
|
|
|
@@ -34,14 +49,27 @@ func BuildRefinementPlan(candidates []Candidate, policy Policy) RefinementPlan { |
|
|
|
plan.DroppedBySNR++ |
|
|
|
continue |
|
|
|
} |
|
|
|
priority := c.SNRDb*snrWeight + CandidatePriorityBoost(policy, c.Hint) |
|
|
|
snrScore := c.SNRDb * snrWeight |
|
|
|
bwScore := 0.0 |
|
|
|
peakScore := 0.0 |
|
|
|
policyBoost := CandidatePriorityBoost(policy, c.Hint) |
|
|
|
if c.BandwidthHz > 0 { |
|
|
|
priority += minFloat64(c.BandwidthHz/25000.0, 6) * bwWeight |
|
|
|
bwScore = minFloat64(c.BandwidthHz/25000.0, 6) * bwWeight |
|
|
|
} |
|
|
|
if c.PeakDb > 0 { |
|
|
|
priority += (c.PeakDb / 20.0) * peakWeight |
|
|
|
peakScore = (c.PeakDb / 20.0) * peakWeight |
|
|
|
} |
|
|
|
scored = append(scored, ScheduledCandidate{Candidate: c, Priority: priority}) |
|
|
|
priority := snrScore + bwScore + peakScore + policyBoost |
|
|
|
scored = append(scored, ScheduledCandidate{ |
|
|
|
Candidate: c, |
|
|
|
Priority: priority, |
|
|
|
Breakdown: &PriorityBreakdown{ |
|
|
|
SNRScore: snrScore, |
|
|
|
BandwidthScore: bwScore, |
|
|
|
PeakScore: peakScore, |
|
|
|
PolicyBoost: policyBoost, |
|
|
|
}, |
|
|
|
}) |
|
|
|
} |
|
|
|
sort.Slice(scored, func(i, j int) bool { |
|
|
|
if scored[i].Priority == scored[j].Priority { |
|
|
|
@@ -49,11 +77,31 @@ func BuildRefinementPlan(candidates []Candidate, policy Policy) RefinementPlan { |
|
|
|
} |
|
|
|
return scored[i].Priority > scored[j].Priority |
|
|
|
}) |
|
|
|
if len(scored) > 0 { |
|
|
|
minPriority := scored[0].Priority |
|
|
|
maxPriority := scored[0].Priority |
|
|
|
sumPriority := 0.0 |
|
|
|
for _, s := range scored { |
|
|
|
if s.Priority < minPriority { |
|
|
|
minPriority = s.Priority |
|
|
|
} |
|
|
|
if s.Priority > maxPriority { |
|
|
|
maxPriority = s.Priority |
|
|
|
} |
|
|
|
sumPriority += s.Priority |
|
|
|
} |
|
|
|
plan.PriorityMin = minPriority |
|
|
|
plan.PriorityMax = maxPriority |
|
|
|
plan.PriorityAvg = sumPriority / float64(len(scored)) |
|
|
|
} |
|
|
|
limit := plan.Budget |
|
|
|
if limit <= 0 || limit > len(scored) { |
|
|
|
limit = len(scored) |
|
|
|
} |
|
|
|
plan.Selected = scored[:limit] |
|
|
|
if len(plan.Selected) > 0 { |
|
|
|
plan.PriorityCutoff = plan.Selected[len(plan.Selected)-1].Priority |
|
|
|
} |
|
|
|
plan.DroppedByBudget = len(scored) - len(plan.Selected) |
|
|
|
return plan |
|
|
|
} |
|
|
|
|