選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

300 行
6.6KB

  1. package rds
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. // Decoder performs RDS baseband decode with Costas loop carrier recovery
  7. // and Mueller & Muller symbol timing synchronization.
  8. type Decoder struct {
  9. ps [8]rune
  10. rt [64]rune
  11. lastPI uint16
  12. // Costas loop state (persistent across calls)
  13. costasPhase float64
  14. costasFreq float64
  15. // Symbol sync state
  16. syncMu float64
  17. // Diagnostic counters
  18. TotalDecodes int
  19. BlockAHits int
  20. GroupsFound int
  21. LastDiag string
  22. }
  23. type Result struct {
  24. PI uint16 `json:"pi"`
  25. PS string `json:"ps"`
  26. RT string `json:"rt"`
  27. }
  28. // Decode takes complex baseband samples at ~20kHz and extracts RDS data.
  29. func (d *Decoder) Decode(samples []complex64, sampleRate int) Result {
  30. if len(samples) < 104 || sampleRate <= 0 {
  31. return Result{PI: d.lastPI, PS: d.psString(), RT: d.rtString()}
  32. }
  33. d.TotalDecodes++
  34. sps := float64(sampleRate) / 1187.5 // samples per symbol
  35. // === Mueller & Muller symbol timing recovery ===
  36. // Reset state each call — accumulated samples have phase gaps between frames
  37. mu := sps / 2
  38. symbols := make([]complex64, 0, len(samples)/int(sps)+1)
  39. var prev, prevDecision complex64
  40. for mu < float64(len(samples)-1) {
  41. idx := int(mu)
  42. frac := mu - float64(idx)
  43. if idx+1 >= len(samples) {
  44. break
  45. }
  46. samp := complex64(complex(
  47. float64(real(samples[idx]))*(1-frac)+float64(real(samples[idx+1]))*frac,
  48. float64(imag(samples[idx]))*(1-frac)+float64(imag(samples[idx+1]))*frac,
  49. ))
  50. var decision complex64
  51. if real(samp) > 0 {
  52. decision = 1
  53. } else {
  54. decision = -1
  55. }
  56. if len(symbols) >= 2 {
  57. errR := float64(real(decision)-real(prevDecision))*float64(real(prev)) -
  58. float64(real(samp)-real(prev))*float64(real(prevDecision))
  59. mu += sps + 0.01*errR
  60. } else {
  61. mu += sps
  62. }
  63. prevDecision = decision
  64. prev = samp
  65. symbols = append(symbols, samp)
  66. }
  67. if len(symbols) < 26*4 {
  68. d.LastDiag = fmt.Sprintf("too few symbols: %d", len(symbols))
  69. return Result{PI: d.lastPI, PS: d.psString(), RT: d.rtString()}
  70. }
  71. // === Costas loop for fine frequency/phase synchronization ===
  72. // Reset each call — phase gaps between accumulated frames break continuity
  73. alpha := 0.132
  74. beta := alpha * alpha / 4.0
  75. phase := 0.0
  76. freq := 0.0
  77. synced := make([]complex64, len(symbols))
  78. for i, s := range symbols {
  79. // Multiply by exp(-j*phase) to de-rotate
  80. cosP := float32(math.Cos(phase))
  81. sinP := float32(math.Sin(phase))
  82. synced[i] = complex(
  83. real(s)*cosP+imag(s)*sinP,
  84. imag(s)*cosP-real(s)*sinP,
  85. )
  86. // BPSK phase error: sign(I) * Q
  87. var err float64
  88. if real(synced[i]) > 0 {
  89. err = float64(imag(synced[i]))
  90. } else {
  91. err = -float64(imag(synced[i]))
  92. }
  93. freq += beta * err
  94. phase += freq + alpha*err
  95. for phase > math.Pi {
  96. phase -= 2 * math.Pi
  97. }
  98. for phase < -math.Pi {
  99. phase += 2 * math.Pi
  100. }
  101. }
  102. // state not persisted — samples have gaps
  103. // Measure signal quality: average |I| and |Q| after Costas
  104. var sumI, sumQ float64
  105. for _, s := range synced {
  106. ri := float64(real(s))
  107. rq := float64(imag(s))
  108. if ri < 0 { ri = -ri }
  109. if rq < 0 { rq = -rq }
  110. sumI += ri
  111. sumQ += rq
  112. }
  113. avgI := sumI / float64(len(synced))
  114. avgQ := sumQ / float64(len(synced))
  115. // === BPSK demodulation ===
  116. hardBits := make([]int, len(synced))
  117. for i, s := range synced {
  118. if real(s) > 0 {
  119. hardBits[i] = 1
  120. } else {
  121. hardBits[i] = 0
  122. }
  123. }
  124. // === Differential decoding ===
  125. bits := make([]int, len(hardBits)-1)
  126. for i := 1; i < len(hardBits); i++ {
  127. bits[i-1] = hardBits[i] ^ hardBits[i-1]
  128. }
  129. // === Block sync + CRC decode (try both polarities) ===
  130. // Count block A CRC hits for diagnostics
  131. blockAHits := 0
  132. for i := 0; i+26 <= len(bits); i++ {
  133. if _, ok := decodeBlock(bits[i : i+26]); ok {
  134. blockAHits++
  135. }
  136. }
  137. d.BlockAHits += blockAHits
  138. found1 := d.tryDecode(bits)
  139. invBits := make([]int, len(bits))
  140. for i, b := range bits {
  141. invBits[i] = 1 - b
  142. }
  143. found2 := d.tryDecode(invBits)
  144. if found1 || found2 {
  145. d.GroupsFound++
  146. }
  147. d.LastDiag = fmt.Sprintf("syms=%d sps=%.1f costasFreq=%.4f avgI=%.4f avgQ=%.4f blockAHits=%d groups=%d",
  148. len(symbols), sps, freq, avgI, avgQ, blockAHits, d.GroupsFound)
  149. return Result{PI: d.lastPI, PS: d.psString(), RT: d.rtString()}
  150. }
  151. func (d *Decoder) tryDecode(bits []int) bool {
  152. found := false
  153. for i := 0; i+26*4 <= len(bits); i++ {
  154. bA, okA := decodeBlock(bits[i : i+26])
  155. if !okA || bA.offset != offA {
  156. continue
  157. }
  158. bB, okB := decodeBlock(bits[i+26 : i+52])
  159. if !okB || bB.offset != offB {
  160. continue
  161. }
  162. bC, okC := decodeBlock(bits[i+52 : i+78])
  163. if !okC || (bC.offset != offC && bC.offset != offCp) {
  164. continue
  165. }
  166. bD, okD := decodeBlock(bits[i+78 : i+104])
  167. if !okD || bD.offset != offD {
  168. continue
  169. }
  170. found = true
  171. pi := bA.data
  172. if pi != 0 {
  173. d.lastPI = pi
  174. }
  175. groupType := (bB.data >> 12) & 0xF
  176. versionA := ((bB.data >> 11) & 0x1) == 0
  177. if groupType == 0 {
  178. addr := bB.data & 0x3
  179. if versionA {
  180. chars := []byte{byte(bD.data >> 8), byte(bD.data & 0xFF)}
  181. idx := int(addr) * 2
  182. if idx+1 < len(d.ps) {
  183. d.ps[idx] = sanitizeRune(chars[0])
  184. d.ps[idx+1] = sanitizeRune(chars[1])
  185. }
  186. }
  187. }
  188. if groupType == 2 && versionA {
  189. addr := bB.data & 0xF
  190. chars := []byte{byte(bC.data >> 8), byte(bC.data & 0xFF), byte(bD.data >> 8), byte(bD.data & 0xFF)}
  191. idx := int(addr) * 4
  192. for j := 0; j < 4 && idx+j < len(d.rt); j++ {
  193. d.rt[idx+j] = sanitizeRune(chars[j])
  194. }
  195. }
  196. i += 103
  197. }
  198. return found
  199. }
  200. type block struct {
  201. data uint16
  202. offset uint16
  203. }
  204. const (
  205. offA uint16 = 0x0FC
  206. offB uint16 = 0x198
  207. offC uint16 = 0x168
  208. offCp uint16 = 0x350
  209. offD uint16 = 0x1B4
  210. )
  211. func decodeBlock(bits []int) (block, bool) {
  212. if len(bits) != 26 {
  213. return block{}, false
  214. }
  215. var raw uint32
  216. for _, b := range bits {
  217. raw = (raw << 1) | uint32(b&1)
  218. }
  219. data := uint16(raw >> 10)
  220. synd := crcSyndrome(raw)
  221. switch synd {
  222. case offA, offB, offC, offCp, offD:
  223. return block{data: data, offset: synd}, true
  224. default:
  225. return block{}, false
  226. }
  227. }
  228. func crcSyndrome(raw uint32) uint16 {
  229. poly := uint32(0x1B9)
  230. reg := raw
  231. for i := 25; i >= 10; i-- {
  232. if (reg>>uint(i))&1 == 1 {
  233. reg ^= poly << uint(i-10)
  234. }
  235. }
  236. return uint16(reg & 0x3FF)
  237. }
  238. func sanitizeRune(b byte) rune {
  239. if b < 32 || b > 126 {
  240. return ' '
  241. }
  242. return rune(b)
  243. }
  244. func (d *Decoder) psString() string {
  245. out := make([]rune, 0, len(d.ps))
  246. for _, r := range d.ps {
  247. if r == 0 {
  248. r = ' '
  249. }
  250. out = append(out, r)
  251. }
  252. return trimRight(out)
  253. }
  254. func (d *Decoder) rtString() string {
  255. out := make([]rune, 0, len(d.rt))
  256. for _, r := range d.rt {
  257. if r == 0 {
  258. r = ' '
  259. }
  260. out = append(out, r)
  261. }
  262. return trimRight(out)
  263. }
  264. func trimRight(in []rune) string {
  265. end := len(in)
  266. for end > 0 && in[end-1] == ' ' {
  267. end--
  268. }
  269. return string(in[:end])
  270. }