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.

87 líneas
2.6KB

  1. package main
  2. import (
  3. "testing"
  4. "sdr-wideband-suite/internal/config"
  5. "sdr-wideband-suite/internal/detector"
  6. fftutil "sdr-wideband-suite/internal/fft"
  7. "sdr-wideband-suite/internal/pipeline"
  8. )
  9. func TestNewDSPRuntime(t *testing.T) {
  10. cfg := config.Default()
  11. det := detector.New(cfg.Detector, cfg.SampleRate, cfg.FFTSize)
  12. window := fftutil.Hann(cfg.FFTSize)
  13. rt := newDSPRuntime(cfg, det, window, &gpuStatus{})
  14. if rt == nil {
  15. t.Fatalf("runtime is nil")
  16. }
  17. if rt.plan == nil {
  18. t.Fatalf("fft plan is nil")
  19. }
  20. if rt.cfg.FFTSize != cfg.FFTSize {
  21. t.Fatalf("unexpected fft size: %d", rt.cfg.FFTSize)
  22. }
  23. }
  24. func TestScheduledCandidateSelectionUsesPolicy(t *testing.T) {
  25. cfg := config.Default()
  26. cfg.Resources.MaxRefinementJobs = 1
  27. cfg.Refinement.MinCandidateSNRDb = 6
  28. policy := pipeline.PolicyFromConfig(cfg)
  29. got := pipeline.ScheduleCandidates([]pipeline.Candidate{
  30. {ID: 1, SNRDb: 3, BandwidthHz: 1000},
  31. {ID: 2, SNRDb: 12, BandwidthHz: 5000},
  32. {ID: 3, SNRDb: 8, BandwidthHz: 7000},
  33. }, policy)
  34. if len(got) != 2 {
  35. t.Fatalf("expected 2 scheduled candidates after gating, got %d", len(got))
  36. }
  37. if got[0].Candidate.ID != 2 {
  38. t.Fatalf("expected highest priority candidate, got %d", got[0].Candidate.ID)
  39. }
  40. }
  41. func TestSurveillanceLevelsRespectStrategy(t *testing.T) {
  42. cfg := config.Default()
  43. det := detector.New(cfg.Detector, cfg.SampleRate, cfg.FFTSize)
  44. window := fftutil.Hann(cfg.FFTSize)
  45. rt := newDSPRuntime(cfg, det, window, &gpuStatus{})
  46. policy := pipeline.Policy{SurveillanceStrategy: "single-resolution"}
  47. plan := rt.buildSurveillancePlan(policy)
  48. if len(plan.Levels) != 1 {
  49. t.Fatalf("expected single level for single-resolution, got %d", len(plan.Levels))
  50. }
  51. if plan.Levels[0].Role != pipeline.RoleSurveillancePrimary {
  52. t.Fatalf("expected primary role, got %q", plan.Levels[0].Role)
  53. }
  54. policy.SurveillanceStrategy = "multi-res"
  55. policy.Intent = "wideband-surveillance"
  56. plan = rt.buildSurveillancePlan(policy)
  57. if len(plan.Levels) != 2 {
  58. t.Fatalf("expected secondary level for multi-res, got %d", len(plan.Levels))
  59. }
  60. if plan.Levels[1].Decimation != 2 {
  61. t.Fatalf("expected decimation factor 2, got %d", plan.Levels[1].Decimation)
  62. }
  63. if plan.Levels[1].Role != pipeline.RoleSurveillanceDerived {
  64. t.Fatalf("expected derived role, got %q", plan.Levels[1].Role)
  65. }
  66. }
  67. func TestWindowSpanBounds(t *testing.T) {
  68. windows := []pipeline.RefinementWindow{
  69. {SpanHz: 8000},
  70. {SpanHz: 16000},
  71. {SpanHz: 12000},
  72. }
  73. minSpan, maxSpan, ok := windowSpanBounds(windows)
  74. if !ok {
  75. t.Fatalf("expected spans to be found")
  76. }
  77. if minSpan != 8000 || maxSpan != 16000 {
  78. t.Fatalf("unexpected span bounds: min %.0f max %.0f", minSpan, maxSpan)
  79. }
  80. }