-
Notifications
You must be signed in to change notification settings - Fork 1
/
t.go
104 lines (95 loc) · 2.39 KB
/
t.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2018 Scott Cotton. All rights reserved. Use of this source
// code is governed by a license that can be found in the License file.
package hilbert
import (
"zikichombo.org/dsp/fft"
snd "zikichombo.org/sound"
)
// Type T implements a Processor for the Hilbert
// transform.
type T struct {
ft *fft.T
ftBuf []complex128
inBuf []float64
oBuf []float64
init bool
n int
ii int
src snd.Source
snk snd.Sink
}
// New generates a new Hilbert transformer, placing
// a rotated version of src in dst. New processes
// n elements at a time with a quality factor of q.
//
// Normally, n*q samples should be atleast 1 period of the slowest
// frequency for which the transform is (relatively) accurate.
// The larger the ratio q/n, also the fewer edge effects
// in the output. However, in our experience so long as the
// lowest frequency constraint is respected, we have found q>=2
// to be pretty good with diminishing returns. q=1 sucks.
//
// T is fairly accurate phase-wise, but suffers from some
// amplitude fluctuation, amplified at lower frequencies.
//
func New(dst snd.Sink, src snd.Source, n, q int) *T {
if q < 1 {
panic("invalid q")
}
m := n * q
res := &T{}
res.ft = fft.New(m)
res.ftBuf = res.ft.Win(nil)
res.inBuf = make([]float64, m)
res.oBuf = make([]float64, n)
res.n = n
if q%2 == 1 {
res.src = src
} else {
res.src = &pad{Source: src, n: n / 2}
}
res.snk = &discard{Sink: dst, n: m / 2}
res.ii = (m - n) / 2
return res
}
// N() implements snd.Processor, giving the
// number of input samples mapped to M().
func (t *T) N() int {
return t.n
}
// M() implements snd.Processor.
func (t *T) M() int {
return t.n
}
// Org returns the last processed original signal, a
// slice of size N().
func (t *T) Org() []float64 {
return t.inBuf[t.ii : t.ii+t.n]
}
// Rotated gives the rotated signal, a slice of size M().
func (t *T) Rotated() []float64 {
return t.oBuf
}
// Process processes one block of samples.
func (t *T) Process() error {
copy(t.inBuf, t.inBuf[t.n:])
newStart := len(t.inBuf) - t.n
n, e := t.src.Receive(t.inBuf[newStart:])
if e != nil {
return e
}
for i := newStart + n; i < len(t.inBuf); i++ {
t.inBuf[i] = 0.0
}
for i, v := range t.inBuf {
t.ftBuf[i] = complex(v, 0.0)
}
t.ft.Do(t.ftBuf)
rotate(t.ftBuf)
t.ft.Inv(t.ftBuf)
ii := t.ii
for i := 0; i < t.n; i++ {
t.oBuf[i] = real(t.ftBuf[ii+i])
}
return t.snk.Send(t.oBuf)
}