Browse Source

Further improvements to model based harmonics

tags/1.6.1
Trevor Irons 5 years ago
parent
commit
7e2d7b4eae
1 changed files with 52 additions and 134 deletions
  1. 52
    134
      akvo/tressel/harmonic.py

+ 52
- 134
akvo/tressel/harmonic.py View File

@@ -4,48 +4,7 @@ from scipy.optimize import minimize
4 4
 from scipy.linalg import lstsq as sclstsq
5 5
 import scipy.linalg as lin
6 6
 
7
-def harmonic2 ( f1, f2, sN, fs, nK, t ): 
8
-    """
9
-    Performs inverse calculation of two harmonics contaminating a signal. 
10
-    Args:
11
-        f01 = base frequency of the first sinusoidal noise 
12
-        f02 = base frequency of the second sinusoidal noise 
13
-        sN = signal containing noise 
14
-        fs = sampling frequency
15
-        nK = number of harmonics to calculate 
16
-        t = time samples 
17
-    """
18
-    print("building matrix 2")
19
-    A = np.zeros( (len(t),  4*nK) )
20
-    #f1 = f1MHz * 1e-3
21
-    #f2 = f2MHz * 1e-3
22
-    for irow, tt in enumerate(t): 
23
-        A[irow, 0:2*nK:2]  = np.cos( np.arange(nK)*2*np.pi*(f1/fs)*irow )
24
-        A[irow, 1:2*nK:2]  = np.sin( np.arange(nK)*2*np.pi*(f1/fs)*irow )
25
-        A[irow, 2*nK::2]   = np.cos( np.arange(nK)*2*np.pi*(f2/fs)*irow )
26
-        A[irow, 2*nK+1::2] = np.sin( np.arange(nK)*2*np.pi*(f2/fs)*irow )
27
-
28
-    v = np.linalg.lstsq(A, sN, rcond=1e-8)
29
-    #v = sclstsq(A, sN) #, rcond=1e-6)
30
-
31
-    alpha = v[0][0:2*nK:2] + 1e-16
32
-    beta  = v[0][1:2*nK:2] + 1e-16
33
-    amp = np.sqrt( alpha**2 + beta**2 )
34
-    phase = np.arctan(- beta/alpha)
35
-    
36
-    alpha2 = v[0][2*nK::2]   + 1e-16
37
-    beta2  = v[0][2*nK+1::2] + 1e-16
38
-    amp2 = np.sqrt( alpha2**2 + beta2**2 )
39
-    phase2 = np.arctan(- beta2/alpha2)
40
-
41
-    h = np.zeros(len(t))
42
-    for ik in range(nK):
43
-        h += np.sqrt( alpha[ik]**2 + beta[ik]**2)  * np.cos( 2.*np.pi*ik * (f1/fs) * np.arange(0, len(t), 1 )  + phase[ik] ) \
44
-           + np.sqrt(alpha2[ik]**2 + beta2[ik]**2) * np.cos( 2.*np.pi*ik * (f2/fs) * np.arange(0, len(t), 1 )  + phase2[ik] )
45
-
46
-    return sN-h
47
-
48
-def harmonic ( f0, sN, fs, nK, t ): 
7
+def harmonicEuler ( f0, sN, fs, nK, t ): 
49 8
     """
50 9
     Performs inverse calculation of harmonics contaminating a signal. 
51 10
     Args:
@@ -55,85 +14,56 @@ def harmonic ( f0, sN, fs, nK, t ):
55 14
         nK = number of harmonics to calculate 
56 15
         t = time samples 
57 16
     """
58
-    print("building matrix ")
59
-    A = np.zeros( (len(t),  2*nK) )
60
-    for irow, tt in enumerate(t): 
61
-        A[irow, 0::2] = np.cos( np.arange(nK)*2*np.pi*(f0/fs)*irow )
62
-        A[irow, 1::2] = np.sin( np.arange(nK)*2*np.pi*(f0/fs)*irow )
63
-
64
-    v = np.linalg.lstsq(A, sN, rcond=1e-16) # rcond=None) #, rcond=1e-8)
65
-    #v = sclstsq(A, sN) #, rcond=1e-6)
66
-    alpha = v[0][0::2]
67
-    beta  = v[0][1::2]
68 17
     
69
-    #print("Solving A A.T")
70
-    #v = lin.solve(np.dot(A,A.T).T, sN) #, rcond=1e-6)
71
-    #v = np.dot(A.T, v)
72
-    #v = np.dot(np.linalg.inv(np.dot(A.T, A)), np.dot(A.T, sN))
73
-    #alpha = v[0::2]
74
-    #beta  = v[1::2]
18
+    A = np.exp(1j* np.tile( np.arange(1,nK+1),(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile(np.arange(len(t)),(nK,1)).T  )
75 19
 
76
-    amp = np.sqrt( alpha**2 + beta**2 )
77
-    phase = np.arctan(- beta/alpha)
20
+    v = np.linalg.lstsq(A, sN, rcond=None) 
21
+    alpha = np.real(v[0]) 
22
+    beta  = np.imag(v[0]) 
78 23
 
79
-    #print("amp:", amp, " phase", phase)
24
+    amp = np.abs(v[0])     
25
+    phase = np.angle(v[0]) 
80 26
 
81 27
     h = np.zeros(len(t))
82 28
     for ik in range(nK):
83
-        h += np.sqrt(alpha[ik]**2 + beta[ik]**2) * np.cos( 2.*np.pi*ik * (f0/fs) * np.arange(0, len(t), 1 )  + phase[ik] )
84
-
85
-    #plt.matshow(A, aspect='auto')
86
-    #plt.colorbar()
87
-
88
-    #plt.figure()
89
-    #plt.plot(alpha)
90
-    #plt.plot(beta)
91
-    #plt.plot(amp)
92
-
93
-    #plt.figure()
94
-    #plt.plot(h)
95
-    #plt.title("modelled noise")
29
+        h +=  2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 )  + phase[ik] )
30
+    
96 31
     return sN-h
