forked from maddyblue/go-dsp
-
Notifications
You must be signed in to change notification settings - Fork 2
/
dsputils.go
115 lines (98 loc) · 3.18 KB
/
dsputils.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
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Package dsputils provides functions useful in digital signal processing.
package dsputils
import (
"math"
)
// ToComplex returns the complex equivalent of the real-valued slice.
func ToComplex(x []float64) []complex128 {
y := make([]complex128, len(x))
for n, v := range x {
y[n] = complex(v, 0)
}
return y
}
// IsPowerOf2 returns true if x is a power of 2, else false.
func IsPowerOf2(x int) bool {
return x&(x-1) == 0
}
// NextPowerOf2 returns the next power of 2 >= x.
func NextPowerOf2(x int) int {
if IsPowerOf2(x) {
return x
}
return int(math.Pow(2, math.Ceil(math.Log2(float64(x)))))
}
// ZeroPad returns x with zeros appended to the end to the specified length.
// If len(x) >= length, x is returned, otherwise a new array is returned.
func ZeroPad(x []complex128, length int) []complex128 {
if len(x) >= length {
return x
}
r := make([]complex128, length)
copy(r, x)
return r
}
// ZeroPadF returns x with zeros appended to the end to the specified length.
// If len(x) >= length, x is returned, otherwise a new array is returned.
func ZeroPadF(x []float64, length int) []float64 {
if len(x) >= length {
return x
}
r := make([]float64, length)
copy(r, x)
return r
}
// ZeroPad2 returns ZeroPad of x, with the length as the next power of 2 >= len(x).
func ZeroPad2(x []complex128) []complex128 {
return ZeroPad(x, NextPowerOf2(len(x)))
}
// ToComplex2 returns the complex equivalent of the real-valued matrix.
func ToComplex2(x [][]float64) [][]complex128 {
y := make([][]complex128, len(x))
for n, v := range x {
y[n] = ToComplex(v)
}
return y
}
// Segment returns segs equal-length slices that are segments of x with noverlap% of overlap.
// The returned slices are not copies of x, but slices into it.
// Trailing entries in x that connot be included in the equal-length segments are discarded.
// noverlap is a percentage, thus 0 <= noverlap <= 1, and noverlap = 0.5 is 50% overlap.
func Segment(x []complex128, segs int, noverlap float64) [][]complex128 {
lx := len(x)
// determine step, length, and overlap
var overlap, length, step, tot int
for length = lx; length > 0; length-- {
overlap = int(float64(length) * noverlap)
tot = segs*(length-overlap) + overlap
if tot <= lx {
step = length - overlap
break
}
}
if length == 0 {
panic("too many segments")
}
r := make([][]complex128, segs)
s := 0
for n := range r {
r[n] = x[s : s+length]
s += step
}
return r
}