Wideband autonomous SDR analysis engine forked from sdr-visual-suite
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

237 líneas
7.1KB

  1. package runtime
  2. import (
  3. "testing"
  4. "sdr-wideband-suite/internal/config"
  5. )
  6. func TestApplyConfigUpdate(t *testing.T) {
  7. cfg := config.Default()
  8. mgr := New(cfg)
  9. center := 7.2e6
  10. sampleRate := 1_024_000
  11. fftSize := 4096
  12. threshold := -35.0
  13. bw := 1536
  14. cfarMode := "OS"
  15. cfarWrap := true
  16. cfarGuard := 2
  17. cfarTrain := 12
  18. cfarRank := 18
  19. cfarScale := 5.5
  20. mode := "wideband-balanced"
  21. profile := "wideband-balanced"
  22. intent := "wideband-surveillance"
  23. monitorSpan := 500000.0
  24. signalPriorities := []string{"digital", "weak"}
  25. autoRecord := []string{"WFM"}
  26. autoDecode := []string{"FT8"}
  27. survFPS := 12
  28. displayBins := 1024
  29. displayFPS := 8
  30. maxRefJobs := 24
  31. minSpan := 4000.0
  32. maxSpan := 200000.0
  33. autoSpan := false
  34. maxDecode := 12
  35. decisionHold := 1500
  36. updated, err := mgr.ApplyConfig(ConfigUpdate{
  37. CenterHz: &center,
  38. SampleRate: &sampleRate,
  39. FFTSize: &fftSize,
  40. TunerBwKHz: &bw,
  41. Pipeline: &PipelineUpdate{
  42. Mode: &mode,
  43. Profile: &profile,
  44. Intent: &intent,
  45. MonitorSpanHz: &monitorSpan,
  46. SignalPriorities: &signalPriorities,
  47. AutoRecordClasses: &autoRecord,
  48. AutoDecodeClasses: &autoDecode,
  49. },
  50. Surveillance: &SurveillanceUpdate{FrameRate: &survFPS, DisplayBins: &displayBins, DisplayFPS: &displayFPS},
  51. Refinement: &RefinementUpdate{MinSpanHz: &minSpan, MaxSpanHz: &maxSpan, AutoSpan: &autoSpan},
  52. Resources: &ResourcesUpdate{MaxRefinementJobs: &maxRefJobs, MaxDecodeJobs: &maxDecode, DecisionHoldMs: &decisionHold},
  53. Detector: &DetectorUpdate{
  54. ThresholdDb: &threshold,
  55. CFARMode: &cfarMode,
  56. CFARWrapAround: &cfarWrap,
  57. CFARGuardCells: &cfarGuard,
  58. CFARTrainCells: &cfarTrain,
  59. CFARRank: &cfarRank,
  60. CFARScaleDb: &cfarScale,
  61. },
  62. })
  63. if err != nil {
  64. t.Fatalf("apply: %v", err)
  65. }
  66. if updated.CenterHz != center {
  67. t.Fatalf("center hz: %v", updated.CenterHz)
  68. }
  69. if updated.SampleRate != sampleRate {
  70. t.Fatalf("sample rate: %v", updated.SampleRate)
  71. }
  72. if updated.FFTSize != fftSize {
  73. t.Fatalf("fft size: %v", updated.FFTSize)
  74. }
  75. if updated.Surveillance.AnalysisFFTSize != fftSize {
  76. t.Fatalf("analysis fft size: %v", updated.Surveillance.AnalysisFFTSize)
  77. }
  78. if updated.Detector.ThresholdDb != threshold {
  79. t.Fatalf("threshold: %v", updated.Detector.ThresholdDb)
  80. }
  81. if updated.Detector.CFARMode != cfarMode {
  82. t.Fatalf("cfar mode: %v", updated.Detector.CFARMode)
  83. }
  84. if updated.Detector.CFARWrapAround != cfarWrap {
  85. t.Fatalf("cfar wrap: %v", updated.Detector.CFARWrapAround)
  86. }
  87. if updated.Detector.CFARGuardCells != cfarGuard {
  88. t.Fatalf("cfar guard: %v", updated.Detector.CFARGuardCells)
  89. }
  90. if updated.Detector.CFARTrainCells != cfarTrain {
  91. t.Fatalf("cfar train: %v", updated.Detector.CFARTrainCells)
  92. }
  93. if updated.Detector.CFARRank != cfarRank {
  94. t.Fatalf("cfar rank: %v", updated.Detector.CFARRank)
  95. }
  96. if updated.Detector.CFARScaleDb != cfarScale {
  97. t.Fatalf("cfar scale: %v", updated.Detector.CFARScaleDb)
  98. }
  99. if updated.TunerBwKHz != bw {
  100. t.Fatalf("tuner bw: %v", updated.TunerBwKHz)
  101. }
  102. if updated.Pipeline.Mode != mode {
  103. t.Fatalf("pipeline mode: %v", updated.Pipeline.Mode)
  104. }
  105. if updated.Pipeline.Goals.Intent != intent {
  106. t.Fatalf("pipeline intent: %v", updated.Pipeline.Goals.Intent)
  107. }
  108. if updated.Pipeline.Goals.MonitorSpanHz != monitorSpan {
  109. t.Fatalf("monitor span: %v", updated.Pipeline.Goals.MonitorSpanHz)
  110. }
  111. if len(updated.Pipeline.Goals.SignalPriorities) != len(signalPriorities) {
  112. t.Fatalf("signal priorities not applied")
  113. }
  114. if len(updated.Pipeline.Goals.AutoRecordClasses) != len(autoRecord) {
  115. t.Fatalf("auto record classes not applied")
  116. }
  117. if len(updated.Pipeline.Goals.AutoDecodeClasses) != len(autoDecode) {
  118. t.Fatalf("auto decode classes not applied")
  119. }
  120. if updated.Surveillance.FrameRate != survFPS || updated.FrameRate != survFPS {
  121. t.Fatalf("surveillance frame rate: %v / %v", updated.Surveillance.FrameRate, updated.FrameRate)
  122. }
  123. if updated.Resources.MaxRefinementJobs != maxRefJobs {
  124. t.Fatalf("max refinement jobs: %v", updated.Resources.MaxRefinementJobs)
  125. }
  126. if updated.Resources.MaxDecodeJobs != maxDecode {
  127. t.Fatalf("max decode jobs: %v", updated.Resources.MaxDecodeJobs)
  128. }
  129. if updated.Resources.DecisionHoldMs != decisionHold {
  130. t.Fatalf("decision hold: %v", updated.Resources.DecisionHoldMs)
  131. }
  132. if updated.Surveillance.DisplayBins != displayBins || updated.Surveillance.DisplayFPS != displayFPS {
  133. t.Fatalf("display settings not applied: bins=%d fps=%d", updated.Surveillance.DisplayBins, updated.Surveillance.DisplayFPS)
  134. }
  135. if updated.Refinement.MinSpanHz != minSpan || updated.Refinement.MaxSpanHz != maxSpan {
  136. t.Fatalf("refinement span not applied: %v / %v", updated.Refinement.MinSpanHz, updated.Refinement.MaxSpanHz)
  137. }
  138. if updated.Refinement.AutoSpan == nil || *updated.Refinement.AutoSpan != autoSpan {
  139. t.Fatalf("refinement auto span not applied")
  140. }
  141. }
  142. func TestApplyConfigRejectsInvalid(t *testing.T) {
  143. cfg := config.Default()
  144. {
  145. mgr := New(cfg)
  146. bad := 0
  147. if _, err := mgr.ApplyConfig(ConfigUpdate{SampleRate: &bad}); err == nil {
  148. t.Fatalf("expected error")
  149. }
  150. snap := mgr.Snapshot()
  151. if snap.SampleRate != cfg.SampleRate {
  152. t.Fatalf("sample rate changed on error")
  153. }
  154. }
  155. {
  156. mgr := New(cfg)
  157. badAlpha := -0.5
  158. if _, err := mgr.ApplyConfig(ConfigUpdate{Detector: &DetectorUpdate{EmaAlpha: &badAlpha}}); err == nil {
  159. t.Fatalf("expected ema_alpha error")
  160. }
  161. if mgr.Snapshot().Detector.EmaAlpha != cfg.Detector.EmaAlpha {
  162. t.Fatalf("ema_alpha changed on error")
  163. }
  164. }
  165. {
  166. mgr := New(cfg)
  167. badAlpha := 1.5
  168. if _, err := mgr.ApplyConfig(ConfigUpdate{Detector: &DetectorUpdate{EmaAlpha: &badAlpha}}); err == nil {
  169. t.Fatalf("expected ema_alpha upper bound error")
  170. }
  171. if mgr.Snapshot().Detector.EmaAlpha != cfg.Detector.EmaAlpha {
  172. t.Fatalf("ema_alpha changed on error")
  173. }
  174. }
  175. {
  176. mgr := New(cfg)
  177. badHyst := -1.0
  178. if _, err := mgr.ApplyConfig(ConfigUpdate{Detector: &DetectorUpdate{HysteresisDb: &badHyst}}); err == nil {
  179. t.Fatalf("expected hysteresis_db error")
  180. }
  181. if mgr.Snapshot().Detector.HysteresisDb != cfg.Detector.HysteresisDb {
  182. t.Fatalf("hysteresis_db changed on error")
  183. }
  184. }
  185. {
  186. mgr := New(cfg)
  187. badStable := 0
  188. if _, err := mgr.ApplyConfig(ConfigUpdate{Detector: &DetectorUpdate{MinStableFrames: &badStable}}); err == nil {
  189. t.Fatalf("expected min_stable_frames error")
  190. }
  191. if mgr.Snapshot().Detector.MinStableFrames != cfg.Detector.MinStableFrames {
  192. t.Fatalf("min_stable_frames changed on error")
  193. }
  194. }
  195. {
  196. mgr := New(cfg)
  197. badGap := -10
  198. if _, err := mgr.ApplyConfig(ConfigUpdate{Detector: &DetectorUpdate{GapToleranceMs: &badGap}}); err == nil {
  199. t.Fatalf("expected gap_tolerance_ms error")
  200. }
  201. if mgr.Snapshot().Detector.GapToleranceMs != cfg.Detector.GapToleranceMs {
  202. t.Fatalf("gap_tolerance_ms changed on error")
  203. }
  204. }
  205. }
  206. func TestApplySettings(t *testing.T) {
  207. cfg := config.Default()
  208. mgr := New(cfg)
  209. agc := true
  210. dc := true
  211. iq := true
  212. updated, err := mgr.ApplySettings(SettingsUpdate{
  213. AGC: &agc,
  214. DCBlock: &dc,
  215. IQBalance: &iq,
  216. })
  217. if err != nil {
  218. t.Fatalf("apply settings: %v", err)
  219. }
  220. if !updated.AGC || !updated.DCBlock || !updated.IQBalance {
  221. t.Fatalf("settings not applied: %+v", updated)
  222. }
  223. }