##// END OF EJS Templates
Fix float slice (deprecationwarning)
Juan C. Espinoza -
r903:10adebce36d7
parent child
Show More
@@ -1,2746 +1,2746
1 1 import numpy
2 2 import math
3 3 from scipy import optimize, interpolate, signal, stats, ndimage
4 4 import re
5 5 import datetime
6 6 import copy
7 7 import sys
8 8 import importlib
9 9 import itertools
10 10
11 11 from jroproc_base import ProcessingUnit, Operation
12 12 from schainpy.model.data.jrodata import Parameters, hildebrand_sekhon
13 13
14 14
15 15 class ParametersProc(ProcessingUnit):
16 16
17 17 nSeconds = None
18 18
19 19 def __init__(self):
20 20 ProcessingUnit.__init__(self)
21 21
22 22 # self.objectDict = {}
23 23 self.buffer = None
24 24 self.firstdatatime = None
25 25 self.profIndex = 0
26 26 self.dataOut = Parameters()
27 27
28 28 def __updateObjFromInput(self):
29 29
30 30 self.dataOut.inputUnit = self.dataIn.type
31 31
32 32 self.dataOut.timeZone = self.dataIn.timeZone
33 33 self.dataOut.dstFlag = self.dataIn.dstFlag
34 34 self.dataOut.errorCount = self.dataIn.errorCount
35 35 self.dataOut.useLocalTime = self.dataIn.useLocalTime
36 36
37 37 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
38 38 self.dataOut.systemHeaderObj = self.dataIn.systemHeaderObj.copy()
39 39 self.dataOut.channelList = self.dataIn.channelList
40 40 self.dataOut.heightList = self.dataIn.heightList
41 41 self.dataOut.dtype = numpy.dtype([('real','<f4'),('imag','<f4')])
42 42 # self.dataOut.nHeights = self.dataIn.nHeights
43 43 # self.dataOut.nChannels = self.dataIn.nChannels
44 44 self.dataOut.nBaud = self.dataIn.nBaud
45 45 self.dataOut.nCode = self.dataIn.nCode
46 46 self.dataOut.code = self.dataIn.code
47 47 # self.dataOut.nProfiles = self.dataOut.nFFTPoints
48 48 self.dataOut.flagDiscontinuousBlock = self.dataIn.flagDiscontinuousBlock
49 49 # self.dataOut.utctime = self.firstdatatime
50 50 self.dataOut.utctime = self.dataIn.utctime
51 51 self.dataOut.flagDecodeData = self.dataIn.flagDecodeData #asumo q la data esta decodificada
52 52 self.dataOut.flagDeflipData = self.dataIn.flagDeflipData #asumo q la data esta sin flip
53 53 self.dataOut.nCohInt = self.dataIn.nCohInt
54 54 # self.dataOut.nIncohInt = 1
55 55 self.dataOut.ippSeconds = self.dataIn.ippSeconds
56 56 # self.dataOut.windowOfFilter = self.dataIn.windowOfFilter
57 57 self.dataOut.timeInterval = self.dataIn.timeInterval
58 58 self.dataOut.heightList = self.dataIn.getHeiRange()
59 59 self.dataOut.frequency = self.dataIn.frequency
60 60 self.dataOut.noise = self.dataIn.noise
61 61
62 62 def run(self):
63 63
64 64 #---------------------- Voltage Data ---------------------------
65 65
66 66 if self.dataIn.type == "Voltage":
67 67
68 68 self.__updateObjFromInput()
69 69 self.dataOut.data_pre = self.dataIn.data.copy()
70 70 self.dataOut.flagNoData = False
71 71 self.dataOut.utctimeInit = self.dataIn.utctime
72 72 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
73 73 return
74 74
75 75 #---------------------- Spectra Data ---------------------------
76 76
77 77 if self.dataIn.type == "Spectra":
78 78
79 79 self.dataOut.data_pre = (self.dataIn.data_spc,self.dataIn.data_cspc)
80 80 self.dataOut.abscissaList = self.dataIn.getVelRange(1)
81 81 # self.dataOut.noise = self.dataIn.getNoise()
82 82 self.dataOut.normFactor = self.dataIn.normFactor
83 83 self.dataOut.groupList = self.dataIn.pairsList
84 84 self.dataOut.flagNoData = False
85 85
86 86 #---------------------- Correlation Data ---------------------------
87 87
88 88 if self.dataIn.type == "Correlation":
89 89 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.dataIn.splitFunctions()
90 90
91 91 self.dataOut.data_pre = (self.dataIn.data_cf[acf_ind,:], self.dataIn.data_cf[ccf_ind,:,:])
92 92 self.dataOut.normFactor = (self.dataIn.normFactor[acf_ind,:], self.dataIn.normFactor[ccf_ind,:])
93 93 self.dataOut.groupList = (acf_pairs, ccf_pairs)
94 94
95 95 self.dataOut.abscissaList = self.dataIn.lagRange
96 96 self.dataOut.noise = self.dataIn.noise
97 97 self.dataOut.data_SNR = self.dataIn.SNR
98 98 self.dataOut.flagNoData = False
99 99 self.dataOut.nAvg = self.dataIn.nAvg
100 100
101 101 #---------------------- Parameters Data ---------------------------
102 102
103 103 if self.dataIn.type == "Parameters":
104 104 self.dataOut.copy(self.dataIn)
105 105 self.dataOut.utctimeInit = self.dataIn.utctime
106 106 self.dataOut.flagNoData = False
107 107
108 108 return True
109 109
110 110 self.__updateObjFromInput()
111 111 self.dataOut.utctimeInit = self.dataIn.utctime
112 112 self.dataOut.paramInterval = self.dataIn.timeInterval
113 113
114 114 return
115 115
116 116 class SpectralMoments(Operation):
117 117
118 118 '''
119 119 Function SpectralMoments()
120 120
121 121 Calculates moments (power, mean, standard deviation) and SNR of the signal
122 122
123 123 Type of dataIn: Spectra
124 124
125 125 Configuration Parameters:
126 126
127 127 dirCosx : Cosine director in X axis
128 128 dirCosy : Cosine director in Y axis
129 129
130 130 elevation :
131 131 azimuth :
132 132
133 133 Input:
134 134 channelList : simple channel list to select e.g. [2,3,7]
135 135 self.dataOut.data_pre : Spectral data
136 136 self.dataOut.abscissaList : List of frequencies
137 137 self.dataOut.noise : Noise level per channel
138 138
139 139 Affected:
140 140 self.dataOut.data_param : Parameters per channel
141 141 self.dataOut.data_SNR : SNR per channel
142 142
143 143 '''
144 144
145 145 def run(self, dataOut):
146 146
147 147 dataOut.data_pre = dataOut.data_pre[0]
148 148 data = dataOut.data_pre
149 149 absc = dataOut.abscissaList[:-1]
150 150 noise = dataOut.noise
151 151 nChannel = data.shape[0]
152 152 data_param = numpy.zeros((nChannel, 4, data.shape[2]))
153 153
154 154 for ind in range(nChannel):
155 155 data_param[ind,:,:] = self.__calculateMoments(data[ind,:,:], absc, noise[ind])
156 156
157 157 dataOut.data_param = data_param[:,1:,:]
158 158 dataOut.data_SNR = data_param[:,0]
159 159 dataOut.data_DOP = data_param[:,1]
160 160 return
161 161
162 162 def __calculateMoments(self, oldspec, oldfreq, n0, nicoh = None, graph = None, smooth = None, type1 = None, fwindow = None, snrth = None, dc = None, aliasing = None, oldfd = None, wwauto = None):
163 163
164 164 if (nicoh is None): nicoh = 1
165 165 if (graph is None): graph = 0
166 166 if (smooth is None): smooth = 0
167 167 elif (self.smooth < 3): smooth = 0
168 168
169 169 if (type1 is None): type1 = 0
170 170 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
171 171 if (snrth is None): snrth = -3
172 172 if (dc is None): dc = 0
173 173 if (aliasing is None): aliasing = 0
174 174 if (oldfd is None): oldfd = 0
175 175 if (wwauto is None): wwauto = 0
176 176
177 177 if (n0 < 1.e-20): n0 = 1.e-20
178 178
179 179 freq = oldfreq
180 180 vec_power = numpy.zeros(oldspec.shape[1])
181 181 vec_fd = numpy.zeros(oldspec.shape[1])
182 182 vec_w = numpy.zeros(oldspec.shape[1])
183 183 vec_snr = numpy.zeros(oldspec.shape[1])
184 184
185 185 for ind in range(oldspec.shape[1]):
186 186
187 187 spec = oldspec[:,ind]
188 188 aux = spec*fwindow
189 189 max_spec = aux.max()
190 190 m = list(aux).index(max_spec)
191 191
192 192 #Smooth
193 193 if (smooth == 0): spec2 = spec
194 194 else: spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
195 195
196 196 # Calculo de Momentos
197 197 bb = spec2[range(m,spec2.size)]
198 198 bb = (bb<n0).nonzero()
199 199 bb = bb[0]
200 200
201 201 ss = spec2[range(0,m + 1)]
202 202 ss = (ss<n0).nonzero()
203 203 ss = ss[0]
204 204
205 205 if (bb.size == 0):
206 206 bb0 = spec.size - 1 - m
207 207 else:
208 208 bb0 = bb[0] - 1
209 209 if (bb0 < 0):
210 210 bb0 = 0
211 211
212 212 if (ss.size == 0): ss1 = 1
213 213 else: ss1 = max(ss) + 1
214 214
215 215 if (ss1 > m): ss1 = m
216 216
217 217 valid = numpy.asarray(range(int(m + bb0 - ss1 + 1))) + ss1
218 218 power = ((spec2[valid] - n0)*fwindow[valid]).sum()
219 219 fd = ((spec2[valid]- n0)*freq[valid]*fwindow[valid]).sum()/power
220 220 w = math.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum()/power)
221 221 snr = (spec2.mean()-n0)/n0
222 222
223 223 if (snr < 1.e-20) :
224 224 snr = 1.e-20
225 225
226 226 vec_power[ind] = power
227 227 vec_fd[ind] = fd
228 228 vec_w[ind] = w
229 229 vec_snr[ind] = snr
230 230
231 231 moments = numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
232 232 return moments
233 233
234 234 #------------------ Get SA Parameters --------------------------
235 235
236 236 def GetSAParameters(self):
237 237 #SA en frecuencia
238 238 pairslist = self.dataOut.groupList
239 239 num_pairs = len(pairslist)
240 240
241 241 vel = self.dataOut.abscissaList
242 242 spectra = self.dataOut.data_pre
243 243 cspectra = self.dataIn.data_cspc
244 244 delta_v = vel[1] - vel[0]
245 245
246 246 #Calculating the power spectrum
247 247 spc_pow = numpy.sum(spectra, 3)*delta_v
248 248 #Normalizing Spectra
249 249 norm_spectra = spectra/spc_pow
250 250 #Calculating the norm_spectra at peak
251 251 max_spectra = numpy.max(norm_spectra, 3)
252 252
253 253 #Normalizing Cross Spectra
254 254 norm_cspectra = numpy.zeros(cspectra.shape)
255 255
256 256 for i in range(num_chan):
257 257 norm_cspectra[i,:,:] = cspectra[i,:,:]/numpy.sqrt(spc_pow[pairslist[i][0],:]*spc_pow[pairslist[i][1],:])
258 258
259 259 max_cspectra = numpy.max(norm_cspectra,2)
260 260 max_cspectra_index = numpy.argmax(norm_cspectra, 2)
261 261
262 262 for i in range(num_pairs):
263 263 cspc_par[i,:,:] = __calculateMoments(norm_cspectra)
264 264 #------------------- Get Lags ----------------------------------
265 265
266 266 class SALags(Operation):
267 267 '''
268 268 Function GetMoments()
269 269
270 270 Input:
271 271 self.dataOut.data_pre
272 272 self.dataOut.abscissaList
273 273 self.dataOut.noise
274 274 self.dataOut.normFactor
275 275 self.dataOut.data_SNR
276 276 self.dataOut.groupList
277 277 self.dataOut.nChannels
278 278
279 279 Affected:
280 280 self.dataOut.data_param
281 281
282 282 '''
283 283 def run(self, dataOut):
284 284 data_acf = dataOut.data_pre[0]
285 285 data_ccf = dataOut.data_pre[1]
286 286 normFactor_acf = dataOut.normFactor[0]
287 287 normFactor_ccf = dataOut.normFactor[1]
288 288 pairs_acf = dataOut.groupList[0]
289 289 pairs_ccf = dataOut.groupList[1]
290 290
291 291 nHeights = dataOut.nHeights
292 292 absc = dataOut.abscissaList
293 293 noise = dataOut.noise
294 294 SNR = dataOut.data_SNR
295 295 nChannels = dataOut.nChannels
296 296 # pairsList = dataOut.groupList
297 297 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairsList, nChannels)
298 298
299 299 for l in range(len(pairs_acf)):
300 300 data_acf[l,:,:] = data_acf[l,:,:]/normFactor_acf[l,:]
301 301
302 302 for l in range(len(pairs_ccf)):
303 303 data_ccf[l,:,:] = data_ccf[l,:,:]/normFactor_ccf[l,:]
304 304
305 305 dataOut.data_param = numpy.zeros((len(pairs_ccf)*2 + 1, nHeights))
306 306 dataOut.data_param[:-1,:] = self.__calculateTaus(data_acf, data_ccf, absc)
307 307 dataOut.data_param[-1,:] = self.__calculateLag1Phase(data_acf, absc)
308 308 return
309 309
310 310 # def __getPairsAutoCorr(self, pairsList, nChannels):
311 311 #
312 312 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
313 313 #
314 314 # for l in range(len(pairsList)):
315 315 # firstChannel = pairsList[l][0]
316 316 # secondChannel = pairsList[l][1]
317 317 #
318 318 # #Obteniendo pares de Autocorrelacion
319 319 # if firstChannel == secondChannel:
320 320 # pairsAutoCorr[firstChannel] = int(l)
321 321 #
322 322 # pairsAutoCorr = pairsAutoCorr.astype(int)
323 323 #
324 324 # pairsCrossCorr = range(len(pairsList))
325 325 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
326 326 #
327 327 # return pairsAutoCorr, pairsCrossCorr
328 328
329 329 def __calculateTaus(self, data_acf, data_ccf, lagRange):
330 330
331 331 lag0 = data_acf.shape[1]/2
332 332 #Funcion de Autocorrelacion
333 333 mean_acf = stats.nanmean(data_acf, axis = 0)
334 334
335 335 #Obtencion Indice de TauCross
336 336 ind_ccf = data_ccf.argmax(axis = 1)
337 337 #Obtencion Indice de TauAuto
338 338 ind_acf = numpy.zeros(ind_ccf.shape,dtype = 'int')
339 339 ccf_lag0 = data_ccf[:,lag0,:]
340 340
341 341 for i in range(ccf_lag0.shape[0]):
342 342 ind_acf[i,:] = numpy.abs(mean_acf - ccf_lag0[i,:]).argmin(axis = 0)
343 343
344 344 #Obtencion de TauCross y TauAuto
345 345 tau_ccf = lagRange[ind_ccf]
346 346 tau_acf = lagRange[ind_acf]
347 347
348 348 Nan1, Nan2 = numpy.where(tau_ccf == lagRange[0])
349 349
350 350 tau_ccf[Nan1,Nan2] = numpy.nan
351 351 tau_acf[Nan1,Nan2] = numpy.nan
352 352 tau = numpy.vstack((tau_ccf,tau_acf))
353 353
354 354 return tau
355 355
356 356 def __calculateLag1Phase(self, data, lagTRange):
357 357 data1 = stats.nanmean(data, axis = 0)
358 358 lag1 = numpy.where(lagTRange == 0)[0][0] + 1
359 359
360 360 phase = numpy.angle(data1[lag1,:])
361 361
362 362 return phase
363 363
364 364 class SpectralFitting(Operation):
365 365 '''
366 366 Function GetMoments()
367 367
368 368 Input:
369 369 Output:
370 370 Variables modified:
371 371 '''
372 372
373 373 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None):
374 374
375 375
376 376 if path != None:
377 377 sys.path.append(path)
378 378 self.dataOut.library = importlib.import_module(file)
379 379
380 380 #To be inserted as a parameter
381 381 groupArray = numpy.array(groupList)
382 382 # groupArray = numpy.array([[0,1],[2,3]])
383 383 self.dataOut.groupList = groupArray
384 384
385 385 nGroups = groupArray.shape[0]
386 386 nChannels = self.dataIn.nChannels
387 387 nHeights=self.dataIn.heightList.size
388 388
389 389 #Parameters Array
390 390 self.dataOut.data_param = None
391 391
392 392 #Set constants
393 393 constants = self.dataOut.library.setConstants(self.dataIn)
394 394 self.dataOut.constants = constants
395 395 M = self.dataIn.normFactor
396 396 N = self.dataIn.nFFTPoints
397 397 ippSeconds = self.dataIn.ippSeconds
398 398 K = self.dataIn.nIncohInt
399 399 pairsArray = numpy.array(self.dataIn.pairsList)
400 400
401 401 #List of possible combinations
402 402 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
403 403 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
404 404
405 405 if getSNR:
406 406 listChannels = groupArray.reshape((groupArray.size))
407 407 listChannels.sort()
408 408 noise = self.dataIn.getNoise()
409 409 self.dataOut.data_SNR = self.__getSNR(self.dataIn.data_spc[listChannels,:,:], noise[listChannels])
410 410
411 411 for i in range(nGroups):
412 412 coord = groupArray[i,:]
413 413
414 414 #Input data array
415 415 data = self.dataIn.data_spc[coord,:,:]/(M*N)
416 416 data = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
417 417
418 418 #Cross Spectra data array for Covariance Matrixes
419 419 ind = 0
420 420 for pairs in listComb:
421 421 pairsSel = numpy.array([coord[x],coord[y]])
422 422 indCross[ind] = int(numpy.where(numpy.all(pairsArray == pairsSel, axis = 1))[0][0])
423 423 ind += 1
424 424 dataCross = self.dataIn.data_cspc[indCross,:,:]/(M*N)
425 425 dataCross = dataCross**2/K
426 426
427 427 for h in range(nHeights):
428 428 # print self.dataOut.heightList[h]
429 429
430 430 #Input
431 431 d = data[:,h]
432 432
433 433 #Covariance Matrix
434 434 D = numpy.diag(d**2/K)
435 435 ind = 0
436 436 for pairs in listComb:
437 437 #Coordinates in Covariance Matrix
438 438 x = pairs[0]
439 439 y = pairs[1]
440 440 #Channel Index
441 441 S12 = dataCross[ind,:,h]
442 442 D12 = numpy.diag(S12)
443 443 #Completing Covariance Matrix with Cross Spectras
444 444 D[x*N:(x+1)*N,y*N:(y+1)*N] = D12
445 445 D[y*N:(y+1)*N,x*N:(x+1)*N] = D12
446 446 ind += 1
447 447 Dinv=numpy.linalg.inv(D)
448 448 L=numpy.linalg.cholesky(Dinv)
449 449 LT=L.T
450 450
451 451 dp = numpy.dot(LT,d)
452 452
453 453 #Initial values
454 454 data_spc = self.dataIn.data_spc[coord,:,h]
455 455
456 456 if (h>0)and(error1[3]<5):
457 457 p0 = self.dataOut.data_param[i,:,h-1]
458 458 else:
459 459 p0 = numpy.array(self.dataOut.library.initialValuesFunction(data_spc, constants, i))
460 460
461 461 try:
462 462 #Least Squares
463 463 minp,covp,infodict,mesg,ier = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants),full_output=True)
464 464 # minp,covp = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants))
465 465 #Chi square error
466 466 error0 = numpy.sum(infodict['fvec']**2)/(2*N)
467 467 #Error with Jacobian
468 468 error1 = self.dataOut.library.errorFunction(minp,constants,LT)
469 469 except:
470 470 minp = p0*numpy.nan
471 471 error0 = numpy.nan
472 472 error1 = p0*numpy.nan
473 473
474 474 #Save
475 475 if self.dataOut.data_param is None:
476 476 self.dataOut.data_param = numpy.zeros((nGroups, p0.size, nHeights))*numpy.nan
477 477 self.dataOut.data_error = numpy.zeros((nGroups, p0.size + 1, nHeights))*numpy.nan
478 478
479 479 self.dataOut.data_error[i,:,h] = numpy.hstack((error0,error1))
480 480 self.dataOut.data_param[i,:,h] = minp
481 481 return
482 482
483 483 def __residFunction(self, p, dp, LT, constants):
484 484
485 485 fm = self.dataOut.library.modelFunction(p, constants)
486 486 fmp=numpy.dot(LT,fm)
487 487
488 488 return dp-fmp
489 489
490 490 def __getSNR(self, z, noise):
491 491
492 492 avg = numpy.average(z, axis=1)
493 493 SNR = (avg.T-noise)/noise
494 494 SNR = SNR.T
495 495 return SNR
496 496
497 497 def __chisq(p,chindex,hindex):
498 498 #similar to Resid but calculates CHI**2
499 499 [LT,d,fm]=setupLTdfm(p,chindex,hindex)
500 500 dp=numpy.dot(LT,d)
501 501 fmp=numpy.dot(LT,fm)
502 502 chisq=numpy.dot((dp-fmp).T,(dp-fmp))
503 503 return chisq
504 504
505 505 class WindProfiler(Operation):
506 506
507 507 __isConfig = False
508 508
509 509 __initime = None
510 510 __lastdatatime = None
511 511 __integrationtime = None
512 512
513 513 __buffer = None
514 514
515 515 __dataReady = False
516 516
517 517 __firstdata = None
518 518
519 519 n = None
520 520
521 521 def __init__(self):
522 522 Operation.__init__(self)
523 523
524 524 def __calculateCosDir(self, elev, azim):
525 525 zen = (90 - elev)*numpy.pi/180
526 526 azim = azim*numpy.pi/180
527 527 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
528 528 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
529 529
530 530 signX = numpy.sign(numpy.cos(azim))
531 531 signY = numpy.sign(numpy.sin(azim))
532 532
533 533 cosDirX = numpy.copysign(cosDirX, signX)
534 534 cosDirY = numpy.copysign(cosDirY, signY)
535 535 return cosDirX, cosDirY
536 536
537 537 def __calculateAngles(self, theta_x, theta_y, azimuth):
538 538
539 539 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
540 540 zenith_arr = numpy.arccos(dir_cosw)
541 541 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
542 542
543 543 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
544 544 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
545 545
546 546 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
547 547
548 548 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
549 549
550 550 #
551 551 if horOnly:
552 552 A = numpy.c_[dir_cosu,dir_cosv]
553 553 else:
554 554 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
555 555 A = numpy.asmatrix(A)
556 556 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
557 557
558 558 return A1
559 559
560 560 def __correctValues(self, heiRang, phi, velRadial, SNR):
561 561 listPhi = phi.tolist()
562 562 maxid = listPhi.index(max(listPhi))
563 563 minid = listPhi.index(min(listPhi))
564 564
565 565 rango = range(len(phi))
566 566 # rango = numpy.delete(rango,maxid)
567 567
568 568 heiRang1 = heiRang*math.cos(phi[maxid])
569 569 heiRangAux = heiRang*math.cos(phi[minid])
570 570 indOut = (heiRang1 < heiRangAux[0]).nonzero()
571 571 heiRang1 = numpy.delete(heiRang1,indOut)
572 572
573 573 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
574 574 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
575 575
576 576 for i in rango:
577 577 x = heiRang*math.cos(phi[i])
578 578 y1 = velRadial[i,:]
579 579 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
580 580
581 581 x1 = heiRang1
582 582 y11 = f1(x1)
583 583
584 584 y2 = SNR[i,:]
585 585 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
586 586 y21 = f2(x1)
587 587
588 588 velRadial1[i,:] = y11
589 589 SNR1[i,:] = y21
590 590
591 591 return heiRang1, velRadial1, SNR1
592 592
593 593 def __calculateVelUVW(self, A, velRadial):
594 594
595 595 #Operacion Matricial
596 596 # velUVW = numpy.zeros((velRadial.shape[1],3))
597 597 # for ind in range(velRadial.shape[1]):
598 598 # velUVW[ind,:] = numpy.dot(A,velRadial[:,ind])
599 599 # velUVW = velUVW.transpose()
600 600 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
601 601 velUVW[:,:] = numpy.dot(A,velRadial)
602 602
603 603
604 604 return velUVW
605 605
606 606 # def techniqueDBS(self, velRadial0, dirCosx, disrCosy, azimuth, correct, horizontalOnly, heiRang, SNR0):
607 607
608 608 def techniqueDBS(self, kwargs):
609 609 """
610 610 Function that implements Doppler Beam Swinging (DBS) technique.
611 611
612 612 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
613 613 Direction correction (if necessary), Ranges and SNR
614 614
615 615 Output: Winds estimation (Zonal, Meridional and Vertical)
616 616
617 617 Parameters affected: Winds, height range, SNR
618 618 """
619 619 velRadial0 = kwargs['velRadial']
620 620 heiRang = kwargs['heightList']
621 621 SNR0 = kwargs['SNR']
622 622
623 623 if kwargs.has_key('dirCosx') and kwargs.has_key('dirCosy'):
624 624 theta_x = numpy.array(kwargs['dirCosx'])
625 625 theta_y = numpy.array(kwargs['dirCosy'])
626 626 else:
627 627 elev = numpy.array(kwargs['elevation'])
628 628 azim = numpy.array(kwargs['azimuth'])
629 629 theta_x, theta_y = self.__calculateCosDir(elev, azim)
630 630 azimuth = kwargs['correctAzimuth']
631 631 if kwargs.has_key('horizontalOnly'):
632 632 horizontalOnly = kwargs['horizontalOnly']
633 633 else: horizontalOnly = False
634 634 if kwargs.has_key('correctFactor'):
635 635 correctFactor = kwargs['correctFactor']
636 636 else: correctFactor = 1
637 637 if kwargs.has_key('channelList'):
638 638 channelList = kwargs['channelList']
639 639 if len(channelList) == 2:
640 640 horizontalOnly = True
641 641 arrayChannel = numpy.array(channelList)
642 642 param = param[arrayChannel,:,:]
643 643 theta_x = theta_x[arrayChannel]
644 644 theta_y = theta_y[arrayChannel]
645 645
646 646 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
647 647 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
648 648 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
649 649
650 650 #Calculo de Componentes de la velocidad con DBS
651 651 winds = self.__calculateVelUVW(A,velRadial1)
652 652
653 653 return winds, heiRang1, SNR1
654 654
655 655 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
656 656
657 657 nPairs = len(pairs_ccf)
658 658 posx = numpy.asarray(posx)
659 659 posy = numpy.asarray(posy)
660 660
661 661 #Rotacion Inversa para alinear con el azimuth
662 662 if azimuth!= None:
663 663 azimuth = azimuth*math.pi/180
664 664 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
665 665 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
666 666 else:
667 667 posx1 = posx
668 668 posy1 = posy
669 669
670 670 #Calculo de Distancias
671 671 distx = numpy.zeros(nPairs)
672 672 disty = numpy.zeros(nPairs)
673 673 dist = numpy.zeros(nPairs)
674 674 ang = numpy.zeros(nPairs)
675 675
676 676 for i in range(nPairs):
677 677 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
678 678 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
679 679 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
680 680 ang[i] = numpy.arctan2(disty[i],distx[i])
681 681
682 682 return distx, disty, dist, ang
683 683 #Calculo de Matrices
684 684 # nPairs = len(pairs)
685 685 # ang1 = numpy.zeros((nPairs, 2, 1))
686 686 # dist1 = numpy.zeros((nPairs, 2, 1))
687 687 #
688 688 # for j in range(nPairs):
689 689 # dist1[j,0,0] = dist[pairs[j][0]]
690 690 # dist1[j,1,0] = dist[pairs[j][1]]
691 691 # ang1[j,0,0] = ang[pairs[j][0]]
692 692 # ang1[j,1,0] = ang[pairs[j][1]]
693 693 #
694 694 # return distx,disty, dist1,ang1
695 695
696 696
697 697 def __calculateVelVer(self, phase, lagTRange, _lambda):
698 698
699 699 Ts = lagTRange[1] - lagTRange[0]
700 700 velW = -_lambda*phase/(4*math.pi*Ts)
701 701
702 702 return velW
703 703
704 704 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
705 705 nPairs = tau1.shape[0]
706 706 nHeights = tau1.shape[1]
707 707 vel = numpy.zeros((nPairs,3,nHeights))
708 708 dist1 = numpy.reshape(dist, (dist.size,1))
709 709
710 710 angCos = numpy.cos(ang)
711 711 angSin = numpy.sin(ang)
712 712
713 713 vel0 = dist1*tau1/(2*tau2**2)
714 714 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
715 715 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
716 716
717 717 ind = numpy.where(numpy.isinf(vel))
718 718 vel[ind] = numpy.nan
719 719
720 720 return vel
721 721
722 722 # def __getPairsAutoCorr(self, pairsList, nChannels):
723 723 #
724 724 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
725 725 #
726 726 # for l in range(len(pairsList)):
727 727 # firstChannel = pairsList[l][0]
728 728 # secondChannel = pairsList[l][1]
729 729 #
730 730 # #Obteniendo pares de Autocorrelacion
731 731 # if firstChannel == secondChannel:
732 732 # pairsAutoCorr[firstChannel] = int(l)
733 733 #
734 734 # pairsAutoCorr = pairsAutoCorr.astype(int)
735 735 #
736 736 # pairsCrossCorr = range(len(pairsList))
737 737 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
738 738 #
739 739 # return pairsAutoCorr, pairsCrossCorr
740 740
741 741 # def techniqueSA(self, pairsSelected, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, lagTRange, correctFactor):
742 742 def techniqueSA(self, kwargs):
743 743
744 744 """
745 745 Function that implements Spaced Antenna (SA) technique.
746 746
747 747 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
748 748 Direction correction (if necessary), Ranges and SNR
749 749
750 750 Output: Winds estimation (Zonal, Meridional and Vertical)
751 751
752 752 Parameters affected: Winds
753 753 """
754 754 position_x = kwargs['positionX']
755 755 position_y = kwargs['positionY']
756 756 azimuth = kwargs['azimuth']
757 757
758 758 if kwargs.has_key('correctFactor'):
759 759 correctFactor = kwargs['correctFactor']
760 760 else:
761 761 correctFactor = 1
762 762
763 763 groupList = kwargs['groupList']
764 764 pairs_ccf = groupList[1]
765 765 tau = kwargs['tau']
766 766 _lambda = kwargs['_lambda']
767 767
768 768 #Cross Correlation pairs obtained
769 769 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairssList, nChannels)
770 770 # pairsArray = numpy.array(pairsList)[pairsCrossCorr]
771 771 # pairsSelArray = numpy.array(pairsSelected)
772 772 # pairs = []
773 773 #
774 774 # #Wind estimation pairs obtained
775 775 # for i in range(pairsSelArray.shape[0]/2):
776 776 # ind1 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i], axis = 1))[0][0]
777 777 # ind2 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i + 1], axis = 1))[0][0]
778 778 # pairs.append((ind1,ind2))
779 779
780 780 indtau = tau.shape[0]/2
781 781 tau1 = tau[:indtau,:]
782 782 tau2 = tau[indtau:-1,:]
783 783 # tau1 = tau1[pairs,:]
784 784 # tau2 = tau2[pairs,:]
785 785 phase1 = tau[-1,:]
786 786
787 787 #---------------------------------------------------------------------
788 788 #Metodo Directo
789 789 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
790 790 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
791 791 winds = stats.nanmean(winds, axis=0)
792 792 #---------------------------------------------------------------------
793 793 #Metodo General
794 794 # distx, disty, dist = self.calculateDistance(position_x,position_y,pairsCrossCorr, pairsList, azimuth)
795 795 # #Calculo Coeficientes de Funcion de Correlacion
796 796 # F,G,A,B,H = self.calculateCoef(tau1,tau2,distx,disty,n)
797 797 # #Calculo de Velocidades
798 798 # winds = self.calculateVelUV(F,G,A,B,H)
799 799
800 800 #---------------------------------------------------------------------
801 801 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
802 802 winds = correctFactor*winds
803 803 return winds
804 804
805 805 def __checkTime(self, currentTime, paramInterval, outputInterval):
806 806
807 807 dataTime = currentTime + paramInterval
808 808 deltaTime = dataTime - self.__initime
809 809
810 810 if deltaTime >= outputInterval or deltaTime < 0:
811 811 self.__dataReady = True
812 812 return
813 813
814 814 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax, binkm=2):
815 815 '''
816 816 Function that implements winds estimation technique with detected meteors.
817 817
818 818 Input: Detected meteors, Minimum meteor quantity to wind estimation
819 819
820 820 Output: Winds estimation (Zonal and Meridional)
821 821
822 822 Parameters affected: Winds
823 823 '''
824 824 # print arrayMeteor.shape
825 825 #Settings
826 826 nInt = (heightMax - heightMin)/binkm
827 827 # print nInt
828 828 nInt = int(nInt)
829 829 # print nInt
830 830 winds = numpy.zeros((2,nInt))*numpy.nan
831 831
832 832 #Filter errors
833 833 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
834 834 finalMeteor = arrayMeteor[error,:]
835 835
836 836 #Meteor Histogram
837 837 finalHeights = finalMeteor[:,2]
838 838 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
839 839 nMeteorsPerI = hist[0]
840 840 heightPerI = hist[1]
841 841
842 842 #Sort of meteors
843 843 indSort = finalHeights.argsort()
844 844 finalMeteor2 = finalMeteor[indSort,:]
845 845
846 846 # Calculating winds
847 847 ind1 = 0
848 848 ind2 = 0
849 849
850 850 for i in range(nInt):
851 851 nMet = nMeteorsPerI[i]
852 852 ind1 = ind2
853 853 ind2 = ind1 + nMet
854 854
855 855 meteorAux = finalMeteor2[ind1:ind2,:]
856 856
857 857 if meteorAux.shape[0] >= meteorThresh:
858 858 vel = meteorAux[:, 6]
859 859 zen = meteorAux[:, 4]*numpy.pi/180
860 860 azim = meteorAux[:, 3]*numpy.pi/180
861 861
862 862 n = numpy.cos(zen)
863 863 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
864 864 # l = m*numpy.tan(azim)
865 865 l = numpy.sin(zen)*numpy.sin(azim)
866 866 m = numpy.sin(zen)*numpy.cos(azim)
867 867
868 868 A = numpy.vstack((l, m)).transpose()
869 869 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
870 870 windsAux = numpy.dot(A1, vel)
871 871
872 872 winds[0,i] = windsAux[0]
873 873 winds[1,i] = windsAux[1]
874 874
875 875 return winds, heightPerI[:-1]
876 876
877 877 def techniqueNSM_SA(self, **kwargs):
878 878 metArray = kwargs['metArray']
879 879 heightList = kwargs['heightList']
880 880 timeList = kwargs['timeList']
881 881
882 882 rx_location = kwargs['rx_location']
883 883 groupList = kwargs['groupList']
884 884 azimuth = kwargs['azimuth']
885 885 dfactor = kwargs['dfactor']
886 886 k = kwargs['k']
887 887
888 888 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
889 889 d = dist*dfactor
890 890 #Phase calculation
891 891 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
892 892
893 893 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
894 894
895 895 velEst = numpy.zeros((heightList.size,2))*numpy.nan
896 896 azimuth1 = azimuth1*numpy.pi/180
897 897
898 898 for i in range(heightList.size):
899 899 h = heightList[i]
900 900 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
901 901 metHeight = metArray1[indH,:]
902 902 if metHeight.shape[0] >= 2:
903 903 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
904 904 iazim = metHeight[:,1].astype(int)
905 905 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
906 906 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
907 907 A = numpy.asmatrix(A)
908 908 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
909 909 velHor = numpy.dot(A1,velAux)
910 910
911 911 velEst[i,:] = numpy.squeeze(velHor)
912 912 return velEst
913 913
914 914 def __getPhaseSlope(self, metArray, heightList, timeList):
915 915 meteorList = []
916 916 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
917 917 #Putting back together the meteor matrix
918 918 utctime = metArray[:,0]
919 919 uniqueTime = numpy.unique(utctime)
920 920
921 921 phaseDerThresh = 0.5
922 922 ippSeconds = timeList[1] - timeList[0]
923 923 sec = numpy.where(timeList>1)[0][0]
924 924 nPairs = metArray.shape[1] - 6
925 925 nHeights = len(heightList)
926 926
927 927 for t in uniqueTime:
928 928 metArray1 = metArray[utctime==t,:]
929 929 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
930 930 tmet = metArray1[:,1].astype(int)
931 931 hmet = metArray1[:,2].astype(int)
932 932
933 933 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
934 934 metPhase[:,:] = numpy.nan
935 935 metPhase[:,hmet,tmet] = metArray1[:,6:].T
936 936
937 937 #Delete short trails
938 938 metBool = ~numpy.isnan(metPhase[0,:,:])
939 939 heightVect = numpy.sum(metBool, axis = 1)
940 940 metBool[heightVect<sec,:] = False
941 941 metPhase[:,heightVect<sec,:] = numpy.nan
942 942
943 943 #Derivative
944 944 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
945 945 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
946 946 metPhase[phDerAux] = numpy.nan
947 947
948 948 #--------------------------METEOR DETECTION -----------------------------------------
949 949 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
950 950
951 951 for p in numpy.arange(nPairs):
952 952 phase = metPhase[p,:,:]
953 953 phDer = metDer[p,:,:]
954 954
955 955 for h in indMet:
956 956 height = heightList[h]
957 957 phase1 = phase[h,:] #82
958 958 phDer1 = phDer[h,:]
959 959
960 960 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
961 961
962 962 indValid = numpy.where(~numpy.isnan(phase1))[0]
963 963 initMet = indValid[0]
964 964 endMet = 0
965 965
966 966 for i in range(len(indValid)-1):
967 967
968 968 #Time difference
969 969 inow = indValid[i]
970 970 inext = indValid[i+1]
971 971 idiff = inext - inow
972 972 #Phase difference
973 973 phDiff = numpy.abs(phase1[inext] - phase1[inow])
974 974
975 975 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
976 976 sizeTrail = inow - initMet + 1
977 977 if sizeTrail>3*sec: #Too short meteors
978 978 x = numpy.arange(initMet,inow+1)*ippSeconds
979 979 y = phase1[initMet:inow+1]
980 980 ynnan = ~numpy.isnan(y)
981 981 x = x[ynnan]
982 982 y = y[ynnan]
983 983 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
984 984 ylin = x*slope + intercept
985 985 rsq = r_value**2
986 986 if rsq > 0.5:
987 987 vel = slope#*height*1000/(k*d)
988 988 estAux = numpy.array([utctime,p,height, vel, rsq])
989 989 meteorList.append(estAux)
990 990 initMet = inext
991 991 metArray2 = numpy.array(meteorList)
992 992
993 993 return metArray2
994 994
995 995 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
996 996
997 997 azimuth1 = numpy.zeros(len(pairslist))
998 998 dist = numpy.zeros(len(pairslist))
999 999
1000 1000 for i in range(len(rx_location)):
1001 1001 ch0 = pairslist[i][0]
1002 1002 ch1 = pairslist[i][1]
1003 1003
1004 1004 diffX = rx_location[ch0][0] - rx_location[ch1][0]
1005 1005 diffY = rx_location[ch0][1] - rx_location[ch1][1]
1006 1006 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
1007 1007 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
1008 1008
1009 1009 azimuth1 -= azimuth0
1010 1010 return azimuth1, dist
1011 1011
1012 1012 def techniqueNSM_DBS(self, **kwargs):
1013 1013 metArray = kwargs['metArray']
1014 1014 heightList = kwargs['heightList']
1015 1015 timeList = kwargs['timeList']
1016 1016 zenithList = kwargs['zenithList']
1017 1017 nChan = numpy.max(cmet) + 1
1018 1018 nHeights = len(heightList)
1019 1019
1020 1020 utctime = metArray[:,0]
1021 1021 cmet = metArray[:,1]
1022 1022 hmet = metArray1[:,3].astype(int)
1023 1023 h1met = heightList[hmet]*zenithList[cmet]
1024 1024 vmet = metArray1[:,5]
1025 1025
1026 1026 for i in range(nHeights - 1):
1027 1027 hmin = heightList[i]
1028 1028 hmax = heightList[i + 1]
1029 1029
1030 1030 vthisH = vmet[(h1met>=hmin) & (h1met<hmax)]
1031 1031
1032 1032
1033 1033
1034 1034 return data_output
1035 1035
1036 1036 def run(self, dataOut, technique, **kwargs):
1037 1037
1038 1038 param = dataOut.data_param
1039 1039 if dataOut.abscissaList != None:
1040 1040 absc = dataOut.abscissaList[:-1]
1041 1041 noise = dataOut.noise
1042 1042 heightList = dataOut.heightList
1043 1043 SNR = dataOut.data_SNR
1044 1044
1045 1045 if technique == 'DBS':
1046 1046
1047 1047 kwargs['velRadial'] = param[:,1,:] #Radial velocity
1048 1048 kwargs['heightList'] = heightList
1049 1049 kwargs['SNR'] = SNR
1050 1050
1051 1051 dataOut.data_output, dataOut.heightList, dataOut.data_SNR = self.techniqueDBS(kwargs) #DBS Function
1052 1052 dataOut.utctimeInit = dataOut.utctime
1053 1053 dataOut.outputInterval = dataOut.paramInterval
1054 1054
1055 1055 elif technique == 'SA':
1056 1056
1057 1057 #Parameters
1058 1058 # position_x = kwargs['positionX']
1059 1059 # position_y = kwargs['positionY']
1060 1060 # azimuth = kwargs['azimuth']
1061 1061 #
1062 1062 # if kwargs.has_key('crosspairsList'):
1063 1063 # pairs = kwargs['crosspairsList']
1064 1064 # else:
1065 1065 # pairs = None
1066 1066 #
1067 1067 # if kwargs.has_key('correctFactor'):
1068 1068 # correctFactor = kwargs['correctFactor']
1069 1069 # else:
1070 1070 # correctFactor = 1
1071 1071
1072 1072 # tau = dataOut.data_param
1073 1073 # _lambda = dataOut.C/dataOut.frequency
1074 1074 # pairsList = dataOut.groupList
1075 1075 # nChannels = dataOut.nChannels
1076 1076
1077 1077 kwargs['groupList'] = dataOut.groupList
1078 1078 kwargs['tau'] = dataOut.data_param
1079 1079 kwargs['_lambda'] = dataOut.C/dataOut.frequency
1080 1080 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
1081 1081 dataOut.data_output = self.techniqueSA(kwargs)
1082 1082 dataOut.utctimeInit = dataOut.utctime
1083 1083 dataOut.outputInterval = dataOut.timeInterval
1084 1084
1085 1085 elif technique == 'Meteors':
1086 1086 dataOut.flagNoData = True
1087 1087 self.__dataReady = False
1088 1088
1089 1089 if kwargs.has_key('nHours'):
1090 1090 nHours = kwargs['nHours']
1091 1091 else:
1092 1092 nHours = 1
1093 1093
1094 1094 if kwargs.has_key('meteorsPerBin'):
1095 1095 meteorThresh = kwargs['meteorsPerBin']
1096 1096 else:
1097 1097 meteorThresh = 6
1098 1098
1099 1099 if kwargs.has_key('hmin'):
1100 1100 hmin = kwargs['hmin']
1101 1101 else: hmin = 70
1102 1102 if kwargs.has_key('hmax'):
1103 1103 hmax = kwargs['hmax']
1104 1104 else: hmax = 110
1105 1105
1106 1106 if kwargs.has_key('BinKm'):
1107 1107 binkm = kwargs['BinKm']
1108 1108 else:
1109 1109 binkm = 2
1110 1110
1111 1111 dataOut.outputInterval = nHours*3600
1112 1112
1113 1113 if self.__isConfig == False:
1114 1114 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
1115 1115 #Get Initial LTC time
1116 1116 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
1117 1117 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
1118 1118
1119 1119 self.__isConfig = True
1120 1120
1121 1121 if self.__buffer is None:
1122 1122 self.__buffer = dataOut.data_param
1123 1123 self.__firstdata = copy.copy(dataOut)
1124 1124
1125 1125 else:
1126 1126 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
1127 1127
1128 1128 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
1129 1129
1130 1130 if self.__dataReady:
1131 1131 dataOut.utctimeInit = self.__initime
1132 1132
1133 1133 self.__initime += dataOut.outputInterval #to erase time offset
1134 1134
1135 1135 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax, binkm)
1136 1136 dataOut.flagNoData = False
1137 1137 self.__buffer = None
1138 1138
1139 1139 elif technique == 'Meteors1':
1140 1140 dataOut.flagNoData = True
1141 1141 self.__dataReady = False
1142 1142
1143 1143 if kwargs.has_key('nMins'):
1144 1144 nMins = kwargs['nMins']
1145 1145 else: nMins = 20
1146 1146 if kwargs.has_key('rx_location'):
1147 1147 rx_location = kwargs['rx_location']
1148 1148 else: rx_location = [(0,1),(1,1),(1,0)]
1149 1149 if kwargs.has_key('azimuth'):
1150 1150 azimuth = kwargs['azimuth']
1151 1151 else: azimuth = 51
1152 1152 if kwargs.has_key('dfactor'):
1153 1153 dfactor = kwargs['dfactor']
1154 1154 if kwargs.has_key('mode'):
1155 1155 mode = kwargs['mode']
1156 1156 else: mode = 'SA'
1157 1157
1158 1158 #Borrar luego esto
1159 1159 if dataOut.groupList is None:
1160 1160 dataOut.groupList = [(0,1),(0,2),(1,2)]
1161 1161 groupList = dataOut.groupList
1162 1162 C = 3e8
1163 1163 freq = 50e6
1164 1164 lamb = C/freq
1165 1165 k = 2*numpy.pi/lamb
1166 1166
1167 1167 timeList = dataOut.abscissaList
1168 1168 heightList = dataOut.heightList
1169 1169
1170 1170 if self.__isConfig == False:
1171 1171 dataOut.outputInterval = nMins*60
1172 1172 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
1173 1173 #Get Initial LTC time
1174 1174 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
1175 1175 minuteAux = initime.minute
1176 1176 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
1177 1177 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
1178 1178
1179 1179 self.__isConfig = True
1180 1180
1181 1181 if self.__buffer is None:
1182 1182 self.__buffer = dataOut.data_param
1183 1183 self.__firstdata = copy.copy(dataOut)
1184 1184
1185 1185 else:
1186 1186 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
1187 1187
1188 1188 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
1189 1189
1190 1190 if self.__dataReady:
1191 1191 dataOut.utctimeInit = self.__initime
1192 1192 self.__initime += dataOut.outputInterval #to erase time offset
1193 1193
1194 1194 metArray = self.__buffer
1195 1195 if mode == 'SA':
1196 1196 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
1197 1197 elif mode == 'DBS':
1198 1198 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList)
1199 1199 dataOut.data_output = dataOut.data_output.T
1200 1200 dataOut.flagNoData = False
1201 1201 self.__buffer = None
1202 1202
1203 1203 return
1204 1204
1205 1205 class EWDriftsEstimation(Operation):
1206 1206
1207 1207 def __init__(self):
1208 1208 Operation.__init__(self)
1209 1209
1210 1210 def __correctValues(self, heiRang, phi, velRadial, SNR):
1211 1211 listPhi = phi.tolist()
1212 1212 maxid = listPhi.index(max(listPhi))
1213 1213 minid = listPhi.index(min(listPhi))
1214 1214
1215 1215 rango = range(len(phi))
1216 1216 # rango = numpy.delete(rango,maxid)
1217 1217
1218 1218 heiRang1 = heiRang*math.cos(phi[maxid])
1219 1219 heiRangAux = heiRang*math.cos(phi[minid])
1220 1220 indOut = (heiRang1 < heiRangAux[0]).nonzero()
1221 1221 heiRang1 = numpy.delete(heiRang1,indOut)
1222 1222
1223 1223 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
1224 1224 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
1225 1225
1226 1226 for i in rango:
1227 1227 x = heiRang*math.cos(phi[i])
1228 1228 y1 = velRadial[i,:]
1229 1229 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
1230 1230
1231 1231 x1 = heiRang1
1232 1232 y11 = f1(x1)
1233 1233
1234 1234 y2 = SNR[i,:]
1235 1235 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
1236 1236 y21 = f2(x1)
1237 1237
1238 1238 velRadial1[i,:] = y11
1239 1239 SNR1[i,:] = y21
1240 1240
1241 1241 return heiRang1, velRadial1, SNR1
1242 1242
1243 1243 def run(self, dataOut, zenith, zenithCorrection):
1244 1244 heiRang = dataOut.heightList
1245 1245 velRadial = dataOut.data_param[:,3,:]
1246 1246 SNR = dataOut.data_SNR
1247 1247
1248 1248 zenith = numpy.array(zenith)
1249 1249 zenith -= zenithCorrection
1250 1250 zenith *= numpy.pi/180
1251 1251
1252 1252 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
1253 1253
1254 1254 alp = zenith[0]
1255 1255 bet = zenith[1]
1256 1256
1257 1257 w_w = velRadial1[0,:]
1258 1258 w_e = velRadial1[1,:]
1259 1259
1260 1260 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
1261 1261 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
1262 1262
1263 1263 winds = numpy.vstack((u,w))
1264 1264
1265 1265 dataOut.heightList = heiRang1
1266 1266 dataOut.data_output = winds
1267 1267 dataOut.data_SNR = SNR1
1268 1268
1269 1269 dataOut.utctimeInit = dataOut.utctime
1270 1270 dataOut.outputInterval = dataOut.timeInterval
1271 1271 return
1272 1272
1273 1273 #--------------- Non Specular Meteor ----------------
1274 1274
1275 1275 class NonSpecularMeteorDetection(Operation):
1276 1276
1277 1277 def run(self, mode, SNRthresh=8, phaseDerThresh=0.5, cohThresh=0.8, allData = False):
1278 1278 data_acf = self.dataOut.data_pre[0]
1279 1279 data_ccf = self.dataOut.data_pre[1]
1280 1280
1281 1281 lamb = self.dataOut.C/self.dataOut.frequency
1282 1282 tSamp = self.dataOut.ippSeconds*self.dataOut.nCohInt
1283 1283 paramInterval = self.dataOut.paramInterval
1284 1284
1285 1285 nChannels = data_acf.shape[0]
1286 1286 nLags = data_acf.shape[1]
1287 1287 nProfiles = data_acf.shape[2]
1288 1288 nHeights = self.dataOut.nHeights
1289 1289 nCohInt = self.dataOut.nCohInt
1290 1290 sec = numpy.round(nProfiles/self.dataOut.paramInterval)
1291 1291 heightList = self.dataOut.heightList
1292 1292 ippSeconds = self.dataOut.ippSeconds*self.dataOut.nCohInt*self.dataOut.nAvg
1293 1293 utctime = self.dataOut.utctime
1294 1294
1295 1295 self.dataOut.abscissaList = numpy.arange(0,paramInterval+ippSeconds,ippSeconds)
1296 1296
1297 1297 #------------------------ SNR --------------------------------------
1298 1298 power = data_acf[:,0,:,:].real
1299 1299 noise = numpy.zeros(nChannels)
1300 1300 SNR = numpy.zeros(power.shape)
1301 1301 for i in range(nChannels):
1302 1302 noise[i] = hildebrand_sekhon(power[i,:], nCohInt)
1303 1303 SNR[i] = (power[i]-noise[i])/noise[i]
1304 1304 SNRm = numpy.nanmean(SNR, axis = 0)
1305 1305 SNRdB = 10*numpy.log10(SNR)
1306 1306
1307 1307 if mode == 'SA':
1308 1308 nPairs = data_ccf.shape[0]
1309 1309 #---------------------- Coherence and Phase --------------------------
1310 1310 phase = numpy.zeros(data_ccf[:,0,:,:].shape)
1311 1311 # phase1 = numpy.copy(phase)
1312 1312 coh1 = numpy.zeros(data_ccf[:,0,:,:].shape)
1313 1313
1314 1314 for p in range(nPairs):
1315 1315 ch0 = self.dataOut.groupList[p][0]
1316 1316 ch1 = self.dataOut.groupList[p][1]
1317 1317 ccf = data_ccf[p,0,:,:]/numpy.sqrt(data_acf[ch0,0,:,:]*data_acf[ch1,0,:,:])
1318 1318 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
1319 1319 # phase1[p,:,:] = numpy.angle(ccf) #median filter
1320 1320 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
1321 1321 # coh1[p,:,:] = numpy.abs(ccf) #median filter
1322 1322 coh = numpy.nanmax(coh1, axis = 0)
1323 1323 # struc = numpy.ones((5,1))
1324 1324 # coh = ndimage.morphology.grey_dilation(coh, size=(10,1))
1325 1325 #---------------------- Radial Velocity ----------------------------
1326 1326 phaseAux = numpy.mean(numpy.angle(data_acf[:,1,:,:]), axis = 0)
1327 1327 velRad = phaseAux*lamb/(4*numpy.pi*tSamp)
1328 1328
1329 1329 if allData:
1330 1330 boolMetFin = ~numpy.isnan(SNRm)
1331 1331 # coh[:-1,:] = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
1332 1332 else:
1333 1333 #------------------------ Meteor mask ---------------------------------
1334 1334 # #SNR mask
1335 1335 # boolMet = (SNRdB>SNRthresh)#|(~numpy.isnan(SNRdB))
1336 1336 #
1337 1337 # #Erase small objects
1338 1338 # boolMet1 = self.__erase_small(boolMet, 2*sec, 5)
1339 1339 #
1340 1340 # auxEEJ = numpy.sum(boolMet1,axis=0)
1341 1341 # indOver = auxEEJ>nProfiles*0.8 #Use this later
1342 1342 # indEEJ = numpy.where(indOver)[0]
1343 1343 # indNEEJ = numpy.where(~indOver)[0]
1344 1344 #
1345 1345 # boolMetFin = boolMet1
1346 1346 #
1347 1347 # if indEEJ.size > 0:
1348 1348 # boolMet1[:,indEEJ] = False #Erase heights with EEJ
1349 1349 #
1350 1350 # boolMet2 = coh > cohThresh
1351 1351 # boolMet2 = self.__erase_small(boolMet2, 2*sec,5)
1352 1352 #
1353 1353 # #Final Meteor mask
1354 1354 # boolMetFin = boolMet1|boolMet2
1355 1355
1356 1356 #Coherence mask
1357 1357 boolMet1 = coh > 0.75
1358 1358 struc = numpy.ones((30,1))
1359 1359 boolMet1 = ndimage.morphology.binary_dilation(boolMet1, structure=struc)
1360 1360
1361 1361 #Derivative mask
1362 1362 derPhase = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
1363 1363 boolMet2 = derPhase < 0.2
1364 1364 # boolMet2 = ndimage.morphology.binary_opening(boolMet2)
1365 1365 # boolMet2 = ndimage.morphology.binary_closing(boolMet2, structure = numpy.ones((10,1)))
1366 1366 boolMet2 = ndimage.median_filter(boolMet2,size=5)
1367 1367 boolMet2 = numpy.vstack((boolMet2,numpy.full((1,nHeights), True, dtype=bool)))
1368 1368 # #Final mask
1369 1369 # boolMetFin = boolMet2
1370 1370 boolMetFin = boolMet1&boolMet2
1371 1371 # boolMetFin = ndimage.morphology.binary_dilation(boolMetFin)
1372 1372 #Creating data_param
1373 1373 coordMet = numpy.where(boolMetFin)
1374 1374
1375 1375 tmet = coordMet[0]
1376 1376 hmet = coordMet[1]
1377 1377
1378 1378 data_param = numpy.zeros((tmet.size, 6 + nPairs))
1379 1379 data_param[:,0] = utctime
1380 1380 data_param[:,1] = tmet
1381 1381 data_param[:,2] = hmet
1382 1382 data_param[:,3] = SNRm[tmet,hmet]
1383 1383 data_param[:,4] = velRad[tmet,hmet]
1384 1384 data_param[:,5] = coh[tmet,hmet]
1385 1385 data_param[:,6:] = phase[:,tmet,hmet].T
1386 1386
1387 1387 elif mode == 'DBS':
1388 1388 self.dataOut.groupList = numpy.arange(nChannels)
1389 1389
1390 1390 #Radial Velocities
1391 1391 # phase = numpy.angle(data_acf[:,1,:,:])
1392 1392 phase = ndimage.median_filter(numpy.angle(data_acf[:,1,:,:]), size = (1,5,1))
1393 1393 velRad = phase*lamb/(4*numpy.pi*tSamp)
1394 1394
1395 1395 #Spectral width
1396 1396 acf1 = ndimage.median_filter(numpy.abs(data_acf[:,1,:,:]), size = (1,5,1))
1397 1397 acf2 = ndimage.median_filter(numpy.abs(data_acf[:,2,:,:]), size = (1,5,1))
1398 1398
1399 1399 spcWidth = (lamb/(2*numpy.sqrt(6)*numpy.pi*tSamp))*numpy.sqrt(numpy.log(acf1/acf2))
1400 1400 # velRad = ndimage.median_filter(velRad, size = (1,5,1))
1401 1401 if allData:
1402 1402 boolMetFin = ~numpy.isnan(SNRdB)
1403 1403 else:
1404 1404 #SNR
1405 1405 boolMet1 = (SNRdB>SNRthresh) #SNR mask
1406 1406 boolMet1 = ndimage.median_filter(boolMet1, size=(1,5,5))
1407 1407
1408 1408 #Radial velocity
1409 1409 boolMet2 = numpy.abs(velRad) < 30
1410 1410 boolMet2 = ndimage.median_filter(boolMet2, (1,5,5))
1411 1411
1412 1412 #Spectral Width
1413 1413 boolMet3 = spcWidth < 30
1414 1414 boolMet3 = ndimage.median_filter(boolMet3, (1,5,5))
1415 1415 # boolMetFin = self.__erase_small(boolMet1, 10,5)
1416 1416 boolMetFin = boolMet1&boolMet2&boolMet3
1417 1417
1418 1418 #Creating data_param
1419 1419 coordMet = numpy.where(boolMetFin)
1420 1420
1421 1421 cmet = coordMet[0]
1422 1422 tmet = coordMet[1]
1423 1423 hmet = coordMet[2]
1424 1424
1425 1425 data_param = numpy.zeros((tmet.size, 7))
1426 1426 data_param[:,0] = utctime
1427 1427 data_param[:,1] = cmet
1428 1428 data_param[:,2] = tmet
1429 1429 data_param[:,3] = hmet
1430 1430 data_param[:,4] = SNR[cmet,tmet,hmet].T
1431 1431 data_param[:,5] = velRad[cmet,tmet,hmet].T
1432 1432 data_param[:,6] = spcWidth[cmet,tmet,hmet].T
1433 1433
1434 1434 # self.dataOut.data_param = data_int
1435 1435 if len(data_param) == 0:
1436 1436 self.dataOut.flagNoData = True
1437 1437 else:
1438 1438 self.dataOut.data_param = data_param
1439 1439
1440 1440 def __erase_small(self, binArray, threshX, threshY):
1441 1441 labarray, numfeat = ndimage.measurements.label(binArray)
1442 1442 binArray1 = numpy.copy(binArray)
1443 1443
1444 1444 for i in range(1,numfeat + 1):
1445 1445 auxBin = (labarray==i)
1446 1446 auxSize = auxBin.sum()
1447 1447
1448 1448 x,y = numpy.where(auxBin)
1449 1449 widthX = x.max() - x.min()
1450 1450 widthY = y.max() - y.min()
1451 1451
1452 1452 #width X: 3 seg -> 12.5*3
1453 1453 #width Y:
1454 1454
1455 1455 if (auxSize < 50) or (widthX < threshX) or (widthY < threshY):
1456 1456 binArray1[auxBin] = False
1457 1457
1458 1458 return binArray1
1459 1459
1460 1460 #--------------- Specular Meteor ----------------
1461 1461
1462 1462 class SMDetection(Operation):
1463 1463 '''
1464 1464 Function DetectMeteors()
1465 1465 Project developed with paper:
1466 1466 HOLDSWORTH ET AL. 2004
1467 1467
1468 1468 Input:
1469 1469 self.dataOut.data_pre
1470 1470
1471 1471 centerReceiverIndex: From the channels, which is the center receiver
1472 1472
1473 1473 hei_ref: Height reference for the Beacon signal extraction
1474 1474 tauindex:
1475 1475 predefinedPhaseShifts: Predefined phase offset for the voltge signals
1476 1476
1477 1477 cohDetection: Whether to user Coherent detection or not
1478 1478 cohDet_timeStep: Coherent Detection calculation time step
1479 1479 cohDet_thresh: Coherent Detection phase threshold to correct phases
1480 1480
1481 1481 noise_timeStep: Noise calculation time step
1482 1482 noise_multiple: Noise multiple to define signal threshold
1483 1483
1484 1484 multDet_timeLimit: Multiple Detection Removal time limit in seconds
1485 1485 multDet_rangeLimit: Multiple Detection Removal range limit in km
1486 1486
1487 1487 phaseThresh: Maximum phase difference between receiver to be consider a meteor
1488 1488 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
1489 1489
1490 1490 hmin: Minimum Height of the meteor to use it in the further wind estimations
1491 1491 hmax: Maximum Height of the meteor to use it in the further wind estimations
1492 1492 azimuth: Azimuth angle correction
1493 1493
1494 1494 Affected:
1495 1495 self.dataOut.data_param
1496 1496
1497 1497 Rejection Criteria (Errors):
1498 1498 0: No error; analysis OK
1499 1499 1: SNR < SNR threshold
1500 1500 2: angle of arrival (AOA) ambiguously determined
1501 1501 3: AOA estimate not feasible
1502 1502 4: Large difference in AOAs obtained from different antenna baselines
1503 1503 5: echo at start or end of time series
1504 1504 6: echo less than 5 examples long; too short for analysis
1505 1505 7: echo rise exceeds 0.3s
1506 1506 8: echo decay time less than twice rise time
1507 1507 9: large power level before echo
1508 1508 10: large power level after echo
1509 1509 11: poor fit to amplitude for estimation of decay time
1510 1510 12: poor fit to CCF phase variation for estimation of radial drift velocity
1511 1511 13: height unresolvable echo: not valid height within 70 to 110 km
1512 1512 14: height ambiguous echo: more then one possible height within 70 to 110 km
1513 1513 15: radial drift velocity or projected horizontal velocity exceeds 200 m/s
1514 1514 16: oscilatory echo, indicating event most likely not an underdense echo
1515 1515
1516 1516 17: phase difference in meteor Reestimation
1517 1517
1518 1518 Data Storage:
1519 1519 Meteors for Wind Estimation (8):
1520 1520 Utc Time | Range Height
1521 1521 Azimuth Zenith errorCosDir
1522 1522 VelRad errorVelRad
1523 1523 Phase0 Phase1 Phase2 Phase3
1524 1524 TypeError
1525 1525
1526 1526 '''
1527 1527
1528 1528 def run(self, dataOut, hei_ref = None, tauindex = 0,
1529 1529 phaseOffsets = None,
1530 1530 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
1531 1531 noise_timeStep = 4, noise_multiple = 4,
1532 1532 multDet_timeLimit = 1, multDet_rangeLimit = 3,
1533 1533 phaseThresh = 20, SNRThresh = 5,
1534 1534 hmin = 50, hmax=150, azimuth = 0,
1535 1535 channelPositions = None) :
1536 1536
1537 1537
1538 1538 #Getting Pairslist
1539 1539 if channelPositions is None:
1540 1540 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
1541 1541 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
1542 1542 meteorOps = SMOperations()
1543 1543 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
1544 1544 heiRang = dataOut.getHeiRange()
1545 1545 #Get Beacon signal - No Beacon signal anymore
1546 1546 # newheis = numpy.where(self.dataOut.heightList>self.dataOut.radarControllerHeaderObj.Taus[tauindex])
1547 1547 #
1548 1548 # if hei_ref != None:
1549 1549 # newheis = numpy.where(self.dataOut.heightList>hei_ref)
1550 1550 #
1551 1551
1552 1552
1553 1553 #****************REMOVING HARDWARE PHASE DIFFERENCES***************
1554 1554 # see if the user put in pre defined phase shifts
1555 1555 voltsPShift = dataOut.data_pre.copy()
1556 1556
1557 1557 # if predefinedPhaseShifts != None:
1558 1558 # hardwarePhaseShifts = numpy.array(predefinedPhaseShifts)*numpy.pi/180
1559 1559 #
1560 1560 # # elif beaconPhaseShifts:
1561 1561 # # #get hardware phase shifts using beacon signal
1562 1562 # # hardwarePhaseShifts = self.__getHardwarePhaseDiff(self.dataOut.data_pre, pairslist, newheis, 10)
1563 1563 # # hardwarePhaseShifts = numpy.insert(hardwarePhaseShifts,centerReceiverIndex,0)
1564 1564 #
1565 1565 # else:
1566 1566 # hardwarePhaseShifts = numpy.zeros(5)
1567 1567 #
1568 1568 # voltsPShift = numpy.zeros((self.dataOut.data_pre.shape[0],self.dataOut.data_pre.shape[1],self.dataOut.data_pre.shape[2]), dtype = 'complex')
1569 1569 # for i in range(self.dataOut.data_pre.shape[0]):
1570 1570 # voltsPShift[i,:,:] = self.__shiftPhase(self.dataOut.data_pre[i,:,:], hardwarePhaseShifts[i])
1571 1571
1572 1572 #******************END OF REMOVING HARDWARE PHASE DIFFERENCES*********
1573 1573
1574 1574 #Remove DC
1575 1575 voltsDC = numpy.mean(voltsPShift,1)
1576 1576 voltsDC = numpy.mean(voltsDC,1)
1577 1577 for i in range(voltsDC.shape[0]):
1578 1578 voltsPShift[i] = voltsPShift[i] - voltsDC[i]
1579 1579
1580 1580 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
1581 1581 # voltsPShift = voltsPShift[:,:,:newheis[0][0]]
1582 1582
1583 1583 #************ FIND POWER OF DATA W/COH OR NON COH DETECTION (3.4) **********
1584 1584 #Coherent Detection
1585 1585 if cohDetection:
1586 1586 #use coherent detection to get the net power
1587 1587 cohDet_thresh = cohDet_thresh*numpy.pi/180
1588 1588 voltsPShift = self.__coherentDetection(voltsPShift, cohDet_timeStep, dataOut.timeInterval, pairslist0, cohDet_thresh)
1589 1589
1590 1590 #Non-coherent detection!
1591 1591 powerNet = numpy.nansum(numpy.abs(voltsPShift[:,:,:])**2,0)
1592 1592 #********** END OF COH/NON-COH POWER CALCULATION**********************
1593 1593
1594 1594 #********** FIND THE NOISE LEVEL AND POSSIBLE METEORS ****************
1595 1595 #Get noise
1596 1596 noise, noise1 = self.__getNoise(powerNet, noise_timeStep, dataOut.timeInterval)
1597 1597 # noise = self.getNoise1(powerNet, noise_timeStep, self.dataOut.timeInterval)
1598 1598 #Get signal threshold
1599 1599 signalThresh = noise_multiple*noise
1600 1600 #Meteor echoes detection
1601 1601 listMeteors = self.__findMeteors(powerNet, signalThresh)
1602 1602 #******* END OF NOISE LEVEL AND POSSIBLE METEORS CACULATION **********
1603 1603
1604 1604 #************** REMOVE MULTIPLE DETECTIONS (3.5) ***************************
1605 1605 #Parameters
1606 1606 heiRange = dataOut.getHeiRange()
1607 1607 rangeInterval = heiRange[1] - heiRange[0]
1608 1608 rangeLimit = multDet_rangeLimit/rangeInterval
1609 1609 timeLimit = multDet_timeLimit/dataOut.timeInterval
1610 1610 #Multiple detection removals
1611 1611 listMeteors1 = self.__removeMultipleDetections(listMeteors, rangeLimit, timeLimit)
1612 1612 #************ END OF REMOVE MULTIPLE DETECTIONS **********************
1613 1613
1614 1614 #********************* METEOR REESTIMATION (3.7, 3.8, 3.9, 3.10) ********************
1615 1615 #Parameters
1616 1616 phaseThresh = phaseThresh*numpy.pi/180
1617 1617 thresh = [phaseThresh, noise_multiple, SNRThresh]
1618 1618 #Meteor reestimation (Errors N 1, 6, 12, 17)
1619 1619 listMeteors2, listMeteorsPower, listMeteorsVolts = self.__meteorReestimation(listMeteors1, voltsPShift, pairslist0, thresh, noise, dataOut.timeInterval, dataOut.frequency)
1620 1620 # listMeteors2, listMeteorsPower, listMeteorsVolts = self.meteorReestimation3(listMeteors2, listMeteorsPower, listMeteorsVolts, voltsPShift, pairslist, thresh, noise)
1621 1621 #Estimation of decay times (Errors N 7, 8, 11)
1622 1622 listMeteors3 = self.__estimateDecayTime(listMeteors2, listMeteorsPower, dataOut.timeInterval, dataOut.frequency)
1623 1623 #******************* END OF METEOR REESTIMATION *******************
1624 1624
1625 1625 #********************* METEOR PARAMETERS CALCULATION (3.11, 3.12, 3.13) **************************
1626 1626 #Calculating Radial Velocity (Error N 15)
1627 1627 radialStdThresh = 10
1628 1628 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
1629 1629
1630 1630 if len(listMeteors4) > 0:
1631 1631 #Setting New Array
1632 1632 date = dataOut.utctime
1633 1633 arrayParameters = self.__setNewArrays(listMeteors4, date, heiRang)
1634 1634
1635 1635 #Correcting phase offset
1636 1636 if phaseOffsets != None:
1637 1637 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
1638 1638 arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
1639 1639
1640 1640 #Second Pairslist
1641 1641 pairsList = []
1642 1642 pairx = (0,1)
1643 1643 pairy = (2,3)
1644 1644 pairsList.append(pairx)
1645 1645 pairsList.append(pairy)
1646 1646
1647 1647 jph = numpy.array([0,0,0,0])
1648 1648 h = (hmin,hmax)
1649 1649 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
1650 1650
1651 1651 # #Calculate AOA (Error N 3, 4)
1652 1652 # #JONES ET AL. 1998
1653 1653 # error = arrayParameters[:,-1]
1654 1654 # AOAthresh = numpy.pi/8
1655 1655 # phases = -arrayParameters[:,9:13]
1656 1656 # arrayParameters[:,4:7], arrayParameters[:,-1] = meteorOps.getAOA(phases, pairsList, error, AOAthresh, azimuth)
1657 1657 #
1658 1658 # #Calculate Heights (Error N 13 and 14)
1659 1659 # error = arrayParameters[:,-1]
1660 1660 # Ranges = arrayParameters[:,2]
1661 1661 # zenith = arrayParameters[:,5]
1662 1662 # arrayParameters[:,3], arrayParameters[:,-1] = meteorOps.getHeights(Ranges, zenith, error, hmin, hmax)
1663 1663 # error = arrayParameters[:,-1]
1664 1664 #********************* END OF PARAMETERS CALCULATION **************************
1665 1665
1666 1666 #***************************+ PASS DATA TO NEXT STEP **********************
1667 1667 # arrayFinal = arrayParameters.reshape((1,arrayParameters.shape[0],arrayParameters.shape[1]))
1668 1668 dataOut.data_param = arrayParameters
1669 1669
1670 1670 if arrayParameters is None:
1671 1671 dataOut.flagNoData = True
1672 1672 else:
1673 1673 dataOut.flagNoData = True
1674 1674
1675 1675 return
1676 1676
1677 1677 def __getHardwarePhaseDiff(self, voltage0, pairslist, newheis, n):
1678 1678
1679 1679 minIndex = min(newheis[0])
1680 1680 maxIndex = max(newheis[0])
1681 1681
1682 1682 voltage = voltage0[:,:,minIndex:maxIndex+1]
1683 1683 nLength = voltage.shape[1]/n
1684 1684 nMin = 0
1685 1685 nMax = 0
1686 1686 phaseOffset = numpy.zeros((len(pairslist),n))
1687 1687
1688 1688 for i in range(n):
1689 1689 nMax += nLength
1690 1690 phaseCCF = -numpy.angle(self.__calculateCCF(voltage[:,nMin:nMax,:], pairslist, [0]))
1691 1691 phaseCCF = numpy.mean(phaseCCF, axis = 2)
1692 1692 phaseOffset[:,i] = phaseCCF.transpose()
1693 1693 nMin = nMax
1694 1694 # phaseDiff, phaseArrival = self.estimatePhaseDifference(voltage, pairslist)
1695 1695
1696 1696 #Remove Outliers
1697 1697 factor = 2
1698 1698 wt = phaseOffset - signal.medfilt(phaseOffset,(1,5))
1699 1699 dw = numpy.std(wt,axis = 1)
1700 1700 dw = dw.reshape((dw.size,1))
1701 1701 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
1702 1702 phaseOffset[ind] = numpy.nan
1703 1703 phaseOffset = stats.nanmean(phaseOffset, axis=1)
1704 1704
1705 1705 return phaseOffset
1706 1706
1707 1707 def __shiftPhase(self, data, phaseShift):
1708 1708 #this will shift the phase of a complex number
1709 1709 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
1710 1710 return dataShifted
1711 1711
1712 1712 def __estimatePhaseDifference(self, array, pairslist):
1713 1713 nChannel = array.shape[0]
1714 1714 nHeights = array.shape[2]
1715 1715 numPairs = len(pairslist)
1716 1716 # phaseCCF = numpy.zeros((nChannel, 5, nHeights))
1717 1717 phaseCCF = numpy.angle(self.__calculateCCF(array, pairslist, [-2,-1,0,1,2]))
1718 1718
1719 1719 #Correct phases
1720 1720 derPhaseCCF = phaseCCF[:,1:,:] - phaseCCF[:,0:-1,:]
1721 1721 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
1722 1722
1723 1723 if indDer[0].shape[0] > 0:
1724 1724 for i in range(indDer[0].shape[0]):
1725 1725 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i],indDer[2][i]])
1726 1726 phaseCCF[indDer[0][i],indDer[1][i]+1:,:] += signo*2*numpy.pi
1727 1727
1728 1728 # for j in range(numSides):
1729 1729 # phaseCCFAux = self.calculateCCF(arrayCenter, arraySides[j,:,:], [-2,1,0,1,2])
1730 1730 # phaseCCF[j,:,:] = numpy.angle(phaseCCFAux)
1731 1731 #
1732 1732 #Linear
1733 1733 phaseInt = numpy.zeros((numPairs,1))
1734 1734 angAllCCF = phaseCCF[:,[0,1,3,4],0]
1735 1735 for j in range(numPairs):
1736 1736 fit = stats.linregress([-2,-1,1,2],angAllCCF[j,:])
1737 1737 phaseInt[j] = fit[1]
1738 1738 #Phase Differences
1739 1739 phaseDiff = phaseInt - phaseCCF[:,2,:]
1740 1740 phaseArrival = phaseInt.reshape(phaseInt.size)
1741 1741
1742 1742 #Dealias
1743 1743 phaseArrival = numpy.angle(numpy.exp(1j*phaseArrival))
1744 1744 # indAlias = numpy.where(phaseArrival > numpy.pi)
1745 1745 # phaseArrival[indAlias] -= 2*numpy.pi
1746 1746 # indAlias = numpy.where(phaseArrival < -numpy.pi)
1747 1747 # phaseArrival[indAlias] += 2*numpy.pi
1748 1748
1749 1749 return phaseDiff, phaseArrival
1750 1750
1751 1751 def __coherentDetection(self, volts, timeSegment, timeInterval, pairslist, thresh):
1752 1752 #this function will run the coherent detection used in Holdworth et al. 2004 and return the net power
1753 1753 #find the phase shifts of each channel over 1 second intervals
1754 1754 #only look at ranges below the beacon signal
1755 1755 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
1756 1756 numBlocks = int(volts.shape[1]/numProfPerBlock)
1757 1757 numHeights = volts.shape[2]
1758 1758 nChannel = volts.shape[0]
1759 1759 voltsCohDet = volts.copy()
1760 1760
1761 1761 pairsarray = numpy.array(pairslist)
1762 1762 indSides = pairsarray[:,1]
1763 1763 # indSides = numpy.array(range(nChannel))
1764 1764 # indSides = numpy.delete(indSides, indCenter)
1765 1765 #
1766 1766 # listCenter = numpy.array_split(volts[indCenter,:,:], numBlocks, 0)
1767 1767 listBlocks = numpy.array_split(volts, numBlocks, 1)
1768 1768
1769 1769 startInd = 0
1770 1770 endInd = 0
1771 1771
1772 1772 for i in range(numBlocks):
1773 1773 startInd = endInd
1774 1774 endInd = endInd + listBlocks[i].shape[1]
1775 1775
1776 1776 arrayBlock = listBlocks[i]
1777 1777 # arrayBlockCenter = listCenter[i]
1778 1778
1779 1779 #Estimate the Phase Difference
1780 1780 phaseDiff, aux = self.__estimatePhaseDifference(arrayBlock, pairslist)
1781 1781 #Phase Difference RMS
1782 1782 arrayPhaseRMS = numpy.abs(phaseDiff)
1783 1783 phaseRMSaux = numpy.sum(arrayPhaseRMS < thresh,0)
1784 1784 indPhase = numpy.where(phaseRMSaux==4)
1785 1785 #Shifting
1786 1786 if indPhase[0].shape[0] > 0:
1787 1787 for j in range(indSides.size):
1788 1788 arrayBlock[indSides[j],:,indPhase] = self.__shiftPhase(arrayBlock[indSides[j],:,indPhase], phaseDiff[j,indPhase].transpose())
1789 1789 voltsCohDet[:,startInd:endInd,:] = arrayBlock
1790 1790
1791 1791 return voltsCohDet
1792 1792
1793 1793 def __calculateCCF(self, volts, pairslist ,laglist):
1794 1794
1795 1795 nHeights = volts.shape[2]
1796 1796 nPoints = volts.shape[1]
1797 1797 voltsCCF = numpy.zeros((len(pairslist), len(laglist), nHeights),dtype = 'complex')
1798 1798
1799 1799 for i in range(len(pairslist)):
1800 1800 volts1 = volts[pairslist[i][0]]
1801 1801 volts2 = volts[pairslist[i][1]]
1802 1802
1803 1803 for t in range(len(laglist)):
1804 1804 idxT = laglist[t]
1805 1805 if idxT >= 0:
1806 1806 vStacked = numpy.vstack((volts2[idxT:,:],
1807 1807 numpy.zeros((idxT, nHeights),dtype='complex')))
1808 1808 else:
1809 1809 vStacked = numpy.vstack((numpy.zeros((-idxT, nHeights),dtype='complex'),
1810 1810 volts2[:(nPoints + idxT),:]))
1811 1811 voltsCCF[i,t,:] = numpy.sum((numpy.conjugate(volts1)*vStacked),axis=0)
1812 1812
1813 1813 vStacked = None
1814 1814 return voltsCCF
1815 1815
1816 1816 def __getNoise(self, power, timeSegment, timeInterval):
1817 1817 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
1818 1818 numBlocks = int(power.shape[0]/numProfPerBlock)
1819 1819 numHeights = power.shape[1]
1820 1820
1821 1821 listPower = numpy.array_split(power, numBlocks, 0)
1822 1822 noise = numpy.zeros((power.shape[0], power.shape[1]))
1823 1823 noise1 = numpy.zeros((power.shape[0], power.shape[1]))
1824 1824
1825 1825 startInd = 0
1826 1826 endInd = 0
1827 1827
1828 1828 for i in range(numBlocks): #split por canal
1829 1829 startInd = endInd
1830 1830 endInd = endInd + listPower[i].shape[0]
1831 1831
1832 1832 arrayBlock = listPower[i]
1833 1833 noiseAux = numpy.mean(arrayBlock, 0)
1834 1834 # noiseAux = numpy.median(noiseAux)
1835 1835 # noiseAux = numpy.mean(arrayBlock)
1836 1836 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
1837 1837
1838 1838 noiseAux1 = numpy.mean(arrayBlock)
1839 1839 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
1840 1840
1841 1841 return noise, noise1
1842 1842
1843 1843 def __findMeteors(self, power, thresh):
1844 1844 nProf = power.shape[0]
1845 1845 nHeights = power.shape[1]
1846 1846 listMeteors = []
1847 1847
1848 1848 for i in range(nHeights):
1849 1849 powerAux = power[:,i]
1850 1850 threshAux = thresh[:,i]
1851 1851
1852 1852 indUPthresh = numpy.where(powerAux > threshAux)[0]
1853 1853 indDNthresh = numpy.where(powerAux <= threshAux)[0]
1854 1854
1855 1855 j = 0
1856 1856
1857 1857 while (j < indUPthresh.size - 2):
1858 1858 if (indUPthresh[j + 2] == indUPthresh[j] + 2):
1859 1859 indDNAux = numpy.where(indDNthresh > indUPthresh[j])
1860 1860 indDNthresh = indDNthresh[indDNAux]
1861 1861
1862 1862 if (indDNthresh.size > 0):
1863 1863 indEnd = indDNthresh[0] - 1
1864 1864 indInit = indUPthresh[j] if isinstance(indUPthresh[j], (int, float)) else indUPthresh[j][0] ##CHECK!!!!
1865 1865
1866 1866 meteor = powerAux[indInit:indEnd + 1]
1867 1867 indPeak = meteor.argmax() + indInit
1868 1868 FLA = sum(numpy.conj(meteor)*numpy.hstack((meteor[1:],0)))
1869 1869
1870 1870 listMeteors.append(numpy.array([i,indInit,indPeak,indEnd,FLA])) #CHEQUEAR!!!!!
1871 1871 j = numpy.where(indUPthresh == indEnd)[0] + 1
1872 1872 else: j+=1
1873 1873 else: j+=1
1874 1874
1875 1875 return listMeteors
1876 1876
1877 1877 def __removeMultipleDetections(self,listMeteors, rangeLimit, timeLimit):
1878 1878
1879 1879 arrayMeteors = numpy.asarray(listMeteors)
1880 1880 listMeteors1 = []
1881 1881
1882 1882 while arrayMeteors.shape[0] > 0:
1883 1883 FLAs = arrayMeteors[:,4]
1884 1884 maxFLA = FLAs.argmax()
1885 1885 listMeteors1.append(arrayMeteors[maxFLA,:])
1886 1886
1887 1887 MeteorInitTime = arrayMeteors[maxFLA,1]
1888 1888 MeteorEndTime = arrayMeteors[maxFLA,3]
1889 1889 MeteorHeight = arrayMeteors[maxFLA,0]
1890 1890
1891 1891 #Check neighborhood
1892 1892 maxHeightIndex = MeteorHeight + rangeLimit
1893 1893 minHeightIndex = MeteorHeight - rangeLimit
1894 1894 minTimeIndex = MeteorInitTime - timeLimit
1895 1895 maxTimeIndex = MeteorEndTime + timeLimit
1896 1896
1897 1897 #Check Heights
1898 1898 indHeight = numpy.logical_and(arrayMeteors[:,0] >= minHeightIndex, arrayMeteors[:,0] <= maxHeightIndex)
1899 1899 indTime = numpy.logical_and(arrayMeteors[:,3] >= minTimeIndex, arrayMeteors[:,1] <= maxTimeIndex)
1900 1900 indBoth = numpy.where(numpy.logical_and(indTime,indHeight))
1901 1901
1902 1902 arrayMeteors = numpy.delete(arrayMeteors, indBoth, axis = 0)
1903 1903
1904 1904 return listMeteors1
1905 1905
1906 1906 def __meteorReestimation(self, listMeteors, volts, pairslist, thresh, noise, timeInterval,frequency):
1907 1907 numHeights = volts.shape[2]
1908 1908 nChannel = volts.shape[0]
1909 1909
1910 1910 thresholdPhase = thresh[0]
1911 1911 thresholdNoise = thresh[1]
1912 1912 thresholdDB = float(thresh[2])
1913 1913
1914 1914 thresholdDB1 = 10**(thresholdDB/10)
1915 1915 pairsarray = numpy.array(pairslist)
1916 1916 indSides = pairsarray[:,1]
1917 1917
1918 1918 pairslist1 = list(pairslist)
1919 1919 pairslist1.append((0,4))
1920 1920 pairslist1.append((1,3))
1921 1921
1922 1922 listMeteors1 = []
1923 1923 listPowerSeries = []
1924 1924 listVoltageSeries = []
1925 1925 #volts has the war data
1926 1926
1927 1927 if frequency == 30.175e6:
1928 1928 timeLag = 45*10**-3
1929 1929 else:
1930 1930 timeLag = 15*10**-3
1931 1931 lag = int(numpy.ceil(timeLag/timeInterval))
1932 1932
1933 1933 for i in range(len(listMeteors)):
1934 1934
1935 1935 ###################### 3.6 - 3.7 PARAMETERS REESTIMATION #########################
1936 1936 meteorAux = numpy.zeros(16)
1937 1937
1938 1938 #Loading meteor Data (mHeight, mStart, mPeak, mEnd)
1939 1939 mHeight = int(listMeteors[i][0])
1940 1940 mStart = int(listMeteors[i][1])
1941 1941 mPeak = int(listMeteors[i][2])
1942 1942 mEnd = int(listMeteors[i][3])
1943 1943
1944 1944 #get the volt data between the start and end times of the meteor
1945 1945 meteorVolts = volts[:,mStart:mEnd+1,mHeight]
1946 1946 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
1947 1947
1948 1948 #3.6. Phase Difference estimation
1949 1949 phaseDiff, aux = self.__estimatePhaseDifference(meteorVolts, pairslist)
1950 1950
1951 1951 #3.7. Phase difference removal & meteor start, peak and end times reestimated
1952 1952 #meteorVolts0.- all Channels, all Profiles
1953 1953 meteorVolts0 = volts[:,:,mHeight]
1954 1954 meteorThresh = noise[:,mHeight]*thresholdNoise
1955 1955 meteorNoise = noise[:,mHeight]
1956 1956 meteorVolts0[indSides,:] = self.__shiftPhase(meteorVolts0[indSides,:], phaseDiff) #Phase Shifting
1957 1957 powerNet0 = numpy.nansum(numpy.abs(meteorVolts0)**2, axis = 0) #Power
1958 1958
1959 1959 #Times reestimation
1960 1960 mStart1 = numpy.where(powerNet0[:mPeak] < meteorThresh[:mPeak])[0]
1961 1961 if mStart1.size > 0:
1962 1962 mStart1 = mStart1[-1] + 1
1963 1963
1964 1964 else:
1965 1965 mStart1 = mPeak
1966 1966
1967 1967 mEnd1 = numpy.where(powerNet0[mPeak:] < meteorThresh[mPeak:])[0][0] + mPeak - 1
1968 1968 mEndDecayTime1 = numpy.where(powerNet0[mPeak:] < meteorNoise[mPeak:])[0]
1969 1969 if mEndDecayTime1.size == 0:
1970 1970 mEndDecayTime1 = powerNet0.size
1971 1971 else:
1972 1972 mEndDecayTime1 = mEndDecayTime1[0] + mPeak - 1
1973 1973 # mPeak1 = meteorVolts0[mStart1:mEnd1 + 1].argmax()
1974 1974
1975 1975 #meteorVolts1.- all Channels, from start to end
1976 1976 meteorVolts1 = meteorVolts0[:,mStart1:mEnd1 + 1]
1977 1977 meteorVolts2 = meteorVolts0[:,mPeak + lag:mEnd1 + 1]
1978 1978 if meteorVolts2.shape[1] == 0:
1979 1979 meteorVolts2 = meteorVolts0[:,mPeak:mEnd1 + 1]
1980 1980 meteorVolts1 = meteorVolts1.reshape(meteorVolts1.shape[0], meteorVolts1.shape[1], 1)
1981 1981 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1], 1)
1982 1982 ##################### END PARAMETERS REESTIMATION #########################
1983 1983
1984 1984 ##################### 3.8 PHASE DIFFERENCE REESTIMATION ########################
1985 1985 # if mEnd1 - mStart1 > 4: #Error Number 6: echo less than 5 samples long; too short for analysis
1986 1986 if meteorVolts2.shape[1] > 0:
1987 1987 #Phase Difference re-estimation
1988 1988 phaseDiff1, phaseDiffint = self.__estimatePhaseDifference(meteorVolts2, pairslist1) #Phase Difference Estimation
1989 1989 # phaseDiff1, phaseDiffint = self.estimatePhaseDifference(meteorVolts2, pairslist)
1990 1990 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1])
1991 1991 phaseDiff11 = numpy.reshape(phaseDiff1, (phaseDiff1.shape[0],1))
1992 1992 meteorVolts2[indSides,:] = self.__shiftPhase(meteorVolts2[indSides,:], phaseDiff11[0:4]) #Phase Shifting
1993 1993
1994 1994 #Phase Difference RMS
1995 1995 phaseRMS1 = numpy.sqrt(numpy.mean(numpy.square(phaseDiff1)))
1996 1996 powerNet1 = numpy.nansum(numpy.abs(meteorVolts1[:,:])**2,0)
1997 1997 #Data from Meteor
1998 1998 mPeak1 = powerNet1.argmax() + mStart1
1999 1999 mPeakPower1 = powerNet1.max()
2000 2000 noiseAux = sum(noise[mStart1:mEnd1 + 1,mHeight])
2001 2001 mSNR1 = (sum(powerNet1)-noiseAux)/noiseAux
2002 2002 Meteor1 = numpy.array([mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1])
2003 2003 Meteor1 = numpy.hstack((Meteor1,phaseDiffint))
2004 2004 PowerSeries = powerNet0[mStart1:mEndDecayTime1 + 1]
2005 2005 #Vectorize
2006 2006 meteorAux[0:7] = [mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1]
2007 2007 meteorAux[7:11] = phaseDiffint[0:4]
2008 2008
2009 2009 #Rejection Criterions
2010 2010 if phaseRMS1 > thresholdPhase: #Error Number 17: Phase variation
2011 2011 meteorAux[-1] = 17
2012 2012 elif mSNR1 < thresholdDB1: #Error Number 1: SNR < threshold dB
2013 2013 meteorAux[-1] = 1
2014 2014
2015 2015
2016 2016 else:
2017 2017 meteorAux[0:4] = [mHeight, mStart, mPeak, mEnd]
2018 2018 meteorAux[-1] = 6 #Error Number 6: echo less than 5 samples long; too short for analysis
2019 2019 PowerSeries = 0
2020 2020
2021 2021 listMeteors1.append(meteorAux)
2022 2022 listPowerSeries.append(PowerSeries)
2023 2023 listVoltageSeries.append(meteorVolts1)
2024 2024
2025 2025 return listMeteors1, listPowerSeries, listVoltageSeries
2026 2026
2027 2027 def __estimateDecayTime(self, listMeteors, listPower, timeInterval, frequency):
2028 2028
2029 2029 threshError = 10
2030 2030 #Depending if it is 30 or 50 MHz
2031 2031 if frequency == 30.175e6:
2032 2032 timeLag = 45*10**-3
2033 2033 else:
2034 2034 timeLag = 15*10**-3
2035 lag = numpy.ceil(timeLag/timeInterval)
2035 lag = int(numpy.ceil(timeLag/timeInterval))
2036 2036
2037 2037 listMeteors1 = []
2038 2038
2039 2039 for i in range(len(listMeteors)):
2040 2040 meteorPower = listPower[i]
2041 2041 meteorAux = listMeteors[i]
2042 2042
2043 2043 if meteorAux[-1] == 0:
2044 2044
2045 2045 try:
2046 2046 indmax = meteorPower.argmax()
2047 2047 indlag = indmax + lag
2048 2048
2049 2049 y = meteorPower[indlag:]
2050 2050 x = numpy.arange(0, y.size)*timeLag
2051 2051
2052 2052 #first guess
2053 2053 a = y[0]
2054 2054 tau = timeLag
2055 2055 #exponential fit
2056 2056 popt, pcov = optimize.curve_fit(self.__exponential_function, x, y, p0 = [a, tau])
2057 2057 y1 = self.__exponential_function(x, *popt)
2058 2058 #error estimation
2059 2059 error = sum((y - y1)**2)/(numpy.var(y)*(y.size - popt.size))
2060 2060
2061 2061 decayTime = popt[1]
2062 2062 riseTime = indmax*timeInterval
2063 2063 meteorAux[11:13] = [decayTime, error]
2064 2064
2065 2065 #Table items 7, 8 and 11
2066 2066 if (riseTime > 0.3): #Number 7: Echo rise exceeds 0.3s
2067 2067 meteorAux[-1] = 7
2068 2068 elif (decayTime < 2*riseTime) : #Number 8: Echo decay time less than than twice rise time
2069 2069 meteorAux[-1] = 8
2070 2070 if (error > threshError): #Number 11: Poor fit to amplitude for estimation of decay time
2071 2071 meteorAux[-1] = 11
2072 2072
2073 2073
2074 2074 except:
2075 2075 meteorAux[-1] = 11
2076 2076
2077 2077
2078 2078 listMeteors1.append(meteorAux)
2079 2079
2080 2080 return listMeteors1
2081 2081
2082 2082 #Exponential Function
2083 2083
2084 2084 def __exponential_function(self, x, a, tau):
2085 2085 y = a*numpy.exp(-x/tau)
2086 2086 return y
2087 2087
2088 2088 def __getRadialVelocity(self, listMeteors, listVolts, radialStdThresh, pairslist, timeInterval):
2089 2089
2090 2090 pairslist1 = list(pairslist)
2091 2091 pairslist1.append((0,4))
2092 2092 pairslist1.append((1,3))
2093 2093 numPairs = len(pairslist1)
2094 2094 #Time Lag
2095 2095 timeLag = 45*10**-3
2096 2096 c = 3e8
2097 2097 lag = numpy.ceil(timeLag/timeInterval)
2098 2098 freq = 30.175e6
2099 2099
2100 2100 listMeteors1 = []
2101 2101
2102 2102 for i in range(len(listMeteors)):
2103 2103 meteorAux = listMeteors[i]
2104 2104 if meteorAux[-1] == 0:
2105 2105 mStart = listMeteors[i][1]
2106 2106 mPeak = listMeteors[i][2]
2107 2107 mLag = mPeak - mStart + lag
2108 2108
2109 2109 #get the volt data between the start and end times of the meteor
2110 2110 meteorVolts = listVolts[i]
2111 2111 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
2112 2112
2113 2113 #Get CCF
2114 2114 allCCFs = self.__calculateCCF(meteorVolts, pairslist1, [-2,-1,0,1,2])
2115 2115
2116 2116 #Method 2
2117 2117 slopes = numpy.zeros(numPairs)
2118 2118 time = numpy.array([-2,-1,1,2])*timeInterval
2119 2119 angAllCCF = numpy.angle(allCCFs[:,[0,4,2,3],0])
2120 2120
2121 2121 #Correct phases
2122 2122 derPhaseCCF = angAllCCF[:,1:] - angAllCCF[:,0:-1]
2123 2123 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
2124 2124
2125 2125 if indDer[0].shape[0] > 0:
2126 2126 for i in range(indDer[0].shape[0]):
2127 2127 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i]])
2128 2128 angAllCCF[indDer[0][i],indDer[1][i]+1:] += signo*2*numpy.pi
2129 2129
2130 2130 # fit = scipy.stats.linregress(numpy.array([-2,-1,1,2])*timeInterval, numpy.array([phaseLagN2s[i],phaseLagN1s[i],phaseLag1s[i],phaseLag2s[i]]))
2131 2131 for j in range(numPairs):
2132 2132 fit = stats.linregress(time, angAllCCF[j,:])
2133 2133 slopes[j] = fit[0]
2134 2134
2135 2135 #Remove Outlier
2136 2136 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
2137 2137 # slopes = numpy.delete(slopes,indOut)
2138 2138 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
2139 2139 # slopes = numpy.delete(slopes,indOut)
2140 2140
2141 2141 radialVelocity = -numpy.mean(slopes)*(0.25/numpy.pi)*(c/freq)
2142 2142 radialError = numpy.std(slopes)*(0.25/numpy.pi)*(c/freq)
2143 2143 meteorAux[-2] = radialError
2144 2144 meteorAux[-3] = radialVelocity
2145 2145
2146 2146 #Setting Error
2147 2147 #Number 15: Radial Drift velocity or projected horizontal velocity exceeds 200 m/s
2148 2148 if numpy.abs(radialVelocity) > 200:
2149 2149 meteorAux[-1] = 15
2150 2150 #Number 12: Poor fit to CCF variation for estimation of radial drift velocity
2151 2151 elif radialError > radialStdThresh:
2152 2152 meteorAux[-1] = 12
2153 2153
2154 2154 listMeteors1.append(meteorAux)
2155 2155 return listMeteors1
2156 2156
2157 2157 def __setNewArrays(self, listMeteors, date, heiRang):
2158 2158
2159 2159 #New arrays
2160 2160 arrayMeteors = numpy.array(listMeteors)
2161 2161 arrayParameters = numpy.zeros((len(listMeteors), 13))
2162 2162
2163 2163 #Date inclusion
2164 2164 # date = re.findall(r'\((.*?)\)', date)
2165 2165 # date = date[0].split(',')
2166 2166 # date = map(int, date)
2167 2167 #
2168 2168 # if len(date)<6:
2169 2169 # date.append(0)
2170 2170 #
2171 2171 # date = [date[0]*10000 + date[1]*100 + date[2], date[3]*10000 + date[4]*100 + date[5]]
2172 2172 # arrayDate = numpy.tile(date, (len(listMeteors), 1))
2173 2173 arrayDate = numpy.tile(date, (len(listMeteors)))
2174 2174
2175 2175 #Meteor array
2176 2176 # arrayMeteors[:,0] = heiRang[arrayMeteors[:,0].astype(int)]
2177 2177 # arrayMeteors = numpy.hstack((arrayDate, arrayMeteors))
2178 2178
2179 2179 #Parameters Array
2180 2180 arrayParameters[:,0] = arrayDate #Date
2181 2181 arrayParameters[:,1] = heiRang[arrayMeteors[:,0].astype(int)] #Range
2182 2182 arrayParameters[:,6:8] = arrayMeteors[:,-3:-1] #Radial velocity and its error
2183 2183 arrayParameters[:,8:12] = arrayMeteors[:,7:11] #Phases
2184 2184 arrayParameters[:,-1] = arrayMeteors[:,-1] #Error
2185 2185
2186 2186
2187 2187 return arrayParameters
2188 2188
2189 2189 class CorrectSMPhases(Operation):
2190 2190
2191 2191 def run(self, dataOut, phaseOffsets, hmin = 50, hmax = 150, azimuth = 45, channelPositions = None):
2192 2192
2193 2193 arrayParameters = dataOut.data_param
2194 2194 pairsList = []
2195 2195 pairx = (0,1)
2196 2196 pairy = (2,3)
2197 2197 pairsList.append(pairx)
2198 2198 pairsList.append(pairy)
2199 2199 jph = numpy.zeros(4)
2200 2200
2201 2201 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
2202 2202 # arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
2203 2203 arrayParameters[:,8:12] = numpy.angle(numpy.exp(1j*(arrayParameters[:,8:12] + phaseOffsets)))
2204 2204
2205 2205 meteorOps = SMOperations()
2206 2206 if channelPositions is None:
2207 2207 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
2208 2208 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
2209 2209
2210 2210 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
2211 2211 h = (hmin,hmax)
2212 2212
2213 2213 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
2214 2214
2215 2215 dataOut.data_param = arrayParameters
2216 2216 return
2217 2217
2218 2218 class SMPhaseCalibration(Operation):
2219 2219
2220 2220 __buffer = None
2221 2221
2222 2222 __initime = None
2223 2223
2224 2224 __dataReady = False
2225 2225
2226 2226 __isConfig = False
2227 2227
2228 2228 def __checkTime(self, currentTime, initTime, paramInterval, outputInterval):
2229 2229
2230 2230 dataTime = currentTime + paramInterval
2231 2231 deltaTime = dataTime - initTime
2232 2232
2233 2233 if deltaTime >= outputInterval or deltaTime < 0:
2234 2234 return True
2235 2235
2236 2236 return False
2237 2237
2238 2238 def __getGammas(self, pairs, d, phases):
2239 2239 gammas = numpy.zeros(2)
2240 2240
2241 2241 for i in range(len(pairs)):
2242 2242
2243 2243 pairi = pairs[i]
2244 2244
2245 2245 phip3 = phases[:,pairi[1]]
2246 2246 d3 = d[pairi[1]]
2247 2247 phip2 = phases[:,pairi[0]]
2248 2248 d2 = d[pairi[0]]
2249 2249 #Calculating gamma
2250 2250 # jdcos = alp1/(k*d1)
2251 2251 # jgamma = numpy.angle(numpy.exp(1j*(d0*alp1/d1 - alp0)))
2252 2252 jgamma = -phip2*d3/d2 - phip3
2253 2253 jgamma = numpy.angle(numpy.exp(1j*jgamma))
2254 2254 # jgamma[jgamma>numpy.pi] -= 2*numpy.pi
2255 2255 # jgamma[jgamma<-numpy.pi] += 2*numpy.pi
2256 2256
2257 2257 #Revised distribution
2258 2258 jgammaArray = numpy.hstack((jgamma,jgamma+0.5*numpy.pi,jgamma-0.5*numpy.pi))
2259 2259
2260 2260 #Histogram
2261 2261 nBins = 64.0
2262 2262 rmin = -0.5*numpy.pi
2263 2263 rmax = 0.5*numpy.pi
2264 2264 phaseHisto = numpy.histogram(jgammaArray, bins=nBins, range=(rmin,rmax))
2265 2265
2266 2266 meteorsY = phaseHisto[0]
2267 2267 phasesX = phaseHisto[1][:-1]
2268 2268 width = phasesX[1] - phasesX[0]
2269 2269 phasesX += width/2
2270 2270
2271 2271 #Gaussian aproximation
2272 2272 bpeak = meteorsY.argmax()
2273 2273 peak = meteorsY.max()
2274 2274 jmin = bpeak - 5
2275 2275 jmax = bpeak + 5 + 1
2276 2276
2277 2277 if jmin<0:
2278 2278 jmin = 0
2279 2279 jmax = 6
2280 2280 elif jmax > meteorsY.size:
2281 2281 jmin = meteorsY.size - 6
2282 2282 jmax = meteorsY.size
2283 2283
2284 2284 x0 = numpy.array([peak,bpeak,50])
2285 2285 coeff = optimize.leastsq(self.__residualFunction, x0, args=(meteorsY[jmin:jmax], phasesX[jmin:jmax]))
2286 2286
2287 2287 #Gammas
2288 2288 gammas[i] = coeff[0][1]
2289 2289
2290 2290 return gammas
2291 2291
2292 2292 def __residualFunction(self, coeffs, y, t):
2293 2293
2294 2294 return y - self.__gauss_function(t, coeffs)
2295 2295
2296 2296 def __gauss_function(self, t, coeffs):
2297 2297
2298 2298 return coeffs[0]*numpy.exp(-0.5*((t - coeffs[1]) / coeffs[2])**2)
2299 2299
2300 2300 def __getPhases(self, azimuth, h, pairsList, d, gammas, meteorsArray):
2301 2301 meteorOps = SMOperations()
2302 2302 nchan = 4
2303 2303 pairx = pairsList[0]
2304 2304 pairy = pairsList[1]
2305 2305 center_xangle = 0
2306 2306 center_yangle = 0
2307 2307 range_angle = numpy.array([10*numpy.pi,numpy.pi,numpy.pi/2,numpy.pi/4])
2308 2308 ntimes = len(range_angle)
2309 2309
2310 2310 nstepsx = 20.0
2311 2311 nstepsy = 20.0
2312 2312
2313 2313 for iz in range(ntimes):
2314 2314 min_xangle = -range_angle[iz]/2 + center_xangle
2315 2315 max_xangle = range_angle[iz]/2 + center_xangle
2316 2316 min_yangle = -range_angle[iz]/2 + center_yangle
2317 2317 max_yangle = range_angle[iz]/2 + center_yangle
2318 2318
2319 2319 inc_x = (max_xangle-min_xangle)/nstepsx
2320 2320 inc_y = (max_yangle-min_yangle)/nstepsy
2321 2321
2322 2322 alpha_y = numpy.arange(nstepsy)*inc_y + min_yangle
2323 2323 alpha_x = numpy.arange(nstepsx)*inc_x + min_xangle
2324 2324 penalty = numpy.zeros((nstepsx,nstepsy))
2325 2325 jph_array = numpy.zeros((nchan,nstepsx,nstepsy))
2326 2326 jph = numpy.zeros(nchan)
2327 2327
2328 2328 # Iterations looking for the offset
2329 2329 for iy in range(int(nstepsy)):
2330 2330 for ix in range(int(nstepsx)):
2331 2331 jph[pairy[1]] = alpha_y[iy]
2332 2332 jph[pairy[0]] = -gammas[1] - alpha_y[iy]*d[pairy[1]]/d[pairy[0]]
2333 2333
2334 2334 jph[pairx[1]] = alpha_x[ix]
2335 2335 jph[pairx[0]] = -gammas[0] - alpha_x[ix]*d[pairx[1]]/d[pairx[0]]
2336 2336
2337 2337 jph_array[:,ix,iy] = jph
2338 2338
2339 2339 meteorsArray1 = meteorOps.getMeteorParams(meteorsArray, azimuth, h, pairsList, d, jph)
2340 2340 error = meteorsArray1[:,-1]
2341 2341 ind1 = numpy.where(error==0)[0]
2342 2342 penalty[ix,iy] = ind1.size
2343 2343
2344 2344 i,j = numpy.unravel_index(penalty.argmax(), penalty.shape)
2345 2345 phOffset = jph_array[:,i,j]
2346 2346
2347 2347 center_xangle = phOffset[pairx[1]]
2348 2348 center_yangle = phOffset[pairy[1]]
2349 2349
2350 2350 phOffset = numpy.angle(numpy.exp(1j*jph_array[:,i,j]))
2351 2351 phOffset = phOffset*180/numpy.pi
2352 2352 return phOffset
2353 2353
2354 2354
2355 2355 def run(self, dataOut, hmin, hmax, channelPositions=None, nHours = 1):
2356 2356
2357 2357 dataOut.flagNoData = True
2358 2358 self.__dataReady = False
2359 2359 dataOut.outputInterval = nHours*3600
2360 2360
2361 2361 if self.__isConfig == False:
2362 2362 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2363 2363 #Get Initial LTC time
2364 2364 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2365 2365 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2366 2366
2367 2367 self.__isConfig = True
2368 2368
2369 2369 if self.__buffer is None:
2370 2370 self.__buffer = dataOut.data_param.copy()
2371 2371
2372 2372 else:
2373 2373 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2374 2374
2375 2375 self.__dataReady = self.__checkTime(dataOut.utctime, self.__initime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2376 2376
2377 2377 if self.__dataReady:
2378 2378 dataOut.utctimeInit = self.__initime
2379 2379 self.__initime += dataOut.outputInterval #to erase time offset
2380 2380
2381 2381 freq = dataOut.frequency
2382 2382 c = dataOut.C #m/s
2383 2383 lamb = c/freq
2384 2384 k = 2*numpy.pi/lamb
2385 2385 azimuth = 0
2386 2386 h = (hmin, hmax)
2387 2387 pairs = ((0,1),(2,3))
2388 2388
2389 2389 if channelPositions is None:
2390 2390 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
2391 2391 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
2392 2392 meteorOps = SMOperations()
2393 2393 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
2394 2394
2395 2395 # distances1 = [-distances[0]*lamb, distances[1]*lamb, -distances[2]*lamb, distances[3]*lamb]
2396 2396
2397 2397 meteorsArray = self.__buffer
2398 2398 error = meteorsArray[:,-1]
2399 2399 boolError = (error==0)|(error==3)|(error==4)|(error==13)|(error==14)
2400 2400 ind1 = numpy.where(boolError)[0]
2401 2401 meteorsArray = meteorsArray[ind1,:]
2402 2402 meteorsArray[:,-1] = 0
2403 2403 phases = meteorsArray[:,8:12]
2404 2404
2405 2405 #Calculate Gammas
2406 2406 gammas = self.__getGammas(pairs, distances, phases)
2407 2407 # gammas = numpy.array([-21.70409463,45.76935864])*numpy.pi/180
2408 2408 #Calculate Phases
2409 2409 phasesOff = self.__getPhases(azimuth, h, pairs, distances, gammas, meteorsArray)
2410 2410 phasesOff = phasesOff.reshape((1,phasesOff.size))
2411 2411 dataOut.data_output = -phasesOff
2412 2412 dataOut.flagNoData = False
2413 2413 dataOut.channelList = pairslist0
2414 2414 self.__buffer = None
2415 2415
2416 2416
2417 2417 return
2418 2418
2419 2419 class SMOperations():
2420 2420
2421 2421 def __init__(self):
2422 2422
2423 2423 return
2424 2424
2425 2425 def getMeteorParams(self, arrayParameters0, azimuth, h, pairsList, distances, jph):
2426 2426
2427 2427 arrayParameters = arrayParameters0.copy()
2428 2428 hmin = h[0]
2429 2429 hmax = h[1]
2430 2430
2431 2431 #Calculate AOA (Error N 3, 4)
2432 2432 #JONES ET AL. 1998
2433 2433 AOAthresh = numpy.pi/8
2434 2434 error = arrayParameters[:,-1]
2435 2435 phases = -arrayParameters[:,8:12] + jph
2436 2436 # phases = numpy.unwrap(phases)
2437 2437 arrayParameters[:,3:6], arrayParameters[:,-1] = self.__getAOA(phases, pairsList, distances, error, AOAthresh, azimuth)
2438 2438
2439 2439 #Calculate Heights (Error N 13 and 14)
2440 2440 error = arrayParameters[:,-1]
2441 2441 Ranges = arrayParameters[:,1]
2442 2442 zenith = arrayParameters[:,4]
2443 2443 arrayParameters[:,2], arrayParameters[:,-1] = self.__getHeights(Ranges, zenith, error, hmin, hmax)
2444 2444
2445 2445 #----------------------- Get Final data ------------------------------------
2446 2446 # error = arrayParameters[:,-1]
2447 2447 # ind1 = numpy.where(error==0)[0]
2448 2448 # arrayParameters = arrayParameters[ind1,:]
2449 2449
2450 2450 return arrayParameters
2451 2451
2452 2452 def __getAOA(self, phases, pairsList, directions, error, AOAthresh, azimuth):
2453 2453
2454 2454 arrayAOA = numpy.zeros((phases.shape[0],3))
2455 2455 cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList,directions)
2456 2456
2457 2457 arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
2458 2458 cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
2459 2459 arrayAOA[:,2] = cosDirError
2460 2460
2461 2461 azimuthAngle = arrayAOA[:,0]
2462 2462 zenithAngle = arrayAOA[:,1]
2463 2463
2464 2464 #Setting Error
2465 2465 indError = numpy.where(numpy.logical_or(error == 3, error == 4))[0]
2466 2466 error[indError] = 0
2467 2467 #Number 3: AOA not fesible
2468 2468 indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
2469 2469 error[indInvalid] = 3
2470 2470 #Number 4: Large difference in AOAs obtained from different antenna baselines
2471 2471 indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
2472 2472 error[indInvalid] = 4
2473 2473 return arrayAOA, error
2474 2474
2475 2475 def __getDirectionCosines(self, arrayPhase, pairsList, distances):
2476 2476
2477 2477 #Initializing some variables
2478 2478 ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
2479 2479 ang_aux = ang_aux.reshape(1,ang_aux.size)
2480 2480
2481 2481 cosdir = numpy.zeros((arrayPhase.shape[0],2))
2482 2482 cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
2483 2483
2484 2484
2485 2485 for i in range(2):
2486 2486 ph0 = arrayPhase[:,pairsList[i][0]]
2487 2487 ph1 = arrayPhase[:,pairsList[i][1]]
2488 2488 d0 = distances[pairsList[i][0]]
2489 2489 d1 = distances[pairsList[i][1]]
2490 2490
2491 2491 ph0_aux = ph0 + ph1
2492 2492 ph0_aux = numpy.angle(numpy.exp(1j*ph0_aux))
2493 2493 # ph0_aux[ph0_aux > numpy.pi] -= 2*numpy.pi
2494 2494 # ph0_aux[ph0_aux < -numpy.pi] += 2*numpy.pi
2495 2495 #First Estimation
2496 2496 cosdir0[:,i] = (ph0_aux)/(2*numpy.pi*(d0 - d1))
2497 2497
2498 2498 #Most-Accurate Second Estimation
2499 2499 phi1_aux = ph0 - ph1
2500 2500 phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
2501 2501 #Direction Cosine 1
2502 2502 cosdir1 = (phi1_aux + ang_aux)/(2*numpy.pi*(d0 + d1))
2503 2503
2504 2504 #Searching the correct Direction Cosine
2505 2505 cosdir0_aux = cosdir0[:,i]
2506 2506 cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
2507 2507 #Minimum Distance
2508 2508 cosDiff = (cosdir1 - cosdir0_aux)**2
2509 2509 indcos = cosDiff.argmin(axis = 1)
2510 2510 #Saving Value obtained
2511 2511 cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
2512 2512
2513 2513 return cosdir0, cosdir
2514 2514
2515 2515 def __calculateAOA(self, cosdir, azimuth):
2516 2516 cosdirX = cosdir[:,0]
2517 2517 cosdirY = cosdir[:,1]
2518 2518
2519 2519 zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
2520 2520 azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth#0 deg north, 90 deg east
2521 2521 angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
2522 2522
2523 2523 return angles
2524 2524
2525 2525 def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
2526 2526
2527 2527 Ramb = 375 #Ramb = c/(2*PRF)
2528 2528 Re = 6371 #Earth Radius
2529 2529 heights = numpy.zeros(Ranges.shape)
2530 2530
2531 2531 R_aux = numpy.array([0,1,2])*Ramb
2532 2532 R_aux = R_aux.reshape(1,R_aux.size)
2533 2533
2534 2534 Ranges = Ranges.reshape(Ranges.size,1)
2535 2535
2536 2536 Ri = Ranges + R_aux
2537 2537 hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
2538 2538
2539 2539 #Check if there is a height between 70 and 110 km
2540 2540 h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
2541 2541 ind_h = numpy.where(h_bool == 1)[0]
2542 2542
2543 2543 hCorr = hi[ind_h, :]
2544 2544 ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
2545 2545
2546 2546 hCorr = hi[ind_hCorr]
2547 2547 heights[ind_h] = hCorr
2548 2548
2549 2549 #Setting Error
2550 2550 #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
2551 2551 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
2552 2552 indError = numpy.where(numpy.logical_or(error == 13, error == 14))[0]
2553 2553 error[indError] = 0
2554 2554 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
2555 2555 error[indInvalid2] = 14
2556 2556 indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
2557 2557 error[indInvalid1] = 13
2558 2558
2559 2559 return heights, error
2560 2560
2561 2561 def getPhasePairs(self, channelPositions):
2562 2562 chanPos = numpy.array(channelPositions)
2563 2563 listOper = list(itertools.combinations(range(5),2))
2564 2564
2565 2565 distances = numpy.zeros(4)
2566 2566 axisX = []
2567 2567 axisY = []
2568 2568 distX = numpy.zeros(3)
2569 2569 distY = numpy.zeros(3)
2570 2570 ix = 0
2571 2571 iy = 0
2572 2572
2573 2573 pairX = numpy.zeros((2,2))
2574 2574 pairY = numpy.zeros((2,2))
2575 2575
2576 2576 for i in range(len(listOper)):
2577 2577 pairi = listOper[i]
2578 2578
2579 2579 posDif = numpy.abs(chanPos[pairi[0],:] - chanPos[pairi[1],:])
2580 2580
2581 2581 if posDif[0] == 0:
2582 2582 axisY.append(pairi)
2583 2583 distY[iy] = posDif[1]
2584 2584 iy += 1
2585 2585 elif posDif[1] == 0:
2586 2586 axisX.append(pairi)
2587 2587 distX[ix] = posDif[0]
2588 2588 ix += 1
2589 2589
2590 2590 for i in range(2):
2591 2591 if i==0:
2592 2592 dist0 = distX
2593 2593 axis0 = axisX
2594 2594 else:
2595 2595 dist0 = distY
2596 2596 axis0 = axisY
2597 2597
2598 2598 side = numpy.argsort(dist0)[:-1]
2599 2599 axis0 = numpy.array(axis0)[side,:]
2600 2600 chanC = int(numpy.intersect1d(axis0[0,:], axis0[1,:])[0])
2601 2601 axis1 = numpy.unique(numpy.reshape(axis0,4))
2602 2602 side = axis1[axis1 != chanC]
2603 2603 diff1 = chanPos[chanC,i] - chanPos[side[0],i]
2604 2604 diff2 = chanPos[chanC,i] - chanPos[side[1],i]
2605 2605 if diff1<0:
2606 2606 chan2 = side[0]
2607 2607 d2 = numpy.abs(diff1)
2608 2608 chan1 = side[1]
2609 2609 d1 = numpy.abs(diff2)
2610 2610 else:
2611 2611 chan2 = side[1]
2612 2612 d2 = numpy.abs(diff2)
2613 2613 chan1 = side[0]
2614 2614 d1 = numpy.abs(diff1)
2615 2615
2616 2616 if i==0:
2617 2617 chanCX = chanC
2618 2618 chan1X = chan1
2619 2619 chan2X = chan2
2620 2620 distances[0:2] = numpy.array([d1,d2])
2621 2621 else:
2622 2622 chanCY = chanC
2623 2623 chan1Y = chan1
2624 2624 chan2Y = chan2
2625 2625 distances[2:4] = numpy.array([d1,d2])
2626 2626 # axisXsides = numpy.reshape(axisX[ix,:],4)
2627 2627 #
2628 2628 # channelCentX = int(numpy.intersect1d(pairX[0,:], pairX[1,:])[0])
2629 2629 # channelCentY = int(numpy.intersect1d(pairY[0,:], pairY[1,:])[0])
2630 2630 #
2631 2631 # ind25X = numpy.where(pairX[0,:] != channelCentX)[0][0]
2632 2632 # ind20X = numpy.where(pairX[1,:] != channelCentX)[0][0]
2633 2633 # channel25X = int(pairX[0,ind25X])
2634 2634 # channel20X = int(pairX[1,ind20X])
2635 2635 # ind25Y = numpy.where(pairY[0,:] != channelCentY)[0][0]
2636 2636 # ind20Y = numpy.where(pairY[1,:] != channelCentY)[0][0]
2637 2637 # channel25Y = int(pairY[0,ind25Y])
2638 2638 # channel20Y = int(pairY[1,ind20Y])
2639 2639
2640 2640 # pairslist = [(channelCentX, channel25X),(channelCentX, channel20X),(channelCentY,channel25Y),(channelCentY, channel20Y)]
2641 2641 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
2642 2642
2643 2643 return pairslist, distances
2644 2644 # def __getAOA(self, phases, pairsList, error, AOAthresh, azimuth):
2645 2645 #
2646 2646 # arrayAOA = numpy.zeros((phases.shape[0],3))
2647 2647 # cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList)
2648 2648 #
2649 2649 # arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
2650 2650 # cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
2651 2651 # arrayAOA[:,2] = cosDirError
2652 2652 #
2653 2653 # azimuthAngle = arrayAOA[:,0]
2654 2654 # zenithAngle = arrayAOA[:,1]
2655 2655 #
2656 2656 # #Setting Error
2657 2657 # #Number 3: AOA not fesible
2658 2658 # indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
2659 2659 # error[indInvalid] = 3
2660 2660 # #Number 4: Large difference in AOAs obtained from different antenna baselines
2661 2661 # indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
2662 2662 # error[indInvalid] = 4
2663 2663 # return arrayAOA, error
2664 2664 #
2665 2665 # def __getDirectionCosines(self, arrayPhase, pairsList):
2666 2666 #
2667 2667 # #Initializing some variables
2668 2668 # ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
2669 2669 # ang_aux = ang_aux.reshape(1,ang_aux.size)
2670 2670 #
2671 2671 # cosdir = numpy.zeros((arrayPhase.shape[0],2))
2672 2672 # cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
2673 2673 #
2674 2674 #
2675 2675 # for i in range(2):
2676 2676 # #First Estimation
2677 2677 # phi0_aux = arrayPhase[:,pairsList[i][0]] + arrayPhase[:,pairsList[i][1]]
2678 2678 # #Dealias
2679 2679 # indcsi = numpy.where(phi0_aux > numpy.pi)
2680 2680 # phi0_aux[indcsi] -= 2*numpy.pi
2681 2681 # indcsi = numpy.where(phi0_aux < -numpy.pi)
2682 2682 # phi0_aux[indcsi] += 2*numpy.pi
2683 2683 # #Direction Cosine 0
2684 2684 # cosdir0[:,i] = -(phi0_aux)/(2*numpy.pi*0.5)
2685 2685 #
2686 2686 # #Most-Accurate Second Estimation
2687 2687 # phi1_aux = arrayPhase[:,pairsList[i][0]] - arrayPhase[:,pairsList[i][1]]
2688 2688 # phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
2689 2689 # #Direction Cosine 1
2690 2690 # cosdir1 = -(phi1_aux + ang_aux)/(2*numpy.pi*4.5)
2691 2691 #
2692 2692 # #Searching the correct Direction Cosine
2693 2693 # cosdir0_aux = cosdir0[:,i]
2694 2694 # cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
2695 2695 # #Minimum Distance
2696 2696 # cosDiff = (cosdir1 - cosdir0_aux)**2
2697 2697 # indcos = cosDiff.argmin(axis = 1)
2698 2698 # #Saving Value obtained
2699 2699 # cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
2700 2700 #
2701 2701 # return cosdir0, cosdir
2702 2702 #
2703 2703 # def __calculateAOA(self, cosdir, azimuth):
2704 2704 # cosdirX = cosdir[:,0]
2705 2705 # cosdirY = cosdir[:,1]
2706 2706 #
2707 2707 # zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
2708 2708 # azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth #0 deg north, 90 deg east
2709 2709 # angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
2710 2710 #
2711 2711 # return angles
2712 2712 #
2713 2713 # def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
2714 2714 #
2715 2715 # Ramb = 375 #Ramb = c/(2*PRF)
2716 2716 # Re = 6371 #Earth Radius
2717 2717 # heights = numpy.zeros(Ranges.shape)
2718 2718 #
2719 2719 # R_aux = numpy.array([0,1,2])*Ramb
2720 2720 # R_aux = R_aux.reshape(1,R_aux.size)
2721 2721 #
2722 2722 # Ranges = Ranges.reshape(Ranges.size,1)
2723 2723 #
2724 2724 # Ri = Ranges + R_aux
2725 2725 # hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
2726 2726 #
2727 2727 # #Check if there is a height between 70 and 110 km
2728 2728 # h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
2729 2729 # ind_h = numpy.where(h_bool == 1)[0]
2730 2730 #
2731 2731 # hCorr = hi[ind_h, :]
2732 2732 # ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
2733 2733 #
2734 2734 # hCorr = hi[ind_hCorr]
2735 2735 # heights[ind_h] = hCorr
2736 2736 #
2737 2737 # #Setting Error
2738 2738 # #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
2739 2739 # #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
2740 2740 #
2741 2741 # indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
2742 2742 # error[indInvalid2] = 14
2743 2743 # indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
2744 2744 # error[indInvalid1] = 13
2745 2745 #
2746 2746 # return heights, error
General Comments 0
You need to be logged in to leave comments. Login now