Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

161 wiersze
4.7KB

  1. package pipeline
  2. import (
  3. "testing"
  4. "sdr-wideband-suite/internal/config"
  5. )
  6. func TestNormalizeMonitorWindows(t *testing.T) {
  7. goals := config.PipelineGoalConfig{
  8. MonitorWindows: []config.MonitorWindow{
  9. {Label: "a", StartHz: 100, EndHz: 200},
  10. {Label: "b", CenterHz: 500, SpanHz: 50},
  11. },
  12. }
  13. windows := NormalizeMonitorWindows(goals, 0)
  14. if len(windows) != 2 {
  15. t.Fatalf("expected 2 windows, got %d", len(windows))
  16. }
  17. if windows[0].StartHz != 100 || windows[0].EndHz != 200 {
  18. t.Fatalf("unexpected first window: %+v", windows[0])
  19. }
  20. if windows[1].CenterHz != 500 || windows[1].SpanHz != 50 {
  21. t.Fatalf("unexpected second window: %+v", windows[1])
  22. }
  23. }
  24. func TestMonitorWindowBounds(t *testing.T) {
  25. windows := []MonitorWindow{
  26. {StartHz: 100, EndHz: 200},
  27. {StartHz: 50, EndHz: 90},
  28. {StartHz: 500, EndHz: 800},
  29. }
  30. start, end, ok := MonitorWindowBounds(windows)
  31. if !ok {
  32. t.Fatalf("expected bounds")
  33. }
  34. if start != 50 || end != 800 {
  35. t.Fatalf("unexpected bounds: %.0f %.0f", start, end)
  36. }
  37. }
  38. func TestCandidateInMonitorWindows(t *testing.T) {
  39. policy := Policy{
  40. MonitorWindows: []MonitorWindow{
  41. {StartHz: 100, EndHz: 200},
  42. {StartHz: 300, EndHz: 400},
  43. },
  44. }
  45. if !candidateInMonitor(policy, Candidate{CenterHz: 150}) {
  46. t.Fatalf("expected candidate inside window")
  47. }
  48. if candidateInMonitor(policy, Candidate{CenterHz: 250}) {
  49. t.Fatalf("expected candidate outside windows")
  50. }
  51. }
  52. func TestMonitorWindowMatchesOverlap(t *testing.T) {
  53. policy := Policy{
  54. MonitorWindows: finalizeMonitorWindows([]MonitorWindow{
  55. {Label: "wide", StartHz: 100, EndHz: 300, SpanHz: 200},
  56. {Label: "narrow", StartHz: 150, EndHz: 220, SpanHz: 70},
  57. }),
  58. }
  59. matches := MonitorWindowMatches(policy, Candidate{CenterHz: 180, BandwidthHz: 20})
  60. if len(matches) != 2 {
  61. t.Fatalf("expected 2 matches, got %d", len(matches))
  62. }
  63. if matches[0].Index == matches[1].Index {
  64. t.Fatalf("expected distinct window matches")
  65. }
  66. }
  67. func TestMonitorWindowBiasPrefersNarrowWindow(t *testing.T) {
  68. goals := config.PipelineGoalConfig{
  69. MonitorWindows: []config.MonitorWindow{
  70. {Label: "wide", StartHz: 100, EndHz: 300},
  71. {Label: "narrow", StartHz: 150, EndHz: 200},
  72. },
  73. }
  74. policy := Policy{MonitorWindows: NormalizeMonitorWindows(goals, 0)}
  75. bias, detail := MonitorWindowBias(policy, Candidate{CenterHz: 175, BandwidthHz: 10})
  76. if detail == nil {
  77. t.Fatalf("expected monitor match detail")
  78. }
  79. if detail.Label != "narrow" {
  80. t.Fatalf("expected narrow window to be preferred, got %q", detail.Label)
  81. }
  82. if bias <= 0 {
  83. t.Fatalf("expected positive bias, got %.3f", bias)
  84. }
  85. }
  86. func TestMonitorWindowPriorityBiasUsesPriority(t *testing.T) {
  87. goals := config.PipelineGoalConfig{
  88. MonitorWindows: []config.MonitorWindow{
  89. {Label: "low", StartHz: 100, EndHz: 200, Priority: -1},
  90. {Label: "high", StartHz: 300, EndHz: 400, Priority: 1},
  91. },
  92. }
  93. policy := Policy{MonitorWindows: NormalizeMonitorWindows(goals, 0)}
  94. var low, high *MonitorWindow
  95. for i := range policy.MonitorWindows {
  96. win := &policy.MonitorWindows[i]
  97. switch win.Label {
  98. case "low":
  99. low = win
  100. case "high":
  101. high = win
  102. }
  103. }
  104. if low == nil || high == nil {
  105. t.Fatalf("expected both windows")
  106. }
  107. if low.Priority != -1 || high.Priority != 1 {
  108. t.Fatalf("unexpected priority values: low=%.2f high=%.2f", low.Priority, high.Priority)
  109. }
  110. if high.PriorityBias <= low.PriorityBias {
  111. t.Fatalf("expected high priority bias > low priority bias, got %.3f vs %.3f", high.PriorityBias, low.PriorityBias)
  112. }
  113. }
  114. func TestMonitorWindowZoneBiases(t *testing.T) {
  115. goals := config.PipelineGoalConfig{
  116. MonitorWindows: []config.MonitorWindow{
  117. {Label: "record", StartHz: 100, EndHz: 200, Zone: "record"},
  118. {Label: "decode", StartHz: 300, EndHz: 400, Zone: "decode"},
  119. },
  120. }
  121. policy := Policy{MonitorWindows: NormalizeMonitorWindows(goals, 0)}
  122. if len(policy.MonitorWindows) != 2 {
  123. t.Fatalf("expected 2 windows, got %d", len(policy.MonitorWindows))
  124. }
  125. var recordWin, decodeWin *MonitorWindow
  126. for i := range policy.MonitorWindows {
  127. win := &policy.MonitorWindows[i]
  128. switch win.Label {
  129. case "record":
  130. recordWin = win
  131. case "decode":
  132. decodeWin = win
  133. }
  134. }
  135. if recordWin == nil || decodeWin == nil {
  136. t.Fatalf("expected both window entries")
  137. }
  138. if recordWin.RecordBias <= 0 || recordWin.DecodeBias != 0 {
  139. t.Fatalf("unexpected record window biases: %+v", recordWin)
  140. }
  141. if decodeWin.DecodeBias <= 0 || decodeWin.RecordBias != 0 {
  142. t.Fatalf("unexpected decode window biases: %+v", decodeWin)
  143. }
  144. matches := MonitorWindowMatches(policy, Candidate{CenterHz: 150, BandwidthHz: 0})
  145. if len(matches) != 1 {
  146. t.Fatalf("expected 1 match, got %d", len(matches))
  147. }
  148. if matches[0].RecordBias <= 0 || matches[0].DecodeBias != 0 {
  149. t.Fatalf("unexpected match biases: %+v", matches[0])
  150. }
  151. }