32
+    
33
+    res = sN-h # residual 
97 34
 
98
-
99
-def harmonicEuler ( f0, sN, fs, nK, t ): 
100
-    """
101
-    Performs inverse calculation of harmonics contaminating a signal. 
102
-    Args:
103
-        f0 = base frequency of the sinusoidal noise 
104
-        sN = signal containing noise 
105
-        fs = sampling frequency
106
-        nK = number of harmonics to calculate 
107
-        t = time samples 
108
-    """
35
+    # calculate jacobian 
36
+    #J = jacEuler(f0, sN, fs, nK, t)
37
+    #plt.matshow(np.real(J), aspect='auto')
109 38
     
110
-    #print("building Euler matrix ")
111
-    #A = np.zeros( (len(t),  nK), dtype=np.complex64)
112
-    #for irow, tt in enumerate(t): 
113
-    #    A[irow,:] = np.exp(1j* np.arange(1,nK+1) * 2*np.pi* (f0/fs) * irow)
39
+    #Jv = J * np.tile(v[0], (len(t) ,1)) 
40
+    #plt.matshow(np.real(Jv), aspect='auto')
114 41
     
115
-    #AA = np.zeros( (len(t),  nK), dtype=np.complex64)
116
-    A = np.exp(1j* np.tile( np.arange(1,nK+1),(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile(np.arange(len(t)),(nK,1)).T  )
117
-    #AA =  np.tile(np.arange(len(t)), (nK,1)).T 
42
+    #print ("shape J",  np.shape(J))
43
+    #print ("shape v",  np.shape(v[0]))
44
+    #print ("shape Jv",  np.shape(Jv))
118 45
 
119
-    #plt.matshow( np.imag(A), aspect='auto' )
120
-    #plt.matshow( np.real(AA), aspect='auto' )
46
+    #plt.figure()
47
+    #plt.plot(v[0])
48
+    #plt.figure()
49
+    #plt.plot(Jv)
121 50
     #plt.show()
122 51
     #exit()
123
-    #print ("A norm", np.linalg.norm(A - AA))
124 52
 
125
-    v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
126
-    alpha = np.real(v[0]) #[0::2]
127
-    beta  = np.imag(v[0]) #[1::2]
53
+    #jac =  np.linalg.norm( np.dot(Jv.T, res)) 
54
+    #print("norm ||", jac , "||", " at freq", f0)
128 55
 
129
-    amp = np.abs(v[0])     #np.sqrt( alpha**2 + beta**2 )
130
-    phase = np.angle(v[0]) # np.arctan(- beta/alpha)
56
+    #return res, jac 
131 57
 
132
-    h = np.zeros(len(t))
133
-    for ik in range(nK):
134
-        h +=  2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 )  + phase[ik] )
135 58
 
136
-    return sN-h
59
+def jacEuler( f0, sN, fs, nK, t):
60
+    print("building Jacobian matrix ")
61
+    J = np.zeros( (len(t),  nK), dtype=np.complex64 )
62
+    for it, tt in enumerate(t):
63
+        for ik, k in enumerate( np.arange(0, nK) ):
64
+            c = 1j*2.*np.pi*(ik+1.)
65
+            J[it, ik] = (c*np.exp(it*c*f0/fs)) / fs 
66
+    return J
137 67
 
138 68
 def harmonicEuler2 ( f0, f1, sN, fs, nK, t ): 
139 69
     """
@@ -145,14 +75,12 @@ def harmonicEuler2 ( f0, f1, sN, fs, nK, t ):
145 75
         nK = number of harmonics to calculate 
146 76
         t = time samples 
147 77
     """
