Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

139 строки
3.3KB

  1. package main
  2. import (
  3. "log"
  4. "sort"
  5. "strconv"
  6. "time"
  7. "sdr-visual-suite/internal/config"
  8. "sdr-visual-suite/internal/demod/gpudemod"
  9. "sdr-visual-suite/internal/detector"
  10. "sdr-visual-suite/internal/dsp"
  11. )
  12. func mustParseDuration(raw string, fallback time.Duration) time.Duration {
  13. if raw == "" {
  14. return fallback
  15. }
  16. if d, err := time.ParseDuration(raw); err == nil {
  17. return d
  18. }
  19. return fallback
  20. }
  21. func buildDecoderMap(cfg config.Config) map[string]string {
  22. out := map[string]string{}
  23. if cfg.Decoder.FT8Cmd != "" {
  24. out["FT8"] = cfg.Decoder.FT8Cmd
  25. }
  26. if cfg.Decoder.WSPRCmd != "" {
  27. out["WSPR"] = cfg.Decoder.WSPRCmd
  28. }
  29. if cfg.Decoder.DMRCmd != "" {
  30. out["DMR"] = cfg.Decoder.DMRCmd
  31. }
  32. if cfg.Decoder.DStarCmd != "" {
  33. out["D-STAR"] = cfg.Decoder.DStarCmd
  34. }
  35. if cfg.Decoder.FSKCmd != "" {
  36. out["FSK"] = cfg.Decoder.FSKCmd
  37. }
  38. if cfg.Decoder.PSKCmd != "" {
  39. out["PSK"] = cfg.Decoder.PSKCmd
  40. }
  41. return out
  42. }
  43. func decoderKeys(cfg config.Config) []string {
  44. m := buildDecoderMap(cfg)
  45. keys := make([]string, 0, len(m))
  46. for k := range m {
  47. keys = append(keys, k)
  48. }
  49. sort.Strings(keys)
  50. return keys
  51. }
  52. func extractSignalIQ(iq []complex64, sampleRate int, centerHz float64, sigHz float64, bwHz float64) []complex64 {
  53. if len(iq) == 0 || sampleRate <= 0 {
  54. return nil
  55. }
  56. results := extractSignalIQBatch(iq, sampleRate, centerHz, []detector.Signal{{CenterHz: sigHz, BWHz: bwHz}})
  57. if len(results) == 0 {
  58. return nil
  59. }
  60. return results[0]
  61. }
  62. func extractSignalIQBatch(iq []complex64, sampleRate int, centerHz float64, signals []detector.Signal) [][]complex64 {
  63. out := make([][]complex64, len(signals))
  64. if len(iq) == 0 || sampleRate <= 0 || len(signals) == 0 {
  65. return out
  66. }
  67. decimTarget := 200000
  68. if decimTarget <= 0 {
  69. decimTarget = sampleRate
  70. }
  71. var runner *gpudemod.BatchRunner
  72. if gpudemod.Available() {
  73. if gpuRunner, err := gpudemod.NewBatchRunner(len(iq), sampleRate); err == nil {
  74. runner = gpuRunner
  75. defer runner.Close()
  76. }
  77. }
  78. if runner != nil {
  79. jobs := make([]gpudemod.ExtractJob, len(signals))
  80. for i, sig := range signals {
  81. jobs[i] = gpudemod.ExtractJob{OffsetHz: sig.CenterHz - centerHz, BW: sig.BWHz, OutRate: decimTarget}
  82. }
  83. if gpuOuts, _, err := runner.ShiftFilterDecimateBatch(iq, jobs); err == nil && len(gpuOuts) == len(signals) {
  84. log.Printf("gpudemod: batch extraction used for %d signals", len(signals))
  85. for i := range gpuOuts {
  86. out[i] = gpuOuts[i]
  87. }
  88. return out
  89. } else if err != nil {
  90. log.Printf("gpudemod: batch extraction failed for %d signals: %v", len(signals), err)
  91. }
  92. }
  93. for i, sig := range signals {
  94. offset := sig.CenterHz - centerHz
  95. shifted := dsp.FreqShift(iq, sampleRate, offset)
  96. cutoff := sig.BWHz / 2
  97. if cutoff < 200 {
  98. cutoff = 200
  99. }
  100. if cutoff > float64(sampleRate)/2-1 {
  101. cutoff = float64(sampleRate)/2 - 1
  102. }
  103. taps := dsp.LowpassFIR(cutoff, sampleRate, 101)
  104. filtered := dsp.ApplyFIR(shifted, taps)
  105. decim := sampleRate / decimTarget
  106. if decim < 1 {
  107. decim = 1
  108. }
  109. out[i] = dsp.Decimate(filtered, decim)
  110. }
  111. return out
  112. }
  113. func parseSince(raw string) (time.Time, error) {
  114. if raw == "" {
  115. return time.Time{}, nil
  116. }
  117. if ms, err := strconv.ParseInt(raw, 10, 64); err == nil {
  118. if ms > 1e12 {
  119. return time.UnixMilli(ms), nil
  120. }
  121. return time.Unix(ms, 0), nil
  122. }
  123. if t, err := time.Parse(time.RFC3339Nano, raw); err == nil {
  124. return t, nil
  125. }
  126. return time.Parse(time.RFC3339, raw)
  127. }