Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

78 рядки
2.0KB

  1. package recorder
  2. import (
  3. "math"
  4. "testing"
  5. )
  6. func TestStereoDecodeStatefulPilotLock(t *testing.T) {
  7. const (
  8. sampleRate = 192000
  9. blockSize = 4096
  10. blocks = 10
  11. pilotAmp = 0.1
  12. toneL = 440.0
  13. toneR = 880.0
  14. )
  15. sess := &streamSession{}
  16. var out []float32
  17. locked := false
  18. for b := 0; b < blocks; b++ {
  19. mono := make([]float32, blockSize)
  20. base := b * blockSize
  21. for i := 0; i < blockSize; i++ {
  22. t := float64(base+i) / float64(sampleRate)
  23. l := math.Sin(2 * math.Pi * toneL * t)
  24. r := math.Sin(2 * math.Pi * toneR * t)
  25. lpr := 0.5 * (l + r)
  26. lmr := 0.5 * (l - r)
  27. composite := lpr + lmr*math.Cos(2*math.Pi*38000*t) + pilotAmp*math.Sin(2*math.Pi*19000*t)
  28. mono[i] = float32(composite)
  29. }
  30. out, locked = sess.stereoDecodeStateful(mono, sampleRate)
  31. }
  32. if !locked {
  33. t.Fatalf("expected pilot lock after warmup blocks")
  34. }
  35. if len(out) != blockSize*2 {
  36. t.Fatalf("unexpected output size: got %d, want %d", len(out), blockSize*2)
  37. }
  38. left := make([]float32, blockSize)
  39. right := make([]float32, blockSize)
  40. for i := 0; i < blockSize; i++ {
  41. left[i] = out[i*2]
  42. right[i] = out[i*2+1]
  43. }
  44. magL440 := toneMagnitude(left, toneL, sampleRate)
  45. magL880 := toneMagnitude(left, toneR, sampleRate)
  46. magR440 := toneMagnitude(right, toneL, sampleRate)
  47. magR880 := toneMagnitude(right, toneR, sampleRate)
  48. if magL440 < 0.05 || magR880 < 0.05 {
  49. t.Fatalf("decoded tones too weak: L440=%.3f R880=%.3f", magL440, magR880)
  50. }
  51. leftIsL := magL440 >= magL880*1.3 && magR880 >= magR440*1.3
  52. rightIsL := magL880 >= magL440*1.3 && magR440 >= magR880*1.3
  53. if !leftIsL && !rightIsL {
  54. t.Fatalf(
  55. "channels not cleanly separated: L440=%.3f L880=%.3f R440=%.3f R880=%.3f",
  56. magL440, magL880, magR440, magR880,
  57. )
  58. }
  59. }
  60. func toneMagnitude(x []float32, freq float64, sampleRate int) float64 {
  61. var iSum, qSum float64
  62. for n, v := range x {
  63. angle := 2 * math.Pi * freq * float64(n) / float64(sampleRate)
  64. iSum += float64(v) * math.Cos(angle)
  65. qSum += float64(v) * math.Sin(angle)
  66. }
  67. return math.Hypot(iSum, qSum) / float64(len(x))
  68. }