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

164 行
4.7KB

  1. package config
  2. import (
  3. "os"
  4. "time"
  5. "gopkg.in/yaml.v3"
  6. )
  7. type Band struct {
  8. Name string `yaml:"name" json:"name"`
  9. StartHz float64 `yaml:"start_hz" json:"start_hz"`
  10. EndHz float64 `yaml:"end_hz" json:"end_hz"`
  11. }
  12. type DetectorConfig struct {
  13. ThresholdDb float64 `yaml:"threshold_db" json:"threshold_db"`
  14. MinDurationMs int `yaml:"min_duration_ms" json:"min_duration_ms"`
  15. HoldMs int `yaml:"hold_ms" json:"hold_ms"`
  16. }
  17. type RecorderConfig struct {
  18. Enabled bool `yaml:"enabled" json:"enabled"`
  19. MinSNRDb float64 `yaml:"min_snr_db" json:"min_snr_db"`
  20. MinDuration string `yaml:"min_duration" json:"min_duration"`
  21. MaxDuration string `yaml:"max_duration" json:"max_duration"`
  22. PrerollMs int `yaml:"preroll_ms" json:"preroll_ms"`
  23. RecordIQ bool `yaml:"record_iq" json:"record_iq"`
  24. RecordAudio bool `yaml:"record_audio" json:"record_audio"`
  25. AutoDemod bool `yaml:"auto_demod" json:"auto_demod"`
  26. AutoDecode bool `yaml:"auto_decode" json:"auto_decode"`
  27. MaxDiskMB int `yaml:"max_disk_mb" json:"max_disk_mb"`
  28. OutputDir string `yaml:"output_dir" json:"output_dir"`
  29. ClassFilter []string `yaml:"class_filter" json:"class_filter"`
  30. RingSeconds int `yaml:"ring_seconds" json:"ring_seconds"`
  31. }
  32. type DecoderConfig struct {
  33. FT8Cmd string `yaml:"ft8_cmd" json:"ft8_cmd"`
  34. WSPRCmd string `yaml:"wspr_cmd" json:"wspr_cmd"`
  35. DMRCmd string `yaml:"dmr_cmd" json:"dmr_cmd"`
  36. DStarCmd string `yaml:"dstar_cmd" json:"dstar_cmd"`
  37. FSKCmd string `yaml:"fsk_cmd" json:"fsk_cmd"`
  38. PSKCmd string `yaml:"psk_cmd" json:"psk_cmd"`
  39. }
  40. type Config struct {
  41. Bands []Band `yaml:"bands" json:"bands"`
  42. CenterHz float64 `yaml:"center_hz" json:"center_hz"`
  43. SampleRate int `yaml:"sample_rate" json:"sample_rate"`
  44. FFTSize int `yaml:"fft_size" json:"fft_size"`
  45. GainDb float64 `yaml:"gain_db" json:"gain_db"`
  46. TunerBwKHz int `yaml:"tuner_bw_khz" json:"tuner_bw_khz"`
  47. UseGPUFFT bool `yaml:"use_gpu_fft" json:"use_gpu_fft"`
  48. AGC bool `yaml:"agc" json:"agc"`
  49. DCBlock bool `yaml:"dc_block" json:"dc_block"`
  50. IQBalance bool `yaml:"iq_balance" json:"iq_balance"`
  51. Detector DetectorConfig `yaml:"detector" json:"detector"`
  52. Recorder RecorderConfig `yaml:"recorder" json:"recorder"`
  53. Decoder DecoderConfig `yaml:"decoder" json:"decoder"`
  54. WebAddr string `yaml:"web_addr" json:"web_addr"`
  55. EventPath string `yaml:"event_path" json:"event_path"`
  56. FrameRate int `yaml:"frame_rate" json:"frame_rate"`
  57. WaterfallLines int `yaml:"waterfall_lines" json:"waterfall_lines"`
  58. WebRoot string `yaml:"web_root" json:"web_root"`
  59. }
  60. func Default() Config {
  61. return Config{
  62. Bands: []Band{
  63. {Name: "example", StartHz: 99.5e6, EndHz: 100.5e6},
  64. },
  65. CenterHz: 100.0e6,
  66. SampleRate: 2_048_000,
  67. FFTSize: 2048,
  68. GainDb: 30,
  69. TunerBwKHz: 1536,
  70. UseGPUFFT: false,
  71. AGC: false,
  72. DCBlock: false,
  73. IQBalance: false,
  74. Detector: DetectorConfig{ThresholdDb: -20, MinDurationMs: 250, HoldMs: 500},
  75. Recorder: RecorderConfig{
  76. Enabled: false,
  77. MinSNRDb: 10,
  78. MinDuration: "1s",
  79. MaxDuration: "300s",
  80. PrerollMs: 500,
  81. RecordIQ: true,
  82. RecordAudio: false,
  83. AutoDemod: true,
  84. AutoDecode: false,
  85. MaxDiskMB: 0,
  86. OutputDir: "data/recordings",
  87. RingSeconds: 8,
  88. },
  89. Decoder: DecoderConfig{},
  90. WebAddr: ":8080",
  91. EventPath: "data/events.jsonl",
  92. FrameRate: 15,
  93. WaterfallLines: 200,
  94. WebRoot: "web",
  95. }
  96. }
  97. func Load(path string) (Config, error) {
  98. cfg := Default()
  99. b, err := os.ReadFile(path)
  100. if err != nil {
  101. return cfg, err
  102. }
  103. if err := yaml.Unmarshal(b, &cfg); err != nil {
  104. return cfg, err
  105. }
  106. if cfg.Detector.MinDurationMs <= 0 {
  107. cfg.Detector.MinDurationMs = 250
  108. }
  109. if cfg.Detector.HoldMs <= 0 {
  110. cfg.Detector.HoldMs = 500
  111. }
  112. if cfg.FrameRate <= 0 {
  113. cfg.FrameRate = 15
  114. }
  115. if cfg.WaterfallLines <= 0 {
  116. cfg.WaterfallLines = 200
  117. }
  118. if cfg.WebRoot == "" {
  119. cfg.WebRoot = "web"
  120. }
  121. if cfg.WebAddr == "" {
  122. cfg.WebAddr = ":8080"
  123. }
  124. if cfg.EventPath == "" {
  125. cfg.EventPath = "data/events.jsonl"
  126. }
  127. if cfg.SampleRate <= 0 {
  128. cfg.SampleRate = 2_048_000
  129. }
  130. if cfg.FFTSize <= 0 {
  131. cfg.FFTSize = 2048
  132. }
  133. if cfg.TunerBwKHz <= 0 {
  134. cfg.TunerBwKHz = 1536
  135. }
  136. if cfg.CenterHz == 0 {
  137. cfg.CenterHz = 100.0e6
  138. }
  139. if cfg.Recorder.OutputDir == "" {
  140. cfg.Recorder.OutputDir = "data/recordings"
  141. }
  142. if cfg.Recorder.RingSeconds <= 0 {
  143. cfg.Recorder.RingSeconds = 8
  144. }
  145. return cfg, nil
  146. }
  147. func (c Config) FrameInterval() time.Duration {
  148. fps := c.FrameRate
  149. if fps <= 0 {
  150. fps = 15
  151. }
  152. return time.Second / time.Duration(fps)
  153. }