Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

97 lignes
1.9KB

  1. package classifier
  2. import "math"
  3. func RuleClassify(feat Features) Classification {
  4. bw := feat.BW3dB
  5. flat := feat.SpectralFlat
  6. sym := feat.Symmetry
  7. p2a := feat.PeakToAvg
  8. best := ClassUnknown
  9. second := ClassUnknown
  10. conf := 0.3
  11. switch {
  12. case bw > 100e3:
  13. best = ClassWFM
  14. conf = 0.9
  15. case bw >= 6e3 && bw <= 16e3:
  16. best = ClassNFM
  17. conf = 0.8
  18. if flat > 0.7 {
  19. second = ClassNoise
  20. }
  21. // digital voice rough guesses
  22. if feat.InstFreqStd < 0.5 && feat.EnvVariance < 0.3 {
  23. second = ClassDMR
  24. }
  25. case bw >= 2000 && bw < 3000:
  26. // candidate for FT8
  27. if feat.EnvVariance < 0.5 && feat.InstFreqStd < 0.7 {
  28. best = ClassFT8
  29. conf = 0.55
  30. }
  31. case bw >= 150 && bw < 500:
  32. // candidate for WSPR
  33. if feat.EnvVariance < 0.4 && feat.InstFreqStd < 0.5 {
  34. best = ClassWSPR
  35. conf = 0.55
  36. }
  37. case bw >= 500 && bw < 3e3:
  38. if sym > 0.2 {
  39. best = ClassSSBUSB
  40. conf = 0.7
  41. } else if sym < -0.2 {
  42. best = ClassSSBLSB
  43. conf = 0.7
  44. } else if p2a > 3 && flat < 0.4 {
  45. best = ClassAM
  46. conf = 0.6
  47. } else if feat.InstFreqStd > 0.8 {
  48. best = ClassFSK
  49. conf = 0.5
  50. } else if feat.InstFreqStd < 0.3 {
  51. best = ClassPSK
  52. conf = 0.5
  53. }
  54. case bw < 150:
  55. best = ClassCW
  56. conf = 0.7
  57. }
  58. // noise hint
  59. if best == ClassUnknown && flat > 0.85 && bw > 2e3 {
  60. best = ClassNoise
  61. conf = 0.6
  62. }
  63. // edge-case: if symmetry is strong, second best opposite side
  64. if (best == ClassSSBUSB || best == ClassSSBLSB) && second == ClassUnknown {
  65. if best == ClassSSBUSB {
  66. second = ClassSSBLSB
  67. } else {
  68. second = ClassSSBUSB
  69. }
  70. }
  71. // slightly scale confidence by feature strength
  72. if best == ClassNFM || best == ClassWFM {
  73. conf = conf * (0.8 + 0.2*clamp01(1-flat))
  74. }
  75. if best == ClassAM {
  76. conf = conf * (0.7 + 0.3*clamp01(p2a/6.0))
  77. }
  78. if math.IsNaN(conf) || conf <= 0 {
  79. conf = 0.3
  80. }
  81. return Classification{
  82. ModType: best,
  83. Confidence: conf,
  84. BW3dB: bw,
  85. Features: feat,
  86. SecondBest: second,
  87. }
  88. }