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

108 行
2.2KB

  1. package recorder
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. type iqBlock struct {
  7. t0 time.Time
  8. samples []complex64
  9. }
  10. // Ring keeps recent IQ blocks for preroll capture.
  11. type Ring struct {
  12. mu sync.RWMutex
  13. blocks []iqBlock
  14. maxBlocks int
  15. sampleRate int
  16. blockSize int
  17. }
  18. func NewRing(sampleRate int, blockSize int, seconds int) *Ring {
  19. if seconds <= 0 {
  20. seconds = 5
  21. }
  22. if sampleRate <= 0 {
  23. sampleRate = 2_048_000
  24. }
  25. if blockSize <= 0 {
  26. blockSize = 2048
  27. }
  28. blocksPerSec := sampleRate / blockSize
  29. if blocksPerSec <= 0 {
  30. blocksPerSec = 1
  31. }
  32. maxBlocks := blocksPerSec * seconds
  33. if maxBlocks < 2 {
  34. maxBlocks = 2
  35. }
  36. return &Ring{maxBlocks: maxBlocks, sampleRate: sampleRate, blockSize: blockSize}
  37. }
  38. func (r *Ring) Reset(sampleRate int, blockSize int, seconds int) {
  39. *r = *NewRing(sampleRate, blockSize, seconds)
  40. }
  41. func (r *Ring) Push(t0 time.Time, samples []complex64) {
  42. if r == nil || len(samples) == 0 {
  43. return
  44. }
  45. r.mu.Lock()
  46. defer r.mu.Unlock()
  47. r.blocks = append(r.blocks, iqBlock{t0: t0, samples: append([]complex64(nil), samples...)})
  48. if len(r.blocks) > r.maxBlocks {
  49. drop := len(r.blocks) - r.maxBlocks
  50. r.blocks = r.blocks[drop:]
  51. }
  52. }
  53. // Slice returns IQ samples between [start,end] (best-effort).
  54. func (r *Ring) Slice(start, end time.Time) []complex64 {
  55. if r == nil || end.Before(start) {
  56. return nil
  57. }
  58. r.mu.RLock()
  59. defer r.mu.RUnlock()
  60. var out []complex64
  61. for _, b := range r.blocks {
  62. blockDur := time.Duration(float64(len(b.samples)) / float64(r.sampleRate) * float64(time.Second))
  63. bEnd := b.t0.Add(blockDur)
  64. if bEnd.Before(start) || b.t0.After(end) {
  65. continue
  66. }
  67. // compute overlap
  68. oStart := maxTime(start, b.t0)
  69. oEnd := minTime(end, bEnd)
  70. if oEnd.Before(oStart) {
  71. continue
  72. }
  73. startIdx := int(float64(oStart.Sub(b.t0)) / float64(time.Second) * float64(r.sampleRate))
  74. endIdx := int(float64(oEnd.Sub(b.t0)) / float64(time.Second) * float64(r.sampleRate))
  75. if startIdx < 0 {
  76. startIdx = 0
  77. }
  78. if endIdx > len(b.samples) {
  79. endIdx = len(b.samples)
  80. }
  81. if endIdx > startIdx {
  82. out = append(out, b.samples[startIdx:endIdx]...)
  83. }
  84. }
  85. return out
  86. }
  87. func minTime(a, b time.Time) time.Time {
  88. if a.Before(b) {
  89. return a
  90. }
  91. return b
  92. }
  93. func maxTime(a, b time.Time) time.Time {
  94. if a.After(b) {
  95. return a
  96. }
  97. return b
  98. }