Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

255 рядки
7.7KB

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