package dsp import "math" type DCBlocker struct { r float64 prevX complex64 prevY complex64 } func NewDCBlocker(r float64) *DCBlocker { if r <= 0 || r >= 1 { r = 0.995 } return &DCBlocker{r: r} } func (d *DCBlocker) Reset() { d.prevX = 0 d.prevY = 0 } func (d *DCBlocker) Apply(iq []complex64) { if d == nil { return } for i := 0; i < len(iq); i++ { x := iq[i] y := complex( float32(float64(real(x)-real(d.prevX))+d.r*float64(real(d.prevY))), float32(float64(imag(x)-imag(d.prevX))+d.r*float64(imag(d.prevY))), ) d.prevX = x d.prevY = y iq[i] = y } } func IQBalance(iq []complex64) { if len(iq) == 0 { return } var sumI, sumQ float64 for _, v := range iq { sumI += float64(real(v)) sumQ += float64(imag(v)) } meanI := sumI / float64(len(iq)) meanQ := sumQ / float64(len(iq)) var varI, varQ, cov float64 for _, v := range iq { i := float64(real(v)) - meanI q := float64(imag(v)) - meanQ varI += i * i varQ += q * q cov += i * q } n := float64(len(iq)) varI /= n varQ /= n cov /= n if varI <= 0 || varQ <= 0 { return } gain := math.Sqrt(varI / varQ) phi := 0.5 * math.Atan2(2*cov, varI-varQ) cosP := math.Cos(phi) sinP := math.Sin(phi) for i := 0; i < len(iq); i++ { re := float64(real(iq[i])) - meanI im := (float64(imag(iq[i])) - meanQ) * gain i2 := re*cosP - im*sinP q2 := re*sinP + im*cosP iq[i] = complex(float32(i2+meanI), float32(q2+meanQ)) } }