Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
S
SineTools
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Thomas Bruns
SineTools
Commits
a0e40b1f
Commit
a0e40b1f
authored
5 years ago
by
Thomas Bruns
Browse files
Options
Downloads
Patches
Plain Diff
corrected 4-param fit, scipy -> numpy migration
parent
54bf8067
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
SineTools.py
+256
-316
256 additions, 316 deletions
SineTools.py
with
256 additions
and
316 deletions
SineTools.py
+
256
−
316
View file @
a0e40b1f
...
...
@@ -8,22 +8,22 @@ auxiliary functions related to sine-approximation
"""
import
scipy
as
sp
import
numpy
as
np
from
scipy
import
linalg
as
la
import
matplotlib.pyplot
as
mp
def
sampletimes
(
Fs
,
T
):
#
def
sampletimes
(
Fs
,
T
):
#
"""
generate a t_i vector with
\n
sample rate Fs
\n
from 0 to T
"""
num
=
s
p
.
ceil
(
T
*
Fs
)
return
s
p
.
linspace
(
0
,
T
,
num
,
dtype
=
s
p
.
float64
)
num
=
n
p
.
ceil
(
T
*
Fs
)
return
n
p
.
linspace
(
0
,
T
,
num
,
dtype
=
n
p
.
float64
)
# a = displacement, velocity or acceleration amplitude
def
sinewave
(
f
,
a
,
phi
,
ti
,
offset
=
0
,
noise
=
0
,
absnoise
=
0
,
drift
=
0
,
ampdrift
=
0
):
def
sinewave
(
f
,
a
,
phi
,
ti
,
offset
=
0
,
noise
=
0
,
absnoise
=
0
,
drift
=
0
,
ampdrift
=
0
):
"""
generate a sampled sine wave s_i = s(t_i) with
\n
amplitude a
\n
...
...
@@ -38,25 +38,18 @@ def sinewave(f, a, phi, ti, offset=0, noise=0, absnoise=0, drift=0, ampdrift=0):
Tau
=
ti
[
-
1
]
-
ti
[
0
]
n
=
0
n
=
0
if
noise
!=
0
:
n
=
a
*
noise
*
sp
.
randn
(
len
(
ti
))
if
noise
!=
0
:
n
=
a
*
noise
*
sp
.
randn
(
len
(
ti
))
if
absnoise
!=
0
:
n
=
n
+
absnoise
*
sp
.
randn
(
len
(
ti
))
d
=
drift
*
a
/
Tau
s
=
(
a
*
(
1
+
ampdrift
/
Tau
*
ti
)
*
sp
.
sin
(
2
*
sp
.
pi
*
f
*
ti
-
phi
)
+
n
+
d
*
ti
+
offset
)
n
=
n
+
absnoise
*
sp
.
randn
(
len
(
ti
))
d
=
drift
*
a
/
Tau
s
=
a
*
(
1
+
ampdrift
/
Tau
*
ti
)
*
np
.
sin
(
2
*
np
.
pi
*
f
*
ti
-
phi
)
+
n
+
d
*
ti
+
offset
return
s
def
fm_counter_sine
(
fm
,
f
,
x
,
phi
,
ti
,
offset
=
0
,
noise
=
0
,
absnoise
=
0
,
drift
=
0
,
ampdrift
=
0
,
lamb
=
633.0e-9
):
def
fm_counter_sine
(
fm
,
f
,
x
,
phi
,
ti
,
offset
=
0
,
noise
=
0
,
absnoise
=
0
,
drift
=
0
,
ampdrift
=
0
,
lamb
=
633.0e-9
):
"""
calculate counter value of heterodyne signal at
\n
carrier freq. fm
\n
...
...
@@ -72,30 +65,20 @@ def fm_counter_sine(
"""
Tau
=
ti
[
-
1
]
-
ti
[
0
]
n
=
0
if
noise
!=
0
:
n
=
x
*
noise
*
sp
.
randn
(
len
(
ti
))
if
noise
!=
0
:
n
=
x
*
noise
*
sp
.
randn
(
len
(
ti
))
if
absnoise
!=
0
:
n
=
n
+
absnoise
*
sp
.
randn
(
len
(
ti
))
d
=
drift
*
x
/
Tau
s
=
(
1.0
/
lamb
*
(
x
*
(
1
+
ampdrift
/
Tau
*
ti
)
*
sp
.
sin
(
2
*
sp
.
pi
*
f
*
ti
-
phi
)
+
n
+
d
*
ti
+
offset
)
)
s
=
sp
.
floor
(
s
+
fm
*
ti
)
n
=
n
+
absnoise
*
sp
.
randn
(
len
(
ti
))
d
=
drift
*
x
/
Tau
s
=
1.0
/
lamb
*
(
x
*
(
1
+
ampdrift
/
Tau
*
ti
)
*
np
.
sin
(
2
*
np
.
pi
*
f
*
ti
-
phi
)
+
n
+
d
*
ti
+
offset
)
s
=
np
.
floor
(
s
+
fm
*
ti
)
return
s
# sine fit at known frequency
def
threeparsinefit
(
y
,
t
,
f0
):
def
threeparsinefit
(
y
,
t
,
f0
):
"""
sine-fit at a known frequency
\n
y vector of sample values
\n
...
...
@@ -105,16 +88,15 @@ def threeparsinefit(y, t, f0):
returns a vector of coefficients [a,b,c]
\n
for y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c
"""
w0
=
2
*
sp
.
pi
*
f0
a
=
sp
.
array
([
sp
.
cos
(
w0
*
t
),
sp
.
sin
(
w0
*
t
),
sp
.
ones
(
t
.
size
)])
abc
=
la
.
lstsq
(
a
.
transpose
(),
y
)
return
abc
[
0
][
0
:
3
]
## fit vector a*sin+b*cos+c
w0
=
2
*
np
.
pi
*
f0
a
=
np
.
array
([
np
.
cos
(
w0
*
t
),
np
.
sin
(
w0
*
t
),
np
.
ones
(
t
.
size
)])
abc
=
la
.
lstsq
(
a
.
transpose
(),
y
)
return
abc
[
0
][
0
:
3
]
## fit vector a*sin+b*cos+c
# sine fit at known frequency and detrending
def
threeparsinefit_lin
(
y
,
t
,
f0
):
def
threeparsinefit_lin
(
y
,
t
,
f0
):
"""
sine-fit with detrending at a known frequency
\n
y vector of sample values
\n
...
...
@@ -124,20 +106,20 @@ def threeparsinefit_lin(y, t, f0):
returns a vector of coefficients [a,b,c,d]
\n
for y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c*t + d
"""
w0
=
2
*
s
p
.
pi
*
f0
a
=
s
p
.
array
([
s
p
.
cos
(
w0
*
t
),
s
p
.
sin
(
w0
*
t
),
s
p
.
ones
(
t
.
size
),
t
,
s
p
.
ones
(
t
.
size
)])
abc
=
la
.
lstsq
(
a
.
transpose
(),
y
)
return
abc
[
0
][
0
:
4
]
## fit vector
w0
=
2
*
n
p
.
pi
*
f0
a
=
n
p
.
array
([
n
p
.
cos
(
w0
*
t
),
n
p
.
sin
(
w0
*
t
),
n
p
.
ones
(
t
.
size
),
t
,
n
p
.
ones
(
t
.
size
)])
abc
=
la
.
lstsq
(
a
.
transpose
(),
y
)
return
abc
[
0
][
0
:
4
]
## fit vector
def
calc_threeparsine
(
abc
,
t
,
f0
):
def
calc_threeparsine
(
abc
,
t
,
f0
):
"""
return y = abc[0]*sin(2*pi*f0*t) + abc[1]*cos(2*pi*f0*t) + abc[2]
"""
w0
=
2
*
s
p
.
pi
*
f0
return
abc
[
0
]
*
s
p
.
cos
(
w0
*
t
)
+
abc
[
1
]
*
s
p
.
sin
(
w0
*
t
)
+
abc
[
2
]
w0
=
2
*
n
p
.
pi
*
f0
return
abc
[
0
]
*
n
p
.
cos
(
w0
*
t
)
+
abc
[
1
]
*
n
p
.
sin
(
w0
*
t
)
+
abc
[
2
]
def
amplitude
(
abc
):
...
...
@@ -145,7 +127,7 @@ def amplitude(abc):
return the amplitude given the coefficients of
\n
y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c
"""
return
s
p
.
absolute
(
abc
[
1
]
+
1j
*
abc
[
0
])
return
n
p
.
absolute
(
abc
[
1
]
+
1j
*
abc
[
0
])
def
phase
(
abc
,
deg
=
False
):
...
...
@@ -154,10 +136,9 @@ def phase(abc, deg=False):
y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c
\n
returns angle in rad by default, in degree if deg=True
"""
return
sp
.
angle
(
abc
[
1
]
+
1j
*
abc
[
0
],
deg
=
deg
)
def
magnitude
(
A1
,
A2
):
return
np
.
angle
(
abc
[
1
]
+
1j
*
abc
[
0
],
deg
=
deg
)
def
magnitude
(
A1
,
A2
):
"""
return the magnitude of the complex ratio of sines A2/A1
\n
given two sets of coefficients
\n
...
...
@@ -166,8 +147,7 @@ def magnitude(A1, A2):
"""
return
amplitude
(
A2
)
/
amplitude
(
A1
)
def
phase_delay
(
A1
,
A2
,
deg
=
False
):
def
phase_delay
(
A1
,
A2
,
deg
=
False
):
"""
return the phase difference of the complex ratio of sines A2/A1
\n
given two sets of coefficients
\n
...
...
@@ -177,9 +157,8 @@ def phase_delay(A1, A2, deg=False):
"""
return
phase
(
A2
,
deg
=
deg
)
-
phase
(
A1
,
deg
=
deg
)
# periodical sinefit at known frequency
def
seq_threeparsinefit
(
y
,
t
,
f0
):
# periodical sinefit at known frequency
def
seq_threeparsinefit
(
y
,
t
,
f0
):
"""
period-wise sine-fit at a known frequency
\n
y vector of sample values
\n
...
...
@@ -189,22 +168,21 @@ def seq_threeparsinefit(y, t, f0):
returns a (n,3)-matrix of coefficient-triplets [[a,b,c], ...]
\n
for y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c
"""
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
Tau
/
dt
)
## samples per section
M
=
int
(
sp
.
floor
(
t
.
size
/
N
))
## number of sections or periods
abc
=
sp
.
zeros
((
M
,
3
))
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
Tau
/
dt
)
## samples per section
M
=
int
(
np
.
floor
(
t
.
size
/
N
))
## number of sections or periods
abc
=
np
.
zeros
((
M
,
3
))
for
i
in
range
(
int
(
M
)):
ti
=
t
[
i
*
N
:
(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:
(
i
+
1
)
*
N
]
abc
[
i
,
:]
=
threeparsinefit
(
yi
,
ti
,
f0
)
return
abc
## matrix of all fit vectors per period
ti
=
t
[
i
*
N
:(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:(
i
+
1
)
*
N
]
abc
[
i
,:]
=
(
threeparsinefit
(
yi
,
ti
,
f0
))
return
abc
## matrix of all fit vectors per period
# four parameter sine-fit (with frequency approximation)
def
fourparsinefit
(
y
,
t
,
f0
,
tol
=
1.0e-7
,
nmax
=
1000
):
def
fourparsinefit
(
y
,
t
,
f0
,
tol
=
1.0e-7
,
nmax
=
1000
):
"""
y sampled data values
\n
t sample times of y
\n
...
...
@@ -214,39 +192,34 @@ def fourparsinefit(y, t, f0, tol=1.0e-7, nmax=1000):
\n
returns the vector [a, b, c, w] of a*sin(w*t)+b*cos(w*t)+c
"""
abcd
=
threeparsinefit
(
y
,
t
,
f0
)
w
=
2
*
s
p
.
pi
*
f0
abcd
=
threeparsinefit
(
y
,
t
,
f0
)
w
=
2
*
n
p
.
pi
*
f0
err
=
1
i
=
0
while
(
err
>
tol
)
and
(
i
<
nmax
):
D
=
sp
.
array
(
[
sp
.
cos
(
w
*
t
),
sp
.
sin
(
w
*
t
),
sp
.
ones
(
t
.
size
),
(
-
1.0
)
*
abcd
[
0
]
*
t
*
sp
.
sin
(
w
*
t
)
+
abcd
[
1
]
*
t
*
sp
.
cos
(
w
*
t
),
]
)
abcd
=
(
la
.
lstsq
(
D
.
transpose
(),
y
))[
0
]
while
((
err
>
tol
)
and
(
i
<
nmax
)):
D
=
np
.
array
([
np
.
cos
(
w
*
t
),
np
.
sin
(
w
*
t
),
np
.
ones
(
t
.
size
),
(
-
1.0
)
*
abcd
[
0
]
*
t
*
np
.
sin
(
w
*
t
)
+
abcd
[
1
]
*
t
*
np
.
cos
(
w
*
t
)
])
print
(
dw
)
abcd
=
(
la
.
lstsq
(
D
.
transpose
(),
y
))[
0
]
dw
=
abcd
[
3
]
w
=
w
+
0.9
*
dw
i
+=
1
err
=
s
p
.
absolute
(
dw
/
w
)
w
=
w
+
0.9
*
dw
i
+=
1
err
=
n
p
.
absolute
(
dw
/
w
)
assert
i
<
nmax
,
"
iteration error
"
return
sp
.
hstack
((
abcd
[
0
:
3
],
w
/
(
2
*
sp
.
pi
)))
def
calc_fourparsine
(
abcf
,
t
):
return
np
.
hstack
((
abcd
[
0
:
3
],
w
/
(
2
*
np
.
pi
)))
def
calc_fourparsine
(
abcf
,
t
):
"""
return y = abc[0]*sin(2*pi*f0*t) + abc[1]*cos(2*pi*f0*t) + abc[2]
"""
w0
=
2
*
sp
.
pi
*
abcf
[
3
]
return
abcf
[
0
]
*
sp
.
cos
(
w0
*
t
)
+
abcf
[
1
]
*
sp
.
sin
(
w0
*
t
)
+
abcf
[
2
]
w0
=
2
*
np
.
pi
*
abcf
[
3
]
return
abcf
[
0
]
*
np
.
cos
(
w0
*
t
)
+
abcf
[
1
]
*
np
.
sin
(
w0
*
t
)
+
abcf
[
2
]
"""
from octave ...
function abcw = fourParSinefit(data,w0)
...
...
@@ -271,8 +244,8 @@ function abcw = fourParSinefit(data,w0)
endfunction
"""
# periodical sinefit at known frequency
def
seq_fourparsinefit
(
y
,
t
,
f0
,
tol
=
1.0e-7
,
nmax
=
1000
,
debug_plot
=
False
):
# periodical sinefit at known frequency
def
seq_fourparsinefit
(
y
,
t
,
f0
,
tol
=
1.0e-7
,
nmax
=
1000
,
debug_plot
=
False
):
"""
period-wise sine-fit at a known frequency
\n
y vector of sample values
\n
...
...
@@ -284,41 +257,39 @@ def seq_fourparsinefit(y, t, f0, tol=1.0e-7, nmax=1000, debug_plot=False):
returns a (n,3)-matrix of coefficient-triplets [[a,b,c], ...]
\n
for y = a*sin(2*pi*f0*t) + b*cos(2*pi*f0*t) + c
"""
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
sp
.
floor
(
Tau
/
dt
))
## samples per section
M
=
int
(
sp
.
floor
(
t
.
size
/
N
))
## number of sections or periods
abcd
=
sp
.
zeros
((
M
,
4
))
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
np
.
floor
(
Tau
/
dt
))
## samples per section
M
=
int
(
np
.
floor
(
t
.
size
/
N
))
## number of sections or periods
abcd
=
np
.
zeros
((
M
,
4
))
for
i
in
range
(
M
):
ti
=
t
[
i
*
N
:
(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:
(
i
+
1
)
*
N
]
abcd
[
i
,
:]
=
fourparsinefit
(
yi
,
ti
,
f0
,
tol
=
tol
,
nmax
=
nmax
)
ti
=
t
[
i
*
N
:(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:(
i
+
1
)
*
N
]
abcd
[
i
,:]
=
(
fourparsinefit
(
yi
,
ti
,
f0
,
tol
=
tol
,
nmax
=
nmax
)
)
if
debug_plot
:
mp
.
ioff
()
fig
=
mp
.
figure
(
"
seq_fourparsinefit
"
)
fig
.
clear
()
p1
=
fig
.
add_subplot
(
211
)
p2
=
fig
.
add_subplot
(
212
,
sharex
=
p1
)
p2
=
fig
.
add_subplot
(
212
,
sharex
=
p1
)
for
i
in
range
(
M
):
p1
.
plot
(
t
[
i
*
N
:
(
i
+
1
)
*
N
],
y
[
i
*
N
:
(
i
+
1
)
*
N
],
"
.
"
)
s
=
calc_fourparsine
(
abcd
[
i
,
:],
t
[
i
*
N
:
(
i
+
1
)
*
N
]
)
# fitted data to plot
p1
.
plot
(
t
[
i
*
N
:
(
i
+
1
)
*
N
],
s
,
"
-
"
)
r
=
y
[
i
*
N
:
(
i
+
1
)
*
N
]
-
s
# residuals to plot
p2
.
plot
(
t
[
i
*
N
:
(
i
+
1
)
*
N
],
r
,
"
.
"
)
yi
=
y
[
i
*
N
:
(
i
+
1
)
*
N
]
p1
.
plot
(
t
[
i
*
N
:(
i
+
1
)
*
N
],
y
[
i
*
N
:(
i
+
1
)
*
N
],
"
.
"
)
s
=
calc_fourparsine
(
abcd
[
i
,:],
t
[
i
*
N
:(
i
+
1
)
*
N
])
# fitted data to plot
p1
.
plot
(
t
[
i
*
N
:(
i
+
1
)
*
N
],
s
,
"
-
"
)
r
=
y
[
i
*
N
:(
i
+
1
)
*
N
]
-
s
# residuals to plot
p2
.
plot
(
t
[
i
*
N
:(
i
+
1
)
*
N
],
r
,
"
.
"
)
yi
=
y
[
i
*
N
:(
i
+
1
)
*
N
]
mp
.
show
()
return
abcd
## matrix of all fit vectors per period
return
abcd
## matrix of all fit vectors per period
# fitting a pseudo-random multi-sine signal with 2*Nf+1 parameters
def
multi_threeparsinefit
(
y
,
t
,
f0
):
# f
o
vector of frequencies
def
multi_threeparsinefit
(
y
,
t
,
f0
):
# f
0
vector of frequencies
"""
fit a time series of a sum of sine-waveforms with a given set of frequencies
\n
y vector of sample values
\n
...
...
@@ -328,37 +299,37 @@ def multi_threeparsinefit(y, t, f0): # fo vector of frequencies
returns a vector of coefficient-triplets [a,b,c] for the frequencies
\n
for y = sum_i (a_i*sin(2*pi*f0_i*t) + b_i*cos(2*pi*f0_i*t) + c_i
"""
w0
=
2
*
sp
.
pi
*
f0
w0
=
2
*
np
.
pi
*
f0
D
=
np
.
ones
((
len
(
t
),
1
))
# for the bias
# set up design matrix
a
=
sp
.
ones
(
len
(
t
))
for
w
in
w0
:
a
=
sp
.
vstack
((
sp
.
vstack
((
sp
.
cos
(
w
*
t
),
sp
.
sin
(
w
*
t
))),
a
))
for
w
in
w0
[::
-
1
]:
D
=
np
.
hstack
((
np
.
cos
(
w
*
t
)[:,
np
.
newaxis
],
np
.
sin
(
w
*
t
)[:,
np
.
newaxis
],
D
))
abc
=
s
p
.
linalg
.
lstsq
(
a
.
transpose
()
,
y
)
return
abc
[
0
]
## fit vector a*
sin+b*cos
+c
abc
=
n
p
.
linalg
.
lstsq
(
D
,
y
)
return
abc
[
0
]
## fit vector a*
cos+b*sin
+c
def
multi_amplitude
(
abc
):
# abc = [a1,b1 , a2,b2, ...,bias]
def
multi_amplitude
(
abc
):
# abc = [a1,b1 , a2,b2, ...,bias]
"""
return the amplitudes given the coefficients of a multi-sine
\n
abc = [a1,b1 , a2,b2, ...,bias]
\n
y = sum_i (a_i*sin(2*pi*f0_i*t) + b_i*cos(2*pi*f0_i*t) + c_i
"""
x
=
abc
[
0
::
2
]
+
1j
*
abc
[
1
::
2
]
return
sp
.
absolute
(
x
)
x
=
abc
[:
-
1
][
0
::
2
]
+
1j
*
abc
[:
-
1
][
1
::
2
]
# make complex without Bias (last value)
return
np
.
absolute
(
x
)
def
multi_phase
(
abc
,
deg
=
False
):
# abc = [bias, a1,b1 , a2,b2, ...]
def
multi_phase
(
abc
,
deg
=
False
):
# abc = [bias, a1,b1 , a2,b2, ...]
"""
return the initial phases given the coefficients of a multi-sine
\n
abc = [a1,b1 , a2,b2, ...,bias]
\n
y = sum_i (a_i*sin(2*pi*f0_i*t) + b_i*cos(2*pi*f0_i*t) + c_i
"""
x
=
abc
[
1
::
2
]
+
1j
*
abc
[
2
::
2
]
return
s
p
.
angle
(
x
,
deg
=
deg
)
x
=
abc
[
:
-
1
][
0
::
2
]
+
1j
*
abc
[
:
-
1
][
1
::
2
]
# make complex without Bias (last value)
return
n
p
.
angle
(
x
,
deg
=
deg
)
def
multi_waveform_abc
(
f
,
abc
,
t
):
def
multi_waveform_abc
(
f
,
abc
,
t
):
"""
generate a sample time series of a multi-sine from coefficients and frequencies
\n
f vector of given frequencies
\n
...
...
@@ -368,18 +339,37 @@ def multi_waveform_abc(f, abc, t):
returns the vector
\n
y = sum_i (a_i*sin(2*pi*f0_i*t) + b_i*cos(2*pi*f0_i*t) + bias
"""
ret
=
0.0
*
t
+
abc
[
-
1
]
# bias
for
fi
,
a
,
b
in
zip
(
f
,
abc
[
0
::
2
],
abc
[
1
::
2
]):
ret
=
ret
+
a
*
sp
.
cos
(
2
*
sp
.
pi
*
fi
*
t
)
+
b
*
sp
.
sin
(
2
*
sp
.
pi
*
fi
*
t
)
return
ret
ret
=
0.0
*
t
+
abc
[
-
1
]
# bias
for
fi
,
a
,
b
in
zip
(
f
,
abc
[
0
::
2
],
abc
[
1
::
2
]):
ret
=
ret
+
a
*
np
.
cos
(
2
*
np
.
pi
*
fi
*
t
)
+
b
*
np
.
sin
(
2
*
np
.
pi
*
fi
*
t
)
return
ret
def
multi_waveform_mp
(
f
,
m
,
p
,
t
,
bias
=
0
,
deg
=
True
):
"""
generate a sample time series of a multi-sine from magnitude/phase and frequencies
\n
f vector of given frequencies
\n
m vector of magnitudes
\n
p vector of phases
\n
t vector of sample times t_i
\n
bias scalar value for total bias
deg = boolean whether phase is in degree
\n
returns the vector
\n
y = sum_i (a_i*sin(2*pi*f0_i*t) + b_i*cos(2*pi*f0_i*t) + bias
"""
ret
=
0.0
*
t
+
bias
# init and bias
if
deg
:
p
=
np
.
deg2rad
(
p
)
for
fi
,
m_i
,
p_i
in
zip
(
f
,
m
,
p
):
ret
=
ret
+
m_i
*
np
.
sin
(
2
*
np
.
pi
*
fi
*
t
+
p_i
)
return
ret
##################################
# Counter based stuff
# periodical sinefit to the linearly increasing heterodyne counter
# version based on Blume
def
seq_threeparcounterfit
(
y
,
t
,
f0
,
diff
=
False
):
def
seq_threeparcounterfit
(
y
,
t
,
f0
,
diff
=
False
):
"""
period-wise (single-)sinefit to the linearly increasing heterodyne counter
version based on
"
Blume et al.
"
\n
...
...
@@ -391,22 +381,21 @@ def seq_threeparcounterfit(y, t, f0, diff=False):
if diff=True use differentiation to remove carrier (c.f. source)
"""
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
s
p
.
floor
(
Tau
/
dt
))
## samples per section
M
=
int
(
s
p
.
floor
(
t
.
size
/
N
))
## number of sections or periods
Tau
=
1.0
/
f0
dt
=
t
[
1
]
-
t
[
0
]
N
=
int
(
n
p
.
floor
(
Tau
/
dt
))
## samples per section
M
=
int
(
n
p
.
floor
(
t
.
size
/
N
))
## number of sections or periods
remove_counter_carrier
(
y
,
diff
=
diff
)
abc
=
s
p
.
zeros
((
M
,
4
))
abc
=
n
p
.
zeros
((
M
,
4
))
for
i
in
range
(
int
(
M
)):
ti
=
t
[
i
*
N
:
(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:
(
i
+
1
)
*
N
]
abc
[
i
,
:]
=
threeparsinefit_lin
(
yi
,
ti
,
f0
)
return
abc
## matrix of all fit vectors per period
ti
=
t
[
i
*
N
:(
i
+
1
)
*
N
]
yi
=
y
[
i
*
N
:(
i
+
1
)
*
N
]
abc
[
i
,:]
=
threeparsinefit_lin
(
yi
,
ti
,
f0
)
return
abc
## matrix of all fit vectors per period
def
remove_counter_carrier
(
y
,
diff
=
False
):
"""
...
...
@@ -414,21 +403,18 @@ def remove_counter_carrier(y, diff=False):
generated by the carrier frequency of a heterodyne signal
\n
y vector of samples of the signal
"""
if
diff
:
d
=
s
p
.
diff
(
y
)
d
=
d
-
s
p
.
mean
(
d
)
y
=
s
p
.
hstack
((
0
,
s
p
.
cumsum
(
d
)))
if
diff
:
d
=
n
p
.
diff
(
y
)
d
=
d
-
n
p
.
mean
(
d
)
y
=
n
p
.
hstack
((
0
,
n
p
.
cumsum
(
d
)))
else
:
slope
=
y
[
-
1
]
-
y
[
0
]
# slope of linear increment
y
=
y
-
slope
*
sp
.
linspace
(
0.0
,
1.0
,
len
(
y
),
endpoint
=
False
)
# removal of linear increment
slope
=
(
y
[
-
1
]
-
y
[
0
])
# slope of linear increment
y
=
y
-
slope
*
np
.
linspace
(
0.0
,
1.0
,
len
(
y
),
endpoint
=
False
)
# removal of linear increment
return
y
# calculate displacement and acceleration to the same analytical s(t)
# Bsp: fm = 2e7, f=10, s0=0.15, phi0=
s
p.pi/3, ti, drift=0.03, ampdrift=0.03,thd=[0,0.02,0,0.004]
def
disp_acc_distorted
(
fm
,
f
,
s0
,
phi0
,
ti
,
drift
=
0
,
ampdrift
=
0
,
thd
=
0
):
# Bsp: fm = 2e7, f=10, s0=0.15, phi0=
n
p.pi/3, ti, drift=0.03, ampdrift=0.03,thd=[0,0.02,0,0.004]
def
disp_acc_distorted
(
fm
,
f
,
s0
,
phi0
,
ti
,
drift
=
0
,
ampdrift
=
0
,
thd
=
0
):
"""
calculate the respective (displacement-) counter and acceleration
for a parmeterized distorted sine-wave motion in order to compare accelerometry with interferometry
\n
...
...
@@ -440,59 +426,45 @@ def disp_acc_distorted(fm, f, s0, phi0, ti, drift=0, ampdrift=0, thd=0):
ampdrift is displacement amplitude druft
\n
thd is vector of higher harmonic amplitudes (c.f. source)
"""
om
=
2
*
sp
.
pi
*
f
om2
=
om
**
2
tau
=
ti
[
-
1
]
-
ti
[
0
]
disp
=
s
p
.
sin
(
om
*
ti
+
phi0
)
if
thd
!=
0
:
om
=
2
*
np
.
pi
*
f
om2
=
om
**
2
tau
=
ti
[
-
1
]
-
ti
[
0
]
disp
=
n
p
.
sin
(
om
*
ti
+
phi0
)
if
(
thd
!=
0
)
:
i
=
2
for
h
in
thd
:
disp
=
disp
+
h
*
s
p
.
sin
(
i
*
om
*
ti
+
phi0
)
i
=
i
+
1
if
ampdrift
!=
0
:
disp
=
disp
*
(
1
+
ampdrift
/
tau
*
ti
)
for
h
in
thd
:
disp
=
disp
+
h
*
n
p
.
sin
(
i
*
om
*
ti
+
phi0
)
i
=
i
+
1
if
ampdrift
!=
0
:
disp
=
disp
*
(
1
+
ampdrift
/
tau
*
ti
)
if
drift
!=
0
:
disp
=
disp
+
s0
*
drift
/
tau
*
ti
disp
=
disp
*
s0
disp
=
s
p
.
floor
((
disp
*
2
/
633e-9
)
+
fm
*
ti
)
disp
=
disp
+
s0
*
drift
/
tau
*
ti
disp
=
disp
*
s0
disp
=
n
p
.
floor
((
disp
*
2
/
633e-9
)
+
fm
*
ti
)
acc
=
-
s0
*
om2
*
(
1
+
ampdrift
/
tau
*
ti
)
*
sp
.
sin
(
om
*
ti
+
phi0
)
acc
=
-
s0
*
om2
*
(
1
+
ampdrift
/
tau
*
ti
)
*
np
.
sin
(
om
*
ti
+
phi0
)
if
ampdrift
!=
0
:
acc
=
acc
+
(
2
*
ampdrift
*
s0
*
om
*
sp
.
cos
(
om
*
ti
+
phi0
))
/
tau
acc
=
acc
+
(
2
*
ampdrift
*
s0
*
om
*
np
.
cos
(
om
*
ti
+
phi0
))
/
tau
if
thd
!=
0
:
i
=
2
for
h
in
thd
:
acc
=
acc
-
s0
*
h
*
om2
*
(
1
+
ampdrift
/
tau
*
ti
)
*
i
**
2
*
sp
.
sin
(
i
*
om
*
ti
+
phi0
)
for
h
in
thd
:
acc
=
acc
-
s0
*
h
*
om2
*
(
1
+
ampdrift
/
tau
*
ti
)
*
i
**
2
*
np
.
sin
(
i
*
om
*
ti
+
phi0
)
if
ampdrift
!=
0
:
acc
=
(
acc
+
(
2
*
ampdrift
*
s0
*
om
*
i
*
h
*
sp
.
cos
(
om
*
ti
+
phi0
))
/
tau
)
i
=
i
+
1
acc
=
acc
+
(
2
*
ampdrift
*
s0
*
om
*
i
*
h
*
np
.
cos
(
om
*
ti
+
phi0
))
/
tau
i
=
i
+
1
return
disp
,
acc
return
disp
,
acc
###################################
# Generation and adaptation of Parameters of the Multi-Sine considering hardware constraints
def
PR_MultiSine_adapt
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
8
,
fs_min
=
0
,
fs_max
=
1e9
,
frange
=
10
,
log
=
True
,
phases
=
None
,
sample_inkr
=
1
,
):
def
PR_MultiSine_adapt
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
8
,
fs_min
=
0
,
fs_max
=
1e9
,
frange
=
10
,
log
=
True
,
phases
=
None
,
sample_inkr
=
1
):
"""
Returns an additive normalized Multisine time series.
\n
f1 = start frequency (may be adapted)
\n
Nperiods = number of periods of f1 (may be increased)
\n
f1 = start frequency (may be adapted
by the algorithm
)
\n
Nperiods = number of periods of f1 (may be increased
by algorithm
)
\n
Nsamples = Minimum Number of samples
\n
Nf = number of frequencies in multi frequency mix
\n
fs_min = minimum sample rate of used device (default 0)
\n
...
...
@@ -506,103 +478,79 @@ def PR_MultiSine_adapt(
returns: freq,phase,fs,ti,multi
\n
freq= array of frequencies
\n
phase=used phases in deg or rad
\n
T1 = (adapted) duration
fs=sample rate
\n
ti=timestamps
\n
multi=array of time series values
\n
"""
if
(
Nsamples
//
sample_inkr
*
sample_inkr
!=
Nsamples
):
# check multiplicity of sample_inkr
Nsamples
=
(
Nsamples
//
sample_inkr
+
1
)
*
sample_inkr
# round to next higher multiple
if
Nsamples
//
sample_inkr
*
sample_inkr
!=
Nsamples
:
# check multiplicity of sample_inkr
Nsamples
=
(
Nsamples
//
sample_inkr
+
1
)
*
sample_inkr
# round to next higher multiple
T0
=
Nperiods
/
f1
# given duration
fs0
=
Nsamples
/
T0
# (implicitly) given sample rate
T0
=
Nperiods
/
f1
# given duration
fs0
=
Nsamples
/
T0
# (implicitly) given sample rate
if
False
:
print
(
"
0 Nperiods:
"
+
str
(
Nperiods
))
print
(
"
0 Nsamples:
"
+
str
(
Nsamples
))
print
(
"
0 fs:
"
+
str
(
fs0
))
print
(
"
0 T0:
"
+
str
(
T0
))
print
(
"
0 f1:
"
+
str
(
f1
))
print
(
"
0 Nperiods:
"
+
str
(
Nperiods
))
print
(
"
0 Nsamples:
"
+
str
(
Nsamples
))
print
(
"
0 fs:
"
+
str
(
fs0
))
print
(
"
0 T0:
"
+
str
(
T0
))
print
(
"
0 f1:
"
+
str
(
f1
))
fs
=
fs0
if
fs0
<
fs_min
:
# sample rate too low, then set to minimum
if
fs0
<
fs_min
:
# sample rate too low, then set to minimum
fs
=
fs_min
print
(
"
sample rate increased
"
)
elif
fs0
>
fs_max
:
# sample rate too high, set to max-allowed and
elif
fs0
>
fs_max
:
# sample rate too high, set to max-allowed and
fs
=
fs_max
Nperiods
=
sp
.
ceil
(
Nperiods
*
fs0
/
fs_max
)
# increase number of periods to get at least Nsamples samples
T0
=
Nperiods
/
f1
print
(
"
sample rate reduced, Nperiods=
"
+
str
(
Nperiods
))
Nsamples
=
T0
*
fs
if
(
Nsamples
//
sample_inkr
*
sample_inkr
!=
Nsamples
):
# check multiplicity of sample_inkr
Nsamples
=
(
Nsamples
//
sample_inkr
+
1
)
*
sample_inkr
# round to next higher multiple
T1
=
Nsamples
/
fs
# adapt exact duration
f1
=
Nperiods
/
T1
# adapt f1 for complete cycles
Nperiods
=
np
.
ceil
(
Nperiods
*
fs0
/
fs_max
)
# increase number of periods to get at least Nsamples samples
T0
=
Nperiods
/
f1
print
(
"
sample rate reduced, Nperiods=
"
+
str
(
Nperiods
))
Nsamples
=
T0
*
fs
if
Nsamples
//
sample_inkr
*
sample_inkr
!=
Nsamples
:
# check multiplicity of sample_inkr
Nsamples
=
(
Nsamples
//
sample_inkr
+
1
)
*
sample_inkr
# round to next higher multiple
T1
=
Nsamples
/
fs
# adapt exact duration
f1
=
Nperiods
/
T1
# adapt f1 for complete cycles
if
False
:
print
(
"
Nperiods:
"
+
str
(
Nperiods
))
print
(
"
Nsamples:
"
+
str
(
Nsamples
))
print
(
"
fs:
"
+
str
(
fs
))
print
(
"
T1:
"
+
str
(
T1
))
print
(
"
f1:
"
+
str
(
f1
))
print
(
"
Nperiods:
"
+
str
(
Nperiods
))
print
(
"
Nsamples:
"
+
str
(
Nsamples
))
print
(
"
fs:
"
+
str
(
fs
))
print
(
"
T1:
"
+
str
(
T1
))
print
(
"
f1:
"
+
str
(
f1
))
f_res
=
1
/
T1
# frequency resolution
f_res
=
1
/
T1
# frequency resolution
# determine a series of frequencies (freq[])
if
log
:
fact
=
s
p
.
power
(
frange
,
1.0
/
(
Nf
-
1
))
# factor for logarithmic scale
freq
=
f1
*
s
p
.
power
(
fact
,
s
p
.
arange
(
Nf
))
else
:
step
=
(
frange
-
1
)
*
f1
/
(
Nf
-
1
)
freq
=
s
p
.
arange
(
f1
,
frange
*
f1
+
step
,
step
)
fact
=
n
p
.
power
(
frange
,
1.0
/
(
Nf
-
1
))
# factor for logarithmic scale
freq
=
f1
*
n
p
.
power
(
fact
,
n
p
.
arange
(
Nf
))
else
:
step
=
(
frange
-
1
)
*
f1
/
(
Nf
-
1
)
freq
=
n
p
.
arange
(
f1
,
frange
*
f1
+
step
,
step
)
# auxiliary function to find the nearest available frequency
def
find_nearest
(
x
,
possible
):
# match the theoretical freqs to the possible periodic freqs
idx
=
(
sp
.
absolute
(
possible
-
x
)).
argmin
()
def
find_nearest
(
x
,
possible
):
# match the theoretical freqs to the possible periodic freqs
idx
=
(
np
.
absolute
(
possible
-
x
)).
argmin
()
return
possible
[
idx
]
fi_pos
=
s
p
.
arange
(
f1
,
frange
*
f1
+
f_res
,
f_res
)
# possible periodic frequencies
f_real
=
[]
fi_pos
=
n
p
.
arange
(
f1
,
frange
*
f1
+
f_res
,
f_res
)
# possible periodic frequencies
f_real
=
[]
for
f
in
freq
:
f_real
.
append
(
find_nearest
(
f
,
fi_pos
))
freq
=
s
p
.
hstack
(
f_real
)
f_real
.
append
(
find_nearest
(
f
,
fi_pos
))
freq
=
n
p
.
hstack
(
f_real
)
if
True
:
print
(
"
freq:
"
+
str
(
freq
))
print
(
"
freq:
"
+
str
(
freq
))
if
phases
is
None
:
# generate random phases
phase
=
sp
.
randn
(
Nf
)
*
2
*
s
p
.
pi
# random phase
else
:
# use given phases
phase
=
phases
phase
=
sp
.
randn
(
Nf
)
*
2
*
n
p
.
pi
# random phase
else
:
# use given phases
phase
=
phases
return
freq
,
phase
,
T1
,
fs
return
freq
,
phase
,
T1
,
fs
###################################
# Pseudo-Random-MultiSine for "quick calibration"
def
PR_MultiSine
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
8
,
fs_min
=
0
,
fs_max
=
1e9
,
frange
=
10
,
log
=
True
,
phases
=
None
,
deg
=
False
,
sample_inkr
=
1
,
):
def
PR_MultiSine
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
8
,
fs_min
=
0
,
fs_max
=
1e9
,
frange
=
10
,
log
=
True
,
phases
=
None
,
deg
=
False
,
sample_inkr
=
1
):
"""
Returns an additive normalized Multisine time series.
\n
f1 = start frequency (may be adapted)
\n
...
...
@@ -625,47 +573,39 @@ def PR_MultiSine(
multi=array of time series values
\n
"""
freq
,
phase
,
T1
,
fs
=
PR_MultiSine_adapt
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
Nf
,
fs_min
=
fs_min
,
fs_max
=
fs_max
,
frange
=
frange
,
log
=
log
,
phases
=
phases
,
sample_inkr
=
sample_inkr
,
)
if
deg
:
# rad -> deg
phase
=
phase
*
sp
.
pi
/
180.0
freq
,
phase
,
T1
,
fs
=
PR_MultiSine_adapt
(
f1
,
Nperiods
,
Nsamples
,
Nf
=
Nf
,
fs_min
=
fs_min
,
fs_max
=
fs_max
,
frange
=
frange
,
log
=
log
,
phases
=
phases
,
sample_inkr
=
sample_inkr
)
ti
=
sp
.
arange
(
T1
*
fs
,
dtype
=
sp
.
float32
)
/
fs
if
deg
:
# rad -> deg
phase
=
phase
*
np
.
pi
/
180.0
ti
=
np
.
arange
(
T1
*
fs
,
dtype
=
np
.
float32
)
/
fs
multi
=
s
p
.
zeros
(
len
(
ti
),
dtype
=
s
p
.
float64
)
for
f
,
p
in
zip
(
freq
,
phase
):
multi
=
multi
+
s
p
.
sin
(
2
*
sp
.
pi
*
f
*
ti
+
p
)
multi
=
n
p
.
zeros
(
len
(
ti
),
dtype
=
n
p
.
float64
)
for
f
,
p
in
zip
(
freq
,
phase
):
multi
=
multi
+
n
p
.
sin
(
2
*
np
.
pi
*
f
*
ti
+
p
)
multi
=
multi
/
s
p
.
amax
(
s
p
.
absolute
(
multi
))
# normalize
multi
=
multi
/
n
p
.
amax
(
n
p
.
absolute
(
multi
))
# normalize
if
False
:
import
matplotlib.pyplot
as
mp
fig
=
mp
.
figure
(
1
)
fig
.
clear
()
pl1
=
fig
.
add_subplot
(
211
)
pl2
=
fig
.
add_subplot
(
212
)
pl1
.
plot
(
ti
,
multi
,
"
-o
"
)
pl2
.
plot
(
s
p
.
hstack
((
ti
,
ti
+
ti
[
-
1
]
+
ti
[
1
])),
s
p
.
hstack
((
multi
,
multi
)),
"
-o
"
)
pl1
.
plot
(
ti
,
multi
,
"
-o
"
)
pl2
.
plot
(
n
p
.
hstack
((
ti
,
ti
+
ti
[
-
1
]
+
ti
[
1
])),
n
p
.
hstack
((
multi
,
multi
)),
"
-o
"
)
mp
.
show
()
return
freq
,
phase
,
fs
,
multi
# frequency series, sample rate, sample timestamps, waveform
return
(
freq
,
phase
,
fs
,
multi
,
)
# frequency series, sample rate, sample timestamps, waveform
# PR_MultiSine(1,10,1500,5,fs_max=101,sample_inkr=7)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment