|
- package pipeline
-
- import "math"
-
- func AddCandidateEvidence(candidate *Candidate, evidence LevelEvidence) {
- if candidate == nil {
- return
- }
- levelName := evidence.Level.Name
- if levelName == "" {
- levelName = "unknown"
- }
- for _, ev := range candidate.Evidence {
- evLevel := ev.Level.Name
- if evLevel == "" {
- evLevel = "unknown"
- }
- if evLevel == levelName && ev.Provenance == evidence.Provenance {
- RefreshCandidateEvidenceState(candidate)
- return
- }
- }
- candidate.Evidence = append(candidate.Evidence, evidence)
- RefreshCandidateEvidenceState(candidate)
- }
-
- func MergeCandidateEvidence(dst *Candidate, src Candidate) {
- if dst == nil || len(src.Evidence) == 0 {
- return
- }
- for _, ev := range src.Evidence {
- AddCandidateEvidence(dst, ev)
- }
- }
-
- func CandidateEvidenceLevelCount(candidate Candidate) int {
- state := CandidateEvidenceStateFor(candidate)
- return state.DetectionLevelCount
- }
-
- func FuseCandidates(primary []Candidate, derived []Candidate) []Candidate {
- if len(primary) == 0 && len(derived) == 0 {
- return nil
- }
- out := make([]Candidate, 0, len(primary)+len(derived))
- out = append(out, primary...)
- if len(derived) == 0 {
- return out
- }
- used := make([]bool, len(derived))
- for i := range out {
- for j, cand := range derived {
- if used[j] {
- continue
- }
- if !candidatesOverlap(out[i], cand) {
- continue
- }
- MergeCandidateEvidence(&out[i], cand)
- used[j] = true
- }
- }
- for j, cand := range derived {
- if used[j] {
- continue
- }
- out = append(out, cand)
- }
- for i := range out {
- RefreshCandidateEvidenceState(&out[i])
- }
- return out
- }
-
- func candidatesOverlap(a Candidate, b Candidate) bool {
- spanA := candidateSpanHz(a)
- spanB := candidateSpanHz(b)
- if spanA <= 0 {
- spanA = 25000
- }
- if spanB <= 0 {
- spanB = 25000
- }
- guard := 0.0
- if binA, binB := candidateBinHz(a), candidateBinHz(b); binA > 0 || binB > 0 {
- guard = 0.5 * math.Max(binA, binB)
- }
- leftA := a.CenterHz - spanA/2 - guard
- rightA := a.CenterHz + spanA/2 + guard
- leftB := b.CenterHz - spanB/2 - guard
- rightB := b.CenterHz + spanB/2 + guard
- return leftA <= rightB && leftB <= rightA
- }
-
- func candidateSpanHz(candidate Candidate) float64 {
- if candidate.BandwidthHz > 0 {
- return candidate.BandwidthHz
- }
- if candidate.LastBin < candidate.FirstBin {
- return 0
- }
- binHz := candidateBinHz(candidate)
- if binHz <= 0 {
- return 0
- }
- return float64(candidate.LastBin-candidate.FirstBin+1) * binHz
- }
-
- func candidateBinHz(candidate Candidate) float64 {
- for _, ev := range candidate.Evidence {
- if IsPresentationLevel(ev.Level) || !IsDetectionLevel(ev.Level) {
- continue
- }
- if ev.Level.BinHz > 0 {
- return ev.Level.BinHz
- }
- if ev.Level.SampleRate > 0 && ev.Level.FFTSize > 0 {
- return float64(ev.Level.SampleRate) / float64(ev.Level.FFTSize)
- }
- }
- return 0
- }
|