您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

82 行
1.6KB

  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. case bw >= 2000 && bw < 3000:
  22. // candidate for FT8/WSPR (very rough): low env variance, narrow BW
  23. if feat.EnvVariance < 0.5 && feat.InstFreqStd < 0.7 {
  24. best = ClassUnknown
  25. second = ClassUnknown
  26. conf = 0.5
  27. }
  28. case bw >= 500 && bw < 3e3:
  29. if sym > 0.2 {
  30. best = ClassSSBUSB
  31. conf = 0.7
  32. } else if sym < -0.2 {
  33. best = ClassSSBLSB
  34. conf = 0.7
  35. } else if p2a > 3 && flat < 0.4 {
  36. best = ClassAM
  37. conf = 0.6
  38. }
  39. case bw < 500:
  40. best = ClassCW
  41. conf = 0.7
  42. }
  43. // noise hint
  44. if best == ClassUnknown && flat > 0.85 && bw > 2e3 {
  45. best = ClassNoise
  46. conf = 0.6
  47. }
  48. // edge-case: if symmetry is strong, second best opposite side
  49. if (best == ClassSSBUSB || best == ClassSSBLSB) && second == ClassUnknown {
  50. if best == ClassSSBUSB {
  51. second = ClassSSBLSB
  52. } else {
  53. second = ClassSSBUSB
  54. }
  55. }
  56. // slightly scale confidence by feature strength
  57. if best == ClassNFM || best == ClassWFM {
  58. conf = conf * (0.8 + 0.2*clamp01(1-flat))
  59. }
  60. if best == ClassAM {
  61. conf = conf * (0.7 + 0.3*clamp01(p2a/6.0))
  62. }
  63. if math.IsNaN(conf) || conf <= 0 {
  64. conf = 0.3
  65. }
  66. return Classification{
  67. ModType: best,
  68. Confidence: conf,
  69. BW3dB: bw,
  70. Features: feat,
  71. SecondBest: second,
  72. }
  73. }