Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

62 wiersze
1.4KB

  1. package recorder
  2. import (
  3. "bytes"
  4. "errors"
  5. "time"
  6. "sdr-visual-suite/internal/demod"
  7. "sdr-visual-suite/internal/dsp"
  8. )
  9. // DemodLive demodulates a recent window and returns WAV bytes.
  10. func (m *Manager) DemodLive(centerHz float64, bw float64, mode string, seconds int) ([]byte, int, error) {
  11. if m == nil || m.ring == nil {
  12. return nil, 0, errors.New("recorder not ready")
  13. }
  14. if seconds <= 0 {
  15. seconds = 2
  16. }
  17. end := time.Now()
  18. start := end.Add(-time.Duration(seconds) * time.Second)
  19. segment := m.ring.Slice(start, end)
  20. if len(segment) == 0 {
  21. return nil, 0, errors.New("no iq in ring")
  22. }
  23. name := mode
  24. if name == "" {
  25. name = "NFM"
  26. }
  27. switch name {
  28. case "AM", "NFM", "WFM", "WFM_STEREO", "USB", "LSB", "CW":
  29. default:
  30. name = "NFM"
  31. }
  32. d := demod.Get(name)
  33. if d == nil {
  34. return nil, 0, errors.New("demodulator not found")
  35. }
  36. offset := centerHz - m.centerHz
  37. shifted := dsp.FreqShift(segment, m.sampleRate, offset)
  38. if bw <= 0 {
  39. bw = 12000
  40. }
  41. cutoff := bw / 2
  42. if cutoff < 200 {
  43. cutoff = 200
  44. }
  45. taps := dsp.LowpassFIR(cutoff, m.sampleRate, 101)
  46. filtered := dsp.ApplyFIR(shifted, taps)
  47. decim := m.sampleRate / (d.OutputSampleRate() * 4)
  48. if decim < 1 {
  49. decim = 1
  50. }
  51. dec := dsp.Decimate(filtered, decim)
  52. audio := d.Demod(dec, m.sampleRate/decim)
  53. buf := &bytes.Buffer{}
  54. if err := writeWAVTo(buf, audio, d.OutputSampleRate(), d.Channels()); err != nil {
  55. return nil, 0, err
  56. }
  57. return buf.Bytes(), d.OutputSampleRate(), nil
  58. }