Wideband autonomous SDR analysis engine forked from sdr-visual-suite
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

156 satır
3.6KB

  1. package main
  2. import (
  3. "sort"
  4. "time"
  5. "sdr-wideband-suite/internal/pipeline"
  6. )
  7. type decisionQueueStats struct {
  8. RecordQueued int `json:"record_queued"`
  9. DecodeQueued int `json:"decode_queued"`
  10. RecordSelected int `json:"record_selected"`
  11. DecodeSelected int `json:"decode_selected"`
  12. RecordOldestS float64 `json:"record_oldest_sec"`
  13. DecodeOldestS float64 `json:"decode_oldest_sec"`
  14. }
  15. type queuedDecision struct {
  16. ID int64
  17. SNRDb float64
  18. FirstSeen time.Time
  19. LastSeen time.Time
  20. }
  21. type decisionQueues struct {
  22. record map[int64]*queuedDecision
  23. decode map[int64]*queuedDecision
  24. }
  25. func newDecisionQueues() *decisionQueues {
  26. return &decisionQueues{record: map[int64]*queuedDecision{}, decode: map[int64]*queuedDecision{}}
  27. }
  28. func (dq *decisionQueues) Apply(decisions []pipeline.SignalDecision, maxRecord int, maxDecode int, now time.Time) decisionQueueStats {
  29. if dq == nil {
  30. return decisionQueueStats{}
  31. }
  32. recSeen := map[int64]bool{}
  33. decSeen := map[int64]bool{}
  34. for i := range decisions {
  35. id := decisions[i].Candidate.ID
  36. if id == 0 {
  37. continue
  38. }
  39. if decisions[i].ShouldRecord {
  40. qd := dq.record[id]
  41. if qd == nil {
  42. qd = &queuedDecision{ID: id, FirstSeen: now}
  43. dq.record[id] = qd
  44. }
  45. qd.SNRDb = decisions[i].Candidate.SNRDb
  46. qd.LastSeen = now
  47. recSeen[id] = true
  48. }
  49. if decisions[i].ShouldAutoDecode {
  50. qd := dq.decode[id]
  51. if qd == nil {
  52. qd = &queuedDecision{ID: id, FirstSeen: now}
  53. dq.decode[id] = qd
  54. }
  55. qd.SNRDb = decisions[i].Candidate.SNRDb
  56. qd.LastSeen = now
  57. decSeen[id] = true
  58. }
  59. }
  60. for id := range dq.record {
  61. if !recSeen[id] {
  62. delete(dq.record, id)
  63. }
  64. }
  65. for id := range dq.decode {
  66. if !decSeen[id] {
  67. delete(dq.decode, id)
  68. }
  69. }
  70. recSelected := selectQueued(dq.record, maxRecord, now)
  71. decSelected := selectQueued(dq.decode, maxDecode, now)
  72. stats := decisionQueueStats{
  73. RecordQueued: len(dq.record),
  74. DecodeQueued: len(dq.decode),
  75. RecordSelected: len(recSelected),
  76. DecodeSelected: len(decSelected),
  77. RecordOldestS: oldestAge(dq.record, now),
  78. DecodeOldestS: oldestAge(dq.decode, now),
  79. }
  80. for i := range decisions {
  81. id := decisions[i].Candidate.ID
  82. if decisions[i].ShouldRecord {
  83. if _, ok := recSelected[id]; !ok {
  84. decisions[i].ShouldRecord = false
  85. decisions[i].Reason = "queued: record budget"
  86. }
  87. }
  88. if decisions[i].ShouldAutoDecode {
  89. if _, ok := decSelected[id]; !ok {
  90. decisions[i].ShouldAutoDecode = false
  91. if decisions[i].Reason == "" {
  92. decisions[i].Reason = "queued: decode budget"
  93. }
  94. }
  95. }
  96. }
  97. return stats
  98. }
  99. func selectQueued(queue map[int64]*queuedDecision, max int, now time.Time) map[int64]struct{} {
  100. selected := map[int64]struct{}{}
  101. if len(queue) == 0 {
  102. return selected
  103. }
  104. type scored struct {
  105. id int64
  106. score float64
  107. }
  108. scoredList := make([]scored, 0, len(queue))
  109. for id, qd := range queue {
  110. age := now.Sub(qd.FirstSeen).Seconds()
  111. boost := age / 2.0
  112. if boost > 5 {
  113. boost = 5
  114. }
  115. scoredList = append(scoredList, scored{id: id, score: qd.SNRDb + boost})
  116. }
  117. sort.Slice(scoredList, func(i, j int) bool {
  118. return scoredList[i].score > scoredList[j].score
  119. })
  120. limit := max
  121. if limit <= 0 || limit > len(scoredList) {
  122. limit = len(scoredList)
  123. }
  124. for i := 0; i < limit; i++ {
  125. selected[scoredList[i].id] = struct{}{}
  126. }
  127. return selected
  128. }
  129. func oldestAge(queue map[int64]*queuedDecision, now time.Time) float64 {
  130. oldest := 0.0
  131. first := true
  132. for _, qd := range queue {
  133. age := now.Sub(qd.FirstSeen).Seconds()
  134. if first || age > oldest {
  135. oldest = age
  136. first = false
  137. }
  138. }
  139. if first {
  140. return 0
  141. }
  142. return oldest
  143. }