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.

166 lignes
4.9KB

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