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

101 строка
2.2KB

  1. package rds
  2. import (
  3. "math"
  4. )
  5. // Decoder performs a simple RDS baseband decode (BPSK, 1187.5 bps).
  6. type Decoder struct {
  7. lastPS string
  8. lastPI uint16
  9. }
  10. type Result struct {
  11. PI uint16 `json:"pi"`
  12. PS string `json:"ps"`
  13. }
  14. // Decode takes baseband samples at ~2400 Hz and attempts to extract PI/PS.
  15. func (d *Decoder) Decode(base []float32, sampleRate int) Result {
  16. if len(base) == 0 || sampleRate <= 0 {
  17. return Result{}
  18. }
  19. // crude clock: 1187.5 bps
  20. baud := 1187.5
  21. spb := float64(sampleRate) / baud
  22. // carrier recovery simplified: assume baseband already mixed
  23. bits := make([]int, 0, int(float64(len(base))/spb))
  24. phase := 0.0
  25. for i := 0; i < len(base); i++ {
  26. phase += 1.0
  27. if phase >= spb {
  28. phase -= spb
  29. // slice decision
  30. v := base[i]
  31. if v >= 0 {
  32. bits = append(bits, 1)
  33. } else {
  34. bits = append(bits, 0)
  35. }
  36. }
  37. }
  38. // parse groups (very naive): look for 16-bit blocks and decode group type 0A for PS
  39. // This is a placeholder: real RDS needs CRC and block sync.
  40. if len(bits) < 104 {
  41. return Result{PI: d.lastPI, PS: d.lastPS}
  42. }
  43. // best effort: just map first 16 bits to PI and next 8 chars from consecutive bytes
  44. pi := bitsToU16(bits[0:16])
  45. ps := decodePS(bits)
  46. if pi != 0 {
  47. d.lastPI = pi
  48. }
  49. if ps != "" {
  50. d.lastPS = ps
  51. }
  52. return Result{PI: d.lastPI, PS: d.lastPS}
  53. }
  54. func bitsToU16(bits []int) uint16 {
  55. var v uint16
  56. for _, b := range bits {
  57. v = (v << 1) | uint16(b&1)
  58. }
  59. return v
  60. }
  61. func decodePS(bits []int) string {
  62. // naive: take next 64 bits as 8 ASCII chars
  63. if len(bits) < 16+64 {
  64. return ""
  65. }
  66. start := 16
  67. out := make([]rune, 0, 8)
  68. for i := 0; i < 8; i++ {
  69. var c byte
  70. for j := 0; j < 8; j++ {
  71. c = (c << 1) | byte(bits[start+i*8+j]&1)
  72. }
  73. if c < 32 || c > 126 {
  74. c = ' '
  75. }
  76. out = append(out, rune(c))
  77. }
  78. // trim
  79. for len(out) > 0 && out[len(out)-1] == ' ' {
  80. out = out[:len(out)-1]
  81. }
  82. return string(out)
  83. }
  84. // BPSKCostas returns a simple carrier-locked version of baseband (placeholder).
  85. func BPSKCostas(in []float32) []float32 {
  86. out := make([]float32, len(in))
  87. var phase float64
  88. for i, v := range in {
  89. phase += 0.0001 * float64(v) * math.Sin(phase)
  90. out[i] = float32(float64(v) * math.Cos(phase))
  91. }
  92. return out
  93. }