148
-    print("building Euler matrix 2 ")
149
-    A = np.zeros( (len(t),  2*nK), dtype=np.complex64)
150
-    for irow, tt in enumerate(t): 
151
-        A[irow,0:nK]    = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f0/fs)*irow )
152
-        A[irow,nK:2*nK] = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f1/fs)*irow )
78
+    A1 = np.exp(1j* np.tile( np.arange(1,nK+1),(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile(np.arange(len(t)),(nK,1)).T  )
79
+    A2 = np.exp(1j* np.tile( np.arange(1,nK+1),(len(t), 1)) * 2*np.pi* (f1/fs) * np.tile(np.arange(len(t)),(nK,1)).T  )
80
+    A = np.concatenate( (A1, A2), axis=1 )
153 81
 
154
-    v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
155 82
 
83
+    v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
156 84
     amp = np.abs(v[0][0:nK])     
157 85
     phase = np.angle(v[0][0:nK]) 
158 86
     amp1 = np.abs(v[0][nK:2*nK])     
@@ -165,17 +93,6 @@ def harmonicEuler2 ( f0, f1, sN, fs, nK, t ):
165 93
 
166 94
     return sN-h
167 95
 
168
-def jacEuler( f0, sN, fs, nK, t):
169
-    print("building Jacobian matrix ")
170
-    J = np.zeros( (len(t),  nK), dtype=np.complex64 )
171
-    for it, tt in enumerate(t):
172
-        for ik, k in enumerate( np.arange(0, nK) ):
173
-            c = 1j*2.*np.pi*(ik+1.)*it
174
-            J[it, ik] = c*np.exp( c*f0/fs ) / fs 
175
-    #plt.matshow(np.imag(J), aspect='auto')
176
-    #plt.show()
177
-    return J
178
-
179 96
 def harmonicNorm ( f0, sN, fs, nK, t ): 
180 97
     return np.linalg.norm( harmonicEuler(f0, sN, fs, nK, t) )
181 98
 
@@ -186,15 +103,15 @@ def minHarmonic(f0, sN, fs, nK, t):
186 103
     f02 = guessf0(sN, fs)
187 104
     print("minHarmonic", f0, fs, nK, " guess=", f02)
188 105
     # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
189
-    res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, nK, t)) #, method='CG', jac=jacEuler) #, hess=None, bounds=None )
106
+    res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, nK, t), jac='2-point', method='BFGS') #, jac=jacEuler) #, hess=None, bounds=None )
190 107
     print(res)
191
-    return harmonicEuler(res.x[0], sN, fs, nK, t)
108
+    return harmonicEuler(res.x[0], sN, fs, nK, t)#[0]
192 109
 
193 110
 def minHarmonic2(f1, f2, sN, fs, nK, t):
194 111
     #f02 = guessf0(sN, fs)
195 112
     #print("minHarmonic2", f0, fs, nK, " guess=", f02)
196 113
     #methods with bounds, L-BFGS-B, TNC, SLSQP
197
-    res = minimize( harmonic2Norm, np.array((f1,f2)), args=(sN, fs, nK, t), jac='2-point') #, bounds=((f1-1.,f1+1.0),(f2-1.0,f2+1.0)), method='TNC' )
114
+    res = minimize( harmonic2Norm, np.array((f1,f2)), args=(sN, fs, nK, t), jac='2-point', method='BFGS') #, bounds=((f1-1.,f1+1.0),(f2-1.0,f2+1.0)), method='TNC' )
198 115
     print(res)
199 116
     return harmonicEuler2(res.x[0], res.x[1], sN, fs, nK, t) 
200 117
 
@@ -213,18 +130,20 @@ if __name__ == "__main__":
213 130
     import matplotlib.pyplot as plt 
214 131
 
215 132
     f0 = 60      # Hz
216
-    f1 = 61      # Hz
217
-    delta  = np.random.rand() 
218
-    delta2 =  np.random.rand() 
133
+    f1 = 60      # Hz
134
+    delta  = np.random.rand() - .5 
135
+    delta2 = np.random.rand() - .5 
219 136
     print("delta", delta)
137
+    print("delta2", delta2)
220 138
     fs = 10000   # GMR 
221 139
     t = np.arange(0, 1, 1/fs)
222
-    phi =  np.random.rand() 
223
-    phi2 = np.random.rand() 
140
+    phi =  2.*np.pi*np.random.rand() - np.pi 
141
+    phi2 = 2.*np.pi*np.random.rand() - np.pi
142
+    print("phi", phi, phi2)
224 143
     A =  1.0
225
-    A2 = 0.0 
144
+    A2 = 1.0 
226 145
     A3 = 1.0 
227
-    nK = 35
146
+    nK = 10
228 147
     T2 = .200
229 148
     sN  = A *np.sin( ( 1*(delta  +f0))*2*np.pi*t + phi ) + \
230 149
           A2*np.sin( ( 1*(delta2 +f1))*2*np.pi*t + phi2 ) + \
@@ -240,11 +159,10 @@ if __name__ == "__main__":
240 159
 
241 160
     # single freq
242 161
     #h = harmonicEuler( f0, sN, fs, nK, t) 
243
-    h = minHarmonic( f0, sN, fs, nK, t) 
162
+    #h = minHarmonic( f0, sN, fs, nK, t) 
244 163
     
245 164
     # two freqs 
246
-    #h = minHarmonic2( f0, f1, sN, fs, nK, t) 
247
-    #h = harmonic2( f0, f1, sN, fs, nK, t) 
165
+    h = minHarmonic2( f0+1e-2, f1-1e-2, sN, fs, nK, t) 
248 166
     #h = harmonicEuler2( f0, f1, sN, fs, nK, t) 
249 167
 
250 168
     plt.figure()

Loading…
Cancel
Save