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.

108 wiersze
3.5KB

  1. package cfar
  2. import (
  3. "math"
  4. "testing"
  5. )
  6. func makeSpectrum(n int, noiseDb float64, signals [][2]int, sigDb float64) []float64 {
  7. s := make([]float64, n)
  8. for i := range s {
  9. s[i] = noiseDb
  10. }
  11. for _, sig := range signals {
  12. for i := sig[0]; i <= sig[1] && i < n; i++ {
  13. s[i] = sigDb
  14. }
  15. }
  16. return s
  17. }
  18. func TestAllVariantsDetectSignal(t *testing.T) {
  19. spec := makeSpectrum(1024, -100, [][2]int{{500, 510}}, -20)
  20. for _, mode := range []Mode{ModeCA, ModeOS, ModeGOSCA, ModeCASO} {
  21. c := New(Config{Mode: mode, GuardCells: 2, TrainCells: 16, Rank: 24, ScaleDb: 6, WrapAround: true})
  22. if c == nil {
  23. t.Fatalf("%s: nil", mode)
  24. }
  25. th := c.Thresholds(spec)
  26. if len(th) != 1024 {
  27. t.Fatalf("%s: len=%d", mode, len(th))
  28. }
  29. if spec[505] < th[505] {
  30. t.Fatalf("%s: signal not above threshold", mode)
  31. }
  32. if spec[200] >= th[200] {
  33. t.Fatalf("%s: noise above threshold", mode)
  34. }
  35. }
  36. }
  37. func TestWrapAroundEdges(t *testing.T) {
  38. spec := makeSpectrum(256, -100, [][2]int{{0, 5}}, -20)
  39. c := New(Config{Mode: ModeCA, GuardCells: 2, TrainCells: 8, ScaleDb: 6, WrapAround: true})
  40. th := c.Thresholds(spec)
  41. if th[0] <= -200 || th[0] > 0 {
  42. t.Fatalf("edge threshold bad: %v", th[0])
  43. }
  44. if th[255] <= -200 || th[255] > 0 {
  45. t.Fatalf("wrap threshold bad: %v", th[255])
  46. }
  47. }
  48. func TestGOSCAMaskingProtection(t *testing.T) {
  49. spec := makeSpectrum(1024, -100, [][2]int{{500, 510}, {530, 540}}, -20)
  50. cGosca := New(Config{Mode: ModeGOSCA, GuardCells: 2, TrainCells: 16, ScaleDb: 6, WrapAround: true})
  51. cCA := New(Config{Mode: ModeCA, GuardCells: 2, TrainCells: 16, ScaleDb: 6, WrapAround: true})
  52. thG := cGosca.Thresholds(spec)
  53. thC := cCA.Thresholds(spec)
  54. midBin := 520
  55. if thG[midBin] < thC[midBin] {
  56. t.Logf("GOSCA=%f CA=%f at bin %d — GOSCA correctly higher", thG[midBin], thC[midBin], midBin)
  57. }
  58. }
  59. func TestCellAveragingUsesLinearPower(t *testing.T) {
  60. spec := []float64{-100, -100, -100, -80, -100, -90, -100, -100, -100}
  61. cfg := Config{GuardCells: 0, TrainCells: 2, ScaleDb: 0, WrapAround: false}
  62. ca := New(Config{Mode: ModeCA, GuardCells: cfg.GuardCells, TrainCells: cfg.TrainCells, ScaleDb: cfg.ScaleDb, WrapAround: cfg.WrapAround})
  63. gosca := New(Config{Mode: ModeGOSCA, GuardCells: cfg.GuardCells, TrainCells: cfg.TrainCells, ScaleDb: cfg.ScaleDb, WrapAround: cfg.WrapAround})
  64. caso := New(Config{Mode: ModeCASO, GuardCells: cfg.GuardCells, TrainCells: cfg.TrainCells, ScaleDb: cfg.ScaleDb, WrapAround: cfg.WrapAround})
  65. mid := 5
  66. caTh := ca.Thresholds(spec)[mid]
  67. goscaTh := gosca.Thresholds(spec)[mid]
  68. casoTh := caso.Thresholds(spec)[mid]
  69. dbApproxCA := (-80.0 + -90.0 + -100.0 + -100.0) / 4.0
  70. dbApproxGOSCA := -85.0
  71. dbApproxCASO := -100.0
  72. if math.Abs(caTh-dbApproxCA) < 1.0 {
  73. t.Fatalf("CA threshold still looks like dB averaging: got %v approx %v", caTh, dbApproxCA)
  74. }
  75. if math.Abs(goscaTh-dbApproxGOSCA) < 1.0 {
  76. t.Fatalf("GOSCA threshold still looks like dB averaging: got %v approx %v", goscaTh, dbApproxGOSCA)
  77. }
  78. if math.Abs(casoTh-dbApproxCASO) < 1.0 {
  79. t.Fatalf("CASO threshold still looks like dB averaging: got %v approx %v", casoTh, dbApproxCASO)
  80. }
  81. if !(goscaTh > caTh && caTh > casoTh) {
  82. t.Fatalf("unexpected ordering: GOSCA=%v CA=%v CASO=%v", goscaTh, caTh, casoTh)
  83. }
  84. }
  85. func BenchmarkCFAR(b *testing.B) {
  86. spec := makeSpectrum(2048, -100, [][2]int{{500, 510}, {1000, 1020}}, -20)
  87. for _, mode := range []Mode{ModeCA, ModeOS, ModeGOSCA, ModeCASO} {
  88. cfg := Config{Mode: mode, GuardCells: 2, TrainCells: 16, Rank: 24, ScaleDb: 6, WrapAround: true}
  89. c := New(cfg)
  90. b.Run(string(mode), func(b *testing.B) {
  91. for i := 0; i < b.N; i++ {
  92. c.Thresholds(spec)
  93. }
  94. })
  95. }
  96. }