No Description

dsp.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright (C) 2017 Keelan Lightfoot
  2. // Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
  3. // System (Univ. of Wisconsin-Madison, Trace R&D Center)
  4. // Copyright (C) 2007-2008 Omnitor AB
  5. // Copyright (C) 2007-2008 Voiceriver Inc
  6. //
  7. // This library is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU Lesser General Public License as published by
  9. // the Free Software Foundation; either version 2.1 of the License, or (at
  10. // your option) any later version.
  11. package gortty
  12. import "math"
  13. type dsp struct {
  14. demLpf float64 // current LPF output value
  15. demTotal float64 // current energy output value
  16. lpfOrder int // LPFOrder Low pass filter order
  17. minThresh float64 // MinThresh ratio for vaild signal
  18. meter0 float64
  19. meter1 float64
  20. meter2 float64
  21. bpfMark *bpf // mark bandpass filter
  22. bpfSpace *bpf // space bandpass filter
  23. lpfDem *lpf //
  24. lpfTotal *lpf
  25. r float64
  26. }
  27. func newDsp(markF, spaceF, sampleRate int) *dsp {
  28. const (
  29. lfpOrder = 20
  30. beta = .95
  31. minThresh = 3
  32. )
  33. return &dsp{
  34. lpfOrder: lfpOrder,
  35. minThresh: minThresh,
  36. bpfMark: newBandPass(markF, sampleRate, beta),
  37. bpfSpace: newBandPass(spaceF, sampleRate, beta),
  38. lpfDem: newLpf(lfpOrder),
  39. lpfTotal: newLpf(lfpOrder),
  40. }
  41. }
  42. func (d *dsp) demod(sam float64) {
  43. // The demodulator is structured as a pair of band pass filters tuned to
  44. // the mark and space frequencies. The output of each is 'rectified' and
  45. // combined, and low pass filtered to produce a signal that goes positive
  46. // for mark and negative for space.
  47. mark := d.bpfMark.update(sam)
  48. space := d.bpfSpace.update(sam)
  49. d.demLpf = d.lpfDem.update(math.Abs(mark) - math.Abs(space))
  50. d.demTotal = d.lpfTotal.update(math.Abs(sam))
  51. }
  52. func (d *dsp) edgeDetected() bool {
  53. return math.Abs(d.demLpf) > d.demTotal*d.minThresh
  54. }
  55. func (d *dsp) carrier() bool {
  56. return math.Abs(d.demLpf) > d.demTotal*d.minThresh && d.demTotal*d.minThresh != 0
  57. }
  58. func (d *dsp) lpfVal() float64 {
  59. return math.Abs(d.demLpf)
  60. }
  61. func (d *dsp) threshVal() float64 {
  62. return d.demTotal * d.minThresh
  63. }
  64. func (d *dsp) level() (float64, float64, float64) {
  65. return d.meter0, d.meter1, d.meter2
  66. }
  67. func (d *dsp) mark() bool {
  68. return d.demLpf > d.minThresh*d.demTotal && math.Abs(d.demLpf) > d.demTotal*d.minThresh
  69. }
  70. func (d *dsp) space() bool {
  71. return -1*d.demLpf > d.minThresh*d.demTotal && math.Abs(d.demLpf) > d.demTotal*d.minThresh
  72. }
  73. type lpf struct {
  74. x []float64
  75. t float64
  76. }
  77. func newLpf(size int) *lpf {
  78. l := new(lpf)
  79. l.x = make([]float64, size)
  80. return l
  81. }
  82. func (l *lpf) update(v float64) float64 {
  83. l.t -= l.x[0]
  84. l.t += v
  85. l.x = append(l.x, v)
  86. l.x = l.x[1:]
  87. return l.t
  88. }
  89. type bpf struct {
  90. dem0 float64
  91. dem1 float64
  92. w float64
  93. beta float64
  94. }
  95. func newBandPass(fc int, fs int, beta float64) *bpf {
  96. f := new(bpf)
  97. f.beta = beta
  98. f.w = (2 * math.Pi * float64(fc) / float64(fs))
  99. return f
  100. }
  101. func (f *bpf) update(v float64) float64 {
  102. n := v + 2.0*math.Cos(f.w)*f.beta*f.dem0 - f.beta*f.beta*f.dem1
  103. f.dem1 = f.dem0
  104. f.dem0 = n
  105. return n
  106. }