##// END OF EJS Templates
UPDATE Repository desarroll drifts_schain, antigua version de WindProfiler en comparar 2.py
avaldez -
r1771:ed72d0635cd3
parent child
Show More
This diff has been collapsed as it changes many lines, (663 lines changed) Show them Hide them
@@ -0,0 +1,663
1 #primer windprofiler
2 class WindProfiler(Operation):
3
4 __isConfig = False
5
6 __initime = None
7 __lastdatatime = None
8 __integrationtime = None
9
10 __buffer = None
11
12 __dataReady = False
13
14 __firstdata = None
15
16 n = None
17
18 def __init__(self):
19 Operation.__init__(self)
20
21 def __calculateCosDir(self, elev, azim):
22 zen = (90 - elev)*numpy.pi/180
23 azim = azim*numpy.pi/180
24 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
25 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
26
27 signX = numpy.sign(numpy.cos(azim))
28 signY = numpy.sign(numpy.sin(azim))
29
30 cosDirX = numpy.copysign(cosDirX, signX)
31 cosDirY = numpy.copysign(cosDirY, signY)
32 return cosDirX, cosDirY
33
34 def __calculateAngles(self, theta_x, theta_y, azimuth):
35
36 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
37 zenith_arr = numpy.arccos(dir_cosw)
38 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
39
40 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
41 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
42
43 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
44
45 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
46
47 if horOnly:
48 A = numpy.c_[dir_cosu,dir_cosv]
49 else:
50 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
51 A = numpy.asmatrix(A)
52 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
53
54 return A1
55
56 def __correctValues(self, heiRang, phi, velRadial, SNR):
57 listPhi = phi.tolist()
58 maxid = listPhi.index(max(listPhi))
59 minid = listPhi.index(min(listPhi))
60
61 rango = list(range(len(phi)))
62
63 heiRang1 = heiRang*math.cos(phi[maxid])
64 heiRangAux = heiRang*math.cos(phi[minid])
65 indOut = (heiRang1 < heiRangAux[0]).nonzero()
66 heiRang1 = numpy.delete(heiRang1,indOut)
67
68 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
69 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
70
71 for i in rango:
72 x = heiRang*math.cos(phi[i])
73 y1 = velRadial[i,:]
74 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
75
76 x1 = heiRang1
77 y11 = f1(x1)
78
79 y2 = SNR[i,:]
80 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
81 y21 = f2(x1)
82
83 velRadial1[i,:] = y11
84 SNR1[i,:] = y21
85
86 return heiRang1, velRadial1, SNR1
87
88 def __calculateVelUVW(self, A, velRadial):
89
90 #Operacion Matricial
91 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
92 velUVW[:,:] = numpy.dot(A,velRadial)
93
94
95 return velUVW
96
97 def techniqueDBS(self, kwargs):
98 """
99 Function that implements Doppler Beam Swinging (DBS) technique.
100
101 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
102 Direction correction (if necessary), Ranges and SNR
103
104 Output: Winds estimation (Zonal, Meridional and Vertical)
105
106 Parameters affected: Winds, height range, SNR
107 """
108 velRadial0 = kwargs['velRadial']
109 heiRang = kwargs['heightList']
110 SNR0 = kwargs['SNR']
111
112 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
113 theta_x = numpy.array(kwargs['dirCosx'])
114 theta_y = numpy.array(kwargs['dirCosy'])
115 else:
116 elev = numpy.array(kwargs['elevation'])
117 azim = numpy.array(kwargs['azimuth'])
118 theta_x, theta_y = self.__calculateCosDir(elev, azim)
119 azimuth = kwargs['correctAzimuth']
120 if 'horizontalOnly' in kwargs:
121 horizontalOnly = kwargs['horizontalOnly']
122 else: horizontalOnly = False
123 if 'correctFactor' in kwargs:
124 correctFactor = kwargs['correctFactor']
125 else: correctFactor = 1
126 if 'channelList' in kwargs:
127 channelList = kwargs['channelList']
128 if len(channelList) == 2:
129 horizontalOnly = True
130 arrayChannel = numpy.array(channelList)
131 param = param[arrayChannel,:,:]
132 theta_x = theta_x[arrayChannel]
133 theta_y = theta_y[arrayChannel]
134
135 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
136 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
137 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
138
139 #Calculo de Componentes de la velocidad con DBS
140 winds = self.__calculateVelUVW(A,velRadial1)
141
142 return winds, heiRang1, SNR1
143
144 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
145
146 nPairs = len(pairs_ccf)
147 posx = numpy.asarray(posx)
148 posy = numpy.asarray(posy)
149
150 #Rotacion Inversa para alinear con el azimuth
151 if azimuth!= None:
152 azimuth = azimuth*math.pi/180
153 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
154 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
155 else:
156 posx1 = posx
157 posy1 = posy
158
159 #Calculo de Distancias
160 distx = numpy.zeros(nPairs)
161 disty = numpy.zeros(nPairs)
162 dist = numpy.zeros(nPairs)
163 ang = numpy.zeros(nPairs)
164
165 for i in range(nPairs):
166 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
167 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
168 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
169 ang[i] = numpy.arctan2(disty[i],distx[i])
170
171 return distx, disty, dist, ang
172 #Calculo de Matrices
173
174
175 def __calculateVelVer(self, phase, lagTRange, _lambda):
176
177 Ts = lagTRange[1] - lagTRange[0]
178 velW = -_lambda*phase/(4*math.pi*Ts)
179
180 return velW
181
182 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
183 nPairs = tau1.shape[0]
184 nHeights = tau1.shape[1]
185 vel = numpy.zeros((nPairs,3,nHeights))
186 dist1 = numpy.reshape(dist, (dist.size,1))
187
188 angCos = numpy.cos(ang)
189 angSin = numpy.sin(ang)
190
191 vel0 = dist1*tau1/(2*tau2**2)
192 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
193 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
194
195 ind = numpy.where(numpy.isinf(vel))
196 vel[ind] = numpy.nan
197
198 return vel
199
200 def techniqueSA(self, kwargs):
201
202 """
203 Function that implements Spaced Antenna (SA) technique.
204
205 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
206 Direction correction (if necessary), Ranges and SNR
207
208 Output: Winds estimation (Zonal, Meridional and Vertical)
209
210 Parameters affected: Winds
211 """
212 position_x = kwargs['positionX']
213 position_y = kwargs['positionY']
214 azimuth = kwargs['azimuth']
215
216 if 'correctFactor' in kwargs:
217 correctFactor = kwargs['correctFactor']
218 else:
219 correctFactor = 1
220
221 groupList = kwargs['groupList']
222 pairs_ccf = groupList[1]
223 tau = kwargs['tau']
224 _lambda = kwargs['_lambda']
225
226 #Cross Correlation pairs obtained
227
228 indtau = tau.shape[0]/2
229 tau1 = tau[:indtau,:]
230 tau2 = tau[indtau:-1,:]
231 phase1 = tau[-1,:]
232
233 #---------------------------------------------------------------------
234 #Metodo Directo
235 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
236 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
237 winds = stats.nanmean(winds, axis=0)
238 #---------------------------------------------------------------------
239 #Metodo General
240
241 #---------------------------------------------------------------------
242 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
243 winds = correctFactor*winds
244 return winds
245
246 def __checkTime(self, currentTime, paramInterval, outputInterval):
247
248 dataTime = currentTime + paramInterval
249 deltaTime = dataTime - self.__initime
250
251 if deltaTime >= outputInterval or deltaTime < 0:
252 self.__dataReady = True
253 return
254
255 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
256 '''
257 Function that implements winds estimation technique with detected meteors.
258
259 Input: Detected meteors, Minimum meteor quantity to wind estimation
260
261 Output: Winds estimation (Zonal and Meridional)
262
263 Parameters affected: Winds
264 '''
265 #Settings
266 nInt = (heightMax - heightMin)/2
267 nInt = int(nInt)
268 winds = numpy.zeros((2,nInt))*numpy.nan
269
270 #Filter errors
271 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
272 finalMeteor = arrayMeteor[error,:]
273
274 #Meteor Histogram
275 finalHeights = finalMeteor[:,2]
276 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
277 nMeteorsPerI = hist[0]
278 heightPerI = hist[1]
279
280 #Sort of meteors
281 indSort = finalHeights.argsort()
282 finalMeteor2 = finalMeteor[indSort,:]
283
284 # Calculating winds
285 ind1 = 0
286 ind2 = 0
287
288 for i in range(nInt):
289 nMet = nMeteorsPerI[i]
290 ind1 = ind2
291 ind2 = ind1 + nMet
292
293 meteorAux = finalMeteor2[ind1:ind2,:]
294
295 if meteorAux.shape[0] >= meteorThresh:
296 vel = meteorAux[:, 6]
297 zen = meteorAux[:, 4]*numpy.pi/180
298 azim = meteorAux[:, 3]*numpy.pi/180
299
300 n = numpy.cos(zen)
301 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
302 # l = m*numpy.tan(azim)
303 l = numpy.sin(zen)*numpy.sin(azim)
304 m = numpy.sin(zen)*numpy.cos(azim)
305
306 A = numpy.vstack((l, m)).transpose()
307 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
308 windsAux = numpy.dot(A1, vel)
309
310 winds[0,i] = windsAux[0]
311 winds[1,i] = windsAux[1]
312
313 return winds, heightPerI[:-1]
314
315 def techniqueNSM_SA(self, **kwargs):
316 metArray = kwargs['metArray']
317 heightList = kwargs['heightList']
318 timeList = kwargs['timeList']
319
320 rx_location = kwargs['rx_location']
321 groupList = kwargs['groupList']
322 azimuth = kwargs['azimuth']
323 dfactor = kwargs['dfactor']
324 k = kwargs['k']
325
326 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
327 d = dist*dfactor
328 #Phase calculation
329 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
330
331 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
332
333 velEst = numpy.zeros((heightList.size,2))*numpy.nan
334 azimuth1 = azimuth1*numpy.pi/180
335
336 for i in range(heightList.size):
337 h = heightList[i]
338 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
339 metHeight = metArray1[indH,:]
340 if metHeight.shape[0] >= 2:
341 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
342 iazim = metHeight[:,1].astype(int)
343 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
344 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
345 A = numpy.asmatrix(A)
346 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
347 velHor = numpy.dot(A1,velAux)
348
349 velEst[i,:] = numpy.squeeze(velHor)
350 return velEst
351
352 def __getPhaseSlope(self, metArray, heightList, timeList):
353 meteorList = []
354 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
355 #Putting back together the meteor matrix
356 utctime = metArray[:,0]
357 uniqueTime = numpy.unique(utctime)
358
359 phaseDerThresh = 0.5
360 ippSeconds = timeList[1] - timeList[0]
361 sec = numpy.where(timeList>1)[0][0]
362 nPairs = metArray.shape[1] - 6
363 nHeights = len(heightList)
364
365 for t in uniqueTime:
366 metArray1 = metArray[utctime==t,:]
367 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
368 tmet = metArray1[:,1].astype(int)
369 hmet = metArray1[:,2].astype(int)
370
371 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
372 metPhase[:,:] = numpy.nan
373 metPhase[:,hmet,tmet] = metArray1[:,6:].T
374
375 #Delete short trails
376 metBool = ~numpy.isnan(metPhase[0,:,:])
377 heightVect = numpy.sum(metBool, axis = 1)
378 metBool[heightVect<sec,:] = False
379 metPhase[:,heightVect<sec,:] = numpy.nan
380
381 #Derivative
382 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
383 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
384 metPhase[phDerAux] = numpy.nan
385
386 #--------------------------METEOR DETECTION -----------------------------------------
387 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
388
389 for p in numpy.arange(nPairs):
390 phase = metPhase[p,:,:]
391 phDer = metDer[p,:,:]
392
393 for h in indMet:
394 height = heightList[h]
395 phase1 = phase[h,:] #82
396 phDer1 = phDer[h,:]
397
398 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
399
400 indValid = numpy.where(~numpy.isnan(phase1))[0]
401 initMet = indValid[0]
402 endMet = 0
403
404 for i in range(len(indValid)-1):
405
406 #Time difference
407 inow = indValid[i]
408 inext = indValid[i+1]
409 idiff = inext - inow
410 #Phase difference
411 phDiff = numpy.abs(phase1[inext] - phase1[inow])
412
413 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
414 sizeTrail = inow - initMet + 1
415 if sizeTrail>3*sec: #Too short meteors
416 x = numpy.arange(initMet,inow+1)*ippSeconds
417 y = phase1[initMet:inow+1]
418 ynnan = ~numpy.isnan(y)
419 x = x[ynnan]
420 y = y[ynnan]
421 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
422 ylin = x*slope + intercept
423 rsq = r_value**2
424 if rsq > 0.5:
425 vel = slope#*height*1000/(k*d)
426 estAux = numpy.array([utctime,p,height, vel, rsq])
427 meteorList.append(estAux)
428 initMet = inext
429 metArray2 = numpy.array(meteorList)
430
431 return metArray2
432
433 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
434
435 azimuth1 = numpy.zeros(len(pairslist))
436 dist = numpy.zeros(len(pairslist))
437
438 for i in range(len(rx_location)):
439 ch0 = pairslist[i][0]
440 ch1 = pairslist[i][1]
441
442 diffX = rx_location[ch0][0] - rx_location[ch1][0]
443 diffY = rx_location[ch0][1] - rx_location[ch1][1]
444 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
445 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
446
447 azimuth1 -= azimuth0
448 return azimuth1, dist
449
450 def techniqueNSM_DBS(self, **kwargs):
451 metArray = kwargs['metArray']
452 heightList = kwargs['heightList']
453 timeList = kwargs['timeList']
454 azimuth = kwargs['azimuth']
455 theta_x = numpy.array(kwargs['theta_x'])
456 theta_y = numpy.array(kwargs['theta_y'])
457
458 utctime = metArray[:,0]
459 cmet = metArray[:,1].astype(int)
460 hmet = metArray[:,3].astype(int)
461 SNRmet = metArray[:,4]
462 vmet = metArray[:,5]
463 spcmet = metArray[:,6]
464
465 nChan = numpy.max(cmet) + 1
466 nHeights = len(heightList)
467
468 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
469 hmet = heightList[hmet]
470 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
471
472 velEst = numpy.zeros((heightList.size,2))*numpy.nan
473
474 for i in range(nHeights - 1):
475 hmin = heightList[i]
476 hmax = heightList[i + 1]
477
478 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
479 indthisH = numpy.where(thisH)
480
481 if numpy.size(indthisH) > 3:
482
483 vel_aux = vmet[thisH]
484 chan_aux = cmet[thisH]
485 cosu_aux = dir_cosu[chan_aux]
486 cosv_aux = dir_cosv[chan_aux]
487 cosw_aux = dir_cosw[chan_aux]
488
489 nch = numpy.size(numpy.unique(chan_aux))
490 if nch > 1:
491 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
492 velEst[i,:] = numpy.dot(A,vel_aux)
493
494 return velEst
495
496 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
497
498 param = dataOut.data_param
499 #if dataOut.abscissaList != None:
500 if numpy.any(dataOut.abscissaList):
501 absc = dataOut.abscissaList[:-1]
502 # noise = dataOut.noise
503 heightList = dataOut.heightList
504 SNR = dataOut.data_snr
505
506 if technique == 'DBS':
507
508 kwargs['velRadial'] = param[:,1,:] #Radial velocity
509 kwargs['heightList'] = heightList
510 kwargs['SNR'] = SNR
511
512 dataOut.data_output, dataOut.heightList, dataOut.data_snr = self.techniqueDBS(kwargs) #DBS Function
513 dataOut.utctimeInit = dataOut.utctime
514 dataOut.outputInterval = dataOut.paramInterval
515
516 elif technique == 'SA':
517
518 #Parameters
519 # position_x = kwargs['positionX']
520 # position_y = kwargs['positionY']
521 # azimuth = kwargs['azimuth']
522 #
523 # if kwargs.has_key('crosspairsList'):
524 # pairs = kwargs['crosspairsList']
525 # else:
526 # pairs = None
527 #
528 # if kwargs.has_key('correctFactor'):
529 # correctFactor = kwargs['correctFactor']
530 # else:
531 # correctFactor = 1
532
533 # tau = dataOut.data_param
534 # _lambda = dataOut.C/dataOut.frequency
535 # pairsList = dataOut.groupList
536 # nChannels = dataOut.nChannels
537
538 kwargs['groupList'] = dataOut.groupList
539 kwargs['tau'] = dataOut.data_param
540 kwargs['_lambda'] = dataOut.C/dataOut.frequency
541 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
542 dataOut.data_output = self.techniqueSA(kwargs)
543 dataOut.utctimeInit = dataOut.utctime
544 dataOut.outputInterval = dataOut.timeInterval
545
546 elif technique == 'Meteors':
547 dataOut.flagNoData = True
548 self.__dataReady = False
549
550 if 'nHours' in kwargs:
551 nHours = kwargs['nHours']
552 else:
553 nHours = 1
554
555 if 'meteorsPerBin' in kwargs:
556 meteorThresh = kwargs['meteorsPerBin']
557 else:
558 meteorThresh = 6
559
560 if 'hmin' in kwargs:
561 hmin = kwargs['hmin']
562 else: hmin = 70
563 if 'hmax' in kwargs:
564 hmax = kwargs['hmax']
565 else: hmax = 110
566
567 dataOut.outputInterval = nHours*3600
568
569 if self.__isConfig == False:
570 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
571 #Get Initial LTC time
572 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
573 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
574
575 self.__isConfig = True
576
577 if self.__buffer is None:
578 self.__buffer = dataOut.data_param
579 self.__firstdata = copy.copy(dataOut)
580
581 else:
582 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
583
584 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
585
586 if self.__dataReady:
587 dataOut.utctimeInit = self.__initime
588
589 self.__initime += dataOut.outputInterval #to erase time offset
590
591 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
592 dataOut.flagNoData = False
593 self.__buffer = None
594
595 elif technique == 'Meteors1':
596 dataOut.flagNoData = True
597 self.__dataReady = False
598
599 if 'nMins' in kwargs:
600 nMins = kwargs['nMins']
601 else: nMins = 20
602 if 'rx_location' in kwargs:
603 rx_location = kwargs['rx_location']
604 else: rx_location = [(0,1),(1,1),(1,0)]
605 if 'azimuth' in kwargs:
606 azimuth = kwargs['azimuth']
607 else: azimuth = 51.06
608 if 'dfactor' in kwargs:
609 dfactor = kwargs['dfactor']
610 if 'mode' in kwargs:
611 mode = kwargs['mode']
612 if 'theta_x' in kwargs:
613 theta_x = kwargs['theta_x']
614 if 'theta_y' in kwargs:
615 theta_y = kwargs['theta_y']
616 else: mode = 'SA'
617
618 #Borrar luego esto
619 if dataOut.groupList is None:
620 dataOut.groupList = [(0,1),(0,2),(1,2)]
621 groupList = dataOut.groupList
622 C = 3e8
623 freq = 50e6
624 lamb = C/freq
625 k = 2*numpy.pi/lamb
626
627 timeList = dataOut.abscissaList
628 heightList = dataOut.heightList
629
630 if self.__isConfig == False:
631 dataOut.outputInterval = nMins*60
632 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
633 #Get Initial LTC time
634 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
635 minuteAux = initime.minute
636 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
637 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
638
639 self.__isConfig = True
640
641 if self.__buffer is None:
642 self.__buffer = dataOut.data_param
643 self.__firstdata = copy.copy(dataOut)
644
645 else:
646 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
647
648 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
649
650 if self.__dataReady:
651 dataOut.utctimeInit = self.__initime
652 self.__initime += dataOut.outputInterval #to erase time offset
653
654 metArray = self.__buffer
655 if mode == 'SA':
656 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
657 elif mode == 'DBS':
658 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
659 dataOut.data_output = dataOut.data_output.T
660 dataOut.flagNoData = False
661 self.__buffer = None
662
663 return
This diff has been collapsed as it changes many lines, (1164 lines changed) Show them Hide them
@@ -1,7613 +1,7181
1 1 # MASTER
2 2 import numpy
3 3 import math
4 4 from scipy import optimize, interpolate, signal, stats, ndimage
5 5 from scipy.fftpack import fft
6 6 import scipy
7 7 import re
8 8 import datetime
9 9 import copy
10 10 import sys
11 import os
11 12 import importlib
12 13 import itertools
13 14 from multiprocessing import Pool, TimeoutError
14 15 from multiprocessing.pool import ThreadPool
15 16 import time
16 17
17 18 from scipy.optimize import fmin_l_bfgs_b #optimize with bounds on state papameters
18 19 from .jroproc_base import ProcessingUnit, Operation, MPDecorator
19 20 from schainpy.model.data.jrodata import Parameters, hildebrand_sekhon
20 21 from schainpy.model.data.jrodata import Spectra
21 #from scipy import asarray as ar,exp
22 from scipy import asarray as ar,exp
22 23 from scipy.optimize import fmin, curve_fit
23 24 from schainpy.utils import log
24 25 import warnings
25 26 from numpy import NaN
26 27 from scipy.optimize.optimize import OptimizeWarning
28 from schainpy.model.io.jroIO_madrigal import MADWriter
27 29 warnings.filterwarnings('ignore')
28 30
29 31 import os
30 32 import csv
31 33 from scipy import signal
32 34 import matplotlib.pyplot as plt
33 35
36 import json
37 import mysql.connector
38 from scipy.signal import savgol_filter
39 from scipy.signal import argrelextrema
40 from scipy.signal import find_peaks
41
34 42 SPEED_OF_LIGHT = 299792458
35 43
36 44 '''solving pickling issue'''
37 45
38 46 def _pickle_method(method):
39 47 func_name = method.__func__.__name__
40 48 obj = method.__self__
41 49 cls = method.__self__.__class__
42 50 return _unpickle_method, (func_name, obj, cls)
43 51
44 52 def _unpickle_method(func_name, obj, cls):
45 53 for cls in cls.mro():
46 54 try:
47 55 func = cls.__dict__[func_name]
48 56 except KeyError:
49 57 pass
50 58 else:
51 59 break
52 60 return func.__get__(obj, cls)
53 61
54
62 # @MPDecorator
55 63 class ParametersProc(ProcessingUnit):
56 64
57 65 METHODS = {}
58 66 nSeconds = None
59 67
60 68 def __init__(self):
61 69 ProcessingUnit.__init__(self)
62 70
63 71 self.buffer = None
64 72 self.firstdatatime = None
65 73 self.profIndex = 0
66 74 self.dataOut = Parameters()
67 75 self.setupReq = False #Agregar a todas las unidades de proc
68 76
69 77 def __updateObjFromInput(self):
70 78
71 79 self.dataOut.inputUnit = self.dataIn.type
72 80
73 81 self.dataOut.timeZone = self.dataIn.timeZone
74 82 self.dataOut.dstFlag = self.dataIn.dstFlag
75 83 self.dataOut.errorCount = self.dataIn.errorCount
76 84 self.dataOut.useLocalTime = self.dataIn.useLocalTime
77 85
78 86 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
79 87 self.dataOut.processingHeaderObj = self.dataIn.processingHeaderObj.copy()
80 88 self.dataOut.systemHeaderObj = self.dataIn.systemHeaderObj.copy()
81 89
82 90 self.dataOut.channelList = self.dataIn.channelList
83 91 self.dataOut.heightList = self.dataIn.heightList
84 92 self.dataOut.ipp = self.dataIn.ipp
85 93 self.dataOut.ippSeconds = self.dataIn.ippSeconds
86 94 self.dataOut.deltaHeight = self.dataIn.deltaHeight
87 95 self.dataOut.dtype = numpy.dtype([('real','<f4'),('imag','<f4')])
88 96
89 97 self.dataOut.nBaud = self.dataIn.nBaud
90 98 self.dataOut.nCode = self.dataIn.nCode
91 99 self.dataOut.code = self.dataIn.code
92 100 self.dataOut.nProfiles = self.dataIn.nProfiles
93 101
94 102 self.dataOut.flagDiscontinuousBlock = self.dataIn.flagDiscontinuousBlock
95 103 self.dataOut.utctime = self.dataIn.utctime
96 104 self.dataOut.flagDecodeData = self.dataIn.flagDecodeData #asumo q la data esta decodificada
97 105 self.dataOut.flagDeflipData = self.dataIn.flagDeflipData #asumo q la data esta sin flip
98 106 self.dataOut.nCohInt = self.dataIn.nCohInt
99 107 self.dataOut.nIncohInt = self.dataIn.nIncohInt
100 108 self.dataOut.ippSeconds = self.dataIn.ippSeconds
101 109 self.dataOut.windowOfFilter = self.dataIn.windowOfFilter
102 110
103 111 self.dataOut.timeInterval1 = self.dataIn.timeInterval
104 112 self.dataOut.heightList = self.dataIn.heightList
105 113 self.dataOut.frequency = self.dataIn.frequency
106 114 self.dataOut.codeList = self.dataIn.codeList
107 115 self.dataOut.azimuthList = self.dataIn.azimuthList
108 116 self.dataOut.elevationList = self.dataIn.elevationList
109 117 self.dataOut.runNextUnit = self.dataIn.runNextUnit
110 118
111 119 def run(self, runNextUnit=0):
112 120
113 121 self.dataIn.runNextUnit = runNextUnit
114 122 #---------------------- Voltage Data ---------------------------
115 123 try:
116 124 intype = self.dataIn.type.decode("utf-8")
117 125 self.dataIn.type = intype
118 126 except:
119 127 pass
120 128
121 129 if self.dataIn.type == "Voltage":
122 130
123 131 self.__updateObjFromInput()
124 132 self.dataOut.data_pre = self.dataIn.data.copy()
125 133 self.dataOut.flagNoData = False
126 134 self.dataOut.utctimeInit = self.dataIn.utctime
127 135 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
128 136 if hasattr(self.dataIn, 'dataPP_POW'):
129 137 self.dataOut.dataPP_POW = self.dataIn.dataPP_POW
130 138
131 139 if hasattr(self.dataIn, 'dataPP_POWER'):
132 140 self.dataOut.dataPP_POWER = self.dataIn.dataPP_POWER
133 141
134 142 if hasattr(self.dataIn, 'dataPP_DOP'):
135 143 self.dataOut.dataPP_DOP = self.dataIn.dataPP_DOP
136 144
137 145 if hasattr(self.dataIn, 'dataPP_SNR'):
138 146 self.dataOut.dataPP_SNR = self.dataIn.dataPP_SNR
139 147
140 148 if hasattr(self.dataIn, 'dataPP_WIDTH'):
141 149 self.dataOut.dataPP_WIDTH = self.dataIn.dataPP_WIDTH
142 150 return
143 151
144 152 #---------------------- Spectra Data ---------------------------
145 153
146 154 if self.dataIn.type == "Spectra":
147 155
148 156 self.dataOut.data_pre = [self.dataIn.data_spc, self.dataIn.data_cspc]
149 157 self.dataOut.data_spc = self.dataIn.data_spc
150 158 self.dataOut.data_cspc = self.dataIn.data_cspc
151 159 if hasattr(self.dataIn, 'data_outlier'):
152 160 self.dataOut.data_outlier = self.dataIn.data_outlier
153 161 if hasattr(self.dataIn,'flagPRofilesByRange'):
154 162 self.dataOut.flagProfilesByRange = self.dataIn.flagProfilesByRange
155 163 if hasattr(self.dataIn,'nProfilesByRange'):
156 164 self.dataOut.nProfilesByRange = self.dataIn.nProfilesByRange
157 165 if hasattr(self.dataIn,'deltaHeight'):
158 166 self.dataOut.deltaHeight = self.dataIn.deltaHeight
159 167 if hasattr(self.dataIn,'noise_estimation'):
160 168 self.dataOut.noise_estimation = self.dataIn.noise_estimation
161 169 if hasattr(self.dataIn, 'channelList'):
162 170 self.dataOut.channelList = self.dataIn.channelList
163 171 if hasattr(self.dataIn, 'pairsList'):
164 172 self.dataOut.pairsList = self.dataIn.pairsList
165 173 self.dataOut.groupList = self.dataIn.pairsList
166 174 self.dataOut.nProfiles = self.dataIn.nProfiles
167 175 self.dataOut.nIncohInt = self.dataIn.nIncohInt
168 176 self.dataOut.nFFTPoints = self.dataIn.nFFTPoints
169 177 self.dataOut.ippFactor = self.dataIn.ippFactor
170 178 self.dataOut.abscissaList = self.dataIn.getVelRange(1)
171 179 self.dataOut.spc_noise = self.dataIn.getNoise()
172 180 self.dataOut.spc_range = (self.dataIn.getFreqRange(1) , self.dataIn.getAcfRange(1) , self.dataIn.getVelRange(1))
173 181 # self.dataOut.normFactor = self.dataIn.normFactor
182 self.dataOut.pairsList = self.dataIn.pairsList
183 self.dataOut.groupList = self.dataIn.pairsList
174 184 self.dataOut.flagNoData = False
175 185
176 186 if hasattr(self.dataIn, 'ChanDist'): #Distances of receiver channels
177 187 self.dataOut.ChanDist = self.dataIn.ChanDist
178 188 else: self.dataOut.ChanDist = None
179 189
180 190 #if hasattr(self.dataIn, 'VelRange'): #Velocities range
181 191 # self.dataOut.VelRange = self.dataIn.VelRange
182 192 #else: self.dataOut.VelRange = None
183 193
184 194 if hasattr(self.dataIn, 'RadarConst'): #Radar Constant
185 195 self.dataOut.RadarConst = self.dataIn.RadarConst
186 196
187 197 if hasattr(self.dataIn, 'NPW'): #NPW
188 198 self.dataOut.NPW = self.dataIn.NPW
189 199
190 200 if hasattr(self.dataIn, 'COFA'): #COFA
191 201 self.dataOut.COFA = self.dataIn.COFA
192 202
193 203
194 204
195 205 #---------------------- Correlation Data ---------------------------
196 206
197 207 if self.dataIn.type == "Correlation":
198 208 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.dataIn.splitFunctions()
199 209
200 210 self.dataOut.data_pre = (self.dataIn.data_cf[acf_ind,:], self.dataIn.data_cf[ccf_ind,:,:])
201 211 self.dataOut.normFactor = (self.dataIn.normFactor[acf_ind,:], self.dataIn.normFactor[ccf_ind,:])
202 212 self.dataOut.groupList = (acf_pairs, ccf_pairs)
203 213
204 214 self.dataOut.abscissaList = self.dataIn.lagRange
205 215 self.dataOut.noise = self.dataIn.noise
206 216 self.dataOut.data_snr = self.dataIn.SNR
207 217 self.dataOut.flagNoData = False
208 218 self.dataOut.nAvg = self.dataIn.nAvg
209 219
210 220 #---------------------- Parameters Data ---------------------------
211 221
212 222 if self.dataIn.type == "Parameters":
213 223 self.dataOut.copy(self.dataIn)
214 224 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
215 225 self.dataOut.processingHeaderObj = self.dataIn.processingHeaderObj.copy()
216 226 self.dataOut.flagNoData = False
217 227 if isinstance(self.dataIn.nIncohInt,numpy.ndarray):
218 228 nch, nheis = self.dataIn.nIncohInt.shape
219 229 if nch != self.dataIn.nChannels:
220 230 aux = numpy.repeat(self.dataIn.nIncohInt, self.dataIn.nChannels, axis=0)
221 231 self.dataOut.nIncohInt = aux
222 232 return True
223 233
224 234 self.__updateObjFromInput()
225 235 self.dataOut.utctimeInit = self.dataIn.utctime
226 236 self.dataOut.paramInterval = self.dataIn.timeInterval
237
227 238 return
228 239
229 240
230 241 def target(tups):
231 242
232 243 obj, args = tups
233 244
234 245 return obj.FitGau(args)
235 246
236 247 class RemoveWideGC(Operation):
237 248 ''' This class remove the wide clutter and replace it with a simple interpolation points
238 249 This mainly applies to CLAIRE radar
239 250
240 251 ClutterWidth : Width to look for the clutter peak
241 252
242 253 Input:
243 254
244 255 self.dataOut.data_pre : SPC and CSPC
245 256 self.dataOut.spc_range : To select wind and rainfall velocities
246 257
247 258 Affected:
248 259
249 260 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
250 261
251 262 Written by D. ScipiΓ³n 25.02.2021
252 263 '''
253 264 def __init__(self):
254 265 Operation.__init__(self)
255 266 self.i = 0
256 267 self.ich = 0
257 268 self.ir = 0
258 269
259 270 def run(self, dataOut, ClutterWidth=2.5):
260 271
261 272 self.spc = dataOut.data_pre[0].copy()
262 273 self.spc_out = dataOut.data_pre[0].copy()
263 274 self.Num_Chn = self.spc.shape[0]
264 275 self.Num_Hei = self.spc.shape[2]
265 276 VelRange = dataOut.spc_range[2][:-1]
266 277 dv = VelRange[1]-VelRange[0]
267 278
268 279 # Find the velocities that corresponds to zero
269 280 gc_values = numpy.squeeze(numpy.where(numpy.abs(VelRange) <= ClutterWidth))
270 281
271 282 # Removing novalid data from the spectra
272 283 for ich in range(self.Num_Chn) :
273 284 for ir in range(self.Num_Hei) :
274 285 # Estimate the noise at each range
275 286 HSn = hildebrand_sekhon(self.spc[ich,:,ir],dataOut.nIncohInt)
276 287
277 288 # Removing the noise floor at each range
278 289 novalid = numpy.where(self.spc[ich,:,ir] < HSn)
279 290 self.spc[ich,novalid,ir] = HSn
280 291
281 292 junk = numpy.append(numpy.insert(numpy.squeeze(self.spc[ich,gc_values,ir]),0,HSn),HSn)
282 293 j1index = numpy.squeeze(numpy.where(numpy.diff(junk)>0))
283 294 j2index = numpy.squeeze(numpy.where(numpy.diff(junk)<0))
284 295 if ((numpy.size(j1index)<=1) | (numpy.size(j2index)<=1)) :
285 296 continue
286 297 junk3 = numpy.squeeze(numpy.diff(j1index))
287 298 junk4 = numpy.squeeze(numpy.diff(j2index))
299
288 300 valleyindex = j2index[numpy.where(junk4>1)]
289 301 peakindex = j1index[numpy.where(junk3>1)]
290 302
291 303 isvalid = numpy.squeeze(numpy.where(numpy.abs(VelRange[gc_values[peakindex]]) <= 2.5*dv))
292 304 if numpy.size(isvalid) == 0 :
293 305 continue
294 306 if numpy.size(isvalid) >1 :
295 307 vindex = numpy.argmax(self.spc[ich,gc_values[peakindex[isvalid]],ir])
296 308 isvalid = isvalid[vindex]
309
297 310 # clutter peak
298 311 gcpeak = peakindex[isvalid]
299 312 vl = numpy.where(valleyindex < gcpeak)
300 313 if numpy.size(vl) == 0:
301 314 continue
302 315 gcvl = valleyindex[vl[0][-1]]
303 316 vr = numpy.where(valleyindex > gcpeak)
304 317 if numpy.size(vr) == 0:
305 318 continue
306 319 gcvr = valleyindex[vr[0][0]]
307 320
308 321 # Removing the clutter
309 322 interpindex = numpy.array([gc_values[gcvl], gc_values[gcvr]])
310 323 gcindex = gc_values[gcvl+1:gcvr-1]
311 324 self.spc_out[ich,gcindex,ir] = numpy.interp(VelRange[gcindex],VelRange[interpindex],self.spc[ich,interpindex,ir])
312 325
313 326 dataOut.data_pre[0] = self.spc_out
314 327
315 328 return dataOut
316 329
317 330 class SpectralFilters(Operation):
318 331 ''' This class allows to replace the novalid values with noise for each channel
319 332 This applies to CLAIRE RADAR
320 333
321 334 PositiveLimit : RightLimit of novalid data
322 335 NegativeLimit : LeftLimit of novalid data
323 336
324 337 Input:
325 338
326 339 self.dataOut.data_pre : SPC and CSPC
327 340 self.dataOut.spc_range : To select wind and rainfall velocities
328 341
329 342 Affected:
330 343
331 344 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
332 345
333 346 Written by D. ScipiΓ³n 29.01.2021
334 347 '''
335 348 def __init__(self):
336 349 Operation.__init__(self)
337 350 self.i = 0
338 351
339 352 def run(self, dataOut, ):
340 353
341 354 self.spc = dataOut.data_pre[0].copy()
342 355 self.Num_Chn = self.spc.shape[0]
343 356 VelRange = dataOut.spc_range[2]
344 357
345 358 # novalid corresponds to data within the Negative and PositiveLimit
346 359 # Removing novalid data from the spectra
347 360 for i in range(self.Num_Chn):
348 361 self.spc[i,novalid,:] = dataOut.noise[i]
349 362 dataOut.data_pre[0] = self.spc
350 363 return dataOut
351 364
352 365
353 366 class GaussianFit(Operation):
354 367
355 368 '''
356 369 Function that fit of one and two generalized gaussians (gg) based
357 370 on the PSD shape across an "power band" identified from a cumsum of
358 371 the measured spectrum - noise.
359 372
360 373 Input:
361 374 self.dataOut.data_pre : SelfSpectra
362 375
363 376 Output:
364 377 self.dataOut.SPCparam : SPC_ch1, SPC_ch2
365 378
366 379 '''
367 380 def __init__(self):
368 381 Operation.__init__(self)
369 382 self.i=0
370 383
371 384 def run(self, dataOut, SNRdBlimit=-9, method='generalized'):
372 385 """This routine will find a couple of generalized Gaussians to a power spectrum
373 386 methods: generalized, squared
374 387 input: spc
375 388 output:
376 389 noise, amplitude0,shift0,width0,p0,Amplitude1,shift1,width1,p1
377 390 """
378 391 print ('Entering ',method,' double Gaussian fit')
379 392 self.spc = dataOut.data_pre[0].copy()
380 393 self.Num_Hei = self.spc.shape[2]
381 394 self.Num_Bin = self.spc.shape[1]
382 395 self.Num_Chn = self.spc.shape[0]
383 396
384 397 start_time = time.time()
385 398
386 399 pool = Pool(processes=self.Num_Chn)
387 400 args = [(dataOut.spc_range[2], ich, dataOut.spc_noise[ich], dataOut.nIncohInt, SNRdBlimit) for ich in range(self.Num_Chn)]
388 401 objs = [self for __ in range(self.Num_Chn)]
389 402 attrs = list(zip(objs, args))
390 403 DGauFitParam = pool.map(target, attrs)
391 404 # Parameters:
392 405 # 0. Noise, 1. Amplitude, 2. Shift, 3. Width 4. Power
393 406 dataOut.DGauFitParams = numpy.asarray(DGauFitParam)
394 407
395 408 # Double Gaussian Curves
396 409 gau0 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
397 410 gau0[:] = numpy.NaN
398 411 gau1 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
399 412 gau1[:] = numpy.NaN
400 413 x_mtr = numpy.transpose(numpy.tile(dataOut.getVelRange(1)[:-1], (self.Num_Hei,1)))
401 414 for iCh in range(self.Num_Chn):
402 415 N0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,0]] * self.Num_Bin))
403 416 N1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,1]] * self.Num_Bin))
404 417 A0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,0]] * self.Num_Bin))
405 418 A1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,1]] * self.Num_Bin))
406 419 v0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,0]] * self.Num_Bin))
407 420 v1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,1]] * self.Num_Bin))
408 421 s0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,0]] * self.Num_Bin))
409 422 s1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,1]] * self.Num_Bin))
410 423 if method == 'generalized':
411 424 p0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,0]] * self.Num_Bin))
412 425 p1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,1]] * self.Num_Bin))
413 426 elif method == 'squared':
414 427 p0 = 2.
415 428 p1 = 2.
416 429 gau0[iCh] = A0*numpy.exp(-0.5*numpy.abs((x_mtr-v0)/s0)**p0)+N0
417 430 gau1[iCh] = A1*numpy.exp(-0.5*numpy.abs((x_mtr-v1)/s1)**p1)+N1
418 431 dataOut.GaussFit0 = gau0
419 432 dataOut.GaussFit1 = gau1
420 433
421 434 print('Leaving ',method ,' double Gaussian fit')
422 435 return dataOut
423 436
424 437 def FitGau(self, X):
425 438 # print('Entering FitGau')
426 439 # Assigning the variables
427 440 Vrange, ch, wnoise, num_intg, SNRlimit = X
428 441 # Noise Limits
429 442 noisebl = wnoise * 0.9
430 443 noisebh = wnoise * 1.1
431 444 # Radar Velocity
432 445 Va = max(Vrange)
433 446 deltav = Vrange[1] - Vrange[0]
434 447 x = numpy.arange(self.Num_Bin)
435 448
436 449 # print ('stop 0')
437 450
438 451 # 5 parameters, 2 Gaussians
439 452 DGauFitParam = numpy.zeros([5, self.Num_Hei,2])
440 453 DGauFitParam[:] = numpy.NaN
441 454
442 455 # SPCparam = []
443 456 # SPC_ch1 = numpy.zeros([self.Num_Bin,self.Num_Hei])
444 457 # SPC_ch2 = numpy.zeros([self.Num_Bin,self.Num_Hei])
445 458 # SPC_ch1[:] = 0 #numpy.NaN
446 459 # SPC_ch2[:] = 0 #numpy.NaN
447 460 # print ('stop 1')
448 461 for ht in range(self.Num_Hei):
449 462 # print (ht)
450 463 # print ('stop 2')
451 464 # Spectra at each range
452 465 spc = numpy.asarray(self.spc)[ch,:,ht]
453 466 snr = ( spc.mean() - wnoise ) / wnoise
454 467 snrdB = 10.*numpy.log10(snr)
455 468
456 469 #print ('stop 3')
457 470 if snrdB < SNRlimit :
458 471 # snr = numpy.NaN
459 472 # SPC_ch1[:,ht] = 0#numpy.NaN
460 473 # SPC_ch1[:,ht] = 0#numpy.NaN
461 474 # SPCparam = (SPC_ch1,SPC_ch2)
462 475 # print ('SNR less than SNRth')
463 476 continue
464 477 # wnoise = hildebrand_sekhon(spc,num_intg)
465 478 # print ('stop 2.01')
466 479 #############################################
467 480 # normalizing spc and noise
468 481 # This part differs from gg1
469 482 # spc_norm_max = max(spc) #commented by D. ScipiΓ³n 19.03.2021
470 483 #spc = spc / spc_norm_max
471 484 # pnoise = pnoise #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
472 485 #############################################
473 486
474 487 # print ('stop 2.1')
475 488 fatspectra=1.0
476 489 # noise per channel.... we might want to use the noise at each range
477 490 # wnoise = noise_ #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
478 491 #wnoise,stdv,i_max,index =enoise(spc,num_intg) #noise estimate using Hildebrand Sekhon, only wnoise is used
479 492 #if wnoise>1.1*pnoise: # to be tested later
480 493 # wnoise=pnoise
481 494 # noisebl = wnoise*0.9
482 495 # noisebh = wnoise*1.1
483 496 spc = spc - wnoise # signal
484 497
485 498 # print ('stop 2.2')
486 499 minx = numpy.argmin(spc)
487 500 #spcs=spc.copy()
488 501 spcs = numpy.roll(spc,-minx)
489 502 cum = numpy.cumsum(spcs)
490 503 # tot_noise = wnoise * self.Num_Bin #64;
491 504
492 505 # print ('stop 2.3')
493 506 # snr = sum(spcs) / tot_noise
494 507 # snrdB = 10.*numpy.log10(snr)
495 508 #print ('stop 3')
496 509 # if snrdB < SNRlimit :
497 510 # snr = numpy.NaN
498 511 # SPC_ch1[:,ht] = 0#numpy.NaN
499 512 # SPC_ch1[:,ht] = 0#numpy.NaN
500 513 # SPCparam = (SPC_ch1,SPC_ch2)
501 514 # print ('SNR less than SNRth')
502 515 # continue
503 516
504 517
505 518 #if snrdB<-18 or numpy.isnan(snrdB) or num_intg<4:
506 519 # return [None,]*4,[None,]*4,None,snrdB,None,None,[None,]*5,[None,]*9,None
507 520 # print ('stop 4')
508 521 cummax = max(cum)
509 522 epsi = 0.08 * fatspectra # cumsum to narrow down the energy region
510 523 cumlo = cummax * epsi
511 524 cumhi = cummax * (1-epsi)
512 525 powerindex = numpy.array(numpy.where(numpy.logical_and(cum>cumlo, cum<cumhi))[0])
513 526
514 527 # print ('stop 5')
515 528 if len(powerindex) < 1:# case for powerindex 0
516 529 # print ('powerindex < 1')
517 530 continue
518 531 powerlo = powerindex[0]
519 532 powerhi = powerindex[-1]
520 533 powerwidth = powerhi-powerlo
521 534 if powerwidth <= 1:
522 535 # print('powerwidth <= 1')
523 536 continue
524 537
525 538 # print ('stop 6')
526 539 firstpeak = powerlo + powerwidth/10.# first gaussian energy location
527 540 secondpeak = powerhi - powerwidth/10. #second gaussian energy location
528 541 midpeak = (firstpeak + secondpeak)/2.
529 542 firstamp = spcs[int(firstpeak)]
530 543 secondamp = spcs[int(secondpeak)]
531 544 midamp = spcs[int(midpeak)]
532 545
533 546 y_data = spc + wnoise
534 547
535 548 ''' single Gaussian '''
536 549 shift0 = numpy.mod(midpeak+minx, self.Num_Bin )
537 550 width0 = powerwidth/4.#Initialization entire power of spectrum divided by 4
538 551 power0 = 2.
539 552 amplitude0 = midamp
540 553 state0 = [shift0,width0,amplitude0,power0,wnoise]
541 554 bnds = ((0,self.Num_Bin-1),(1,powerwidth),(0,None),(0.5,3.),(noisebl,noisebh))
542 555 lsq1 = fmin_l_bfgs_b(self.misfit1, state0, args=(y_data,x,num_intg), bounds=bnds, approx_grad=True)
543 556 # print ('stop 7.1')
544 557 # print (bnds)
545 558
546 559 chiSq1=lsq1[1]
547 560
548 561 # print ('stop 8')
549 562 if fatspectra<1.0 and powerwidth<4:
550 563 choice=0
551 564 Amplitude0=lsq1[0][2]
552 565 shift0=lsq1[0][0]
553 566 width0=lsq1[0][1]
554 567 p0=lsq1[0][3]
555 568 Amplitude1=0.
556 569 shift1=0.
557 570 width1=0.
558 571 p1=0.
559 572 noise=lsq1[0][4]
560 573 #return (numpy.array([shift0,width0,Amplitude0,p0]),
561 574 # numpy.array([shift1,width1,Amplitude1,p1]),noise,snrdB,chiSq1,6.,sigmas1,[None,]*9,choice)
562 575 # print ('stop 9')
563 576 ''' two Gaussians '''
564 577 #shift0=numpy.mod(firstpeak+minx,64); shift1=numpy.mod(secondpeak+minx,64)
565 578 shift0 = numpy.mod(firstpeak+minx, self.Num_Bin )
566 579 shift1 = numpy.mod(secondpeak+minx, self.Num_Bin )
567 580 width0 = powerwidth/6.
568 581 width1 = width0
569 582 power0 = 2.
570 583 power1 = power0
571 584 amplitude0 = firstamp
572 585 amplitude1 = secondamp
573 586 state0 = [shift0,width0,amplitude0,power0,shift1,width1,amplitude1,power1,wnoise]
574 587 #bnds=((0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
575 588 bnds=((0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
576 589 #bnds=(( 0,(self.Num_Bin-1) ),(1,powerwidth/2.),(0,None),(0.5,3.),( 0,(self.Num_Bin-1)),(1,powerwidth/2.),(0,None),(0.5,3.),(0.1,0.5))
577 590
578 591 # print ('stop 10')
579 592 lsq2 = fmin_l_bfgs_b( self.misfit2 , state0 , args=(y_data,x,num_intg) , bounds=bnds , approx_grad=True )
580 593
581 594 # print ('stop 11')
582 595 chiSq2 = lsq2[1]
583 596
584 597 # print ('stop 12')
585 598
586 599 oneG = (chiSq1<5 and chiSq1/chiSq2<2.0) and (abs(lsq2[0][0]-lsq2[0][4])<(lsq2[0][1]+lsq2[0][5])/3. or abs(lsq2[0][0]-lsq2[0][4])<10)
587 600
588 601 # print ('stop 13')
589 602 if snrdB>-12: # when SNR is strong pick the peak with least shift (LOS velocity) error
590 603 if oneG:
591 604 choice = 0
592 605 else:
593 606 w1 = lsq2[0][1]; w2 = lsq2[0][5]
594 607 a1 = lsq2[0][2]; a2 = lsq2[0][6]
595 608 p1 = lsq2[0][3]; p2 = lsq2[0][7]
596 609 s1 = (2**(1+1./p1))*scipy.special.gamma(1./p1)/p1
597 610 s2 = (2**(1+1./p2))*scipy.special.gamma(1./p2)/p2
598 611 gp1 = a1*w1*s1; gp2 = a2*w2*s2 # power content of each ggaussian with proper p scaling
599 612
600 613 if gp1>gp2:
601 614 if a1>0.7*a2:
602 615 choice = 1
603 616 else:
604 617 choice = 2
605 618 elif gp2>gp1:
606 619 if a2>0.7*a1:
607 620 choice = 2
608 621 else:
609 622 choice = 1
610 623 else:
611 624 choice = numpy.argmax([a1,a2])+1
612 625 #else:
613 626 #choice=argmin([std2a,std2b])+1
614 627
615 628 else: # with low SNR go to the most energetic peak
616 629 choice = numpy.argmax([lsq1[0][2]*lsq1[0][1],lsq2[0][2]*lsq2[0][1],lsq2[0][6]*lsq2[0][5]])
617 630
618 631 # print ('stop 14')
619 632 shift0 = lsq2[0][0]
620 633 vel0 = Vrange[0] + shift0 * deltav
621 634 shift1 = lsq2[0][4]
622 635 # vel1=Vrange[0] + shift1 * deltav
623 636
624 637 # max_vel = 1.0
625 638 # Va = max(Vrange)
626 639 # deltav = Vrange[1]-Vrange[0]
627 640 # print ('stop 15')
628 641 #first peak will be 0, second peak will be 1
629 642 # if vel0 > -1.0 and vel0 < max_vel : #first peak is in the correct range # Commented by D.ScipiΓ³n 19.03.2021
630 643 if vel0 > -Va and vel0 < Va : #first peak is in the correct range
631 644 shift0 = lsq2[0][0]
632 645 width0 = lsq2[0][1]
633 646 Amplitude0 = lsq2[0][2]
634 647 p0 = lsq2[0][3]
635 648
636 649 shift1 = lsq2[0][4]
637 650 width1 = lsq2[0][5]
638 651 Amplitude1 = lsq2[0][6]
639 652 p1 = lsq2[0][7]
640 653 noise = lsq2[0][8]
641 654 else:
642 655 shift1 = lsq2[0][0]
643 656 width1 = lsq2[0][1]
644 657 Amplitude1 = lsq2[0][2]
645 658 p1 = lsq2[0][3]
646 659
647 660 shift0 = lsq2[0][4]
648 661 width0 = lsq2[0][5]
649 662 Amplitude0 = lsq2[0][6]
650 663 p0 = lsq2[0][7]
651 664 noise = lsq2[0][8]
652 665
653 666 if Amplitude0<0.05: # in case the peak is noise
654 667 shift0,width0,Amplitude0,p0 = 4*[numpy.NaN]
655 668 if Amplitude1<0.05:
656 669 shift1,width1,Amplitude1,p1 = 4*[numpy.NaN]
657 670
658 671 # print ('stop 16 ')
659 672 # SPC_ch1[:,ht] = noise + Amplitude0*numpy.exp(-0.5*(abs(x-shift0)/width0)**p0)
660 673 # SPC_ch2[:,ht] = noise + Amplitude1*numpy.exp(-0.5*(abs(x-shift1)/width1)**p1)
661 674 # SPCparam = (SPC_ch1,SPC_ch2)
662 675
663 676 DGauFitParam[0,ht,0] = noise
664 677 DGauFitParam[0,ht,1] = noise
665 678 DGauFitParam[1,ht,0] = Amplitude0
666 679 DGauFitParam[1,ht,1] = Amplitude1
667 680 DGauFitParam[2,ht,0] = Vrange[0] + shift0 * deltav
668 681 DGauFitParam[2,ht,1] = Vrange[0] + shift1 * deltav
669 682 DGauFitParam[3,ht,0] = width0 * deltav
670 683 DGauFitParam[3,ht,1] = width1 * deltav
671 684 DGauFitParam[4,ht,0] = p0
672 685 DGauFitParam[4,ht,1] = p1
673 686
674 687 return DGauFitParam
675 688
676 689 def y_model1(self,x,state):
677 690 shift0, width0, amplitude0, power0, noise = state
678 691 model0 = amplitude0*numpy.exp(-0.5*abs((x - shift0)/width0)**power0)
679 692 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
680 693 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
681 694 return model0 + model0u + model0d + noise
682 695
683 696 def y_model2(self,x,state): #Equation for two generalized Gaussians with Nyquist
684 697 shift0, width0, amplitude0, power0, shift1, width1, amplitude1, power1, noise = state
685 698 model0 = amplitude0*numpy.exp(-0.5*abs((x-shift0)/width0)**power0)
686 699 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
687 700 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
688 701
689 702 model1 = amplitude1*numpy.exp(-0.5*abs((x - shift1)/width1)**power1)
690 703 model1u = amplitude1*numpy.exp(-0.5*abs((x - shift1 - self.Num_Bin)/width1)**power1)
691 704 model1d = amplitude1*numpy.exp(-0.5*abs((x - shift1 + self.Num_Bin)/width1)**power1)
692 705 return model0 + model0u + model0d + model1 + model1u + model1d + noise
693 706
694 707 def misfit1(self,state,y_data,x,num_intg): # This function compares how close real data is with the model data, the close it is, the better it is.
695 708
696 709 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model1(x,state)))**2)#/(64-5.) # /(64-5.) can be commented
697 710
698 711 def misfit2(self,state,y_data,x,num_intg):
699 712 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model2(x,state)))**2)#/(64-9.)
700 713
701 714 class Oblique_Gauss_Fit(Operation):
702 715 '''
703 716 Written by R. Flores
704 717 '''
705 718 def __init__(self):
706 719 Operation.__init__(self)
707 720
708 721 def Gauss_fit(self,spc,x,nGauss):
709 722
710 723
711 724 def gaussian(x, a, b, c, d):
712 725 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
713 726 return val
714 727
715 728 if nGauss == 'first':
716 729 spc_1_aux = numpy.copy(spc[:numpy.argmax(spc)+1])
717 730 spc_2_aux = numpy.flip(spc_1_aux)
718 731 spc_3_aux = numpy.concatenate((spc_1_aux,spc_2_aux[1:]))
719 732
720 733 len_dif = len(x)-len(spc_3_aux)
721 734
722 735 spc_zeros = numpy.ones(len_dif)*spc_1_aux[0]
723 736
724 737 spc_new = numpy.concatenate((spc_3_aux,spc_zeros))
725 738
726 739 y = spc_new
727 740
728 741 elif nGauss == 'second':
729 742 y = spc
730 743
731 744
732 745 # estimate starting values from the data
733 746 a = y.max()
734 747 b = x[numpy.argmax(y)]
735 748 if nGauss == 'first':
736 749 c = 1.#b#b#numpy.std(spc)
737 750 elif nGauss == 'second':
738 751 c = b
739 752 else:
740 753 print("ERROR")
741 754
742 755 d = numpy.mean(y[-100:])
743 756
744 757 # define a least squares function to optimize
745 758 def minfunc(params):
746 759 return sum((y-gaussian(x,params[0],params[1],params[2],params[3]))**2)
747 760
748 761 # fit
749 762 popt = fmin(minfunc,[a,b,c,d],disp=False)
750 763 #popt,fopt,niter,funcalls = fmin(minfunc,[a,b,c,d])
751 764
752 765
753 766 return gaussian(x, popt[0], popt[1], popt[2], popt[3]), popt[0], popt[1], popt[2], popt[3]
754 767
755 768 def Gauss_fit_2(self,spc,x,nGauss):
756 769
757 770
758 771 def gaussian(x, a, b, c, d):
759 772 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
760 773 return val
761 774
762 775 if nGauss == 'first':
763 776 spc_1_aux = numpy.copy(spc[:numpy.argmax(spc)+1])
764 777 spc_2_aux = numpy.flip(spc_1_aux)
765 778 spc_3_aux = numpy.concatenate((spc_1_aux,spc_2_aux[1:]))
766 779
767 780 len_dif = len(x)-len(spc_3_aux)
768 781
769 782 spc_zeros = numpy.ones(len_dif)*spc_1_aux[0]
770 783
771 784 spc_new = numpy.concatenate((spc_3_aux,spc_zeros))
772 785
773 786 y = spc_new
774 787
775 788 elif nGauss == 'second':
776 789 y = spc
777 790
778 791
779 792 # estimate starting values from the data
780 793 a = y.max()
781 794 b = x[numpy.argmax(y)]
782 795 if nGauss == 'first':
783 796 c = 1.#b#b#numpy.std(spc)
784 797 elif nGauss == 'second':
785 798 c = b
786 799 else:
787 800 print("ERROR")
788 801
789 802 d = numpy.mean(y[-100:])
790 803 popt,pcov = curve_fit(gaussian,x,y,p0=[a,b,c,d])
791 804 return gaussian(x, popt[0], popt[1], popt[2], popt[3]),popt[0], popt[1], popt[2], popt[3]
792 805
793 806 def Double_Gauss_fit(self,spc,x,A1,B1,C1,A2,B2,C2,D):
794 807
795 808 def double_gaussian(x, a1, b1, c1, a2, b2, c2, d):
796 809 val = a1 * numpy.exp(-(x - b1)**2 / (2*c1**2)) + a2 * numpy.exp(-(x - b2)**2 / (2*c2**2)) + d
797 810 return val
798 811
799 812
800 813 y = spc
801 814
802 815 # estimate starting values from the data
803 816 a1 = A1
804 817 b1 = B1
805 818 c1 = C1#numpy.std(spc)
806 819
807 820 a2 = A2#y.max()
808 821 b2 = B2#x[numpy.argmax(y)]
809 822 c2 = C2#numpy.std(spc)
810 823 d = D
811 824
812 825 # define a least squares function to optimize
813 826 def minfunc(params):
814 827 return sum((y-double_gaussian(x,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))**2)
815 828
816 829 # fit
817 830 popt = fmin(minfunc,[a1,b1,c1,a2,b2,c2,d],disp=False)
818 831
819 832 return double_gaussian(x, popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]), popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
820 833
821 834 def Double_Gauss_fit_2(self,spc,x,A1,B1,C1,A2,B2,C2,D):
822 835
823 836 def double_gaussian(x, a1, b1, c1, a2, b2, c2, d):
824 837 val = a1 * numpy.exp(-(x - b1)**2 / (2*c1**2)) + a2 * numpy.exp(-(x - b2)**2 / (2*c2**2)) + d
825 838 return val
826 839
827 840
828 841 y = spc
829 842
830 843 # estimate starting values from the data
831 844 a1 = A1
832 845 b1 = B1
833 846 c1 = C1#numpy.std(spc)
834 847
835 848 a2 = A2#y.max()
836 849 b2 = B2#x[numpy.argmax(y)]
837 850 c2 = C2#numpy.std(spc)
838 851 d = D
839 852
840 853 # fit
841 854 popt,pcov = curve_fit(double_gaussian,x,y,p0=[a1,b1,c1,a2,b2,c2,d])
842 855 error = numpy.sqrt(numpy.diag(pcov))
843 856
844 857 return popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6], error[0], error[1], error[2], error[3], error[4], error[5], error[6]
845 858
846 859 def windowing_double(self,spc,x,A1,B1,C1,A2,B2,C2,D):
847 860 from scipy.optimize import curve_fit,fmin
848 861
849 862 def R_gaussian(x, a, b, c):
850 863 N = int(numpy.shape(x)[0])
851 864 val = a * numpy.exp(-((x)*c*2*2*numpy.pi)**2 / (2))* numpy.exp(1.j*b*x*4*numpy.pi)
852 865 return val
853 866
854 867 def T(x,N):
855 868 T = 1-abs(x)/N
856 869 return T
857 870
858 871 def R_T_spc_fun(x, a1, b1, c1, a2, b2, c2, d):
859 872
860 873 N = int(numpy.shape(x)[0])
861 874
862 875 x_max = x[-1]
863 876
864 877 x_pos = x[1600:]
865 878 x_neg = x[:1600]
866 879
867 880 R_T_neg_1 = R_gaussian(x, a1, b1, c1)[:1600]*T(x_neg,-x[0])
868 881 R_T_pos_1 = R_gaussian(x, a1, b1, c1)[1600:]*T(x_pos,x[-1])
869 882 R_T_sum_1 = R_T_pos_1 + R_T_neg_1
870 883 R_T_spc_1 = numpy.fft.fft(R_T_sum_1).real
871 884 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
872 885 max_val_1 = numpy.max(R_T_spc_1)
873 886 R_T_spc_1 = R_T_spc_1*a1/max_val_1
874 887
875 888 R_T_neg_2 = R_gaussian(x, a2, b2, c2)[:1600]*T(x_neg,-x[0])
876 889 R_T_pos_2 = R_gaussian(x, a2, b2, c2)[1600:]*T(x_pos,x[-1])
877 890 R_T_sum_2 = R_T_pos_2 + R_T_neg_2
878 891 R_T_spc_2 = numpy.fft.fft(R_T_sum_2).real
879 892 R_T_spc_2 = numpy.fft.fftshift(R_T_spc_2)
880 893 max_val_2 = numpy.max(R_T_spc_2)
881 894 R_T_spc_2 = R_T_spc_2*a2/max_val_2
882 895
883 896 R_T_d = d*numpy.fft.fftshift(signal.unit_impulse(N))
884 897 R_T_d_neg = R_T_d[:1600]*T(x_neg,-x[0])
885 898 R_T_d_pos = R_T_d[1600:]*T(x_pos,x[-1])
886 899 R_T_d_sum = R_T_d_pos + R_T_d_neg
887 900 R_T_spc_3 = numpy.fft.fft(R_T_d_sum).real
888 901 R_T_spc_3 = numpy.fft.fftshift(R_T_spc_3)
889 902
890 903 R_T_final = R_T_spc_1 + R_T_spc_2 + R_T_spc_3
891 904
892 905 return R_T_final
893 906
894 907 y = spc#gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
895 908
896 909 from scipy.stats import norm
897 910 mean,std=norm.fit(spc)
898 911
899 912 # estimate starting values from the data
900 913 a1 = A1
901 914 b1 = B1
902 915 c1 = C1#numpy.std(spc)
903 916
904 917 a2 = A2#y.max()
905 918 b2 = B2#x[numpy.argmax(y)]
906 919 c2 = C2#numpy.std(spc)
907 920 d = D
908 921
909 922 ippSeconds = 250*20*1.e-6/3
910 923
911 924 x_t = ippSeconds * (numpy.arange(1600) -1600 / 2.)
912 925
913 926 x_t = numpy.linspace(x_t[0],x_t[-1],3200)
914 927
915 928 x_freq = numpy.fft.fftfreq(1600,d=ippSeconds)
916 929 x_freq = numpy.fft.fftshift(x_freq)
917 930
918 931 # define a least squares function to optimize
919 932 def minfunc(params):
920 933 return sum((y-R_T_spc_fun(x_t,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))**2/1)#y**2)
921 934
922 935 # fit
923 936 popt_full = fmin(minfunc,[a1,b1,c1,a2,b2,c2,d],full_output=True)
924 937 popt = popt_full[0]
925 938
926 939 return popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
927 940
928 941 def Double_Gauss_fit_weight(self,spc,x,A1,B1,C1,A2,B2,C2,D):
929 942 from scipy.optimize import curve_fit,fmin
930 943
931 944 def double_gaussian(x, a1, b1, c1, a2, b2, c2, d):
932 945 val = a1 * numpy.exp(-(x - b1)**2 / (2*c1**2)) + a2 * numpy.exp(-(x - b2)**2 / (2*c2**2)) + d
933 946 return val
934 947
935 948 y = spc
936 949
937 950 from scipy.stats import norm
938 951 mean,std=norm.fit(spc)
939 952
940 953 # estimate starting values from the data
941 954 a1 = A1
942 955 b1 = B1
943 956 c1 = C1#numpy.std(spc)
944 957
945 958 a2 = A2#y.max()
946 959 b2 = B2#x[numpy.argmax(y)]
947 960 c2 = C2#numpy.std(spc)
948 961 d = D
949 962
950 963 y_clean = signal.medfilt(y)
951 964 # define a least squares function to optimize
952 965 def minfunc(params):
953 966 return sum((y-double_gaussian(x,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))**2/(y_clean**2/1))
954 967
955 968 # fit
956 969 popt_full = fmin(minfunc,[a1,b1,c1,a2,b2,c2,d], disp =False, full_output=True)
957 970 #print("nIter", popt_full[2])
958 971 popt = popt_full[0]
959 972 #popt,pcov = curve_fit(double_gaussian,x,y,p0=[a1,b1,c1,a2,b2,c2,d])
960 973
961 974 #return double_gaussian(x, popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]), popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
962 975 return popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
963 976
964 977 def DH_mode(self,spectra,VelRange):
965 978
966 979 from scipy.optimize import curve_fit
967 980
968 981 def double_gauss(x, a1,b1,c1, a2,b2,c2, d):
969 982 val = a1 * numpy.exp(-(x - b1)**2 / (2*c1**2)) + a2 * numpy.exp(-(x - b2)**2 / (2*c2**2)) + d
970 983 return val
971 984
972 985 spec = (spectra.copy()).flatten()
973 986 amp=spec.max()
974 987 params=numpy.array([amp,-400,30,amp/4,-200,150,1.0e7])
975 988 #try:
976 989 popt,pcov=curve_fit(double_gauss, VelRange, spec, p0=params,bounds=([0,-460,0,0,-400,120,0],[numpy.inf,-340,50,numpy.inf,0,250,numpy.inf]))
977 990
978 991 error = numpy.sqrt(numpy.diag(pcov))
979 992 #doppler_2=popt[4]
980 993 #err_2 = numpy.sqrt(pcov[4][4])
981 994
982 995 #except:
983 996 #pass
984 997 #doppler_2=numpy.NAN
985 998 #err_2 = numpy.NAN
986 999
987 1000 #return doppler_2, err_2
988 1001
989 1002 return popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6], error[0], error[1], error[2], error[3], error[4], error[5], error[6]
990 1003
991 1004 def Tri_Marco(self,spc,freq,a1,b1,c1,a2,b2,c2,d):
992 1005
993 1006 from scipy.optimize import least_squares
994 1007
995 1008 freq_max = numpy.max(numpy.abs(freq))
996 1009 spc_max = numpy.max(spc)
997 1010
998 1011 def tri_gaussian(x, a1, b1, c1, a2, b2, c2, a3, b3, c3, d):
999 1012 z1 = (x-b1)/c1
1000 1013 z2 = (x-b2)/c2
1001 1014 z3 = (x-b3)/c3
1002 1015 val = a1 * numpy.exp(-z1**2/2) + a2 * numpy.exp(-z2**2/2) + a3 * numpy.exp(-z3**2/2) + d
1003 1016 return val
1004 1017
1005 1018 from scipy.signal import medfilt
1006 1019 Nincoh = 20
1007 1020 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1008 1021 c1 = abs(c1)
1009 1022 c2 = abs(c2)
1010 1023
1011 1024 # define a least squares function to optimize
1012 1025 def lsq_func(params):
1013 1026 return (spc-tri_gaussian(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6],params[7],params[8],params[9]))/spcm
1014 1027
1015 1028 # fit
1016 1029 bounds=([0,-numpy.inf,0,0,-numpy.inf,0,0,0,0,0],[numpy.inf,-100,numpy.inf,numpy.inf,0,numpy.inf,numpy.inf,600,numpy.inf,numpy.inf])
1017 1030
1018 1031 params_scale = [spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,spc_max]
1019 1032 #print(a1,b1,c1,a2,b2,c2,d)
1020 1033 popt = least_squares(lsq_func,[a1,b1,c1,a2,b2,c2,a2/4,-b1,c1,d],x_scale=params_scale,bounds=bounds)
1021 1034
1022 1035 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1023 1036 A2f = popt.x[3]; B2f = popt.x[4]; C2f = popt.x[5]
1024 1037 A3f = popt.x[6]; B3f = popt.x[7]; C3f = popt.x[8]
1025 1038 Df = popt.x[9]
1026 1039
1027 1040 return A1f, B1f, C1f, A2f, B2f, C2f, Df
1028 1041
1029 1042 def Tri_Marco(self,spc,freq,a1,b1,c1,a2,b2,c2,d):
1030 1043
1031 1044 from scipy.optimize import least_squares
1032 1045
1033 1046 freq_max = numpy.max(numpy.abs(freq))
1034 1047 spc_max = numpy.max(spc)
1035 1048
1036 1049 def duo_gaussian(x, a1, b1, c1, a2, b2, c2, d):
1037 1050 z1 = (x-b1)/c1
1038 1051 z2 = (x-b2)/c2
1039 1052 #z3 = (x-b3)/c3
1040 1053 val = a1 * numpy.exp(-z1**2/2) + a2 * numpy.exp(-z2**2/2) + d
1041 1054 return val
1042 1055
1043 1056 from scipy.signal import medfilt
1044 1057 Nincoh = 20
1045 1058 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1046 1059 c1 = abs(c1)
1047 1060 c2 = abs(c2)
1048 1061
1049 1062 # define a least squares function to optimize
1050 1063 def lsq_func(params):
1051 1064 return (spc-tri_gaussian(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))/spcm
1052 1065
1053 1066 # fit
1054 1067 bounds=([0,-numpy.inf,0,0,-numpy.inf,0,0],[numpy.inf,-100,numpy.inf,numpy.inf,0,numpy.inf,numpy.inf])
1055 1068
1056 1069 params_scale = [spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,spc_max]
1057 1070 popt = least_squares(lsq_func,[a1,b1,c1,a2,b2,c2,d],x_scale=params_scale,bounds=bounds)
1058 1071
1059 1072 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1060 1073 A2f = popt.x[3]; B2f = popt.x[4]; C2f = popt.x[5]
1061 1074 #A3f = popt.x[6]; B3f = popt.x[7]; C3f = popt.x[8]
1062 1075 Df = popt.x[9]
1063 1076
1064 1077 return A1f, B1f, C1f, A2f, B2f, C2f, Df
1065 1078
1066 1079 def double_gaussian_skew(self,x, a1, b1, c1, a2, b2, c2, k2, d):
1067 1080 z1 = (x-b1)/c1
1068 1081 z2 = (x-b2)/c2
1069 1082 h2 = 1-k2*z2
1070 1083 h2[h2<0] = 0
1071 1084 y2 = -1/k2*numpy.log(h2)
1072 1085 val = a1 * numpy.exp(-z1**2/2) + a2 * numpy.exp(-y2**2/2)/(1-k2*z2) + d
1073 1086 return val
1074 1087
1075 1088 def gaussian(self, x, a, b, c, d):
1076 1089 z = (x-b)/c
1077 1090 val = a * numpy.exp(-z**2/2) + d
1078 1091 return val
1079 1092
1080 1093 def double_gaussian(self, x, a1, b1, c1, a2, b2, c2, d):
1081 1094 z1 = (x-b1)/c1
1082 1095 z2 = (x-b2)/c2
1083 1096 val = a1 * numpy.exp(-z1**2/2) + a2 * numpy.exp(-z2**2/2) + d
1084 1097 return val
1085 1098
1086 1099 def double_gaussian_double_skew(self,x, a1, b1, c1, k1, a2, b2, c2, k2, d):
1087 1100
1088 1101 z1 = (x-b1)/c1
1089 1102 h1 = 1-k1*z1
1090 1103 h1[h1<0] = 0
1091 1104 y1 = -1/k1*numpy.log(h1)
1092 1105
1093 1106 z2 = (x-b2)/c2
1094 1107 h2 = 1-k2*z2
1095 1108 h2[h2<0] = 0
1096 1109 y2 = -1/k2*numpy.log(h2)
1097 1110
1098 1111 val = a1 * numpy.exp(-y1**2/2)/(1-k1*z1) + a2 * numpy.exp(-y2**2/2)/(1-k2*z2) + d
1099 1112 return val
1100 1113
1101 1114 def gaussian_skew(self,x, a2, b2, c2, k2, d):
1102 1115 z2 = (x-b2)/c2
1103 1116 h2 = 1-k2*z2
1104 1117 h2[h2<0] = 0
1105 1118 y2 = -1/k2*numpy.log(h2)
1106 1119 val = a2 * numpy.exp(-y2**2/2)/(1-k2*z2) + d
1107 1120 return val
1108 1121
1109 1122 def triple_gaussian_skew(self,x, a1, b1, c1, a2, b2, c2, k2, a3, b3, c3, k3, d):
1110 1123 z1 = (x-b1)/c1
1111 1124 z2 = (x-b2)/c2
1112 1125 z3 = (x-b3)/c3
1113 1126 h2 = 1-k2*z2
1114 1127 h2[h2<0] = 0
1115 1128 y2 = -1/k2*numpy.log(h2)
1116 1129 h3 = 1-k3*z3
1117 1130 h3[h3<0] = 0
1118 1131 y3 = -1/k3*numpy.log(h3)
1119 1132 val = a1 * numpy.exp(-z1**2/2) + a2 * numpy.exp(-y2**2/2)/(1-k2*z2) + a3 * numpy.exp(-y3**2/2)/(1-k3*z3) + d
1120 1133 return val
1121 1134
1122 1135 def Double_Gauss_Skew_fit_weight_bound_no_inputs(self,spc,freq):
1123 1136
1124 1137 from scipy.optimize import least_squares
1125 1138
1126 1139 freq_max = numpy.max(numpy.abs(freq))
1127 1140 spc_max = numpy.max(spc)
1128 1141
1129 1142 from scipy.signal import medfilt
1130 1143 Nincoh = 20
1131 1144 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1132 1145
1133 1146 # define a least squares function to optimize
1134 1147 def lsq_func(params):
1135 1148 return (spc-self.double_gaussian_skew(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6],params[7]))/spcm
1136 1149
1137 1150 # fit
1138 1151 bounds=([0,-numpy.inf,0,0,-400,0,0,0],[numpy.inf,-340,numpy.inf,numpy.inf,0,numpy.inf,numpy.inf,numpy.inf])
1139 1152 params_scale = [spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,1,spc_max]
1140 1153 x0_value = numpy.array([spc_max,-400,30,spc_max/4,-200,150,1,1.0e7])
1141 1154 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1142 1155 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1143 1156 A2f = popt.x[3]; B2f = popt.x[4]; C2f = popt.x[5]; K2f = popt.x[6]
1144 1157 Df = popt.x[7]
1145 1158
1146 1159 aux = self.gaussian_skew(freq, A2f, B2f, C2f, K2f, Df)
1147 1160 doppler = freq[numpy.argmax(aux)]
1148 1161
1149 1162 return A1f, B1f, C1f, A2f, B2f, C2f, K2f, Df, doppler
1150 1163
1151 1164 def Double_Gauss_Double_Skew_fit_weight_bound_no_inputs(self,spc,freq,Nincoh,hei):
1152 1165
1153 1166 from scipy.optimize import least_squares
1154 1167
1155 1168 freq_max = numpy.max(numpy.abs(freq))
1156 1169 spc_max = numpy.max(spc)
1157 1170
1158 1171 #from scipy.signal import medfilt
1159 1172 #Nincoh = 20
1160 1173 #Nincoh = 80
1161 1174 Nincoh = Nincoh
1162 1175 #spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1163 1176 spcm = spc/numpy.sqrt(Nincoh)
1164 1177
1165 1178 # define a least squares function to optimize
1166 1179 def lsq_func(params):
1167 1180 return (spc-self.double_gaussian_double_skew(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6],params[7],params[8]))/spcm
1168 1181
1169 1182 # fit
1170 1183 bounds=([0,-numpy.inf,0,-5,0,-400,0,0,0],[numpy.inf,-200,numpy.inf,5,numpy.inf,0,numpy.inf,numpy.inf,numpy.inf])
1171 1184
1172 1185 params_scale = [spc_max,freq_max,freq_max,1,spc_max,freq_max,freq_max,1,spc_max]
1173 1186
1174 1187 dop1_x0 = freq[numpy.argmax(spc)]
1175 1188 if dop1_x0 < 0:
1176 1189 dop2_x0 = dop1_x0 + 100
1177 1190 if dop1_x0 > 0:
1178 1191 dop2_x0 = dop1_x0 - 100
1179 1192
1180 1193 x0_value = numpy.array([spc_max,dop1_x0,30,-.1,spc_max/4, dop2_x0,150,1,1.0e7])
1181 1194 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1182 1195 J = popt.jac
1183 1196
1184 1197 try:
1185 1198 cov = numpy.linalg.inv(J.T.dot(J))
1186 1199 error = numpy.sqrt(numpy.diagonal(cov))
1187 1200 except:
1188 1201 error = numpy.ones((9))*numpy.NAN
1189 1202
1190 1203 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]; K1f = popt.x[3]
1191 1204 A2f = popt.x[4]; B2f = popt.x[5]; C2f = popt.x[6]; K2f = popt.x[7]
1192 1205 Df = popt.x[8]
1193 1206 aux1 = self.gaussian_skew(freq, A1f, B1f, C1f, K1f, Df)
1194 1207 doppler1 = freq[numpy.argmax(aux1)]
1195 1208
1196 1209 aux2 = self.gaussian_skew(freq, A2f, B2f, C2f, K2f, Df)
1197 1210 doppler2 = freq[numpy.argmax(aux2)]
1198 1211 #print("error",error)
1199 1212 #exit(1)
1200 1213
1201 1214
1202 1215 return A1f, B1f, C1f, K1f, A2f, B2f, C2f, K2f, Df, doppler1, doppler2, error
1203 1216
1204 1217 def Double_Gauss_fit_weight_bound_no_inputs(self,spc,freq,Nincoh):
1205 1218
1206 1219 from scipy.optimize import least_squares
1207 1220
1208 1221 freq_max = numpy.max(numpy.abs(freq))
1209 1222 spc_max = numpy.max(spc)
1210 1223
1211 1224 from scipy.signal import medfilt
1212 1225 Nincoh = 20
1213 1226 Nincoh = 80
1214 1227 Nincoh = Nincoh
1215 1228 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1216 1229
1217 1230 # define a least squares function to optimize
1218 1231 def lsq_func(params):
1219 1232 return (spc-self.double_gaussian(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))/spcm
1220 1233
1221 1234 # fit
1222 1235 # bounds=([0,-460,0,0,-400,120,0],[numpy.inf,-340,50,numpy.inf,0,250,numpy.inf])
1223 1236 # bounds=([0,-numpy.inf,0,0,-numpy.inf,0,-numpy.inf,0],[numpy.inf,-200,numpy.inf,numpy.inf,0,numpy.inf,0,numpy.inf])
1224 1237 #print(a1,b1,c1,a2,b2,c2,k2,d)
1225 1238
1226 1239 dop1_x0 = freq[numpy.argmax(spcm)]
1227 1240
1228 1241 bounds=([0,-numpy.inf,0,0,dop1_x0-50,0,0],[numpy.inf,-300,numpy.inf,numpy.inf,0,numpy.inf,numpy.inf])
1229 1242 params_scale = [spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,spc_max]
1230 1243 x0_value = numpy.array([spc_max,-400.5,30,spc_max/4,dop1_x0,150,1.0e7])
1231 1244 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1232 1245 J = popt.jac
1233 1246
1234 1247 try:
1235 1248 cov = numpy.linalg.inv(J.T.dot(J))
1236 1249 error = numpy.sqrt(numpy.diagonal(cov))
1237 1250 except:
1238 1251 error = numpy.ones((7))*numpy.NAN
1239 1252
1240 1253 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1241 1254 A2f = popt.x[3]; B2f = popt.x[4]; C2f = popt.x[5]
1242 1255 Df = popt.x[6]
1243 1256 return A1f, B1f, C1f, A2f, B2f, C2f, Df, error
1244 1257
1245 1258 def Double_Gauss_Double_Skew_fit_weight_bound_with_inputs(self, spc, freq, a1, b1, c1, a2, b2, c2, k2, d):
1246 1259
1247 1260 from scipy.optimize import least_squares
1248 1261
1249 1262 freq_max = numpy.max(numpy.abs(freq))
1250 1263 spc_max = numpy.max(spc)
1251 1264
1252 1265 from scipy.signal import medfilt
1253 1266 Nincoh = dataOut.nIncohInt
1254 1267 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1255 1268
1256 1269 # define a least squares function to optimize
1257 1270 def lsq_func(params):
1258 1271 return (spc-self.double_gaussian_double_skew(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6],params[7],params[8]))/spcm
1259 1272
1260 1273
1261 1274 bounds=([0,-numpy.inf,0,-numpy.inf,0,-400,0,0,0],[numpy.inf,-340,numpy.inf,0,numpy.inf,0,numpy.inf,numpy.inf,numpy.inf])
1262 1275
1263 1276 params_scale = [spc_max,freq_max,freq_max,1,spc_max,freq_max,freq_max,1,spc_max]
1264 1277
1265 1278 x0_value = numpy.array([a1,b1,c1,-.1,a2,b2,c2,k2,d])
1266 1279
1267 1280 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1268 1281
1269 1282 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]; K1f = popt.x[3]
1270 1283 A2f = popt.x[4]; B2f = popt.x[5]; C2f = popt.x[6]; K2f = popt.x[7]
1271 1284 Df = popt.x[8]
1272 1285
1273 1286 aux = self.gaussian_skew(freq, A2f, B2f, C2f, K2f, Df)
1274 1287 doppler = x[numpy.argmax(aux)]
1275 1288
1276 1289 return A1f, B1f, C1f, K1f, A2f, B2f, C2f, K2f, Df, doppler
1277 1290
1278 1291 def Triple_Gauss_Skew_fit_weight_bound_no_inputs(self,spc,freq):
1279 1292
1280 1293 from scipy.optimize import least_squares
1281 1294
1282 1295 freq_max = numpy.max(numpy.abs(freq))
1283 1296 spc_max = numpy.max(spc)
1284 1297
1285 1298 from scipy.signal import medfilt
1286 1299 Nincoh = 20
1287 1300 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1288 1301
1289 1302 # define a least squares function to optimize
1290 1303 def lsq_func(params):
1291 1304 return (spc-self.triple_gaussian_skew(freq,params[0],params[1],params[2],params[3],params[4],params[5],params[6],params[7],params[8],params[9],params[10],params[11]))/spcm
1292 1305
1293 1306 # fit
1294 1307 bounds=([0,-numpy.inf,0,0,-400,0,0,0,0,0,0,0],[numpy.inf,-340,numpy.inf,numpy.inf,0,numpy.inf,numpy.inf,numpy.inf,numpy.inf,numpy.inf,numpy.inf,numpy.inf])
1295 1308
1296 1309 params_scale = [spc_max,freq_max,freq_max,spc_max,freq_max,freq_max,1,spc_max,freq_max,freq_max,1,spc_max]
1297 1310 x0_value = numpy.array([spc_max,-400,30,spc_max/4,-200,150,1,spc_max/4,400,150,1,1.0e7])
1298 1311 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1299 1312
1300 1313 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1301 1314 A2f = popt.x[3]; B2f = popt.x[4]; C2f = popt.x[5]; K2f = popt.x[6]
1302 1315 A3f = popt.x[7]; B3f = popt.x[8]; C3f = popt.x[9]; K3f = popt.x[10]
1303 1316 Df = popt.x[11]
1304 1317
1305 1318 aux = self.gaussian_skew(freq, A2f, B2f, C2f, K2f, Df)
1306 1319 doppler = freq[numpy.argmax(aux)]
1307 1320
1308 1321 return A1f, B1f, C1f, A2f, B2f, C2f, K2f, A3f, B3f, C3f, K3f, Df, doppler
1309 1322
1310 1323 def CEEJ_Skew_fit_weight_bound_no_inputs(self,spc,freq,Nincoh):
1311 1324
1312 1325 from scipy.optimize import least_squares
1313 1326
1314 1327 freq_max = numpy.max(numpy.abs(freq))
1315 1328 spc_max = numpy.max(spc)
1316 1329
1317 1330 from scipy.signal import medfilt
1318 1331 Nincoh = 20
1319 1332 Nincoh = 80
1320 1333 Nincoh = Nincoh
1321 1334 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1322 1335
1323 1336 # define a least squares function to optimize
1324 1337 def lsq_func(params):
1325 1338 return (spc-self.gaussian_skew(freq,params[0],params[1],params[2],params[3],params[4]))#/spcm
1326 1339
1327 1340
1328 1341 bounds=([0,0,0,-numpy.inf,0],[numpy.inf,numpy.inf,numpy.inf,0,numpy.inf])
1329 1342
1330 1343 params_scale = [spc_max,freq_max,freq_max,1,spc_max]
1331 1344
1332 1345 x0_value = numpy.array([spc_max,freq[numpy.argmax(spc)],30,-.1,numpy.mean(spc[:50])])
1333 1346
1334 1347 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1335 1348
1336 1349 J = popt.jac
1337 1350
1338 1351 try:
1339 1352 error = numpy.ones((9))*numpy.NAN
1340 1353 cov = numpy.linalg.inv(J.T.dot(J))
1341 1354 error[:4] = numpy.sqrt(numpy.diagonal(cov))[:4]
1342 1355 error[-1] = numpy.sqrt(numpy.diagonal(cov))[-1]
1343 1356 except:
1344 1357 error = numpy.ones((9))*numpy.NAN
1345 1358
1346 1359 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]; K1f = popt.x[3]
1347 1360 Df = popt.x[4]
1348 1361
1349 1362 aux1 = self.gaussian_skew(freq, A1f, B1f, C1f, K1f, Df)
1350 1363 doppler1 = freq[numpy.argmax(aux1)]
1351 1364 #print("CEEJ ERROR:",error)
1352 1365
1353 1366 return A1f, B1f, C1f, K1f, numpy.NAN, numpy.NAN, numpy.NAN, numpy.NAN, Df, doppler1, numpy.NAN, error
1354 1367
1355 1368 def CEEJ_fit_weight_bound_no_inputs(self,spc,freq,Nincoh):
1356 1369
1357 1370 from scipy.optimize import least_squares
1358 1371
1359 1372 freq_max = numpy.max(numpy.abs(freq))
1360 1373 spc_max = numpy.max(spc)
1361 1374
1362 1375 from scipy.signal import medfilt
1363 1376 Nincoh = 20
1364 1377 Nincoh = 80
1365 1378 Nincoh = Nincoh
1366 1379 spcm = medfilt(spc,11)/numpy.sqrt(Nincoh)
1367 1380
1368 1381 # define a least squares function to optimize
1369 1382 def lsq_func(params):
1370 1383 return (spc-self.gaussian(freq,params[0],params[1],params[2],params[3]))#/spcm
1371 1384
1372 1385
1373 1386 bounds=([0,0,0,0],[numpy.inf,numpy.inf,numpy.inf,numpy.inf])
1374 1387
1375 1388 params_scale = [spc_max,freq_max,freq_max,spc_max]
1376 1389
1377 1390 x0_value = numpy.array([spc_max,freq[numpy.argmax(spcm)],30,numpy.mean(spc[:50])])
1378 1391
1379 1392 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1380 1393
1381 1394 J = popt.jac
1382 1395
1383 1396 try:
1384 1397 error = numpy.ones((4))*numpy.NAN
1385 1398 cov = numpy.linalg.inv(J.T.dot(J))
1386 1399 error = numpy.sqrt(numpy.diagonal(cov))
1387 1400 except:
1388 1401 error = numpy.ones((4))*numpy.NAN
1389 1402
1390 1403 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1391 1404 Df = popt.x[3]
1392 1405
1393 1406 return A1f, B1f, C1f, Df, error
1394 1407
1395 1408 def Simple_fit_bound(self,spc,freq,Nincoh):
1396 1409
1397 1410 freq_max = numpy.max(numpy.abs(freq))
1398 1411 spc_max = numpy.max(spc)
1399 1412
1400 1413 Nincoh = Nincoh
1401 1414
1402 1415 def lsq_func(params):
1403 1416 return (spc-self.gaussian(freq,params[0],params[1],params[2],params[3]))
1404 1417
1405 1418 bounds=([0,-50,0,0],[numpy.inf,+50,numpy.inf,numpy.inf])
1406 1419
1407 1420 params_scale = [spc_max,freq_max,freq_max,spc_max]
1408 1421
1409 1422 x0_value = numpy.array([spc_max,-20.5,5,1.0e7])
1410 1423
1411 1424 popt = least_squares(lsq_func,x0=x0_value,x_scale=params_scale,bounds=bounds,verbose=0)
1412 1425
1413 1426 J = popt.jac
1414 1427
1415 1428 try:
1416 1429 cov = numpy.linalg.inv(J.T.dot(J))
1417 1430 error = numpy.sqrt(numpy.diagonal(cov))
1418 1431 except:
1419 1432 error = numpy.ones((4))*numpy.NAN
1420 1433
1421 1434 A1f = popt.x[0]; B1f = popt.x[1]; C1f = popt.x[2]
1422 1435 Df = popt.x[3]
1423 1436
1424 1437 return A1f, B1f, C1f, Df, error
1425 1438
1426 1439 def clean_outliers(self,param):
1427 1440
1428 1441 threshold = 700
1429 1442
1430 1443 param = numpy.where(param < -threshold, numpy.nan, param)
1431 1444 param = numpy.where(param > +threshold, numpy.nan, param)
1432 1445
1433 1446 return param
1434 1447
1435 1448 def windowing_single(self,spc,x,A,B,C,D,nFFTPoints):
1436 1449 from scipy.optimize import curve_fit,fmin
1437 1450
1438 1451 def R_gaussian(x, a, b, c):
1439 1452 N = int(numpy.shape(x)[0])
1440 1453 val = a * numpy.exp(-((x)*c*2*2*numpy.pi)**2 / (2))* numpy.exp(1.j*b*x*4*numpy.pi)
1441 1454 return val
1442 1455
1443 1456 def T(x,N):
1444 1457 T = 1-abs(x)/N
1445 1458 return T
1446 1459
1447 1460 def R_T_spc_fun(x, a, b, c, d, nFFTPoints):
1448 1461
1449 1462 N = int(numpy.shape(x)[0])
1450 1463
1451 1464 x_max = x[-1]
1452 1465
1453 1466 x_pos = x[int(nFFTPoints/2):]
1454 1467 x_neg = x[:int(nFFTPoints/2)]
1455 1468
1456 1469 R_T_neg_1 = R_gaussian(x, a, b, c)[:int(nFFTPoints/2)]*T(x_neg,-x[0])
1457 1470 R_T_pos_1 = R_gaussian(x, a, b, c)[int(nFFTPoints/2):]*T(x_pos,x[-1])
1458 1471 R_T_sum_1 = R_T_pos_1 + R_T_neg_1
1459 1472 R_T_spc_1 = numpy.fft.fft(R_T_sum_1).real
1460 1473 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
1461 1474 max_val_1 = numpy.max(R_T_spc_1)
1462 1475 R_T_spc_1 = R_T_spc_1*a/max_val_1
1463 1476
1464 1477 R_T_d = d*numpy.fft.fftshift(signal.unit_impulse(N))
1465 1478 R_T_d_neg = R_T_d[:int(nFFTPoints/2)]*T(x_neg,-x[0])
1466 1479 R_T_d_pos = R_T_d[int(nFFTPoints/2):]*T(x_pos,x[-1])
1467 1480 R_T_d_sum = R_T_d_pos + R_T_d_neg
1468 1481 R_T_spc_3 = numpy.fft.fft(R_T_d_sum).real
1469 1482 R_T_spc_3 = numpy.fft.fftshift(R_T_spc_3)
1470 1483
1471 1484 R_T_final = R_T_spc_1 + R_T_spc_3
1472 1485
1473 1486 return R_T_final
1474 1487
1475 1488 y = spc#gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
1476 1489
1477 1490 from scipy.stats import norm
1478 1491 mean,std=norm.fit(spc)
1479 1492
1480 1493 # estimate starting values from the data
1481 1494 a = A
1482 1495 b = B
1483 1496 c = C#numpy.std(spc)
1484 1497 d = D
1485 1498 '''
1486 1499 ippSeconds = 250*20*1.e-6/3
1487 1500
1488 1501 x_t = ippSeconds * (numpy.arange(1600) -1600 / 2.)
1489 1502
1490 1503 x_t = numpy.linspace(x_t[0],x_t[-1],3200)
1491 1504
1492 1505 x_freq = numpy.fft.fftfreq(1600,d=ippSeconds)
1493 1506 x_freq = numpy.fft.fftshift(x_freq)
1494 1507 '''
1495 1508 # define a least squares function to optimize
1496 1509 def minfunc(params):
1497 1510 return sum((y-R_T_spc_fun(x,params[0],params[1],params[2],params[3],params[4],params[5],params[6]))**2/1)#y**2)
1498 1511
1499 1512 # fit
1500 1513
1501 1514 popt_full = fmin(minfunc,[a,b,c,d],full_output=True)
1502 1515 #print("nIter", popt_full[2])
1503 1516 popt = popt_full[0]
1504 1517
1505 1518 #return R_T_spc_fun(x_t,popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]), popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
1506 1519 return popt[0], popt[1], popt[2], popt[3]
1507 1520
1508 1521 def run(self, dataOut, mode = 0, Hmin1 = None, Hmax1 = None, Hmin2 = None, Hmax2 = None, Dop = 'Shift'):
1509 1522
1510 1523 pwcode = 1
1511 1524
1512 1525 if dataOut.flagDecodeData:
1513 1526 pwcode = numpy.sum(dataOut.code[0]**2)
1514 1527 #normFactor = min(self.nFFTPoints,self.nProfiles)*self.nIncohInt*self.nCohInt*pwcode*self.windowOfFilter
1515 1528 normFactor = dataOut.nProfiles * dataOut.nIncohInt * dataOut.nCohInt * pwcode * dataOut.windowOfFilter
1516 1529 factor = normFactor
1517 1530 z = dataOut.data_spc / factor
1518 1531 z = numpy.where(numpy.isfinite(z), z, numpy.NAN)
1519 1532 dataOut.power = numpy.average(z, axis=1)
1520 1533 dataOut.powerdB = 10 * numpy.log10(dataOut.power)
1521 1534
1522 1535 x = dataOut.getVelRange(0)
1523 1536
1524 1537 dataOut.Oblique_params = numpy.ones((1,7,dataOut.nHeights))*numpy.NAN
1525 1538 dataOut.Oblique_param_errors = numpy.ones((1,7,dataOut.nHeights))*numpy.NAN
1526 1539 dataOut.dplr_2_u = numpy.ones((1,1,dataOut.nHeights))*numpy.NAN
1527 1540
1528 1541 if mode == 6:
1529 1542 dataOut.Oblique_params = numpy.ones((1,9,dataOut.nHeights))*numpy.NAN
1530 1543 elif mode == 7:
1531 1544 dataOut.Oblique_params = numpy.ones((1,13,dataOut.nHeights))*numpy.NAN
1532 1545 elif mode == 8:
1533 1546 dataOut.Oblique_params = numpy.ones((1,10,dataOut.nHeights))*numpy.NAN
1534 1547 elif mode == 9:
1535 1548 dataOut.Oblique_params = numpy.ones((1,11,dataOut.nHeights))*numpy.NAN
1536 1549 dataOut.Oblique_param_errors = numpy.ones((1,9,dataOut.nHeights))*numpy.NAN
1537 1550 elif mode == 11:
1538 1551 dataOut.Oblique_params = numpy.ones((1,7,dataOut.nHeights))*numpy.NAN
1539 1552 dataOut.Oblique_param_errors = numpy.ones((1,7,dataOut.nHeights))*numpy.NAN
1540 1553 elif mode == 10: #150 km
1541 1554 dataOut.Oblique_params = numpy.ones((1,4,dataOut.nHeights))*numpy.NAN
1542 1555 dataOut.Oblique_param_errors = numpy.ones((1,4,dataOut.nHeights))*numpy.NAN
1543 1556 dataOut.snr_log10 = numpy.ones((1,dataOut.nHeights))*numpy.NAN
1544 1557
1545 1558 dataOut.VelRange = x
1546 1559
1547 1560
1548 1561
1549 1562 #l1=range(22,36) #+62
1550 1563 #l1=range(32,36)
1551 1564 #l2=range(58,99) #+62
1552 1565
1553 1566 #if Hmin1 == None or Hmax1 == None or Hmin2 == None or Hmax2 == None:
1554 1567
1555 1568 minHei1 = 105.
1556 1569 maxHei1 = 122.5
1557 1570 maxHei1 = 130.5
1558 1571
1559 1572 if mode == 10: #150 km
1560 1573 minHei1 = 100
1561 1574 maxHei1 = 100
1562 1575
1563 1576 inda1 = numpy.where(dataOut.heightList >= minHei1)
1564 1577 indb1 = numpy.where(dataOut.heightList <= maxHei1)
1565 1578
1566 1579 minIndex1 = inda1[0][0]
1567 1580 maxIndex1 = indb1[0][-1]
1568 1581
1569 1582 minHei2 = 150.
1570 1583 maxHei2 = 201.25
1571 1584 maxHei2 = 225.3
1572 1585
1573 1586 if mode == 10: #150 km
1574 1587 minHei2 = 110
1575 1588 maxHei2 = 165
1576 1589
1577 1590 inda2 = numpy.where(dataOut.heightList >= minHei2)
1578 1591 indb2 = numpy.where(dataOut.heightList <= maxHei2)
1579 1592
1580 1593 minIndex2 = inda2[0][0]
1581 1594 maxIndex2 = indb2[0][-1]
1582 1595
1583 1596 l1=range(minIndex1,maxIndex1)
1584 1597 l2=range(minIndex2,maxIndex2)
1585 1598
1586 1599 if mode == 4:
1587 1600 '''
1588 1601 for ind in range(dataOut.nHeights):
1589 1602 if(dataOut.heightList[ind]>=168 and dataOut.heightList[ind]<188):
1590 1603 try:
1591 1604 dataOut.Oblique_params[0,0,ind],dataOut.Oblique_params[0,1,ind],dataOut.Oblique_params[0,2,ind],dataOut.Oblique_params[0,3,ind],dataOut.Oblique_params[0,4,ind],dataOut.Oblique_params[0,5,ind],dataOut.Oblique_params[0,6,ind],dataOut.Oblique_param_errors[0,0,ind],dataOut.Oblique_param_errors[0,1,ind],dataOut.Oblique_param_errors[0,2,ind],dataOut.Oblique_param_errors[0,3,ind],dataOut.Oblique_param_errors[0,4,ind],dataOut.Oblique_param_errors[0,5,ind],dataOut.Oblique_param_errors[0,6,ind] = self.DH_mode(dataOut.data_spc[0,:,ind],dataOut.VelRange)
1592 1605 except:
1593 1606 pass
1594 1607 '''
1595 1608 for ind in itertools.chain(l1, l2):
1596 1609
1597 1610 try:
1598 1611 dataOut.Oblique_params[0,0,ind],dataOut.Oblique_params[0,1,ind],dataOut.Oblique_params[0,2,ind],dataOut.Oblique_params[0,3,ind],dataOut.Oblique_params[0,4,ind],dataOut.Oblique_params[0,5,ind],dataOut.Oblique_params[0,6,ind],dataOut.Oblique_param_errors[0,0,ind],dataOut.Oblique_param_errors[0,1,ind],dataOut.Oblique_param_errors[0,2,ind],dataOut.Oblique_param_errors[0,3,ind],dataOut.Oblique_param_errors[0,4,ind],dataOut.Oblique_param_errors[0,5,ind],dataOut.Oblique_param_errors[0,6,ind] = self.DH_mode(dataOut.data_spc[0,:,ind],dataOut.VelRange)
1599 1612 dataOut.dplr_2_u[0,0,ind] = dataOut.Oblique_params[0,4,ind]/numpy.sin(numpy.arccos(102/dataOut.heightList[ind]))
1600 1613 except:
1601 1614 pass
1602 1615
1603 1616 else:
1604 1617 for hei in itertools.chain(l1, l2):
1605 1618 if numpy.isnan(dataOut.snl[0,hei]) or dataOut.snl[0,hei]<.0:
1606 1619
1607 1620 continue #Avoids the analysis when there is only noise
1608 1621
1609 1622 try:
1610 1623 spc = dataOut.data_spc[0,:,hei]
1611 1624
1612 1625 if mode == 6: #Skew Weighted Bounded
1613 1626 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_params[0,7,hei],dataOut.Oblique_params[0,8,hei] = self.Double_Gauss_Skew_fit_weight_bound_no_inputs(spc,x)
1614 1627 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,8,hei]/numpy.sin(numpy.arccos(100./dataOut.heightList[hei]))
1615 1628
1616 1629 elif mode == 7: #Triple Skew Weighted Bounded
1617 1630 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_params[0,7,hei],dataOut.Oblique_params[0,8,hei],dataOut.Oblique_params[0,9,hei],dataOut.Oblique_params[0,10,hei],dataOut.Oblique_params[0,11,hei],dataOut.Oblique_params[0,12,hei] = self.Triple_Gauss_Skew_fit_weight_bound_no_inputs(spc,x)
1618 1631 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,12,hei]/numpy.sin(numpy.arccos(100./dataOut.heightList[hei]))
1619 1632
1620 1633 elif mode == 8: #Double Skewed Weighted Bounded with inputs
1621 1634 a1, b1, c1, a2, b2, c2, k2, d, dopp = self.Double_Gauss_Skew_fit_weight_bound_no_inputs(spc,x)
1622 1635 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_params[0,7,hei],dataOut.Oblique_params[0,8,hei],dataOut.Oblique_params[0,9,hei] = self.Double_Gauss_Skew_fit_weight_bound_no_inputs(spc,x, a1, b1, c1, a2, b2, c2, k2, d)
1623 1636 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,9,hei]/numpy.sin(numpy.arccos(100./dataOut.heightList[hei]))
1624 1637
1625 1638 elif mode == 9: #Double Skewed Weighted Bounded no inputs
1626 1639 #if numpy.max(spc) <= 0:
1627 1640 from scipy.signal import medfilt
1628 1641 spcm = medfilt(spc,11)
1629 1642 if x[numpy.argmax(spcm)] <= 0:
1630 1643 #print("EEJ", dataOut.heightList[hei], hei)
1631 1644 #if hei != 70:
1632 1645 #continue
1633 1646 #else:
1634 1647 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_params[0,7,hei],dataOut.Oblique_params[0,8,hei],dataOut.Oblique_params[0,9,hei],dataOut.Oblique_params[0,10,hei],dataOut.Oblique_param_errors[0,:,hei] = self.Double_Gauss_Double_Skew_fit_weight_bound_no_inputs(spcm,x,dataOut.nIncohInt,dataOut.heightList[hei])
1635 1648 #if dataOut.Oblique_params[0,-2,hei] < -500 or dataOut.Oblique_params[0,-2,hei] > 500 or dataOut.Oblique_params[0,-1,hei] < -500 or dataOut.Oblique_params[0,-1,hei] > 500:
1636 1649 # dataOut.Oblique_params[0,:,hei] *= numpy.NAN
1637 1650 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,10,hei]/numpy.sin(numpy.arccos(100./dataOut.heightList[hei]))
1638 1651
1639 1652 else:
1640 1653 #print("CEEJ")
1641 1654 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_params[0,7,hei],dataOut.Oblique_params[0,8,hei],dataOut.Oblique_params[0,9,hei],dataOut.Oblique_params[0,10,hei],dataOut.Oblique_param_errors[0,:,hei] = self.CEEJ_Skew_fit_weight_bound_no_inputs(spcm,x,dataOut.nIncohInt)
1642 1655 #if dataOut.Oblique_params[0,-2,hei] < -500 or dataOut.Oblique_params[0,-2,hei] > 500 or dataOut.Oblique_params[0,-1,hei] < -500 or dataOut.Oblique_params[0,-1,hei] > 500:
1643 1656 # dataOut.Oblique_params[0,:,hei] *= numpy.NAN
1644 1657 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,10,hei]/numpy.sin(numpy.arccos(100./dataOut.heightList[hei]))
1645 1658 elif mode == 11: #Double Weighted Bounded no inputs
1646 1659 #if numpy.max(spc) <= 0:
1647 1660 from scipy.signal import medfilt
1648 1661 spcm = medfilt(spc,11)
1649 1662
1650 1663 if x[numpy.argmax(spcm)] <= 0:
1651 1664 #print("EEJ")
1652 1665 #print("EEJ",dataOut.heightList[hei])
1653 1666 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_param_errors[0,:,hei] = self.Double_Gauss_fit_weight_bound_no_inputs(spc,x,dataOut.nIncohInt)
1654 1667 #if dataOut.Oblique_params[0,-2,hei] < -500 or dataOut.Oblique_params[0,-2,hei] > 500 or dataOut.Oblique_params[0,-1,hei] < -500 or dataOut.Oblique_params[0,-1,hei] > 500:
1655 1668 # dataOut.Oblique_params[0,:,hei] *= numpy.NAN
1656 1669 else:
1657 1670 #print("CEEJ",dataOut.heightList[hei])
1658 1671 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_param_errors[0,:,hei] = self.CEEJ_fit_weight_bound_no_inputs(spc,x,dataOut.nIncohInt)
1659 1672
1660 1673 elif mode == 10: #150km
1661 1674 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_param_errors[0,:,hei] = self.Simple_fit_bound(spc,x,dataOut.nIncohInt)
1662 1675 snr = (dataOut.power[0,hei]*factor - dataOut.Oblique_params[0,3,hei])/dataOut.Oblique_params[0,3,hei]
1663 1676 dataOut.snr_log10[0,hei] = numpy.log10(snr)
1664 1677
1665 1678 else:
1666 1679 spc_fit, A1, B1, C1, D1 = self.Gauss_fit_2(spc,x,'first')
1667 1680
1668 1681 spc_diff = spc - spc_fit
1669 1682 spc_diff[spc_diff < 0] = 0
1670 1683
1671 1684 spc_fit_diff, A2, B2, C2, D2 = self.Gauss_fit_2(spc_diff,x,'second')
1672 1685
1673 1686 D = (D1+D2)
1674 1687
1675 1688 if mode == 0: #Double Fit
1676 1689 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei],dataOut.Oblique_param_errors[0,0,hei],dataOut.Oblique_param_errors[0,1,hei],dataOut.Oblique_param_errors[0,2,hei],dataOut.Oblique_param_errors[0,3,hei],dataOut.Oblique_param_errors[0,4,hei],dataOut.Oblique_param_errors[0,5,hei],dataOut.Oblique_param_errors[0,6,hei] = self.Double_Gauss_fit_2(spc,x,A1,B1,C1,A2,B2,C2,D)
1677 1690 #spc_double_fit,dataOut.Oblique_params = self.Double_Gauss_fit(spc,x,A1,B1,C1,A2,B2,C2,D)
1678 1691
1679 1692 elif mode == 1: #Double Fit Windowed
1680 1693 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei] = self.windowing_double(spc,dataOut.getFreqRange(0),A1,B1,C1,A2,B2,C2,D)
1681 1694
1682 1695 elif mode == 2: #Double Fit Weight
1683 1696 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei] = self.Double_Gauss_fit_weight(spc,x,A1,B1,C1,A2,B2,C2,D)
1684 1697
1685 1698 elif mode == 3: #Simple Fit
1686 1699 dataOut.Oblique_params[0,0,hei] = A1
1687 1700 dataOut.Oblique_params[0,1,hei] = B1
1688 1701 dataOut.Oblique_params[0,2,hei] = C1
1689 1702 dataOut.Oblique_params[0,3,hei] = A2
1690 1703 dataOut.Oblique_params[0,4,hei] = B2
1691 1704 dataOut.Oblique_params[0,5,hei] = C2
1692 1705 dataOut.Oblique_params[0,6,hei] = D
1693 1706
1694 1707 elif mode == 5: #Triple Fit Weight
1695 1708 if hei in l1:
1696 1709 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei] = self.duo_Marco(spc,x,A1,B1,C1,A2,B2,C2,D)
1697 1710 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,4,hei]/numpy.sin(numpy.arccos(102/dataOut.heightList[hei]))
1698 1711 #print(dataOut.Oblique_params[0,0,hei])
1699 1712 #print(dataOut.dplr_2_u[0,0,hei])
1700 1713 else:
1701 1714 dataOut.Oblique_params[0,0,hei],dataOut.Oblique_params[0,1,hei],dataOut.Oblique_params[0,2,hei],dataOut.Oblique_params[0,3,hei],dataOut.Oblique_params[0,4,hei],dataOut.Oblique_params[0,5,hei],dataOut.Oblique_params[0,6,hei] = self.Double_Gauss_fit_weight(spc,x,A1,B1,C1,A2,B2,C2,D)
1702 1715 dataOut.dplr_2_u[0,0,hei] = dataOut.Oblique_params[0,4,hei]/numpy.sin(numpy.arccos(102/dataOut.heightList[hei]))
1703 1716
1704 1717
1705 1718 except:
1706 1719 ###dataOut.Oblique_params[0,:,hei] = dataOut.Oblique_params[0,:,hei]*numpy.NAN
1707 1720 pass
1708 1721
1709 1722 #exit(1)
1710 1723 dataOut.paramInterval = dataOut.nProfiles*dataOut.nCohInt*dataOut.ippSeconds
1711 1724 dataOut.lat=-11.95
1712 1725 dataOut.lon=-76.87
1713 1726 '''
1714 1727 dataOut.Oblique_params = numpy.where(dataOut.Oblique_params<-700, numpy.nan, dop_t1)
1715 1728 dataOut.Oblique_params = numpy.where(dataOut.Oblique_params<+700, numpy.nan, dop_t1)
1716 1729 AquΓ­ debo exceptuar las amplitudes
1717 1730 '''
1718 1731 if mode == 9: #Double Skew Gaussian
1719 1732 #dataOut.Dop_EEJ_T1 = dataOut.Oblique_params[:,-2,:] #Pos[Max_value]
1720 1733 #dataOut.Dop_EEJ_T1 = dataOut.Oblique_params[:,1,:] #Shift
1721 1734 dataOut.Spec_W_T1 = dataOut.Oblique_params[:,2,:]
1722 1735 #dataOut.Dop_EEJ_T2 = dataOut.Oblique_params[:,-1,:] #Pos[Max_value]
1723 1736 #dataOut.Dop_EEJ_T2 = dataOut.Oblique_params[:,5,:] #Shift
1724 1737 dataOut.Spec_W_T2 = dataOut.Oblique_params[:,6,:]
1725 1738 if Dop == 'Shift':
1726 1739 dataOut.Dop_EEJ_T1 = dataOut.Oblique_params[:,1,:] #Shift
1727 1740 dataOut.Dop_EEJ_T2 = dataOut.Oblique_params[:,5,:] #Shift
1728 1741 elif Dop == 'Max':
1729 1742 dataOut.Dop_EEJ_T1 = dataOut.Oblique_params[:,-2,:] #Pos[Max_value]
1730 1743 dataOut.Dop_EEJ_T2 = dataOut.Oblique_params[:,-1,:] #Pos[Max_value]
1731 1744
1732 1745 dataOut.Err_Dop_EEJ_T1 = dataOut.Oblique_param_errors[:,1,:] #En realidad este es el error?
1733 1746 dataOut.Err_Spec_W_T1 = dataOut.Oblique_param_errors[:,2,:]
1734 1747 dataOut.Err_Dop_EEJ_T2 = dataOut.Oblique_param_errors[:,5,:] #En realidad este es el error?
1735 1748 dataOut.Err_Spec_W_T2 = dataOut.Oblique_param_errors[:,6,:]
1736 1749
1737 1750 elif mode == 11: #Double Gaussian
1738 1751 dataOut.Dop_EEJ_T1 = dataOut.Oblique_params[:,1,:]
1739 1752 dataOut.Spec_W_T1 = dataOut.Oblique_params[:,2,:]
1740 1753 dataOut.Dop_EEJ_T2 = dataOut.Oblique_params[:,4,:]
1741 1754 dataOut.Spec_W_T2 = dataOut.Oblique_params[:,5,:]
1742 1755
1743 1756 dataOut.Err_Dop_EEJ_T1 = dataOut.Oblique_param_errors[:,1,:]
1744 1757 dataOut.Err_Spec_W_T1 = dataOut.Oblique_param_errors[:,2,:]
1745 1758 dataOut.Err_Dop_EEJ_T2 = dataOut.Oblique_param_errors[:,4,:]
1746 1759 dataOut.Err_Spec_W_T2 = dataOut.Oblique_param_errors[:,5,:]
1747 1760
1748 1761 #print("Before: ", dataOut.Dop_EEJ_T2)
1749 1762 dataOut.Spec_W_T1 = self.clean_outliers(dataOut.Spec_W_T1)
1750 1763 dataOut.Spec_W_T2 = self.clean_outliers(dataOut.Spec_W_T2)
1751 1764 dataOut.Dop_EEJ_T1 = self.clean_outliers(dataOut.Dop_EEJ_T1)
1752 1765 dataOut.Dop_EEJ_T2 = self.clean_outliers(dataOut.Dop_EEJ_T2)
1753 1766 #print("After: ", dataOut.Dop_EEJ_T2)
1754 1767 dataOut.Err_Spec_W_T1 = self.clean_outliers(dataOut.Err_Spec_W_T1)
1755 1768 dataOut.Err_Spec_W_T2 = self.clean_outliers(dataOut.Err_Spec_W_T2)
1756 1769 dataOut.Err_Dop_EEJ_T1 = self.clean_outliers(dataOut.Err_Dop_EEJ_T1)
1757 1770 dataOut.Err_Dop_EEJ_T2 = self.clean_outliers(dataOut.Err_Dop_EEJ_T2)
1758 1771 #print("Before data_snr: ", dataOut.data_snr)
1759 1772 #dataOut.data_snr = numpy.where(numpy.isnan(dataOut.Dop_EEJ_T1), numpy.nan, dataOut.data_snr)
1760 1773 dataOut.snl = numpy.where(numpy.isnan(dataOut.Dop_EEJ_T1), numpy.nan, dataOut.snl)
1761 1774
1762 1775 #print("After data_snr: ", dataOut.data_snr)
1763 1776 dataOut.mode = mode
1764 1777 dataOut.flagNoData = numpy.all(numpy.isnan(dataOut.Dop_EEJ_T1)) #Si todos los valores son NaN no se prosigue
1765 1778 ###dataOut.flagNoData = False #Descomentar solo para ploteo sino mantener comentado (para guardado)
1766 1779
1767 1780 return dataOut
1768 1781
1769 1782 class Gaussian_Windowed(Operation):
1770 1783 '''
1771 1784 Written by R. Flores
1772 1785 '''
1773 1786 def __init__(self):
1774 1787 Operation.__init__(self)
1775 1788
1776 1789 def windowing_single(self,spc,x,A,B,C,D,nFFTPoints):
1777 1790 from scipy.optimize import curve_fit,fmin
1778 1791
1779 1792 def gaussian(x, a, b, c, d):
1780 1793 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
1781 1794 return val
1782 1795
1783 1796 def R_gaussian(x, a, b, c):
1784 1797 N = int(numpy.shape(x)[0])
1785 1798 val = a * numpy.exp(-((x)*c*2*2*numpy.pi)**2 / (2))* numpy.exp(1.j*b*x*4*numpy.pi)
1786 1799 return val
1787 1800
1788 1801 def T(x,N):
1789 1802 T = 1-abs(x)/N
1790 1803 return T
1791 1804
1792 1805 def R_T_spc_fun(x, a, b, c, d, nFFTPoints):
1793 1806
1794 1807 N = int(numpy.shape(x)[0])
1795 1808
1796 1809 x_max = x[-1]
1797 1810
1798 1811 x_pos = x[nFFTPoints:]
1799 1812 x_neg = x[:nFFTPoints]
1800 1813 #print([int(nFFTPoints/2))
1801 1814 #print("x: ", x)
1802 1815 #print("x_neg: ", x_neg)
1803 1816 #print("x_pos: ", x_pos)
1804 1817
1805 1818
1806 1819 R_T_neg_1 = R_gaussian(x, a, b, c)[:nFFTPoints]*T(x_neg,-x[0])
1807 1820 R_T_pos_1 = R_gaussian(x, a, b, c)[nFFTPoints:]*T(x_pos,x[-1])
1808 1821 #print(T(x_pos,x[-1]),x_pos,x[-1])
1809 1822 #print(R_T_neg_1.shape,R_T_pos_1.shape)
1810 1823 R_T_sum_1 = R_T_pos_1 + R_T_neg_1
1811 1824 R_T_spc_1 = numpy.fft.fft(R_T_sum_1).real
1812 1825 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
1813 1826 max_val_1 = numpy.max(R_T_spc_1)
1814 1827 R_T_spc_1 = R_T_spc_1*a/max_val_1
1815 1828
1816 1829 R_T_d = d*numpy.fft.fftshift(signal.unit_impulse(N))
1817 1830 R_T_d_neg = R_T_d[:nFFTPoints]*T(x_neg,-x[0])
1818 1831 R_T_d_pos = R_T_d[nFFTPoints:]*T(x_pos,x[-1])
1819 1832 R_T_d_sum = R_T_d_pos + R_T_d_neg
1820 1833 R_T_spc_3 = numpy.fft.fft(R_T_d_sum).real
1821 1834 R_T_spc_3 = numpy.fft.fftshift(R_T_spc_3)
1822 1835
1823 1836 R_T_final = R_T_spc_1 + R_T_spc_3
1824 1837
1825 1838 return R_T_final
1826 1839
1827 1840 y = spc#gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
1828 1841
1829 1842 from scipy.stats import norm
1830 1843 mean,std=norm.fit(spc)
1831 1844
1832 1845 # estimate starting values from the data
1833 1846 a = A
1834 1847 b = B
1835 1848 c = C#numpy.std(spc)
1836 1849 d = D
1837 1850 #'''
1838 1851 #ippSeconds = 250*20*1.e-6/3
1839 1852
1840 1853 #x_t = ippSeconds * (numpy.arange(nFFTPoints) - nFFTPoints / 2.)
1841 1854
1842 1855 #x_t = numpy.linspace(x_t[0],x_t[-1],3200)
1843 1856 #print("x_t: ", x_t)
1844 1857 #print("nFFTPoints: ", nFFTPoints)
1845 1858 x_vel = numpy.linspace(x[0],x[-1],int(2*nFFTPoints))
1846 1859 #print("x_vel: ", x_vel)
1847 1860 #x_freq = numpy.fft.fftfreq(1600,d=ippSeconds)
1848 1861 #x_freq = numpy.fft.fftshift(x_freq)
1849 1862 #'''
1850 1863 # define a least squares function to optimize
1851 1864 def minfunc(params):
1852 1865 #print("y.shape: ", numpy.shape(y))
1853 1866 return sum((y-R_T_spc_fun(x_vel,params[0],params[1],params[2],params[3],nFFTPoints))**2/1)#y**2)
1854 1867
1855 1868 # fit
1856 1869
1857 1870 popt_full = fmin(minfunc,[a,b,c,d], disp=False)
1858 1871 #print("nIter", popt_full[2])
1859 1872 popt = popt_full#[0]
1860 1873
1861 1874 fun = gaussian(x, popt[0], popt[1], popt[2], popt[3])
1862 1875
1863 1876 #return R_T_spc_fun(x_t,popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]), popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
1864 1877 return fun, popt[0], popt[1], popt[2], popt[3]
1865 1878
1866 1879 def run(self, dataOut):
1867 1880
1868 1881 from scipy.signal import medfilt
1869 1882 import matplotlib.pyplot as plt
1870 1883 dataOut.moments = numpy.ones((dataOut.nChannels,4,dataOut.nHeights))*numpy.NAN
1871 1884 dataOut.VelRange = dataOut.getVelRange(0)
1872 1885 for nChannel in range(dataOut.nChannels):
1873 1886 for hei in range(dataOut.heightList.shape[0]):
1874 1887 #print("ipp: ", dataOut.ippSeconds)
1875 1888 spc = numpy.copy(dataOut.data_spc[nChannel,:,hei])
1876 1889
1877 1890 #print(VelRange)
1878 1891 #print(dataOut.getFreqRange(64))
1879 1892 spcm = medfilt(spc,11)
1880 1893 spc_max = numpy.max(spcm)
1881 1894 dop1_x0 = dataOut.VelRange[numpy.argmax(spcm)]
1882 1895 D = numpy.min(spcm)
1883 1896
1884 1897 fun, A, B, C, D = self.windowing_single(spc,dataOut.VelRange,spc_max,dop1_x0,abs(dop1_x0),D,dataOut.nFFTPoints)
1885 1898 dataOut.moments[nChannel,0,hei] = A
1886 1899 dataOut.moments[nChannel,1,hei] = B
1887 1900 dataOut.moments[nChannel,2,hei] = C
1888 1901 dataOut.moments[nChannel,3,hei] = D
1889 1902 '''
1890 1903 plt.figure()
1891 1904 plt.plot(VelRange,spc,marker='*',linestyle='')
1892 1905 plt.plot(VelRange,fun)
1893 1906 plt.title(dataOut.heightList[hei])
1894 1907 plt.show()
1895 1908 '''
1896 1909
1897 1910 return dataOut
1898 1911
1899 1912 class PrecipitationProc(Operation):
1900 1913
1901 1914 '''
1902 1915 Operator that estimates Reflectivity factor (Z), and estimates rainfall Rate (R)
1903 1916
1904 1917 Input:
1905 1918 self.dataOut.data_pre : SelfSpectra
1906 1919
1907 1920 Output:
1908 1921
1909 1922 self.dataOut.data_output : Reflectivity factor, rainfall Rate
1910 1923
1911 1924
1912 1925 Parameters affected:
1913 1926 '''
1914 1927
1915 1928 def __init__(self):
1916 1929 Operation.__init__(self)
1917 1930 self.i=0
1918 1931
1919 1932 def run(self, dataOut, radar=None, Pt=5000, Gt=295.1209, Gr=70.7945, Lambda=0.6741, aL=2.5118,
1920 1933 tauW=4e-06, ThetaT=0.1656317, ThetaR=0.36774087, Km2 = 0.93, Altitude=3350,SNRdBlimit=-30,channel=None):
1921 1934
1922 1935 # print ('Entering PrecepitationProc ... ')
1923 1936
1924 1937 if radar == "MIRA35C" :
1925 1938
1926 1939 self.spc = dataOut.data_pre[0].copy()
1927 1940 self.Num_Hei = self.spc.shape[2]
1928 1941 self.Num_Bin = self.spc.shape[1]
1929 1942 self.Num_Chn = self.spc.shape[0]
1930 1943 Ze = self.dBZeMODE2(dataOut)
1931 1944
1932 1945 else:
1933 1946
1934 1947 self.spc = dataOut.data_pre[0].copy()
1935 1948
1936 1949 #NOTA SE DEBE REMOVER EL RANGO DEL PULSO TX
1937 1950 self.spc[:,:,0:7]= numpy.NaN
1938 1951
1939 1952 self.Num_Hei = self.spc.shape[2]
1940 1953 self.Num_Bin = self.spc.shape[1]
1941 1954 self.Num_Chn = self.spc.shape[0]
1942 1955
1943 1956 VelRange = dataOut.spc_range[2]
1944 1957
1945 1958 ''' Se obtiene la constante del RADAR '''
1946 1959
1947 1960 self.Pt = Pt
1948 1961 self.Gt = Gt
1949 1962 self.Gr = Gr
1950 1963 self.Lambda = Lambda
1951 1964 self.aL = aL
1952 1965 self.tauW = tauW
1953 1966 self.ThetaT = ThetaT
1954 1967 self.ThetaR = ThetaR
1955 1968 self.GSys = 10**(36.63/10) # Ganancia de los LNA 36.63 dB
1956 1969 self.lt = 10**(1.67/10) # Perdida en cables Tx 1.67 dB
1957 1970 self.lr = 10**(5.73/10) # Perdida en cables Rx 5.73 dB
1958 1971
1959 1972 Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
1960 1973 Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * tauW * numpy.pi * ThetaT * ThetaR)
1961 1974 RadarConstant = 10e-26 * Numerator / Denominator #
1962 1975 ExpConstant = 10**(40/10) #Constante Experimental
1963 1976
1964 1977 SignalPower = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
1965 1978 for i in range(self.Num_Chn):
1966 1979 SignalPower[i,:,:] = self.spc[i,:,:] - dataOut.noise[i]
1967 1980 SignalPower[numpy.where(SignalPower < 0)] = 1e-20
1968 1981
1969 1982 if channel is None:
1970 1983 SPCmean = numpy.mean(SignalPower, 0)
1971 1984 else:
1972 1985 SPCmean = SignalPower[channel]
1973 1986 Pr = SPCmean[:,:]/dataOut.normFactor
1974 1987
1975 1988 # Declaring auxiliary variables
1976 1989 Range = dataOut.heightList*1000. #Range in m
1977 1990 # replicate the heightlist to obtain a matrix [Num_Bin,Num_Hei]
1978 1991 rMtrx = numpy.transpose(numpy.transpose([dataOut.heightList*1000.] * self.Num_Bin))
1979 1992 zMtrx = rMtrx+Altitude
1980 1993 # replicate the VelRange to obtain a matrix [Num_Bin,Num_Hei]
1981 1994 VelMtrx = numpy.transpose(numpy.tile(VelRange[:-1], (self.Num_Hei,1)))
1982 1995
1983 1996 # height dependence to air density Foote and Du Toit (1969)
1984 1997 delv_z = 1 + 3.68e-5 * zMtrx + 1.71e-9 * zMtrx**2
1985 1998 VMtrx = VelMtrx / delv_z #Normalized velocity
1986 1999 VMtrx[numpy.where(VMtrx> 9.6)] = numpy.NaN
1987 2000 # Diameter is related to the fall speed of falling drops
1988 2001 D_Vz = -1.667 * numpy.log( 0.9369 - 0.097087 * VMtrx ) # D in [mm]
1989 2002 # Only valid for D>= 0.16 mm
1990 2003 D_Vz[numpy.where(D_Vz < 0.16)] = numpy.NaN
1991 2004
1992 2005 #Calculate Radar Reflectivity ETAn
1993 2006 ETAn = (RadarConstant *ExpConstant) * Pr * rMtrx**2 #Reflectivity (ETA)
1994 2007 ETAd = ETAn * 6.18 * exp( -0.6 * D_Vz ) * delv_z
1995 2008 # Radar Cross Section
1996 2009 sigmaD = Km2 * (D_Vz * 1e-3 )**6 * numpy.pi**5 / Lambda**4
1997 2010 # Drop Size Distribution
1998 2011 DSD = ETAn / sigmaD
1999 2012 # Equivalente Reflectivy
2000 2013 Ze_eqn = numpy.nansum( DSD * D_Vz**6 ,axis=0)
2001 2014 Ze_org = numpy.nansum(ETAn * Lambda**4, axis=0) / (1e-18*numpy.pi**5 * Km2) # [mm^6 /m^3]
2002 2015 # RainFall Rate
2003 2016 RR = 0.0006*numpy.pi * numpy.nansum( D_Vz**3 * DSD * VelMtrx ,0) #mm/hr
2004 2017
2005 2018 # Censoring the data
2006 2019 # Removing data with SNRth < 0dB se debe considerar el SNR por canal
2007 2020 SNRth = 10**(SNRdBlimit/10) #-30dB
2008 2021 novalid = numpy.where((dataOut.data_snr[0,:] <SNRth) | (dataOut.data_snr[1,:] <SNRth) | (dataOut.data_snr[2,:] <SNRth)) # AND condition. Maybe OR condition better
2009 2022 W = numpy.nanmean(dataOut.data_dop,0)
2010 2023 W[novalid] = numpy.NaN
2011 2024 Ze_org[novalid] = numpy.NaN
2012 2025 RR[novalid] = numpy.NaN
2013 2026
2014 2027 dataOut.data_output = RR[8]
2015 2028 dataOut.data_param = numpy.ones([3,self.Num_Hei])
2016 2029 dataOut.channelList = [0,1,2]
2017 2030
2018 2031 dataOut.data_param[0]=10*numpy.log10(Ze_org)
2019 2032 dataOut.data_param[1]=-W
2020 2033 dataOut.data_param[2]=RR
2021 2034
2022 2035 # print ('Leaving PrecepitationProc ... ')
2023 2036 return dataOut
2024 2037
2025 2038 def dBZeMODE2(self, dataOut): # Processing for MIRA35C
2026 2039
2027 2040 NPW = dataOut.NPW
2028 2041 COFA = dataOut.COFA
2029 2042
2030 2043 SNR = numpy.array([self.spc[0,:,:] / NPW[0]]) #, self.spc[1,:,:] / NPW[1]])
2031 2044 RadarConst = dataOut.RadarConst
2032 2045 #frequency = 34.85*10**9
2033 2046
2034 2047 ETA = numpy.zeros(([self.Num_Chn ,self.Num_Hei]))
2035 2048 data_output = numpy.ones([self.Num_Chn , self.Num_Hei])*numpy.NaN
2036 2049
2037 2050 ETA = numpy.sum(SNR,1)
2038 2051
2039 2052 ETA = numpy.where(ETA != 0. , ETA, numpy.NaN)
2040 2053
2041 2054 Ze = numpy.ones([self.Num_Chn, self.Num_Hei] )
2042 2055
2043 2056 for r in range(self.Num_Hei):
2044 2057
2045 2058 Ze[0,r] = ( ETA[0,r] ) * COFA[0,r][0] * RadarConst * ((r/5000.)**2)
2046 2059 #Ze[1,r] = ( ETA[1,r] ) * COFA[1,r][0] * RadarConst * ((r/5000.)**2)
2047 2060
2048 2061 return Ze
2049 2062
2050 2063 # def GetRadarConstant(self):
2051 2064 #
2052 2065 # """
2053 2066 # Constants:
2054 2067 #
2055 2068 # Pt: Transmission Power dB 5kW 5000
2056 2069 # Gt: Transmission Gain dB 24.7 dB 295.1209
2057 2070 # Gr: Reception Gain dB 18.5 dB 70.7945
2058 2071 # Lambda: Wavelenght m 0.6741 m 0.6741
2059 2072 # aL: Attenuation loses dB 4dB 2.5118
2060 2073 # tauW: Width of transmission pulse s 4us 4e-6
2061 2074 # ThetaT: Transmission antenna bean angle rad 0.1656317 rad 0.1656317
2062 2075 # ThetaR: Reception antenna beam angle rad 0.36774087 rad 0.36774087
2063 2076 #
2064 2077 # """
2065 2078 #
2066 2079 # Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
2067 2080 # Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * TauW * numpy.pi * ThetaT * TheraR)
2068 2081 # RadarConstant = Numerator / Denominator
2069 2082 #
2070 2083 # return RadarConstant
2071 2084
2072 2085
2073 2086 class FullSpectralAnalysis(Operation):
2074 2087
2075 2088 """
2076 2089 Function that implements Full Spectral Analysis technique.
2077 2090
2078 2091 Input:
2079 2092 self.dataOut.data_pre : SelfSpectra and CrossSpectra data
2080 2093 self.dataOut.groupList : Pairlist of channels
2081 2094 self.dataOut.ChanDist : Physical distance between receivers
2082 2095
2083 2096
2084 2097 Output:
2085 2098
2086 2099 self.dataOut.data_output : Zonal wind, Meridional wind, and Vertical wind
2087 2100
2088 2101
2089 2102 Parameters affected: Winds, height range, SNR
2090 2103
2091 2104 """
2092 2105 def run(self, dataOut, Xi01=None, Xi02=None, Xi12=None, Eta01=None, Eta02=None, Eta12=None, SNRdBlimit=-30,minheight=None, maxheight=None, NegativeLimit=None, PositiveLimit=None):
2093 2106
2094 2107 spc = dataOut.data_pre[0].copy()
2095 2108 cspc = dataOut.data_pre[1]
2096 2109 nHeights = spc.shape[2]
2097 2110
2098 2111 # first_height = 0.75 #km (ref: data header 20170822)
2099 2112 # resolution_height = 0.075 #km
2100 2113 '''
2101 2114 finding height range. check this when radar parameters are changed!
2102 2115 '''
2103 2116 if maxheight is not None:
2104 2117 # range_max = math.ceil((maxheight - first_height) / resolution_height) # theoretical
2105 2118 range_max = math.ceil(13.26 * maxheight - 3) # empirical, works better
2106 2119 else:
2107 2120 range_max = nHeights
2108 2121 if minheight is not None:
2109 2122 # range_min = int((minheight - first_height) / resolution_height) # theoretical
2110 2123 range_min = int(13.26 * minheight - 5) # empirical, works better
2111 2124 if range_min < 0:
2112 2125 range_min = 0
2113 2126 else:
2114 2127 range_min = 0
2115 2128
2116 2129 pairsList = dataOut.groupList
2117 2130 if dataOut.ChanDist is not None :
2118 2131 ChanDist = dataOut.ChanDist
2119 2132 else:
2120 2133 ChanDist = numpy.array([[Xi01, Eta01],[Xi02,Eta02],[Xi12,Eta12]])
2121 2134
2122 2135 # 4 variables: zonal, meridional, vertical, and average SNR
2123 2136 data_param = numpy.zeros([4,nHeights]) * numpy.NaN
2124 2137 velocityX = numpy.zeros([nHeights]) * numpy.NaN
2125 2138 velocityY = numpy.zeros([nHeights]) * numpy.NaN
2126 2139 velocityZ = numpy.zeros([nHeights]) * numpy.NaN
2127 2140
2128 2141 dbSNR = 10*numpy.log10(numpy.average(dataOut.data_snr,0))
2129 2142
2130 2143 '''***********************************************WIND ESTIMATION**************************************'''
2131 2144 for Height in range(nHeights):
2132 2145
2133 2146 if Height >= range_min and Height < range_max:
2134 2147 # error_code will be useful in future analysis
2135 2148 [Vzon,Vmer,Vver, error_code] = self.WindEstimation(spc[:,:,Height], cspc[:,:,Height], pairsList,
2136 2149 ChanDist, Height, dataOut.noise, dataOut.spc_range, dbSNR[Height], SNRdBlimit, NegativeLimit, PositiveLimit,dataOut.frequency)
2137 2150
2138 2151 if abs(Vzon) < 100. and abs(Vmer) < 100.:
2139 2152 velocityX[Height] = Vzon
2140 2153 velocityY[Height] = -Vmer
2141 2154 velocityZ[Height] = Vver
2142 2155
2143 2156 # Censoring data with SNR threshold
2144 2157 dbSNR [dbSNR < SNRdBlimit] = numpy.NaN
2145 2158
2146 2159 data_param[0] = velocityX
2147 2160 data_param[1] = velocityY
2148 2161 data_param[2] = velocityZ
2149 2162 data_param[3] = dbSNR
2150 2163 dataOut.data_param = data_param
2151 2164 return dataOut
2152 2165
2153 2166 def moving_average(self,x, N=2):
2154 2167 """ convolution for smoothenig data. note that last N-1 values are convolution with zeroes """
2155 2168 return numpy.convolve(x, numpy.ones((N,))/N)[(N-1):]
2156 2169
2157 2170 def gaus(self,xSamples,Amp,Mu,Sigma):
2158 2171 return Amp * numpy.exp(-0.5*((xSamples - Mu)/Sigma)**2)
2159 2172
2160 2173 def Moments(self, ySamples, xSamples):
2161 2174 Power = numpy.nanmean(ySamples) # Power, 0th Moment
2162 2175 yNorm = ySamples / numpy.nansum(ySamples)
2163 2176 RadVel = numpy.nansum(xSamples * yNorm) # Radial Velocity, 1st Moment
2164 2177 Sigma2 = numpy.nansum(yNorm * (xSamples - RadVel)**2) # Spectral Width, 2nd Moment
2165 2178 StdDev = numpy.sqrt(numpy.abs(Sigma2)) # Desv. Estandar, Ancho espectral
2166 2179 return numpy.array([Power,RadVel,StdDev])
2167 2180
2168 2181 def StopWindEstimation(self, error_code):
2169 2182 Vzon = numpy.NaN
2170 2183 Vmer = numpy.NaN
2171 2184 Vver = numpy.NaN
2172 2185 return Vzon, Vmer, Vver, error_code
2173 2186
2174 2187 def AntiAliasing(self, interval, maxstep):
2175 2188 """
2176 2189 function to prevent errors from aliased values when computing phaseslope
2177 2190 """
2178 2191 antialiased = numpy.zeros(len(interval))
2179 2192 copyinterval = interval.copy()
2180 2193
2181 2194 antialiased[0] = copyinterval[0]
2182 2195
2183 2196 for i in range(1,len(antialiased)):
2184 2197 step = interval[i] - interval[i-1]
2185 2198 if step > maxstep:
2186 2199 copyinterval -= 2*numpy.pi
2187 2200 antialiased[i] = copyinterval[i]
2188 2201 elif step < maxstep*(-1):
2189 2202 copyinterval += 2*numpy.pi
2190 2203 antialiased[i] = copyinterval[i]
2191 2204 else:
2192 2205 antialiased[i] = copyinterval[i].copy()
2193 2206
2194 2207 return antialiased
2195 2208
2196 2209 def WindEstimation(self, spc, cspc, pairsList, ChanDist, Height, noise, AbbsisaRange, dbSNR, SNRlimit, NegativeLimit, PositiveLimit, radfreq):
2197 2210 """
2198 2211 Function that Calculates Zonal, Meridional and Vertical wind velocities.
2199 2212 Initial Version by E. Bocanegra updated by J. Zibell until Nov. 2019.
2200 2213
2201 2214 Input:
2202 2215 spc, cspc : self spectra and cross spectra data. In Briggs notation something like S_i*(S_i)_conj, (S_j)_conj respectively.
2203 2216 pairsList : Pairlist of channels
2204 2217 ChanDist : array of xi_ij and eta_ij
2205 2218 Height : height at which data is processed
2206 2219 noise : noise in [channels] format for specific height
2207 2220 Abbsisarange : range of the frequencies or velocities
2208 2221 dbSNR, SNRlimit : signal to noise ratio in db, lower limit
2209 2222
2210 2223 Output:
2211 2224 Vzon, Vmer, Vver : wind velocities
2212 2225 error_code : int that states where code is terminated
2213 2226
2214 2227 0 : no error detected
2215 2228 1 : Gaussian of mean spc exceeds widthlimit
2216 2229 2 : no Gaussian of mean spc found
2217 2230 3 : SNR to low or velocity to high -> prec. e.g.
2218 2231 4 : at least one Gaussian of cspc exceeds widthlimit
2219 2232 5 : zero out of three cspc Gaussian fits converged
2220 2233 6 : phase slope fit could not be found
2221 2234 7 : arrays used to fit phase have different length
2222 2235 8 : frequency range is either too short (len <= 5) or very long (> 30% of cspc)
2223 2236
2224 2237 """
2225 2238
2226 2239 error_code = 0
2227 2240
2228 2241 nChan = spc.shape[0]
2229 2242 nProf = spc.shape[1]
2230 2243 nPair = cspc.shape[0]
2231 2244
2232 2245 SPC_Samples = numpy.zeros([nChan, nProf]) # for normalized spc values for one height
2233 2246 CSPC_Samples = numpy.zeros([nPair, nProf], dtype=numpy.complex_) # for normalized cspc values
2234 2247 phase = numpy.zeros([nPair, nProf]) # phase between channels
2235 2248 PhaseSlope = numpy.zeros(nPair) # slope of the phases, channelwise
2236 2249 PhaseInter = numpy.zeros(nPair) # intercept to the slope of the phases, channelwise
2237 2250 xFrec = AbbsisaRange[0][:-1] # frequency range
2238 2251 xVel = AbbsisaRange[2][:-1] # velocity range
2239 2252 xSamples = xFrec # the frequency range is taken
2240 2253 delta_x = xSamples[1] - xSamples[0] # delta_f or delta_x
2241 2254
2242 2255 # only consider velocities with in NegativeLimit and PositiveLimit
2243 2256 if (NegativeLimit is None):
2244 2257 NegativeLimit = numpy.min(xVel)
2245 2258 if (PositiveLimit is None):
2246 2259 PositiveLimit = numpy.max(xVel)
2247 2260 xvalid = numpy.where((xVel > NegativeLimit) & (xVel < PositiveLimit))
2248 2261 xSamples_zoom = xSamples[xvalid]
2249 2262
2250 2263 '''Getting Eij and Nij'''
2251 2264 Xi01, Xi02, Xi12 = ChanDist[:,0]
2252 2265 Eta01, Eta02, Eta12 = ChanDist[:,1]
2253 2266
2254 2267 # spwd limit - updated by D. ScipiΓ³n 30.03.2021
2255 2268 widthlimit = 10
2256 2269 '''************************* SPC is normalized ********************************'''
2257 2270 spc_norm = spc.copy()
2258 2271 # For each channel
2259 2272 for i in range(nChan):
2260 2273 spc_sub = spc_norm[i,:] - noise[i] # only the signal power
2261 2274 SPC_Samples[i] = spc_sub / (numpy.nansum(spc_sub) * delta_x)
2262 2275
2263 2276 '''********************** FITTING MEAN SPC GAUSSIAN **********************'''
2264 2277
2265 2278 """ the gaussian of the mean: first subtract noise, then normalize. this is legal because
2266 2279 you only fit the curve and don't need the absolute value of height for calculation,
2267 2280 only for estimation of width. for normalization of cross spectra, you need initial,
2268 2281 unnormalized self-spectra With noise.
2269 2282
2270 2283 Technically, you don't even need to normalize the self-spectra, as you only need the
2271 2284 width of the peak. However, it was left this way. Note that the normalization has a flaw:
2272 2285 due to subtraction of the noise, some values are below zero. Raw "spc" values should be
2273 2286 >= 0, as it is the modulus squared of the signals (complex * it's conjugate)
2274 2287 """
2275 2288 # initial conditions
2276 2289 popt = [1e-10,0,1e-10]
2277 2290 # Spectra average
2278 2291 SPCMean = numpy.average(SPC_Samples,0)
2279 2292 # Moments in frequency
2280 2293 SPCMoments = self.Moments(SPCMean[xvalid], xSamples_zoom)
2281 2294
2282 2295 # Gauss Fit SPC in frequency domain
2283 2296 if dbSNR > SNRlimit: # only if SNR > SNRth
2284 2297 try:
2285 2298 popt,pcov = curve_fit(self.gaus,xSamples_zoom,SPCMean[xvalid],p0=SPCMoments)
2286 2299 if popt[2] <= 0 or popt[2] > widthlimit: # CONDITION
2287 2300 return self.StopWindEstimation(error_code = 1)
2288 2301 FitGauss = self.gaus(xSamples_zoom,*popt)
2289 2302 except :#RuntimeError:
2290 2303 return self.StopWindEstimation(error_code = 2)
2291 2304 else:
2292 2305 return self.StopWindEstimation(error_code = 3)
2293 2306
2294 2307 '''***************************** CSPC Normalization *************************
2295 2308 The Spc spectra are used to normalize the crossspectra. Peaks from precipitation
2296 2309 influence the norm which is not desired. First, a range is identified where the
2297 2310 wind peak is estimated -> sum_wind is sum of those frequencies. Next, the area
2298 2311 around it gets cut off and values replaced by mean determined by the boundary
2299 2312 data -> sum_noise (spc is not normalized here, thats why the noise is important)
2300 2313
2301 2314 The sums are then added and multiplied by range/datapoints, because you need
2302 2315 an integral and not a sum for normalization.
2303 2316
2304 2317 A norm is found according to Briggs 92.
2305 2318 '''
2306 2319 # for each pair
2307 2320 for i in range(nPair):
2308 2321 cspc_norm = cspc[i,:].copy()
2309 2322 chan_index0 = pairsList[i][0]
2310 2323 chan_index1 = pairsList[i][1]
2311 2324 CSPC_Samples[i] = cspc_norm / (numpy.sqrt(numpy.nansum(spc_norm[chan_index0])*numpy.nansum(spc_norm[chan_index1])) * delta_x)
2312 2325 phase[i] = numpy.arctan2(CSPC_Samples[i].imag, CSPC_Samples[i].real)
2313 2326
2314 2327 CSPCmoments = numpy.vstack([self.Moments(numpy.abs(CSPC_Samples[0,xvalid]), xSamples_zoom),
2315 2328 self.Moments(numpy.abs(CSPC_Samples[1,xvalid]), xSamples_zoom),
2316 2329 self.Moments(numpy.abs(CSPC_Samples[2,xvalid]), xSamples_zoom)])
2317 2330
2318 2331 popt01, popt02, popt12 = [1e-10,0,1e-10], [1e-10,0,1e-10] ,[1e-10,0,1e-10]
2319 2332 FitGauss01, FitGauss02, FitGauss12 = numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples))
2320 2333
2321 2334 '''*******************************FIT GAUSS CSPC************************************'''
2322 2335 try:
2323 2336 popt01,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[0][xvalid]),p0=CSPCmoments[0])
2324 2337 if popt01[2] > widthlimit: # CONDITION
2325 2338 return self.StopWindEstimation(error_code = 4)
2326 2339 popt02,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[1][xvalid]),p0=CSPCmoments[1])
2327 2340 if popt02[2] > widthlimit: # CONDITION
2328 2341 return self.StopWindEstimation(error_code = 4)
2329 2342 popt12,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[2][xvalid]),p0=CSPCmoments[2])
2330 2343 if popt12[2] > widthlimit: # CONDITION
2331 2344 return self.StopWindEstimation(error_code = 4)
2332 2345
2333 2346 FitGauss01 = self.gaus(xSamples_zoom, *popt01)
2334 2347 FitGauss02 = self.gaus(xSamples_zoom, *popt02)
2335 2348 FitGauss12 = self.gaus(xSamples_zoom, *popt12)
2336 2349 except:
2337 2350 return self.StopWindEstimation(error_code = 5)
2338 2351
2339 2352
2340 2353 '''************* Getting Fij ***************'''
2341 2354 # x-axis point of the gaussian where the center is located from GaussFit of spectra
2342 2355 GaussCenter = popt[1]
2343 2356 ClosestCenter = xSamples_zoom[numpy.abs(xSamples_zoom-GaussCenter).argmin()]
2344 2357 PointGauCenter = numpy.where(xSamples_zoom==ClosestCenter)[0][0]
2345 2358
2346 2359 # Point where e^-1 is located in the gaussian
2347 2360 PeMinus1 = numpy.max(FitGauss) * numpy.exp(-1)
2348 2361 FijClosest = FitGauss[numpy.abs(FitGauss-PeMinus1).argmin()] # The closest point to"Peminus1" in "FitGauss"
2349 2362 PointFij = numpy.where(FitGauss==FijClosest)[0][0]
2350 2363 Fij = numpy.abs(xSamples_zoom[PointFij] - xSamples_zoom[PointGauCenter])
2351 2364
2352 2365 '''********** Taking frequency ranges from mean SPCs **********'''
2353 2366 GauWidth = popt[2] * 3/2 # Bandwidth of Gau01
2354 2367 Range = numpy.empty(2)
2355 2368 Range[0] = GaussCenter - GauWidth
2356 2369 Range[1] = GaussCenter + GauWidth
2357 2370 # Point in x-axis where the bandwidth is located (min:max)
2358 2371 ClosRangeMin = xSamples_zoom[numpy.abs(xSamples_zoom-Range[0]).argmin()]
2359 2372 ClosRangeMax = xSamples_zoom[numpy.abs(xSamples_zoom-Range[1]).argmin()]
2360 2373 PointRangeMin = numpy.where(xSamples_zoom==ClosRangeMin)[0][0]
2361 2374 PointRangeMax = numpy.where(xSamples_zoom==ClosRangeMax)[0][0]
2362 2375 Range = numpy.array([ PointRangeMin, PointRangeMax ])
2363 2376 FrecRange = xSamples_zoom[ Range[0] : Range[1] ]
2364 2377
2365 2378 '''************************** Getting Phase Slope ***************************'''
2366 2379 for i in range(nPair):
2367 2380 if len(FrecRange) > 5:
2368 2381 PhaseRange = phase[i, xvalid[0][Range[0]:Range[1]]].copy()
2369 2382 mask = ~numpy.isnan(FrecRange) & ~numpy.isnan(PhaseRange)
2370 2383 if len(FrecRange) == len(PhaseRange):
2371 2384 try:
2372 2385 slope, intercept, _, _, _ = stats.linregress(FrecRange[mask], self.AntiAliasing(PhaseRange[mask], 4.5))
2373 2386 PhaseSlope[i] = slope
2374 2387 PhaseInter[i] = intercept
2375 2388 except:
2376 2389 return self.StopWindEstimation(error_code = 6)
2377 2390 else:
2378 2391 return self.StopWindEstimation(error_code = 7)
2379 2392 else:
2380 2393 return self.StopWindEstimation(error_code = 8)
2381 2394
2382 2395 '''*** Constants A-H correspond to the convention as in Briggs and Vincent 1992 ***'''
2383 2396
2384 2397 '''Getting constant C'''
2385 2398 cC=(Fij*numpy.pi)**2
2386 2399
2387 2400 '''****** Getting constants F and G ******'''
2388 2401 MijEijNij = numpy.array([[Xi02,Eta02], [Xi12,Eta12]])
2389 2402 # MijEijNij = numpy.array([[Xi01,Eta01], [Xi02,Eta02], [Xi12,Eta12]])
2390 2403 # MijResult0 = (-PhaseSlope[0] * cC) / (2*numpy.pi)
2391 2404 MijResult1 = (-PhaseSlope[1] * cC) / (2*numpy.pi)
2392 2405 MijResult2 = (-PhaseSlope[2] * cC) / (2*numpy.pi)
2393 2406 # MijResults = numpy.array([MijResult0, MijResult1, MijResult2])
2394 2407 MijResults = numpy.array([MijResult1, MijResult2])
2395 2408 (cF,cG) = numpy.linalg.solve(MijEijNij, MijResults)
2396 2409
2397 2410 '''****** Getting constants A, B and H ******'''
2398 2411 W01 = numpy.nanmax( FitGauss01 )
2399 2412 W02 = numpy.nanmax( FitGauss02 )
2400 2413 W12 = numpy.nanmax( FitGauss12 )
2401 2414
2402 2415 WijResult01 = ((cF * Xi01 + cG * Eta01)**2)/cC - numpy.log(W01 / numpy.sqrt(numpy.pi / cC))
2403 2416 WijResult02 = ((cF * Xi02 + cG * Eta02)**2)/cC - numpy.log(W02 / numpy.sqrt(numpy.pi / cC))
2404 2417 WijResult12 = ((cF * Xi12 + cG * Eta12)**2)/cC - numpy.log(W12 / numpy.sqrt(numpy.pi / cC))
2405 2418 WijResults = numpy.array([WijResult01, WijResult02, WijResult12])
2406 2419
2407 2420 WijEijNij = numpy.array([ [Xi01**2, Eta01**2, 2*Xi01*Eta01] , [Xi02**2, Eta02**2, 2*Xi02*Eta02] , [Xi12**2, Eta12**2, 2*Xi12*Eta12] ])
2408 2421 (cA,cB,cH) = numpy.linalg.solve(WijEijNij, WijResults)
2409 2422
2410 2423 VxVy = numpy.array([[cA,cH],[cH,cB]])
2411 2424 VxVyResults = numpy.array([-cF,-cG])
2412 2425 (Vmer,Vzon) = numpy.linalg.solve(VxVy, VxVyResults)
2413 2426 Vver = -SPCMoments[1]*SPEED_OF_LIGHT/(2*radfreq)
2414 2427 error_code = 0
2415 2428
2416 2429 return Vzon, Vmer, Vver, error_code
2417 2430
2418 2431 class SpectralMoments(Operation):
2419 2432
2420 2433 '''
2421 2434 Function SpectralMoments()
2422 2435
2423 2436 Calculates moments (power, mean, standard deviation) and SNR of the signal
2424 2437
2425 2438 Type of dataIn: Spectra
2426 2439
2427 2440 Configuration Parameters:
2428 2441
2429 2442 dirCosx : Cosine director in X axis
2430 2443 dirCosy : Cosine director in Y axis
2431 2444
2432 2445 elevation :
2433 2446 azimuth :
2434 2447
2435 2448 Input:
2436 2449 channelList : simple channel list to select e.g. [2,3,7]
2437 2450 self.dataOut.data_pre : Spectral data
2438 2451 self.dataOut.abscissaList : List of frequencies
2439 2452 self.dataOut.noise : Noise level per channel
2440 2453
2441 2454 Affected:
2442 2455 self.dataOut.moments : Parameters per channel
2443 2456 self.dataOut.data_snr : SNR per channel
2444 2457
2445 2458 '''
2446 2459
2447 2460 def run(self, dataOut, proc_type=0):
2448 2461
2449 2462 absc = dataOut.abscissaList[:-1]
2450 2463 nChannel = dataOut.data_pre[0].shape[0]
2451 2464 nHei = dataOut.data_pre[0].shape[2]
2452 2465 data_param = numpy.zeros((nChannel, 4 + proc_type*3, nHei))
2453 2466
2454 2467 if proc_type == 1:
2455 2468 fwindow = numpy.zeros(absc.size) + 1
2456 2469 b=64
2457 2470 #b=16
2458 2471 fwindow[0:absc.size//2 - b] = 0
2459 2472 fwindow[absc.size//2 + b:] = 0
2460 2473 type1 = 1 # moments calculation & gaussean fitting
2461 2474 nProfiles = dataOut.nProfiles
2462 2475 nCohInt = dataOut.nCohInt
2463 2476 nIncohInt = dataOut.nIncohInt
2464 2477 M = numpy.power(numpy.array(1/(nProfiles * nCohInt) ,dtype='float32'),2)
2465 2478 N = numpy.array(M / nIncohInt,dtype='float32')
2466 2479 data = dataOut.data_pre[0] * N
2467 2480 #noise = dataOut.noise * N
2468 2481 noise = numpy.zeros(nChannel)
2469 2482 for ind in range(nChannel):
2470 2483 noise[ind] = self.__NoiseByChannel(nProfiles, nIncohInt, data[ind,:,:])
2471 2484 smooth=3
2472 2485 else:
2473 2486 data = dataOut.data_pre[0]
2474 2487 noise = dataOut.noise
2475 2488 fwindow = None
2476 2489 type1 = 0
2477 2490 nIncohInt = None
2478 2491 smooth=None
2479 2492
2480 2493 for ind in range(nChannel):
2481 2494 data_param[ind,:,:] = self.__calculateMoments( data[ind,:,:] , absc , noise[ind], nicoh=nIncohInt, smooth=smooth, type1=type1, fwindow=fwindow, id_ch=ind)
2482 2495
2483 2496 if proc_type == 1:
2484 2497 dataOut.moments = data_param[:,1:,:]
2485 2498 dataOut.data_dop = data_param[:,2]
2486 2499 dataOut.data_width = data_param[:,1]
2487 2500 dataOut.data_snr = data_param[:,0]
2488 2501 dataOut.data_pow = data_param[:,6] # to compare with type0 proccessing
2489 2502 dataOut.spcpar=numpy.stack((dataOut.data_dop,dataOut.data_width,dataOut.data_snr, data_param[:,3], data_param[:,4],data_param[:,5]),axis=2)
2490 2503 else:
2491 2504 dataOut.moments = data_param[:,1:,:]
2492 2505 dataOut.data_snr = data_param[:,0]
2493 2506 dataOut.data_pow = data_param[:,1]
2494 2507 dataOut.data_dop = data_param[:,2]
2495 2508 dataOut.data_width = data_param[:,3]
2496 2509 dataOut.spcpar=numpy.stack((dataOut.data_dop,dataOut.data_width,dataOut.data_snr, dataOut.data_pow),axis=2)
2497 2510
2498 2511 return dataOut
2499 2512
2500 2513 def __calculateMoments(self, oldspec, oldfreq, n0, normFactor = 1,nicoh = None, graph = None, smooth = None, type1 = None, fwindow = None, snrth = None, dc = None, aliasing = None, oldfd = None, wwauto = None,id_ch=0):
2501 2514
2502 2515 def __GAUSSWINFIT1(A, flagPDER=0):
2503 2516 nonlocal truex, xvalid
2504 2517 nparams = 4
2505 2518 M=truex.size
2506 2519 mm=numpy.arange(M,dtype='f4')
2507 2520 delta = numpy.zeros(M,dtype='f4')
2508 2521 delta[0] = 1.0
2509 2522 Ts = numpy.array([1.0/(2*truex[0])],dtype='f4')[0]
2510 2523 jj = -1j
2511 2524 #if self.winauto is None: self.winauto = (1.0 - mm/M)
2512 2525 winauto = (1.0 - mm/M)
2513 2526 winauto = winauto/winauto.max() # Normalized to 1
2514 2527 #ON_ERROR,2 # IDL sentence: Return to caller if an error occurs
2515 2528 A[0] = numpy.abs(A[0])
2516 2529 A[2] = numpy.abs(A[2])
2517 2530 A[3] = numpy.abs(A[3])
2518 2531 pi=numpy.array([numpy.pi],dtype='f4')[0]
2519 2532 if A[2] != 0:
2520 2533 Z = numpy.exp(-2*numpy.power((pi*A[2]*mm*Ts),2,dtype='f4')+jj*2*pi*A[1]*mm*Ts, dtype='c8') # Get Z
2521 2534 else:
2522 2535 Z = mm*0.0
2523 2536 A[0] = 0.0
2524 2537 junkF = numpy.roll(2*fft(winauto*(A[0]*Z+A[3]*delta)).real - \
2525 2538 winauto[0]*(A[0]+A[3]), M//2) # *M scale for fft not needed in python
2526 2539 F = junkF[xvalid]
2527 2540 if flagPDER == 0: #NEED PARTIAL?
2528 2541 return F
2529 2542 PDER = numpy.zeros((M,nparams)) #YES, MAKE ARRAY.
2530 2543 PDER[:,0] = numpy.shift(2*(fft(winauto*Z)*M) - winauto[0], M/2)
2531 2544 PDER[:,1] = numpy.shift(2*(fft(winauto*jj*2*numpy.pi*mm*Ts*A[0]*Z)*M), M/2)
2532 2545 PDER[:,2] = numpy.shift(2*(fft(winauto*(-4*numpy.power(numpy.pi*mm*Ts,2)*A[2]*A[0]*Z))*M), M/2)
2533 2546 PDER[:,3] = numpy.shift(2*(fft(winauto*delta)*M) - winauto[0], M/2)
2534 2547 PDER = PDER[xvalid,:]
2535 2548 return F, PDER
2536 2549
2537 2550 def __curvefit_koki(y, a, Weights, FlagNoDerivative=1,
2538 2551 itmax=20, tol=None):
2539 2552 #ON_ERROR,2 IDL SENTENCE: RETURN TO THE CALLER IF ERROR
2540 2553 if tol == None:
2541 2554 tol = numpy.array([1.e-3],dtype='f4')[0]
2542 2555 typ=a.dtype
2543 2556 double = 1 if typ == numpy.float64 else 0
2544 2557 if typ != numpy.float32:
2545 2558 a=a.astype(numpy.float32) #Make params floating
2546 2559 # if we will be estimating partial derivates then compute machine precision
2547 2560 if FlagNoDerivative == 1:
2548 2561 res=numpy.MachAr(float_conv=numpy.float32)
2549 2562 eps=numpy.sqrt(res.eps)
2550 2563
2551 2564 nterms = a.size # Number of parameters
2552 2565 nfree=numpy.array([numpy.size(y) - nterms],dtype='f4')[0] # Degrees of freedom
2553 2566 if nfree <= 0: print('Curvefit - not enough data points.')
2554 2567 flambda= numpy.array([0.001],dtype='f4')[0] # Initial lambda
2555 2568 #diag=numpy.arange(nterms)*(nterms+1) # Subscripta of diagonal elements
2556 2569 # Use diag method in python
2557 2570 converge=1
2558 2571
2559 2572 #Define the partial derivative array
2560 2573 PDER = numpy.zeros((nterms,numpy.size(y)),dtype='f8') if double == 1 else numpy.zeros((nterms,numpy.size(y)),dtype='f4')
2561 2574
2562 2575 for Niter in range(itmax): #Iteration loop
2563 2576
2564 2577 if FlagNoDerivative == 1:
2565 2578 #Evaluate function and estimate partial derivatives
2566 2579 yfit = __GAUSSWINFIT1(a)
2567 2580 for term in range(nterms):
2568 2581 p=a.copy() # Copy current parameters
2569 2582 #Increment size for forward difference derivative
2570 2583 inc = eps * abs(p[term])
2571 2584 if inc == 0: inc = eps
2572 2585 p[term] = p[term] + inc
2573 2586 yfit1 = __GAUSSWINFIT1(p)
2574 2587 PDER[term,:] = (yfit1-yfit)/inc
2575 2588 else:
2576 2589 #The user's procedure will return partial derivatives
2577 2590 yfit,PDER=__GAUSSWINFIT1(a, flagPDER=1)
2578 2591
2579 2592 beta = numpy.dot(PDER,(y-yfit)*Weights)
2580 2593 alpha = numpy.dot(PDER * numpy.tile(Weights,(nterms,1)), numpy.transpose(PDER))
2581 2594 # save current values of return parameters
2582 2595 sigma1 = numpy.sqrt( 1.0 / numpy.diag(alpha) ) # Current sigma.
2583 2596 sigma = sigma1
2584 2597
2585 2598 chisq1 = numpy.sum(Weights*numpy.power(y-yfit,2,dtype='f4'),dtype='f4')/nfree # Current chi squared.
2586 2599 chisq = chisq1
2587 2600 yfit1 = yfit
2588 2601 elev7=numpy.array([1.0e7],dtype='f4')[0]
2589 2602 compara =numpy.sum(abs(y))/elev7/nfree
2590 2603 done_early = chisq1 < compara
2591 2604
2592 2605 if done_early:
2593 2606 chi2 = chisq # Return chi-squared (chi2 obsolete-still works)
2594 2607 if done_early: Niter -= 1
2595 2608 #save_tp(chisq,Niter,yfit)
2596 2609 return yfit, a, converge, sigma, chisq # return result
2597 2610 #c = numpy.dot(c, c) # this operator implemented at the next lines
2598 2611 c_tmp = numpy.sqrt(numpy.diag(alpha))
2599 2612 siz=len(c_tmp)
2600 2613 c=numpy.dot(c_tmp.reshape(siz,1),c_tmp.reshape(1,siz))
2601 2614 lambdaCount = 0
2602 2615 while True:
2603 2616 lambdaCount += 1
2604 2617 # Normalize alpha to have unit diagonal.
2605 2618 array = alpha / c
2606 2619 # Augment the diagonal.
2607 2620 one=numpy.array([1.],dtype='f4')[0]
2608 2621 numpy.fill_diagonal(array,numpy.diag(array)*(one+flambda))
2609 2622 # Invert modified curvature matrix to find new parameters.
2610 2623 try:
2611 2624 array = (1.0/array) if array.size == 1 else numpy.linalg.inv(array)
2612 2625 except Exception as e:
2613 2626 print(e)
2614 2627 array[:]=numpy.NaN
2615 2628
2616 2629 b = a + numpy.dot(numpy.transpose(beta),array/c) # New params
2617 2630 yfit = __GAUSSWINFIT1(b) # Evaluate function
2618 2631 chisq = numpy.sum(Weights*numpy.power(y-yfit,2,dtype='f4'),dtype='f4')/nfree # New chisq
2619 2632 sigma = numpy.sqrt(numpy.diag(array)/numpy.diag(alpha)) # New sigma
2620 2633 if (numpy.isfinite(chisq) == 0) or \
2621 2634 (lambdaCount > 30 and chisq >= chisq1):
2622 2635 # Reject changes made this iteration, use old values.
2623 2636 yfit = yfit1
2624 2637 sigma = sigma1
2625 2638 chisq = chisq1
2626 2639 converge = 0
2627 2640 #print('Failed to converge.')
2628 2641 chi2 = chisq # Return chi-squared (chi2 obsolete-still works)
2629 2642 if done_early: Niter -= 1
2630 2643 #save_tp(chisq,Niter,yfit)
2631 2644 return yfit, a, converge, sigma, chisq, chi2 # return result
2632 2645 ten=numpy.array([10.0],dtype='f4')[0]
2633 2646 flambda *= ten # Assume fit got worse
2634 2647 if chisq <= chisq1:
2635 2648 break
2636 2649 hundred=numpy.array([100.0],dtype='f4')[0]
2637 2650 flambda /= hundred
2638 2651
2639 2652 a=b # Save new parameter estimate.
2640 2653 if ((chisq1-chisq)/chisq1) <= tol: # Finished?
2641 2654 chi2 = chisq # Return chi-squared (chi2 obsolete-still works)
2642 2655 if done_early: Niter -= 1
2643 2656 #save_tp(chisq,Niter,yfit)
2644 2657 return yfit, a, converge, sigma, chisq, chi2 # return result
2645 2658 converge = 0
2646 2659 chi2 = chisq
2647 2660 #print('Failed to converge.')
2648 2661 #save_tp(chisq,Niter,yfit)
2649 2662 return yfit, a, converge, sigma, chisq, chi2
2650 2663
2651 2664 if (nicoh is None): nicoh = 1
2652 2665 if (graph is None): graph = 0
2653 2666 if (smooth is None): smooth = 0
2654 2667 elif (self.smooth < 3): smooth = 0
2655 2668
2656 2669 if (type1 is None): type1 = 0
2657 2670 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
2658 if (snrth is None): snrth = -3 #-20.0
2671 if (snrth is None): snrth = -3
2659 2672 if (dc is None): dc = 0
2660 2673 if (aliasing is None): aliasing = 0
2661 2674 if (oldfd is None): oldfd = 0
2662 2675 if (wwauto is None): wwauto = 0
2663 2676
2664 2677 if (n0 < 1.e-20): n0 = 1.e-20
2665 2678
2666 2679 xvalid = numpy.where(fwindow == 1)[0]
2667 2680 freq = oldfreq
2668 2681 truex = oldfreq
2669 2682 vec_power = numpy.zeros(oldspec.shape[1])
2670 2683 vec_fd = numpy.zeros(oldspec.shape[1])
2671 2684 vec_w = numpy.zeros(oldspec.shape[1])
2672 2685 vec_snr = numpy.zeros(oldspec.shape[1])
2673 2686 vec_n1 = numpy.empty(oldspec.shape[1])
2674 2687 vec_fp = numpy.empty(oldspec.shape[1])
2675 2688 vec_sigma_fd = numpy.empty(oldspec.shape[1])
2676 2689 norm = 1
2677 2690
2678 2691 for ind in range(oldspec.shape[1]):
2679 2692
2680 2693 spec = oldspec[:,ind]
2681 2694 if (smooth == 0):
2682 2695 spec2 = spec
2683 2696 else:
2684 2697 spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
2685 2698
2686 2699 aux = spec2*fwindow
2687 2700 max_spec = aux.max()
2688 2701 m = aux.tolist().index(max_spec)
2689 2702
2690 2703 if hasattr(normFactor, "ndim"):
2691 2704 if normFactor.ndim >= 1:
2692 2705 norm = normFactor[ind]
2693 2706
2694 2707 if m > 2 and m < oldfreq.size - 3:
2695 2708 newindex = m + numpy.array([-2,-1,0,1,2])
2696 2709 newfreq = numpy.arange(20)/20.0*(numpy.max(freq[newindex])-numpy.min(freq[newindex]))+numpy.min(freq[newindex])
2697 2710 #peakspec = SPLINE(,)
2698 2711 tck = interpolate.splrep(freq[newindex], spec2[newindex])
2699 2712 peakspec = interpolate.splev(newfreq, tck)
2700 2713 # max_spec = MAX(peakspec,)
2701 2714 max_spec = numpy.max(peakspec)
2702 2715 mnew = numpy.argmax(peakspec)
2703 2716 #fp = newfreq(mnew)
2704 2717 fp = newfreq[mnew]
2705 2718 else:
2706 2719 fp = freq[m]
2707 2720
2708 2721 if type1==0:
2709 2722
2710 2723 # Moments Estimation
2711 2724 bb = spec2[numpy.arange(m,spec2.size)]
2712 2725 bb = (bb<n0).nonzero()
2713 2726 bb = bb[0]
2714 2727
2715 2728 ss = spec2[numpy.arange(0,m + 1)]
2716 2729 ss = (ss<n0).nonzero()
2717 2730 ss = ss[0]
2718 2731
2719 2732 if (bb.size == 0):
2720 2733 bb0 = spec.size - 1 - m
2721 2734 else:
2722 2735 bb0 = bb[0] - 1
2723 2736 if (bb0 < 0):
2724 2737 bb0 = 0
2725 2738
2726 2739 if (ss.size == 0):
2727 2740 ss1 = 1
2728 2741 else:
2729 2742 ss1 = max(ss) + 1
2730 2743
2731 2744 if (ss1 > m):
2732 2745 ss1 = m
2733 2746
2734 2747 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
2735 2748
2736 2749 signal_power = ((spec2[valid] - n0) * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
2737 2750 total_power = (spec2[valid] * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
2738 2751 power = ((spec2[valid] - n0) * fwindow[valid]).sum()
2739 2752 fd = ((spec2[valid]- n0)*freq[valid] * fwindow[valid]).sum() / power
2740 2753 w = numpy.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum() / power)
2741 2754 spec2 /=(norm) #compensation for sats remove
2742 2755 snr = (spec2.mean()-n0)/n0
2743 2756 if (snr < 1.e-20): snr = 1.e-20
2744 2757
2745 2758 vec_power[ind] = total_power
2746 2759 vec_fd[ind] = fd
2747 2760 vec_w[ind] = w
2748 2761 vec_snr[ind] = snr
2749 2762 else:
2750 2763 # Noise by heights
2751 2764 n1, stdv = self.__get_noise2(spec, nicoh)
2752 2765 # Moments Estimation
2753 2766 bb = spec2[numpy.arange(m,spec2.size)]
2754 2767 bb = (bb<n1).nonzero()
2755 2768 bb = bb[0]
2756 2769
2757 2770 ss = spec2[numpy.arange(0,m + 1)]
2758 2771 ss = (ss<n1).nonzero()
2759 2772 ss = ss[0]
2760 2773
2761 2774 if (bb.size == 0):
2762 2775 bb0 = spec.size - 1 - m
2763 2776 else:
2764 2777 bb0 = bb[0] - 1
2765 2778 if (bb0 < 0):
2766 2779 bb0 = 0
2767 2780
2768 2781 if (ss.size == 0):
2769 2782 ss1 = 1
2770 2783 else:
2771 2784 ss1 = max(ss) + 1
2772 2785
2773 2786 if (ss1 > m):
2774 2787 ss1 = m
2775 2788
2776 2789 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
2777 2790 power = ((spec[valid] - n1)*fwindow[valid]).sum()
2778 2791 fd = ((spec[valid]- n1)*freq[valid]*fwindow[valid]).sum()/power
2779 2792 try:
2780 2793 w = numpy.sqrt(((spec[valid] - n1)*fwindow[valid]*(freq[valid]- fd)**2).sum()/power)
2781 2794 except:
2782 2795 w = float("NaN")
2783 2796 snr = power/(n0*fwindow.sum())
2784 2797 if snr < 1.e-20: snr = 1.e-20
2785 2798
2786 2799 # Here start gaussean adjustment
2787 2800
2788 2801 if snr > numpy.power(10,0.1*snrth):
2789 2802
2790 2803 a = numpy.zeros(4,dtype='f4')
2791 2804 a[0] = snr * n0
2792 2805 a[1] = fd
2793 2806 a[2] = w
2794 2807 a[3] = n0
2795 2808
2796 2809 np = spec.size
2797 2810 aold = a.copy()
2798 2811 spec2 = spec.copy()
2799 2812 oldxvalid = xvalid.copy()
2800 2813
2801 2814 for i in range(2):
2802 2815
2803 2816 ww = 1.0/(numpy.power(spec2,2)/nicoh)
2804 2817 ww[np//2] = 0.0
2805 2818
2806 2819 a = aold.copy()
2807 2820 xvalid = oldxvalid.copy()
2808 2821 #self.show_var(xvalid)
2809 2822
2810 2823 gaussfn = __curvefit_koki(spec[xvalid], a, ww[xvalid])
2811 2824 a = gaussfn[1]
2812 2825 converge = gaussfn[2]
2813 2826
2814 2827 xvalid = numpy.arange(np)
2815 2828 spec2 = __GAUSSWINFIT1(a)
2816 2829
2817 2830 xvalid = oldxvalid.copy()
2818 2831 power = a[0] * np
2819 2832 fd = a[1]
2820 2833 sigma_fd = gaussfn[3][1]
2821 2834 snr = max(power/ (max(a[3],n0) * len(oldxvalid)) * converge, 1e-20)
2822 2835 w = numpy.abs(a[2])
2823 2836 n1 = max(a[3], n0)
2824 2837
2825 2838 #gauss_adj=[fd,w,snr,n1,fp,sigma_fd]
2826 2839 else:
2827 2840 sigma_fd=numpy.nan # to avoid UnboundLocalError: local variable 'sigma_fd' referenced before assignment
2828 2841
2829 2842 vec_fd[ind] = fd
2830 2843 vec_w[ind] = w
2831 2844 vec_snr[ind] = snr
2832 2845 vec_n1[ind] = n1
2833 2846 vec_fp[ind] = fp
2834 2847 vec_sigma_fd[ind] = sigma_fd
2835 2848 vec_power[ind] = power # to compare with type 0 proccessing
2836 2849
2837 2850 if type1==1:
2838 2851 return numpy.vstack((vec_snr, vec_w, vec_fd, vec_n1, vec_fp, vec_sigma_fd, vec_power)) # snr and fd exchanged to compare doppler of both types
2839 2852 else:
2840 2853 return numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
2841 2854
2842 2855 def __get_noise2(self,POWER, fft_avg, TALK=0):
2843 2856 '''
2844 2857 Rutina para cΓ‘lculo de ruido por alturas(n1). Similar a IDL
2845 2858 '''
2846 2859 SPECT_PTS = len(POWER)
2847 2860 fft_avg = fft_avg*1.0
2848 2861 NOMIT = 0
2849 2862 NN = SPECT_PTS - NOMIT
2850 2863 N = NN//2
2851 2864 ARR = numpy.concatenate((POWER[0:N+1],POWER[N+NOMIT+1:SPECT_PTS]))
2852 2865 ARR = numpy.sort(ARR)
2853 2866 NUMS_MIN = (SPECT_PTS+7)//8
2854 2867 RTEST = (1.0+1.0/fft_avg)
2855 2868 SUM = 0.0
2856 2869 SUMSQ = 0.0
2857 2870 J = 0
2858 2871 for I in range(NN):
2859 2872 J = J + 1
2860 2873 SUM = SUM + ARR[I]
2861 2874 SUMSQ = SUMSQ + ARR[I]*ARR[I]
2862 2875 AVE = SUM*1.0/J
2863 2876 if J > NUMS_MIN:
2864 2877 if (SUMSQ*J <= RTEST*SUM*SUM): RNOISE = AVE
2865 2878 else:
2866 2879 if J == NUMS_MIN: RNOISE = AVE
2867 2880 if TALK == 1: print('Noise Power (2):%4.4f' %RNOISE)
2868 2881 stdv = numpy.sqrt(SUMSQ/J - numpy.power(SUM/J,2))
2869 2882 return RNOISE, stdv
2870 2883
2871 2884 def __get_noise1(self, power, fft_avg, TALK=0):
2872 2885 '''
2873 2886 Rutina para cΓ‘lculo de ruido por alturas(n0). Similar a IDL
2874 2887 '''
2875 2888 num_pts = numpy.size(power)
2876 2889 #print('num_pts',num_pts)
2877 2890 #print('power',power.shape)
2878 2891 #print(power[256:267,0:2])
2879 2892 fft_avg = fft_avg*1.0
2880 2893
2881 2894 ind = numpy.argsort(power, axis=None, kind='stable')
2882 2895 #ind = numpy.argsort(numpy.reshape(power,-1))
2883 2896 #print(ind.shape)
2884 2897 #print(ind[0:11])
2885 2898 #print(numpy.reshape(power,-1)[ind[0:11]])
2886 2899 ARR = numpy.reshape(power,-1)[ind]
2887 2900 #print('ARR',len(ARR))
2888 2901 #print('ARR',ARR.shape)
2889 2902 NUMS_MIN = num_pts//10
2890 2903 RTEST = (1.0+1.0/fft_avg)
2891 2904 SUM = 0.0
2892 2905 SUMSQ = 0.0
2893 2906 J = 0
2894 2907 cont = 1
2895 2908 while cont == 1 and J < num_pts:
2896 2909
2897 2910 SUM = SUM + ARR[J]
2898 2911 SUMSQ = SUMSQ + ARR[J]*ARR[J]
2899 2912 J = J + 1
2900 2913
2901 2914 if J > NUMS_MIN:
2902 2915 if (SUMSQ*J <= RTEST*SUM*SUM):
2903 2916 LNOISE = SUM*1.0/J
2904 2917 else:
2905 2918 J = J - 1
2906 2919 SUM = SUM - ARR[J]
2907 2920 SUMSQ = SUMSQ - ARR[J]*ARR[J]
2908 2921 cont = 0
2909 2922 else:
2910 2923 if J == NUMS_MIN: LNOISE = SUM*1.0/J
2911 2924 if TALK == 1: print('Noise Power (1):%8.8f' %LNOISE)
2912 2925 stdv = numpy.sqrt(SUMSQ/J - numpy.power(SUM/J,2))
2913 2926 return LNOISE, stdv
2914 2927
2915 2928 def __NoiseByChannel(self, num_prof, num_incoh, spectra,talk=0):
2916 2929
2917 2930 val_frq = numpy.arange(num_prof-2)+1
2918 2931 val_frq[(num_prof-2)//2:] = val_frq[(num_prof-2)//2:] + 1
2919 2932 junkspc = numpy.sum(spectra[val_frq,:], axis=1)
2920 2933 junkid = numpy.argsort(junkspc)
2921 2934 noisezone = val_frq[junkid[0:num_prof//2]]
2922 2935 specnoise = spectra[noisezone,:]
2923 2936 noise, stdvnoise = self.__get_noise1(specnoise,num_incoh)
2924 2937
2925 2938 if talk:
2926 2939 print('noise =', noise)
2927 2940 return noise
2928 2941 #------------------ Get SA Parameters --------------------------
2929 2942
2930 2943 def GetSAParameters(self):
2931 2944 #SA en frecuencia
2932 2945 pairslist = self.dataOut.groupList
2933 2946 num_pairs = len(pairslist)
2934 2947
2935 2948 vel = self.dataOut.abscissaList
2936 2949 spectra = self.dataOut.data_pre
2937 2950 cspectra = self.dataIn.data_cspc
2938 2951 delta_v = vel[1] - vel[0]
2939 2952
2940 2953 #Calculating the power spectrum
2941 2954 spc_pow = numpy.sum(spectra, 3)*delta_v
2942 2955 #Normalizing Spectra
2943 2956 norm_spectra = spectra/spc_pow
2944 2957 #Calculating the norm_spectra at peak
2945 2958 max_spectra = numpy.max(norm_spectra, 3)
2946 2959
2947 2960 #Normalizing Cross Spectra
2948 2961 norm_cspectra = numpy.zeros(cspectra.shape)
2949 2962
2950 2963 for i in range(num_chan):
2951 2964 norm_cspectra[i,:,:] = cspectra[i,:,:]/numpy.sqrt(spc_pow[pairslist[i][0],:]*spc_pow[pairslist[i][1],:])
2952 2965
2953 2966 max_cspectra = numpy.max(norm_cspectra,2)
2954 2967 max_cspectra_index = numpy.argmax(norm_cspectra, 2)
2955 2968
2956 2969 for i in range(num_pairs):
2957 2970 cspc_par[i,:,:] = __calculateMoments(norm_cspectra)
2958 2971 #------------------- Get Lags ----------------------------------
2959 2972
2960 2973 class JULIADriftsEstimation(Operation):
2961 2974
2962 2975 def __init__(self):
2963 2976 Operation.__init__(self)
2964 2977
2965 2978 def newtotal(self, data):
2966 2979 return numpy.nansum(data)
2967 2980
2968 2981 def data_filter(self, parm, snrth=-20, swth=20, wErrth=500):
2969 2982
2970 2983 Sz0 = parm.shape # Sz0: h,p
2971 2984 drift = parm[:,0]
2972 2985 sw = 2*parm[:,1]
2973 2986 snr = 10*numpy.log10(parm[:,2])
2974 2987 Sz = drift.shape # Sz: h
2975 2988 mask = numpy.ones((Sz[0]))
2976 2989 th=0
2977 2990 valid=numpy.where(numpy.isfinite(snr))
2978 2991 cvalid = len(valid[0])
2979 2992 if cvalid >= 1:
2980 2993 # CΓ‘lculo del ruido promedio de snr para el i-Γ©simo grupo de alturas
2981 2994 nbins = int(numpy.max(snr)-numpy.min(snr))+1 # bin size = 1, similar to IDL
2982 2995 h = numpy.histogram(snr,bins=nbins)
2983 2996 hist = h[0]
2984 2997 values = numpy.round_(h[1])
2985 2998 moda = values[numpy.where(hist == numpy.max(hist))]
2986 2999 indNoise = numpy.where(numpy.abs(snr - numpy.min(moda)) < 3)[0]
2987 3000
2988 3001 noise = snr[indNoise]
2989 3002 noise_mean = numpy.sum(noise)/len(noise)
2990 3003 # CΓ‘lculo de media de snr
2991 3004 med = numpy.median(snr)
2992 3005 # Establece el umbral de snr
2993 3006 if noise_mean > med + 3:
2994 3007 th = med
2995 3008 else:
2996 3009 th = noise_mean + 3
2997 3010 # Establece mΓ‘scara
2998 3011 novalid = numpy.where(snr <= th)[0]
2999 3012 mask[novalid] = numpy.nan
3000 3013 # Elimina datos que no sobrepasen el umbral: PARAMETRO
3001 3014 novalid = numpy.where(snr <= snrth)
3002 3015 cnovalid = len(novalid[0])
3003 3016 if cnovalid > 0:
3004 3017 mask[novalid] = numpy.nan
3005 3018 novalid = numpy.where(numpy.isnan(snr))
3006 3019 cnovalid = len(novalid[0])
3007 3020 if cnovalid > 0:
3008 3021 mask[novalid] = numpy.nan
3009 3022 new_parm = numpy.zeros((Sz0[0],Sz0[1]))
3010 3023 for h in range(Sz0[0]):
3011 3024 for p in range(Sz0[1]):
3012 3025 if numpy.isnan(mask[h]):
3013 3026 new_parm[h,p]=numpy.nan
3014 3027 else:
3015 3028 new_parm[h,p]=parm[h,p]
3016 3029
3017 3030 return new_parm, th
3018 3031
3019 3032 def run(self, dataOut, zenith, zenithCorrection,heights=None, statistics=0, otype=0):
3020 3033
3021 3034 dataOut.lat=-11.95
3022 3035 dataOut.lon=-76.87
3023 3036 nCh=dataOut.spcpar.shape[0]
3024 3037 nHei=dataOut.spcpar.shape[1]
3025 3038 nParam=dataOut.spcpar.shape[2]
3026 3039 # SelecciΓ³n de alturas
3027 3040
3028 3041 if not heights:
3029 3042 parm = numpy.zeros((nCh,nHei,nParam))
3030 3043 parm[:] = dataOut.spcpar[:]
3031 3044 else:
3032 3045 hei=dataOut.heightList
3033 3046 hvalid=numpy.where([hei >= heights[0]][0] & [hei <= heights[1]][0])[0]
3034 3047 nhvalid=len(hvalid)
3035 3048 dataOut.heightList = hei[hvalid]
3036 3049 parm = numpy.zeros((nCh,nhvalid,nParam))
3037 3050 parm[:] = dataOut.spcpar[:,hvalid,:]
3038 3051
3039 3052
3040 3053 # Primer filtrado: Umbral de SNR
3041 3054 for i in range(nCh):
3042 3055 parm[i,:,:] = self.data_filter(parm[i,:,:])[0]
3043 3056
3044 3057 zenith = numpy.array(zenith)
3045 3058 zenith -= zenithCorrection
3046 3059 zenith *= numpy.pi/180
3047 3060 alpha = zenith[0]
3048 3061 beta = zenith[1]
3049 3062 dopplerCH0 = parm[0,:,0]
3050 3063 dopplerCH1 = parm[1,:,0]
3051 3064 swCH0 = parm[0,:,1]
3052 3065 swCH1 = parm[1,:,1]
3053 3066 snrCH0 = 10*numpy.log10(parm[0,:,2])
3054 3067 snrCH1 = 10*numpy.log10(parm[1,:,2])
3055 3068 noiseCH0 = parm[0,:,3]
3056 3069 noiseCH1 = parm[1,:,3]
3057 3070 wErrCH0 = parm[0,:,5]
3058 3071 wErrCH1 = parm[1,:,5]
3059 3072
3060 3073 # Vertical and zonal calculation according to geometry
3061 3074 sinB_A = numpy.sin(beta)*numpy.cos(alpha) - numpy.sin(alpha)* numpy.cos(beta)
3062 3075 drift = -(dopplerCH0 * numpy.sin(beta) - dopplerCH1 * numpy.sin(alpha))/ sinB_A
3063 3076 zonal = (dopplerCH0 * numpy.cos(beta) - dopplerCH1 * numpy.cos(alpha))/ sinB_A
3064 3077 snr = (snrCH0 + snrCH1)/2
3065 3078 noise = (noiseCH0 + noiseCH1)/2
3066 3079 sw = (swCH0 + swCH1)/2
3067 3080 w_w_err= numpy.sqrt(numpy.power(wErrCH0 * numpy.sin(beta)/numpy.abs(sinB_A),2) + numpy.power(wErrCH1 * numpy.sin(alpha)/numpy.abs(sinB_A),2))
3068 3081 w_e_err= numpy.sqrt(numpy.power(wErrCH0 * numpy.cos(beta)/numpy.abs(-1*sinB_A),2) + numpy.power(wErrCH1 * numpy.cos(alpha)/numpy.abs(-1*sinB_A),2))
3069 3082
3070 3083 # for statistics150km
3071 3084 if statistics:
3072 3085 print('Implemented offline.')
3073 3086
3074 3087 if otype == 0:
3075 3088 winds = numpy.vstack((snr, drift, zonal, noise, sw, w_w_err, w_e_err)) # to process statistics drifts
3076 3089 elif otype == 3:
3077 3090 winds = numpy.vstack((snr, drift, zonal)) # to generic plot: 3 RTI's
3078 3091 elif otype == 4:
3079 3092 winds = numpy.vstack((snrCH0, drift, snrCH1, zonal)) # to generic plot: 4 RTI's
3080 3093
3081 3094 snr1 = numpy.vstack((snrCH0, snrCH1))
3082 3095 dataOut.data_output = winds
3083 3096 dataOut.data_snr = snr1
3084 3097
3085 3098 dataOut.utctimeInit = dataOut.utctime
3086 3099 dataOut.outputInterval = dataOut.timeInterval
3087 3100 try:
3088 3101 dataOut.flagNoData = numpy.all(numpy.isnan(dataOut.data_output[0])) # NAN vectors are not written MADRIGAL CASE
3089 3102 except:
3090 3103 print("Check there is no Data")
3091 3104
3092 3105 return dataOut
3093 3106
3094 3107 class SALags(Operation):
3095 3108 '''
3096 3109 Function GetMoments()
3097 3110
3098 3111 Input:
3099 3112 self.dataOut.data_pre
3100 3113 self.dataOut.abscissaList
3101 3114 self.dataOut.noise
3102 3115 self.dataOut.normFactor
3103 3116 self.dataOut.data_snr
3104 3117 self.dataOut.groupList
3105 3118 self.dataOut.nChannels
3106 3119
3107 3120 Affected:
3108 3121 self.dataOut.data_param
3109 3122
3110 3123 '''
3111 3124 def run(self, dataOut):
3112 3125 data_acf = dataOut.data_pre[0]
3113 3126 data_ccf = dataOut.data_pre[1]
3114 3127 normFactor_acf = dataOut.normFactor[0]
3115 3128 normFactor_ccf = dataOut.normFactor[1]
3116 3129 pairs_acf = dataOut.groupList[0]
3117 3130 pairs_ccf = dataOut.groupList[1]
3118 3131
3119 3132 nHeights = dataOut.nHeights
3120 3133 absc = dataOut.abscissaList
3121 3134 noise = dataOut.noise
3122 3135 SNR = dataOut.data_snr
3123 3136 nChannels = dataOut.nChannels
3124 3137 for l in range(len(pairs_acf)):
3125 3138 data_acf[l,:,:] = data_acf[l,:,:]/normFactor_acf[l,:]
3126 3139
3127 3140 for l in range(len(pairs_ccf)):
3128 3141 data_ccf[l,:,:] = data_ccf[l,:,:]/normFactor_ccf[l,:]
3129 3142
3130 3143 dataOut.data_param = numpy.zeros((len(pairs_ccf)*2 + 1, nHeights))
3131 3144 dataOut.data_param[:-1,:] = self.__calculateTaus(data_acf, data_ccf, absc)
3132 3145 dataOut.data_param[-1,:] = self.__calculateLag1Phase(data_acf, absc)
3133 3146 return
3134 3147
3135 3148 def __calculateTaus(self, data_acf, data_ccf, lagRange):
3136 3149
3137 3150 lag0 = data_acf.shape[1]/2
3138 3151 #Funcion de Autocorrelacion
3139 3152 mean_acf = stats.nanmean(data_acf, axis = 0)
3140 3153
3141 3154 #Obtencion Indice de TauCross
3142 3155 ind_ccf = data_ccf.argmax(axis = 1)
3143 3156 #Obtencion Indice de TauAuto
3144 3157 ind_acf = numpy.zeros(ind_ccf.shape,dtype = 'int')
3145 3158 ccf_lag0 = data_ccf[:,lag0,:]
3146 3159
3147 3160 for i in range(ccf_lag0.shape[0]):
3148 3161 ind_acf[i,:] = numpy.abs(mean_acf - ccf_lag0[i,:]).argmin(axis = 0)
3149 3162
3150 3163 #Obtencion de TauCross y TauAuto
3151 3164 tau_ccf = lagRange[ind_ccf]
3152 3165 tau_acf = lagRange[ind_acf]
3153 3166
3154 3167 Nan1, Nan2 = numpy.where(tau_ccf == lagRange[0])
3155 3168
3156 3169 tau_ccf[Nan1,Nan2] = numpy.nan
3157 3170 tau_acf[Nan1,Nan2] = numpy.nan
3158 3171 tau = numpy.vstack((tau_ccf,tau_acf))
3159 3172
3160 3173 return tau
3161 3174
3162 3175 def __calculateLag1Phase(self, data, lagTRange):
3163 3176 data1 = stats.nanmean(data, axis = 0)
3164 3177 lag1 = numpy.where(lagTRange == 0)[0][0] + 1
3165 3178
3166 3179 phase = numpy.angle(data1[lag1,:])
3167 3180
3168 3181 return phase
3169 3182
3170 3183 def fit_func( x, a0, a1, a2): #, a3, a4, a5):
3171 3184 z = (x - a1) / a2
3172 3185 y = a0 * numpy.exp(-z**2 / a2) #+ a3 + a4 * x + a5 * x**2
3173 3186 return y
3174 3187
3175 3188
3176 3189 class SpectralFitting(Operation):
3177 3190 '''
3178 3191 Function GetMoments()
3179 3192
3180 3193 Input:
3181 3194 Output:
3182 3195 Variables modified:
3183 3196 '''
3184 3197 isConfig = False
3185 3198 __dataReady = False
3186 3199 bloques = None
3187 3200 bloque0 = None
3188 3201
3189 3202 def __init__(self):
3190 3203 Operation.__init__(self)
3191 3204 self.i=0
3192 3205 self.isConfig = False
3206 self.aux = 1
3193 3207
3194 3208 def setup(self,nChan,nProf,nHei,nBlocks):
3195 3209 self.__dataReady = False
3196 3210 self.bloques = numpy.zeros([2, nProf, nHei,nBlocks], dtype= complex)
3197 3211 self.bloque0 = numpy.zeros([nChan, nProf, nHei, nBlocks])
3198 3212
3199 3213 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):
3200 3214
3201 3215 if (nicoh is None): nicoh = 1
3202 3216 if (graph is None): graph = 0
3203 3217 if (smooth is None): smooth = 0
3204 3218 elif (self.smooth < 3): smooth = 0
3205 3219
3206 3220 if (type1 is None): type1 = 0
3207 3221 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
3208 3222 if (snrth is None): snrth = -3
3209 3223 if (dc is None): dc = 0
3210 3224 if (aliasing is None): aliasing = 0
3211 3225 if (oldfd is None): oldfd = 0
3212 3226 if (wwauto is None): wwauto = 0
3213 3227
3214 3228 if (n0 < 1.e-20): n0 = 1.e-20
3229
3215 3230 freq = oldfreq
3216 3231 vec_power = numpy.zeros(oldspec.shape[1])
3217 3232 vec_fd = numpy.zeros(oldspec.shape[1])
3218 3233 vec_w = numpy.zeros(oldspec.shape[1])
3219 3234 vec_snr = numpy.zeros(oldspec.shape[1])
3220 3235 oldspec = numpy.ma.masked_invalid(oldspec)
3221 3236
3222 3237 for ind in range(oldspec.shape[1]):
3223 3238 spec = oldspec[:,ind]
3224 3239 aux = spec*fwindow
3225 3240 max_spec = aux.max()
3226 3241 m = list(aux).index(max_spec)
3227 3242 #Smooth
3228 3243 if (smooth == 0): spec2 = spec
3229 3244 else: spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
3230 3245
3231 3246 # Calculo de Momentos
3232 3247 bb = spec2[list(range(m,spec2.size))]
3233 3248 bb = (bb<n0).nonzero()
3234 3249 bb = bb[0]
3235 3250
3236 3251 ss = spec2[list(range(0,m + 1))]
3237 3252 ss = (ss<n0).nonzero()
3238 3253 ss = ss[0]
3239 3254
3240 3255 if (bb.size == 0):
3241 3256 bb0 = spec.size - 1 - m
3242 3257 else:
3243 3258 bb0 = bb[0] - 1
3244 3259 if (bb0 < 0):
3245 3260 bb0 = 0
3246 3261
3247 3262 if (ss.size == 0): ss1 = 1
3248 3263 else: ss1 = max(ss) + 1
3249 3264
3250 3265 if (ss1 > m): ss1 = m
3251 3266
3252 3267 valid = numpy.asarray(list(range(int(m + bb0 - ss1 + 1)))) + ss1
3253 3268 power = ((spec2[valid] - n0)*fwindow[valid]).sum()
3254 3269 fd = ((spec2[valid]- n0)*freq[valid]*fwindow[valid]).sum()/power
3255 3270 w = math.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum()/power)
3256 3271 snr = (spec2.mean()-n0)/n0
3257 3272
3258 3273 if (snr < 1.e-20) :
3259 3274 snr = 1.e-20
3260 3275
3261 3276 vec_power[ind] = power
3262 3277 vec_fd[ind] = fd
3263 3278 vec_w[ind] = w
3264 3279 vec_snr[ind] = snr
3265 3280
3266 3281 moments = numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
3267 3282 return moments
3268 3283
3269 3284 def __DiffCoherent(self, spectra, cspectra, dataOut, noise, snrth, coh_th, hei_th):
3270 3285
3271 3286 nProf = dataOut.nProfiles
3272 3287 heights = dataOut.heightList
3273 3288 nHei = len(heights)
3274 3289 channels = dataOut.channelList
3275 3290 nChan = len(channels)
3276 3291 crosspairs = dataOut.groupList
3277 3292 nPairs = len(crosspairs)
3278 3293 #Separar espectros incoherentes de coherentes snr > 20 dB'
3279 3294 snr_th = 10**(snrth/10.0)
3280 3295 my_incoh_spectra = numpy.zeros([nChan, nProf,nHei], dtype='float')
3281 3296 my_incoh_cspectra = numpy.zeros([nPairs,nProf, nHei], dtype='complex')
3282 3297 my_incoh_aver = numpy.zeros([nChan, nHei])
3283 3298 my_coh_aver = numpy.zeros([nChan, nHei])
3284 3299
3285 3300 coh_spectra = numpy.zeros([nChan, nProf, nHei], dtype='float')
3286 3301 coh_cspectra = numpy.zeros([nPairs, nProf, nHei], dtype='complex')
3287 3302 coh_aver = numpy.zeros([nChan, nHei])
3288 3303
3289 3304 incoh_spectra = numpy.zeros([nChan, nProf, nHei], dtype='float')
3290 3305 incoh_cspectra = numpy.zeros([nPairs, nProf, nHei], dtype='complex')
3291 3306 incoh_aver = numpy.zeros([nChan, nHei])
3292 3307 power = numpy.sum(spectra, axis=1)
3293 3308
3294 3309 if coh_th == None : coh_th = numpy.array([0.75,0.65,0.15]) # 0.65
3295 3310 if hei_th == None : hei_th = numpy.array([60,300,650])
3296 3311 for ic in range(nPairs):
3297 3312 pair = crosspairs[ic]
3298 3313 #si el SNR es mayor que el SNR threshold los datos se toman coherentes
3299 3314 s_n0 = power[pair[0],:]/noise[pair[0]]
3300 3315 s_n1 = power[pair[1],:]/noise[pair[1]]
3301 3316 valid1 =(s_n0>=snr_th).nonzero()
3302 3317 valid2 = (s_n1>=snr_th).nonzero()
3303 3318 valid1 = numpy.array(valid1[0])
3304 3319 valid2 = numpy.array(valid2[0])
3305 3320 valid = valid1
3306 3321 for iv in range(len(valid2)):
3307 3322 indv = numpy.array((valid1 == valid2[iv]).nonzero())
3308 3323 if len(indv[0]) == 0 :
3309 3324 valid = numpy.concatenate((valid,valid2[iv]), axis=None)
3310 3325 if len(valid)>0:
3311 3326 my_coh_aver[pair[0],valid]=1
3312 3327 my_coh_aver[pair[1],valid]=1
3313 3328 # si la coherencia es mayor a la coherencia threshold los datos se toman
3314 3329 coh = numpy.squeeze(numpy.nansum(cspectra[ic,:,:], axis=0)/numpy.sqrt(numpy.nansum(spectra[pair[0],:,:], axis=0)*numpy.nansum(spectra[pair[1],:,:], axis=0)))
3315 3330 for ih in range(len(hei_th)):
3316 3331 hvalid = (heights>hei_th[ih]).nonzero()
3317 3332 hvalid = hvalid[0]
3318 3333 if len(hvalid)>0:
3319 3334 valid = (numpy.absolute(coh[hvalid])>coh_th[ih]).nonzero()
3320 3335 valid = valid[0]
3321 3336 if len(valid)>0:
3322 3337 my_coh_aver[pair[0],hvalid[valid]] =1
3323 3338 my_coh_aver[pair[1],hvalid[valid]] =1
3324 3339
3325 3340 coh_echoes = (my_coh_aver[pair[0],:] == 1).nonzero()
3326 3341 incoh_echoes = (my_coh_aver[pair[0],:] != 1).nonzero()
3327 3342 incoh_echoes = incoh_echoes[0]
3328 3343 if len(incoh_echoes) > 0:
3329 3344 my_incoh_spectra[pair[0],:,incoh_echoes] = spectra[pair[0],:,incoh_echoes]
3330 3345 my_incoh_spectra[pair[1],:,incoh_echoes] = spectra[pair[1],:,incoh_echoes]
3331 3346 my_incoh_cspectra[ic,:,incoh_echoes] = cspectra[ic,:,incoh_echoes]
3332 3347 my_incoh_aver[pair[0],incoh_echoes] = 1
3333 3348 my_incoh_aver[pair[1],incoh_echoes] = 1
3334 3349
3335 3350
3336 3351 for ic in range(nPairs):
3337 3352 pair = crosspairs[ic]
3338 3353
3339 3354 valid1 =(my_coh_aver[pair[0],:]==1 ).nonzero()
3340 3355 valid2 = (my_coh_aver[pair[1],:]==1).nonzero()
3341 3356 valid1 = numpy.array(valid1[0])
3342 3357 valid2 = numpy.array(valid2[0])
3343 3358 valid = valid1
3344 3359
3345 3360 for iv in range(len(valid2)):
3346 3361
3347 3362 indv = numpy.array((valid1 == valid2[iv]).nonzero())
3348 3363 if len(indv[0]) == 0 :
3349 3364 valid = numpy.concatenate((valid,valid2[iv]), axis=None)
3350 3365 valid1 =(my_coh_aver[pair[0],:] !=1 ).nonzero()
3351 3366 valid2 = (my_coh_aver[pair[1],:] !=1).nonzero()
3352 3367 valid1 = numpy.array(valid1[0])
3353 3368 valid2 = numpy.array(valid2[0])
3354 3369 incoh_echoes = valid1
3355 3370 for iv in range(len(valid2)):
3356 3371
3357 3372 indv = numpy.array((valid1 == valid2[iv]).nonzero())
3358 3373 if len(indv[0]) == 0 :
3359 3374 incoh_echoes = numpy.concatenate(( incoh_echoes,valid2[iv]), axis=None)
3360 3375
3361 3376 if len(valid)>0:
3362 3377 coh_spectra[pair[0],:,valid] = spectra[pair[0],:,valid]
3363 3378 coh_spectra[pair[1],:,valid] = spectra[pair[1],:,valid]
3364 3379 coh_cspectra[ic,:,valid] = cspectra[ic,:,valid]
3365 3380 coh_aver[pair[0],valid]=1
3366 3381 coh_aver[pair[1],valid]=1
3367 3382 if len(incoh_echoes)>0:
3368 3383 incoh_spectra[pair[0],:,incoh_echoes] = spectra[pair[0],:,incoh_echoes]
3369 3384 incoh_spectra[pair[1],:,incoh_echoes] = spectra[pair[1],:,incoh_echoes]
3370 3385 incoh_cspectra[ic,:,incoh_echoes] = cspectra[ic,:,incoh_echoes]
3371 3386 incoh_aver[pair[0],incoh_echoes]=1
3372 3387 incoh_aver[pair[1],incoh_echoes]=1
3373 3388
3374 3389 return my_incoh_spectra ,my_incoh_cspectra,my_incoh_aver,my_coh_aver, incoh_spectra, coh_spectra, incoh_cspectra, coh_cspectra, incoh_aver, coh_aver
3375 3390
3376 3391 def __CleanCoherent(self,snrth, spectra, cspectra, coh_aver,dataOut, noise,clean_coh_echoes,index):
3377 3392
3378 3393 nProf = dataOut.nProfiles
3379 3394 heights = dataOut.heightList
3380 3395 nHei = len(heights)
3381 3396 channels = dataOut.channelList
3382 3397 nChan = len(channels)
3383 3398 crosspairs = dataOut.groupList
3384 3399 nPairs = len(crosspairs)
3385 3400
3386 3401 absc = dataOut.abscissaList[:-1]
3387 3402 data_param = numpy.zeros((nChan, 4, spectra.shape[2]))
3388 3403
3389 3404 clean_coh_spectra = spectra.copy()
3390 3405 clean_coh_cspectra = cspectra.copy()
3391 3406 clean_coh_aver = coh_aver.copy()
3392 3407
3393 3408 spwd_th=[10,6] #spwd_th[0] --> For satellites ; spwd_th[1] --> For special events like SUN.
3394 3409 coh_th = 0.75
3395 3410
3396 3411 rtime0 = [6,18] # periodo sin ESF
3397 3412 rtime1 = [10.5,13.5] # periodo con alta coherencia y alto ancho espectral (esperado): SOL.
3398 3413
3399 3414 time = index*5./60 # en base a 5 min de proceso
3400 3415 if clean_coh_echoes == 1 :
3401 3416 for ind in range(nChan):
3402 3417 data_param[ind,:,:] = self.__calculateMoments( spectra[ind,:,:] , absc , noise[ind] )
3403 3418 spwd = data_param[:,3]
3404 3419 # SPECB_JULIA,header=anal_header,jspectra=spectra,vel=velocities,hei=heights, num_aver=1, mode_fit=0,smoothing=smoothing,jvelr=velr,jspwd=spwd,jsnr=snr,jnoise=noise,jstdvnoise=stdvnoise
3405 3420 # para obtener spwd
3406 3421 for ic in range(nPairs):
3407 3422 pair = crosspairs[ic]
3408 3423 coh = numpy.squeeze(numpy.sum(cspectra[ic,:,:], axis=1)/numpy.sqrt(numpy.sum(spectra[pair[0],:,:], axis=1)*numpy.sum(spectra[pair[1],:,:], axis=1)))
3409 3424 for ih in range(nHei) :
3410 3425 # Considering heights higher than 200km in order to avoid removing phenomena like EEJ.
3411 3426 if heights[ih] >= 200 and coh_aver[pair[0],ih] == 1 and coh_aver[pair[1],ih] == 1 :
3412 3427 # Checking coherence
3413 3428 if (numpy.abs(coh[ih]) <= coh_th) or (time >= rtime0[0] and time <= rtime0[1]) :
3414 3429 # Checking spectral widths
3415 3430 if (spwd[pair[0],ih] > spwd_th[0]) or (spwd[pair[1],ih] > spwd_th[0]) :
3416 3431 # satelite
3417 3432 clean_coh_spectra[pair,:,ih] = 0.0
3418 3433 clean_coh_cspectra[ic,:,ih] = 0.0
3419 3434 clean_coh_aver[pair,ih] = 0
3420 3435 else :
3421 3436 if ((spwd[pair[0],ih] < spwd_th[1]) or (spwd[pair[1],ih] < spwd_th[1])) :
3422 3437 # Especial event like sun.
3423 3438 clean_coh_spectra[pair,:,ih] = 0.0
3424 3439 clean_coh_cspectra[ic,:,ih] = 0.0
3425 3440 clean_coh_aver[pair,ih] = 0
3426 3441
3427 3442 return clean_coh_spectra, clean_coh_cspectra, clean_coh_aver
3428 3443
3429 3444 def CleanRayleigh(self,dataOut,spectra,cspectra,save_drifts):
3430 3445
3431 3446 rfunc = cspectra.copy()
3432 3447 n_funct = len(rfunc[0,:,0,0])
3433 3448 val_spc = spectra*0.0
3434 3449 val_cspc = cspectra*0.0
3435 3450 in_sat_spectra = spectra.copy()
3436 3451 in_sat_cspectra = cspectra.copy()
3437 3452
3438 3453 min_hei = 200
3439 3454 nProf = dataOut.nProfiles
3440 3455 heights = dataOut.heightList
3441 3456 nHei = len(heights)
3442 3457 channels = dataOut.channelList
3443 3458 nChan = len(channels)
3444 3459 crosspairs = dataOut.groupList
3445 3460 nPairs = len(crosspairs)
3446 3461 hval=(heights >= min_hei).nonzero()
3447 3462 ih=hval[0]
3448 3463
3449 3464 for ih in range(hval[0][0],nHei):
3450 3465 for ifreq in range(nProf):
3451 3466 for ii in range(n_funct):
3452 3467
3453 3468 func2clean = 10*numpy.log10(numpy.absolute(rfunc[:,ii,ifreq,ih]))
3454 3469 val = (numpy.isfinite(func2clean)==True).nonzero()
3455 3470 if len(val)>0:
3456 3471 min_val = numpy.around(numpy.amin(func2clean)-2) #> (-40)
3457 3472 if min_val <= -40 : min_val = -40
3458 3473 max_val = numpy.around(numpy.amax(func2clean)+2) #< 200
3459 3474 if max_val >= 200 : max_val = 200
3460 3475 step = 1
3461 3476 #Getting bins and the histogram
3462 3477 x_dist = min_val + numpy.arange(1 + ((max_val-(min_val))/step))*step
3463 3478 y_dist,binstep = numpy.histogram(func2clean,bins=range(int(min_val),int(max_val+2),step))
3464 3479 mean = numpy.sum(x_dist * y_dist) / numpy.sum(y_dist)
3465 3480 sigma = numpy.sqrt(numpy.sum(y_dist * (x_dist - mean)**2) / numpy.sum(y_dist))
3466 3481 parg = [numpy.amax(y_dist),mean,sigma]
3467 3482 try :
3468 3483 gauss_fit, covariance = curve_fit(fit_func, x_dist, y_dist,p0=parg)
3469 3484 mode = gauss_fit[1]
3470 3485 stdv = gauss_fit[2]
3471 3486 except:
3472 3487 mode = mean
3473 3488 stdv = sigma
3474 3489
3475 3490 #Removing echoes greater than mode + 3*stdv
3476 3491 factor_stdv = 2.5
3477 3492 noval = (abs(func2clean - mode)>=(factor_stdv*stdv)).nonzero()
3478 3493
3479 3494 if len(noval[0]) > 0:
3480 3495 novall = ((func2clean - mode) >= (factor_stdv*stdv)).nonzero()
3481 3496 cross_pairs = crosspairs[ii]
3482 3497 #Getting coherent echoes which are removed.
3483 3498 if len(novall[0]) > 0:
3484 3499 val_spc[novall[0],cross_pairs[0],ifreq,ih] = 1
3485 3500 val_spc[novall[0],cross_pairs[1],ifreq,ih] = 1
3486 3501 val_cspc[novall[0],ii,ifreq,ih] = 1
3487 3502 #Removing coherent from ISR data
3488 3503 spectra[noval,cross_pairs[0],ifreq,ih] = numpy.nan
3489 3504 spectra[noval,cross_pairs[1],ifreq,ih] = numpy.nan
3490 3505 cspectra[noval,ii,ifreq,ih] = numpy.nan
3491 3506
3492 3507 #Getting average of the spectra and cross-spectra from incoherent echoes.
3493 3508 out_spectra = numpy.zeros([nChan,nProf,nHei], dtype=float) #+numpy.nan
3494 3509 out_cspectra = numpy.zeros([nPairs,nProf,nHei], dtype=complex) #+numpy.nan
3495 3510 for ih in range(nHei):
3496 3511 for ifreq in range(nProf):
3497 3512 for ich in range(nChan):
3498 3513 tmp = spectra[:,ich,ifreq,ih]
3499 3514 valid = (numpy.isfinite(tmp[:])==True).nonzero()
3500 3515 if len(valid[0]) >0 :
3501 3516 out_spectra[ich,ifreq,ih] = numpy.nansum(tmp)/len(valid[0])
3502 3517
3503 3518 for icr in range(nPairs):
3504 3519 tmp = numpy.squeeze(cspectra[:,icr,ifreq,ih])
3505 3520 valid = (numpy.isfinite(tmp)==True).nonzero()
3506 3521 if len(valid[0]) > 0:
3507 3522 out_cspectra[icr,ifreq,ih] = numpy.nansum(tmp)/len(valid[0])
3508 3523 #Removing fake coherent echoes (at least 4 points around the point)
3509 3524 val_spectra = numpy.sum(val_spc,0)
3510 3525 val_cspectra = numpy.sum(val_cspc,0)
3511 3526
3512 3527 val_spectra = self.REM_ISOLATED_POINTS(val_spectra,4)
3513 3528 val_cspectra = self.REM_ISOLATED_POINTS(val_cspectra,4)
3514 3529
3515 3530 for i in range(nChan):
3516 3531 for j in range(nProf):
3517 3532 for k in range(nHei):
3518 3533 if numpy.isfinite(val_spectra[i,j,k]) and val_spectra[i,j,k] < 1 :
3519 3534 val_spc[:,i,j,k] = 0.0
3520 3535 for i in range(nPairs):
3521 3536 for j in range(nProf):
3522 3537 for k in range(nHei):
3523 3538 if numpy.isfinite(val_cspectra[i,j,k]) and val_cspectra[i,j,k] < 1 :
3524 3539 val_cspc[:,i,j,k] = 0.0
3525 3540
3526 3541 tmp_sat_spectra = spectra.copy()
3527 3542 tmp_sat_spectra = tmp_sat_spectra*numpy.nan
3528 3543 tmp_sat_cspectra = cspectra.copy()
3529 3544 tmp_sat_cspectra = tmp_sat_cspectra*numpy.nan
3530 3545
3531 3546 val = (val_spc > 0).nonzero()
3532 3547 if len(val[0]) > 0:
3533 3548 tmp_sat_spectra[val] = in_sat_spectra[val]
3534 3549
3535 3550 val = (val_cspc > 0).nonzero()
3536 3551 if len(val[0]) > 0:
3537 3552 tmp_sat_cspectra[val] = in_sat_cspectra[val]
3538 3553
3539 3554 #Getting average of the spectra and cross-spectra from incoherent echoes.
3540 3555 sat_spectra = numpy.zeros((nChan,nProf,nHei), dtype=float)
3541 3556 sat_cspectra = numpy.zeros((nPairs,nProf,nHei), dtype=complex)
3542 3557 for ih in range(nHei):
3543 3558 for ifreq in range(nProf):
3544 3559 for ich in range(nChan):
3545 3560 tmp = numpy.squeeze(tmp_sat_spectra[:,ich,ifreq,ih])
3546 3561 valid = (numpy.isfinite(tmp)).nonzero()
3547 3562 if len(valid[0]) > 0:
3548 3563 sat_spectra[ich,ifreq,ih] = numpy.nansum(tmp)/len(valid[0])
3549 3564
3550 3565 for icr in range(nPairs):
3551 3566 tmp = numpy.squeeze(tmp_sat_cspectra[:,icr,ifreq,ih])
3552 3567 valid = (numpy.isfinite(tmp)).nonzero()
3553 3568 if len(valid[0]) > 0:
3554 3569 sat_cspectra[icr,ifreq,ih] = numpy.nansum(tmp)/len(valid[0])
3555 3570
3556 3571 return out_spectra, out_cspectra,sat_spectra,sat_cspectra
3557 3572
3558 3573 def REM_ISOLATED_POINTS(self,array,rth):
3559 3574 if rth == None : rth = 4
3560 3575 num_prof = len(array[0,:,0])
3561 3576 num_hei = len(array[0,0,:])
3562 3577 n2d = len(array[:,0,0])
3563 3578
3564 3579 for ii in range(n2d) :
3565 3580 tmp = array[ii,:,:]
3566 3581 tmp = numpy.reshape(tmp,num_prof*num_hei)
3567 3582 indxs1 = (numpy.isfinite(tmp)==True).nonzero()
3568 3583 indxs2 = (tmp > 0).nonzero()
3569 3584 indxs1 = (indxs1[0])
3570 3585 indxs2 = indxs2[0]
3571 3586 indxs = None
3572 3587
3573 3588 for iv in range(len(indxs2)):
3574 3589 indv = numpy.array((indxs1 == indxs2[iv]).nonzero())
3575 3590 if len(indv[0]) > 0 :
3576 3591 indxs = numpy.concatenate((indxs,indxs2[iv]), axis=None)
3577 3592
3578 3593 indxs = indxs[1:]
3579 3594 if len(indxs) < 4 :
3580 3595 array[ii,:,:] = 0.
3581 3596 return
3582 3597
3583 3598 xpos = numpy.mod(indxs ,num_prof)
3584 3599 ypos = (indxs / num_prof)
3585 3600 sx = numpy.argsort(xpos) # Ordering respect to "x" (time)
3586 3601 xpos = xpos[sx]
3587 3602 ypos = ypos[sx]
3588 3603
3589 3604 # *********************************** Cleaning isolated points **********************************
3590 3605 ic = 0
3591 3606 while True :
3592 3607 r = numpy.sqrt(list(numpy.power((xpos[ic]-xpos),2)+ numpy.power((ypos[ic]-ypos),2)))
3593 3608
3594 3609 no_coh1 = (numpy.isfinite(r)==True).nonzero()
3595 3610 no_coh2 = (r <= rth).nonzero()
3596 3611 no_coh1 = numpy.array(no_coh1[0])
3597 3612 no_coh2 = numpy.array(no_coh2[0])
3598 3613 no_coh = None
3599 3614 for iv in range(len(no_coh2)):
3600 3615 indv = numpy.array((no_coh1 == no_coh2[iv]).nonzero())
3601 3616 if len(indv[0]) > 0 :
3602 3617 no_coh = numpy.concatenate((no_coh,no_coh2[iv]), axis=None)
3603 3618 no_coh = no_coh[1:]
3604 3619 if len(no_coh) < 4 :
3605 3620 xpos[ic] = numpy.nan
3606 3621 ypos[ic] = numpy.nan
3607 3622
3608 3623 ic = ic + 1
3609 3624 if (ic == len(indxs)) :
3610 3625 break
3611 3626 indxs = (numpy.isfinite(list(xpos))==True).nonzero()
3612 3627 if len(indxs[0]) < 4 :
3613 3628 array[ii,:,:] = 0.
3614 3629 return
3615 3630
3616 3631 xpos = xpos[indxs[0]]
3617 3632 ypos = ypos[indxs[0]]
3618 3633 for i in range(0,len(ypos)):
3619 3634 ypos[i]=int(ypos[i])
3620 3635 junk = tmp
3621 3636 tmp = junk*0.0
3622 3637
3623 tmp[list(xpos + (ypos*num_hei))] = junk[list(xpos + (ypos*num_hei))]
3638 tmp[list(xpos + (ypos*num_prof))] = junk[list(xpos + (ypos*num_prof))]
3624 3639 array[ii,:,:] = numpy.reshape(tmp,(num_prof,num_hei))
3625 3640
3626 3641 return array
3627 3642
3628 3643 def moments(self,doppler,yarray,npoints):
3629 3644 ytemp = yarray
3630 3645 val = (ytemp > 0).nonzero()
3631 3646 val = val[0]
3632 3647 if len(val) == 0 : val = range(npoints-1)
3633 3648
3634 3649 ynew = 0.5*(ytemp[val[0]]+ytemp[val[len(val)-1]])
3635 3650 ytemp[len(ytemp):] = [ynew]
3636 3651
3637 3652 index = 0
3638 3653 index = numpy.argmax(ytemp)
3639 3654 ytemp = numpy.roll(ytemp,int(npoints/2)-1-index)
3640 3655 ytemp = ytemp[0:npoints-1]
3641 3656
3642 3657 fmom = numpy.sum(doppler*ytemp)/numpy.sum(ytemp)+(index-(npoints/2-1))*numpy.abs(doppler[1]-doppler[0])
3643 3658 smom = numpy.sum(doppler*doppler*ytemp)/numpy.sum(ytemp)
3644 3659 return [fmom,numpy.sqrt(smom)]
3645 3660
3661 def find_max_excluding_neighbors_and_borders(self,matrix):
3662 n, m = matrix.shape # Dimensions of the matrix
3663 if n < 3 or m < 3:
3664 raise ValueError("Matrix too small to exclude borders and neighbors of NaN.")
3665
3666 # Create a mask for the borders
3667 border_mask = numpy.zeros_like(matrix, dtype=bool)
3668 border_mask[0, :] = True # Top border
3669 border_mask[-1, :] = True # Bottom border
3670 border_mask[:, 0] = True # Left border
3671 border_mask[:, -1] = True # Right border
3672
3673 # Exclude elements within 3 indices from the border
3674 three_index_border_mask = numpy.zeros_like(matrix, dtype=bool)
3675 three_index_border_mask[0:3, :] = True # Top 3 rows
3676 three_index_border_mask[-3:, :] = True # Bottom 3 rows
3677 three_index_border_mask[:, 0:3] = True # Left 3 columns
3678 three_index_border_mask[:, -3:] = True # Right 3 columns
3679
3680 # Create a mask for neighbors of NaNs
3681 nan_mask = numpy.isnan(matrix)
3682 nan_neighbors_mask = numpy.zeros_like(matrix, dtype=bool)
3683 for i in range(1, n - 1):
3684 for j in range(1, m - 1):
3685 if nan_mask[i-1:i+2, j-1:j+2].any(): # Check 3x3 region around (i, j)
3686 nan_neighbors_mask[i, j] = True
3687
3688 # Combine all masks (borders, 3 indices from border, and NaN neighbors)
3689 combined_mask = border_mask | three_index_border_mask | nan_neighbors_mask
3690
3691 # Exclude these positions from the matrix
3692 valid_matrix = numpy.where(combined_mask, numpy.nan, matrix)
3693
3694 # Find the maximum value index in the valid matrix
3695 if numpy.isnan(valid_matrix).all():
3696 return None # No valid maximum
3697 max_index = numpy.unravel_index(numpy.nanargmax(valid_matrix), matrix.shape)
3698 return max_index, valid_matrix
3699
3700 def construct_three_phase_path(self,maximas_2, max_index):
3701 """
3702 Constructs a path through maximas_2 starting from the middle point (max_index)
3703 and going downwards, passing through the starting point, and then going upwards.
3704
3705 Parameters:
3706 - maximas_2 (numpy.ndarray): 2D array of points.
3707 - max_index (tuple): Starting position as (row_index, starting_value).
3708
3709 Returns:
3710 - list: A path of points in the three phases: down, through the start, then up.
3711 """
3712 row_index, starting_value = max_index
3713 path = []
3714 # Initialize the path with the starting value
3715 path_o = [starting_value]
3716 path_up = []
3717 path_dw = []
3718 threshold = 4
3719 flag_broken = 0
3720 print(row_index,maximas_2.shape[0])
3721 # Phase 1: Going downwards (rows below the starting point)
3722 current_value = starting_value
3723 for i in range(row_index + 1, maximas_2.shape[0]):
3724
3725 if flag_broken == 1:
3726 path_up.append(numpy.nan)
3727 continue
3728
3729 distances = numpy.abs(maximas_2[i] - current_value)
3730 closest_index = numpy.argmin(distances)
3731
3732 if numpy.nanmin(distances) > threshold:
3733 path_up.append(numpy.nan)
3734 flag_broken = 1
3735 continue
3736
3737 current_value = maximas_2[i, closest_index]
3738 path_up.append(current_value)
3739
3740 flag_broken = 0
3741
3742 # Phase 2: Going upwards (rows above the starting point)
3743 current_value = starting_value
3744 for i in range(row_index - 1, -1, -1):
3745 if flag_broken == 1:
3746 path_dw.append(numpy.nan)
3747 continue
3748 distances = numpy.abs(maximas_2[i] - current_value)
3749 closest_index = numpy.argmin(distances)
3750
3751 if numpy.nanmin(distances) > threshold:
3752 path_dw.append(numpy.nan)
3753 flag_broken = 1
3754 continue
3755
3756 current_value = maximas_2[i, closest_index]
3757 path_dw.append(current_value)
3758 path.append(path_dw[::-1])
3759 path.append(path_o)
3760 path.append(path_up)
3761 return numpy.concatenate(path)
3762
3763 def Vr_correction(self,dataset):
3764
3765 dataset = savgol_filter(dataset, window_length=15, polyorder=3, axis=1)
3766 dataset = savgol_filter(dataset, window_length=15, polyorder=3, axis=1)
3767 dataset = savgol_filter(dataset, window_length=7, polyorder=3, axis=0)
3768 dataset[:12,:] = numpy.nan
3769 dataset[45:, :] = numpy.nan
3770 max_index, _ = self.find_max_excluding_neighbors_and_borders(dataset)
3771 max_index = numpy.array(max_index)
3772 print(max_index)
3773 maximas = argrelextrema(dataset, numpy.greater, axis=1)
3774 heighs = numpy.unique(maximas[0])
3775 #grouped_arrays = {value: maximas[0][numpy.where(maximas[0] == value)] for value in numpy.unique(maximas[0])}
3776 grouped_arrays = [maximas[0][numpy.where(maximas[0] == value)] for value in numpy.unique(maximas[0])]
3777
3778 maximas_2_list = []
3779 num_maximas = 3
3780 for i, h in enumerate(heighs):
3781 n = len(grouped_arrays[i])
3782 idx = numpy.where(maximas[0] == h)[0]
3783 maxs_ = numpy.argsort(dataset[h, maximas[1][idx]])[::-1][:num_maximas]
3784 maxs = maximas[1][idx][maxs_]
3785 heigh = numpy.ones(len(maxs)) * h
3786 arr = numpy.array([heigh, maxs])
3787 if n < num_maximas:
3788 arr = numpy.hstack((arr, numpy.full((arr.shape[0], num_maximas - arr.shape[1]), numpy.nan)))
3789 maximas_2_list.append(arr)
3790
3791 maximas_2 = numpy.array(maximas_2_list)
3792 _maximas_2_ = maximas_2[:, 1]
3793 #
3794 max_index[0] = numpy.where(heighs == max_index[0])[0][0]
3795 #
3796 path = self.construct_three_phase_path(_maximas_2_, max_index)
3797 return int(numpy.nanmedian(path))
3798
3799
3800
3646 3801 def windowing_single_old(self,spc,x,A,B,C,D,nFFTPoints):
3647 3802 '''
3648 3803 Written by R. Flores
3649 3804 '''
3650 3805 from scipy.optimize import curve_fit,fmin
3651 3806
3652 3807 def gaussian(x, a, b, c, d):
3653 3808 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
3654 3809 return val
3655 3810
3656 3811 def R_gaussian(x, a, b, c):
3657 3812 N = int(numpy.shape(x)[0])
3658 3813 val = a * numpy.exp(-((x)*c*2*2*numpy.pi)**2 / (2))* numpy.exp(1.j*b*x*4*numpy.pi)
3659 3814 return val
3660 3815
3661 3816 def T(x,N):
3662 3817 T = 1-abs(x)/N
3663 3818 return T
3664 3819
3665 3820 def R_T_spc_fun(x, a, b, c, d, nFFTPoints):
3666 3821
3667 3822 N = int(numpy.shape(x)[0])
3668 3823
3669 3824 x_max = x[-1]
3670 3825
3671 3826 x_pos = x[nFFTPoints:]
3672 3827 x_neg = x[:nFFTPoints]
3673 3828
3674 3829 R_T_neg_1 = R_gaussian(x, a, b, c)[:nFFTPoints]*T(x_neg,-x[0])
3675 3830 R_T_pos_1 = R_gaussian(x, a, b, c)[nFFTPoints:]*T(x_pos,x[-1])
3676 3831 #print(T(x_pos,x[-1]),x_pos,x[-1])
3677 3832 #print(R_T_neg_1.shape,R_T_pos_1.shape)
3678 3833 R_T_sum_1 = R_T_pos_1 + R_T_neg_1
3679 3834 R_T_spc_1 = numpy.fft.fft(R_T_sum_1).real
3680 3835 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
3681 3836 max_val_1 = numpy.max(R_T_spc_1)
3682 3837 R_T_spc_1 = R_T_spc_1*a/max_val_1
3683 3838 print("R_T_spc_1: ", R_T_spc_1)
3684 3839
3685 3840 R_T_d = d*numpy.fft.fftshift(signal.unit_impulse(N))
3686 3841 R_T_d_neg = R_T_d[:nFFTPoints]*T(x_neg,-x[0])
3687 3842 R_T_d_pos = R_T_d[nFFTPoints:]*T(x_pos,x[-1])
3688 3843 R_T_d_sum = R_T_d_pos + R_T_d_neg
3689 3844 R_T_spc_3 = numpy.fft.fft(R_T_d_sum).real
3690 3845 R_T_spc_3 = numpy.fft.fftshift(R_T_spc_3)
3691 3846
3692 3847 R_T_final = R_T_spc_1# + R_T_spc_3
3693 3848
3694 3849 return R_T_final
3695 3850
3696 3851 y = spc#gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
3697 3852
3698 3853 from scipy.stats import norm
3699 3854 mean,std=norm.fit(spc)
3700 3855
3701 3856 # estimate starting values from the data
3702 3857 print("A: ", A)
3703 3858 a = A-D
3704 3859 b = B
3705 3860 c = C#numpy.std(spc) #C
3706 3861 d = D
3707 3862 #'''
3708 3863 #ippSeconds = 250*20*1.e-6/3
3709 3864
3710 3865 #x_t = ippSeconds * (numpy.arange(nFFTPoints) - nFFTPoints / 2.)
3711 3866
3712 3867 #x_t = numpy.linspace(x_t[0],x_t[-1],3200)
3713 3868 #print("x_t: ", x_t)
3714 3869 #print("nFFTPoints: ", nFFTPoints)
3715 3870 x_vel = numpy.linspace(x[0],x[-1],int(2*nFFTPoints))
3716 3871 #print("x_vel: ", x_vel)
3717 3872 #x_freq = numpy.fft.fftfreq(1600,d=ippSeconds)
3718 3873 #x_freq = numpy.fft.fftshift(x_freq)
3719 3874 #'''
3720 3875 # define a least squares function to optimize
3721 3876 import matplotlib.pyplot as plt
3722 3877 aui = R_T_spc_fun(x_vel,a,b,c,d,nFFTPoints)
3723 3878 print("aux_max: ", numpy.nanmax(aui))
3724 3879 #print(dataOut.heightList[hei])
3725 3880 plt.figure()
3726 3881 plt.plot(x,spc,marker='*',linestyle='--')
3727 3882 plt.plot(x,gaussian(x, a, b, c, d),color='b',marker='^',linestyle='')
3728 3883 plt.plot(x,aui,color='k')
3729 3884 #plt.title(dataOut.heightList[hei])
3730 3885 plt.show()
3731 3886
3732 3887 def minfunc(params):
3733 3888 #print("y.shape: ", numpy.shape(y))
3734 3889 return sum((y-R_T_spc_fun(x_vel,params[0],params[1],params[2],params[3],nFFTPoints))**2/1)#y**2)
3735 3890
3736 3891 # fit
3737 3892
3738 3893 popt_full = fmin(minfunc,[a,b,c,d], disp=False)
3739 3894 #print("nIter", popt_full[2])
3740 3895 popt = popt_full#[0]
3741 3896
3742 3897 fun = gaussian(x, popt[0], popt[1], popt[2], popt[3])
3743 3898 print("pop1[0]: ", popt[0])
3744 3899 #return R_T_spc_fun(x_t,popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]), popt[0], popt[1], popt[2], popt[3], popt[4], popt[5], popt[6]
3745 3900 return fun, popt[0], popt[1], popt[2], popt[3]
3746 3901
3747 3902 def windowing_single(self,spc,x,A,B,C,D,nFFTPoints):
3748 3903 '''
3749 3904 Written by R. Flores
3750 3905 '''
3751 3906 from scipy.optimize import curve_fit,fmin
3752 3907
3753 3908 def gaussian(x, a, b, c, d):
3754 3909 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
3755 3910 return val
3756 3911
3757 3912 def R_gaussian(x, a, b, c):
3758 3913 N = int(numpy.shape(x)[0])
3759 3914
3760 3915 val = (a*numpy.exp((-(1/2)*x*(x*c**2 + 2*1.j*b)))/numpy.sqrt(1/c**2))
3761 3916
3762 3917 return val
3763 3918
3764 3919 def T(x,N):
3765 3920 T = 1-abs(x)/N
3766 3921 return T
3767 3922
3768 3923 def R_T_spc_fun(x, a, id_dop, c, d, nFFTPoints):
3769 3924
3770 3925 N = int(numpy.shape(x)[0])
3771 3926 b = 0
3772 3927 x_max = x[-1]
3773 3928
3774 3929 x_pos = x[nFFTPoints:]
3775 3930 x_neg = x[:nFFTPoints]
3776 3931 R_T_neg_1 = R_gaussian(x, a, b, c)[:nFFTPoints]*T(x_neg,-x[0])
3777 3932 R_T_pos_1 = R_gaussian(x, a, b, c)[nFFTPoints:]*T(x_pos,x[-1])
3778 3933
3779 3934 R_T_sum_1 = R_T_pos_1 + R_T_neg_1
3780 3935 R_T_spc_1 = numpy.fft.fft(R_T_sum_1).real
3781 3936 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
3782 3937 max_val_1 = numpy.max(R_T_spc_1)
3783 3938 R_T_spc_1 = R_T_spc_1*a/max_val_1
3784 3939 #raise NotImplementedError
3785 3940 R_T_d = d*numpy.fft.fftshift(signal.unit_impulse(N))
3786 3941 R_T_d_neg = R_T_d[:nFFTPoints]*T(x_neg,-x[0])
3787 3942 R_T_d_pos = R_T_d[nFFTPoints:]*T(x_pos,x[-1])
3788 3943 R_T_d_sum = R_T_d_pos + R_T_d_neg
3789 3944 R_T_spc_3 = numpy.fft.fft(R_T_d_sum).real
3790 3945 R_T_spc_3 = numpy.fft.fftshift(R_T_spc_3)
3791 3946
3792 3947 R_T_final = R_T_spc_1 + R_T_spc_3
3793 3948
3794 3949 id_dop = int(id_dop)
3795 3950
3796 3951 R_T_final = numpy.roll(R_T_final,-id_dop)
3797 3952
3798 3953 return R_T_final
3799 3954
3800 3955 y = spc#gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
3801 3956
3802 3957 from scipy.stats import norm
3803 3958 mean,std=norm.fit(spc)
3804 3959
3805 3960 # estimate starting values from the data
3806 3961 a = A-D
3807 3962 b = B
3808 3963 c = C#numpy.std(spc) #C
3809 3964 d = D
3810 3965
3811 3966 id_dop = numpy.argmax(spc)
3812 3967 id_dop = int(spc.shape[0]/2 - id_dop)
3813 3968
3814 3969 x_vel = numpy.linspace(x[0],x[-1],int(2*nFFTPoints))
3815 3970
3816 3971 # define a least squares function to optimize
3817 3972
3818 3973 def minfunc(params):
3819 3974 #print("y.shape: ", numpy.shape(y))
3820 3975 return sum((y-R_T_spc_fun(x_vel,params[0],params[1],params[2],params[3],nFFTPoints))**2/1)#y**2)
3821 3976
3822 3977 # fit
3823 3978 popt_full = fmin(minfunc,[a,id_dop,c,d], disp=False)
3824 3979 popt = popt_full#[0]
3825 3980
3826 3981 fun = gaussian(x, a, 0, popt[2], popt[3])
3827 3982 fun = numpy.roll(fun,-int(popt[1]))
3828 3983
3829 3984 return fun, popt[0], popt[1], popt[2], popt[3]
3830 3985
3831 3986 def windowing_single_direct(self,spc_mod,x,A,B,C,D,nFFTPoints,timeInterval):
3832 3987 '''
3833 3988 Written by R. Flores
3834 3989 '''
3835 3990 from scipy.optimize import curve_fit,fmin
3836 3991
3837 3992 def gaussian(x, a, b, c, d):
3838 3993 val = a * numpy.exp(-(x - b)**2 / (2*c**2)) + d
3839 3994 return val
3840 3995
3841 3996 def R_gaussian(x, a, b, c, d):
3842 3997 N = int(numpy.shape(x)[0])
3843 3998 val = (a*numpy.exp(-2*c**2*x**2 + 2*x*1.j*b))*(numpy.sqrt(2*numpy.pi)*c)/((numpy.pi)) + d*signal.unit_impulse(N)*numpy.shape(x)[0]/2
3844 3999
3845 4000 return 2*val/numpy.shape(val)[0]
3846 4001
3847 4002 def T(x,N):
3848 4003 T = 1-abs(x)/N
3849 4004 return T
3850 4005
3851 4006 def R_T_spc_fun(x, a, b, c, d, nFFTPoints, timeInterval): #"x" should be time
3852 4007
3853 4008 #timeInterval = 2
3854 4009 x_double = numpy.linspace(0,timeInterval,nFFTPoints)
3855 4010 x_double_m = numpy.flip(x_double)
3856 4011 x_double_aux = numpy.linspace(0,x_double[-2],nFFTPoints)
3857 4012 x_double_t = numpy.concatenate((x_double_m,x_double_aux))
3858 4013 x_double_t /= max(x_double_t)
3859 4014
3860 4015
3861 4016 R_T_sum_1 = R_gaussian(x, a, b, c, d)
3862 4017
3863 4018 R_T_sum_1_flip = numpy.copy(numpy.flip(R_T_sum_1))
3864 4019 R_T_sum_1_flip[-1] = R_T_sum_1_flip[0]
3865 4020 R_T_sum_1_flip = numpy.roll(R_T_sum_1_flip,1)
3866 4021
3867 4022 R_T_sum_1_flip.imag *= -1
3868 4023
3869 4024 R_T_sum_1_total = numpy.concatenate((R_T_sum_1,R_T_sum_1_flip))
3870 4025 R_T_sum_1_total *= x_double_t #times trian_fun
3871 4026
3872 4027 R_T_sum_1_total = R_T_sum_1_total[:nFFTPoints] + R_T_sum_1_total[nFFTPoints:]
3873 4028
3874 4029 R_T_spc_1 = numpy.fft.fft(R_T_sum_1_total).real
3875 4030 R_T_spc_1 = numpy.fft.fftshift(R_T_spc_1)
3876 4031
3877 4032 freq = numpy.fft.fftfreq(nFFTPoints, d=timeInterval/nFFTPoints)
3878 4033
3879 4034 freq = numpy.fft.fftshift(freq)
3880 4035
3881 4036 freq *= 6/2 #lambda/2
3882 4037
3883 4038 return R_T_spc_1
3884 4039
3885 4040 y = spc_mod
3886 4041
3887 4042 #from scipy.stats import norm
3888 4043
3889 4044 # estimate starting values from the data
3890 4045
3891 4046 a = A-D
3892 4047 b = B
3893 4048 c = C
3894 4049 d = D
3895 4050
3896 4051 # define a least squares function to optimize
3897 4052 import matplotlib.pyplot as plt
3898 4053 #ippSeconds = 2
3899 4054 t_range = numpy.linspace(0,timeInterval,nFFTPoints)
3900 4055 #aui = R_T_spc_fun(t_range,a,b,c,d,nFFTPoints,timeInterval)
3901 4056
3902 4057 def minfunc(params):
3903 4058 return sum((y-R_T_spc_fun(t_range,params[0],params[1],params[2],params[3],nFFTPoints,timeInterval))**2/1)#y**2)
3904 4059
3905 4060 # fit
3906 4061 popt_full = fmin(minfunc,[a,b,c,d], disp=False)
3907 4062 popt = popt_full
3908 4063
3909 4064 fun = R_T_spc_fun(t_range,popt[0],popt[1],popt[2],popt[3],nFFTPoints,timeInterval)
3910 4065
3911 4066 return fun, popt[0], popt[1], popt[2], popt[3]
3912 4067 # **********************************************************************************************
3913 4068 index = 0
3914 4069 fint = 0
3915 4070 buffer = 0
3916 4071 buffer2 = 0
3917 4072 buffer3 = 0
3918 4073
3919 4074 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None, filec=None,coh_th=None, hei_th=None,taver=None,proc=None,nhei=None,nprofs=None,ipp=None,channelList=None,Gaussian_Windowed=0):
3920 4075
3921 4076 if not numpy.any(proc):
3922 4077 nChannels = dataOut.nChannels
3923 4078 nHeights= dataOut.heightList.size
3924 4079 nProf = dataOut.nProfiles
3925 4080 if numpy.any(taver): taver=int(taver)
3926 4081 else : taver = 5
3927 4082 tini=time.localtime(dataOut.utctime)
3928 4083 if (tini.tm_min % taver) == 0 and (tini.tm_sec < 5 and self.fint==0):
3929 4084 self.index = 0
3930 4085 jspc = self.buffer
3931 4086 jcspc = self.buffer2
3932 4087 jnoise = self.buffer3
3933 4088 self.buffer = dataOut.data_spc
3934 4089 self.buffer2 = dataOut.data_cspc
3935 4090 self.buffer3 = dataOut.noise
3936 4091 self.fint = 1
3937 4092 if numpy.any(jspc) :
3938 4093 jspc= numpy.reshape(jspc,(int(len(jspc)/nChannels),nChannels,nProf,nHeights))
3939 4094 jcspc= numpy.reshape(jcspc,(int(len(jcspc)/int(nChannels/2)),int(nChannels/2),nProf,nHeights))
3940 4095 jnoise= numpy.reshape(jnoise,(int(len(jnoise)/nChannels),nChannels))
3941 4096 else:
3942 4097 dataOut.flagNoData = True
3943 4098 return dataOut
3944 4099 else:
3945 4100 if (tini.tm_min % taver) == 0 : self.fint = 1
3946 4101 else : self.fint = 0
3947 4102 self.index += 1
3948 4103 if numpy.any(self.buffer):
3949 4104 self.buffer = numpy.concatenate((self.buffer,dataOut.data_spc), axis=0)
3950 4105 self.buffer2 = numpy.concatenate((self.buffer2,dataOut.data_cspc), axis=0)
3951 4106 self.buffer3 = numpy.concatenate((self.buffer3,dataOut.noise), axis=0)
3952 4107 else:
3953 4108 self.buffer = dataOut.data_spc
3954 4109 self.buffer2 = dataOut.data_cspc
3955 4110 self.buffer3 = dataOut.noise
3956 4111 dataOut.flagNoData = True
3957 4112 return dataOut
3958 4113 if path != None:
3959 4114 sys.path.append(path)
3960 4115 self.library = importlib.import_module(file)
3961 4116 if filec != None:
3962 4117 self.weightf = importlib.import_module(filec)
3963 4118 #self.weightf = importlib.import_module('weightfit')
3964 4119
3965 4120 #To be inserted as a parameter
3966 4121 groupArray = numpy.array(groupList)
3967 4122 #groupArray = numpy.array([[0,1],[2,3]])
3968 4123 dataOut.groupList = groupArray
3969 4124
3970 4125 nGroups = groupArray.shape[0]
3971 4126 nChannels = dataOut.nChannels
3972 4127 nHeights = dataOut.heightList.size
3973 4128
3974 4129 #Parameters Array
3975 4130 dataOut.data_param = None
3976 4131 dataOut.data_paramC = None
3977 4132 dataOut.clean_num_aver = None
3978 4133 dataOut.coh_num_aver = None
3979 4134 dataOut.tmp_spectra_i = None
3980 4135 dataOut.tmp_cspectra_i = None
3981 4136 dataOut.tmp_spectra_c = None
3982 4137 dataOut.tmp_cspectra_c = None
3983 4138 dataOut.sat_spectra = None
3984 4139 dataOut.sat_cspectra = None
3985 4140 dataOut.index = None
3986 4141
3987 4142 #Set constants
3988 4143 constants = self.library.setConstants(dataOut)
3989 4144 dataOut.constants = constants
3990 4145 M = dataOut.normFactor
3991 4146 N = dataOut.nFFTPoints
3992 4147
3993 4148 ippSeconds = dataOut.ippSeconds
3994 4149 K = dataOut.nIncohInt
3995 4150 pairsArray = numpy.array(dataOut.pairsList)
3996 4151
3997 4152 snrth= 15
3998 4153 spectra = dataOut.data_spc
3999 4154 cspectra = dataOut.data_cspc
4000 4155 nProf = dataOut.nProfiles
4001 4156 heights = dataOut.heightList
4002 4157 nHei = len(heights)
4003 4158 channels = dataOut.channelList
4004 4159 nChan = len(channels)
4005 4160 nIncohInt = dataOut.nIncohInt
4006 4161 crosspairs = dataOut.groupList
4007 4162 noise = dataOut.noise
4008 4163 jnoise = jnoise/N
4009 4164 noise = numpy.nansum(jnoise,axis=0)#/len(jnoise)
4010 4165 power = numpy.sum(spectra, axis=1)
4011 4166 nPairs = len(crosspairs)
4012 4167 absc = dataOut.abscissaList[:-1]
4013 print('para escribir h5 ',dataOut.paramInterval)
4014 4168 if not self.isConfig:
4015 4169 self.isConfig = True
4016 4170
4017 4171 index = tini.tm_hour*12+tini.tm_min/taver
4018 4172 dataOut.index= index
4019 4173 jspc = jspc/N/N
4020 4174 jcspc = jcspc/N/N
4021 4175 tmp_spectra,tmp_cspectra,sat_spectra,sat_cspectra = self.CleanRayleigh(dataOut,jspc,jcspc,2)
4022 4176 jspectra = tmp_spectra*len(jspc[:,0,0,0])
4023 4177 jcspectra = tmp_cspectra*len(jspc[:,0,0,0])
4024 4178 my_incoh_spectra ,my_incoh_cspectra,my_incoh_aver,my_coh_aver, incoh_spectra, coh_spectra, incoh_cspectra, coh_cspectra, incoh_aver, coh_aver = self.__DiffCoherent(jspectra, jcspectra, dataOut, noise, snrth,coh_th, hei_th)
4025 4179
4026 4180 clean_coh_spectra, clean_coh_cspectra, clean_coh_aver = self.__CleanCoherent(snrth, coh_spectra, coh_cspectra, coh_aver, dataOut, noise,1,index)
4181
4027 4182 dataOut.data_spc = incoh_spectra
4028 4183 dataOut.data_cspc = incoh_cspectra
4029 4184 dataOut.sat_spectra = sat_spectra
4030 4185 dataOut.sat_cspectra = sat_cspectra
4031 4186 # dataOut.data_spc = tmp_spectra
4032 4187 # dataOut.data_cspc = tmp_cspectra
4033 4188
4034 4189 clean_num_aver = incoh_aver*len(jspc[:,0,0,0])
4035 4190 coh_num_aver = clean_coh_aver*len(jspc[:,0,0,0])
4036 4191 # clean_num_aver = (numpy.zeros([nChan, nHei])+1)*len(jspc[:,0,0,0])
4037 4192 # coh_num_aver = numpy.zeros([nChan, nHei])*0*len(jspc[:,0,0,0])
4038 4193 dataOut.clean_num_aver = clean_num_aver
4039 4194 dataOut.coh_num_aver = coh_num_aver
4040 4195 dataOut.tmp_spectra_i = incoh_spectra
4041 4196 dataOut.tmp_cspectra_i = incoh_cspectra
4042 4197 dataOut.tmp_spectra_c = clean_coh_spectra
4043 4198 dataOut.tmp_cspectra_c = clean_coh_cspectra
4044 4199 #List of possible combinations
4045 4200 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
4046 4201 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
4047 4202 if Gaussian_Windowed == 1:
4048 4203 #dataOut.data_spc = jspectra
4049 4204 '''
4050 4205 Written by R. Flores
4051 4206 '''
4052 4207 print("normFactor: ", dataOut.normFactor)
4053 4208 data_spc_aux = numpy.copy(dataOut.data_spc)#[:,0,:]
4054 4209 data_spc_aux[:,0,:] = (data_spc_aux[:,1,:]+data_spc_aux[:,-1,:])/2
4055 4210 #'''
4056 4211 from scipy.signal import medfilt
4057 4212 import matplotlib.pyplot as plt
4058 4213 dataOut.moments = numpy.ones((dataOut.nChannels,4,dataOut.nHeights))*numpy.NAN
4059 4214 dataOut.VelRange = dataOut.getVelRange(0)
4060 4215 for nChannel in range(dataOut.nChannels):
4061 4216 for hei in range(dataOut.heightList.shape[0]):
4062 4217 #print("ipp: ", dataOut.ippSeconds)
4063 4218 #spc = numpy.copy(dataOut.data_spc[nChannel,:,hei])
4064 4219 spc = data_spc_aux[nChannel,:,hei]
4065 4220 if spc.all() == 0.:
4066 4221 print("CONTINUE")
4067 4222 continue
4068 4223 #print(VelRange)
4069 4224 #print(dataOut.getFreqRange(64))
4070 4225 #print("Hei: ", dataOut.heightList[hei])
4071 4226
4072 4227 spc_mod = numpy.copy(spc)
4073 4228 spcm = medfilt(spc_mod,11)
4074 4229 spc_max = numpy.max(spcm)
4075 4230 dop1_x0 = dataOut.VelRange[numpy.argmax(spcm)]
4076 4231 #D = numpy.min(spcm)
4077 4232 D_in = (numpy.mean(spcm[:15])+numpy.mean(spcm[-15:]))/2.
4078 4233 #print("spc_max: ", spc_max)
4079 4234 #print("dataOut.ippSeconds: ", dataOut.ippSeconds, dataOut.timeInterval)
4080 4235 ##fun, A, B, C, D = self.windowing_single(spc,dataOut.VelRange,spc_max,dop1_x0,abs(dop1_x0),D,dataOut.nFFTPoints)
4081 4236 #fun, A, B, C, D = self.windowing_single(spc,dataOut.VelRange,spc_max,dop1_x0,abs(dop1_x0),D,dataOut.nFFTPoints)
4082 4237 fun, A, B, C, D = self.windowing_single_direct(spc_mod,dataOut.VelRange,spc_max,dop1_x0,abs(dop1_x0/5),D_in,dataOut.nFFTPoints,dataOut.timeInterval)
4083 4238
4084 4239 dataOut.moments[nChannel,0,hei] = A
4085 4240 dataOut.moments[nChannel,1,hei] = B
4086 4241 dataOut.moments[nChannel,2,hei] = C
4087 4242 dataOut.moments[nChannel,3,hei] = D
4088 4243 '''
4089 4244 if nChannel == 0:
4090 4245 print(dataOut.heightList[hei])
4091 4246 plt.figure()
4092 4247 plt.plot(dataOut.VelRange,spc,marker='*',linestyle='--')
4093 4248 plt.plot(dataOut.VelRange,fun)
4094 4249 plt.title(dataOut.heightList[hei])
4095 4250 plt.show()
4096 4251 '''
4097 4252 #plt.show()
4098 4253 #'''
4099 4254 dataOut.data_spc = jspectra
4100 4255 print("SUCCESS")
4101 4256 return dataOut
4102 4257
4103 4258 elif Gaussian_Windowed == 2: #Only to clean spc
4104 4259 dataOut.VelRange = dataOut.getVelRange(0)
4105 4260 return dataOut
4106 4261
4107 4262 if getSNR:
4108 4263 listChannels = groupArray.reshape((groupArray.size))
4109 4264 listChannels.sort()
4110 4265 # norm Este factor debe estar implementado para ploteo o grabado como metadata
4111 4266 # norm = dataOut.nProfiles * dataOut.nIncohInt * dataOut.nCohInt * dataOut.windowOfFilter
4112 4267 dataOut.data_snr = self.__getSNR(dataOut.data_spc[listChannels,:,:], noise[listChannels])
4113 4268 else:
4114 4269 if numpy.any(taver): taver=int(taver)
4115 4270 else : taver = 5
4116 4271 tini=time.localtime(dataOut.utctime)
4117 4272 index = tini.tm_hour*12+tini.tm_min/taver
4118 4273 clean_num_aver = dataOut.clean_num_aver
4119 4274 coh_num_aver = dataOut.coh_num_aver
4120 4275 dataOut.data_spc = dataOut.tmp_spectra_i
4121 4276 dataOut.data_cspc = dataOut.tmp_cspectra_i
4122 4277 clean_coh_spectra = dataOut.tmp_spectra_c
4123 4278 clean_coh_cspectra = dataOut.tmp_cspectra_c
4124 4279 jspectra = dataOut.data_spc+clean_coh_spectra
4125 4280 nHeights = len(dataOut.heightList) # nhei
4126 4281 nProf = int(dataOut.nProfiles)
4127 4282 dataOut.nProfiles = nProf
4128 4283 dataOut.data_param = None
4129 4284 dataOut.data_paramC = None
4130 4285 dataOut.code = numpy.array([[-1.,-1.,1.],[1.,1.,-1.]])
4131 4286 #dataOut.paramInterval = 2.0
4132 4287 #M=600
4133 4288 #N=200
4134 4289 dataOut.flagDecodeData=True
4135 4290 M = int(dataOut.normFactor)
4136 4291 N = int(dataOut.nFFTPoints)
4137 4292 dataOut.nFFTPoints = N
4138 4293 dataOut.nIncohInt= int(dataOut.nIncohInt)
4139 4294 dataOut.nProfiles = int(dataOut.nProfiles)
4140 4295 dataOut.nCohInt = int(dataOut.nCohInt)
4141 print('sale',dataOut.nProfiles,dataOut.nHeights)
4296 #print('sale',dataOut.nProfiles,dataOut.nHeights)
4142 4297 #dataOut.nFFTPoints=nprofs
4143 4298 #dataOut.normFactor = nprofs
4144 4299 dataOut.channelList = channelList
4145 4300 nChan = len(channelList)
4146 4301 #dataOut.ippFactor=1
4147 4302 #ipp = ipp/150*1.e-3
4148 4303 vmax = (300000000/49920000.0/2) / (dataOut.ippSeconds)
4149 4304 #dataOut.ippSeconds=ipp
4150 4305 absc = vmax*( numpy.arange(nProf,dtype='float')-nProf/2.)/nProf
4151 print('sale 2',dataOut.ippSeconds,M,N)
4306 #print('sale 2',dataOut.ippSeconds,M,N)
4152 4307 print('Empieza procesamiento offline')
4153 4308 if path != None:
4154 4309 sys.path.append(path)
4155 4310 self.library = importlib.import_module(file)
4156 4311 constants = self.library.setConstants(dataOut)
4157 4312 constants['M'] = M
4158 4313 dataOut.constants = constants
4159 4314 if filec != None:
4160 4315 self.weightf = importlib.import_module(filec)
4161 4316
4162 4317 groupArray = numpy.array(groupList)
4163 4318 dataOut.groupList = groupArray
4164 4319 nGroups = groupArray.shape[0]
4165 4320 #List of possible combinations
4166 4321 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
4167 4322 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
4168 4323 if dataOut.data_paramC is None:
4169 4324 dataOut.data_paramC = numpy.zeros((nGroups*4, nHeights,2))*numpy.nan
4170 4325 dataOut.data_snr1_i = numpy.zeros((nGroups*2, nHeights))*numpy.nan
4171 4326 # dataOut.smooth_i = numpy.zeros((nGroups*2, nHeights))*numpy.nan
4172 4327
4328 if self.aux == 1:
4329 dataOut.p03last = numpy.zeros(nGroups, 'float32')
4173 4330 for i in range(nGroups):
4174 4331 coord = groupArray[i,:]
4175 4332 #Input data array
4176 4333 data = dataOut.data_spc[coord,:,:]/(M*N)
4177 4334 data = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
4178 4335
4179 4336 #Cross Spectra data array for Covariance Matrixes
4180 4337 ind = 0
4181 4338 for pairs in listComb:
4182 4339 pairsSel = numpy.array([coord[x],coord[y]])
4183 4340 indCross[ind] = int(numpy.where(numpy.all(pairsArray == pairsSel, axis = 1))[0][0])
4184 4341 ind += 1
4185 4342 dataCross = dataOut.data_cspc[indCross,:,:]/(M*N)
4186 4343 dataCross = dataCross**2
4187 4344 nhei = nHeights
4188 4345 poweri = numpy.sum(dataOut.data_spc[:,1:nProf-0,:],axis=1)/clean_num_aver[:,:]
4189 4346 if i == 0 : my_noises = numpy.zeros(4,dtype=float)
4190 4347 n0i = numpy.nanmin(poweri[0+i*2,0:nhei-0])/(nProf-1)
4191 4348 n1i = numpy.nanmin(poweri[1+i*2,0:nhei-0])/(nProf-1)
4192 4349 n0 = n0i
4193 4350 n1= n1i
4194 4351 my_noises[2*i+0] = n0
4195 4352 my_noises[2*i+1] = n1
4196 snrth = -13 #-13.0 # -4 -16 -25
4353 snrth = -12.0 #-11.0 # -4 -16 -25
4197 4354 snrth = 10**(snrth/10.0)
4198 4355 jvelr = numpy.zeros(nHeights, dtype = 'float')
4199 4356 #snr0 = numpy.zeros(nHeights, dtype = 'float')
4200 4357 #snr1 = numpy.zeros(nHeights, dtype = 'float')
4201 4358 hvalid = [0]
4202 4359
4203 4360 coh2 = abs(dataOut.data_cspc[i,1:nProf,:])**2/(dataOut.data_spc[0+i*2,1:nProf-0,:]*dataOut.data_spc[1+i*2,1:nProf-0,:])
4204 4361
4362 SIGNAL_0 = []
4363 SIGNAL_1 = []
4205 4364 for h in range(nHeights):
4206 4365 smooth = clean_num_aver[i+1,h]
4207 4366 signalpn0 = (dataOut.data_spc[i*2,1:(nProf-0),h])/smooth
4208 4367 signalpn1 = (dataOut.data_spc[i*2+1,1:(nProf-0),h])/smooth
4209 4368 signal0 = signalpn0-n0
4210 4369 signal1 = signalpn1-n1
4211 4370 snr0 = numpy.sum(signal0/n0)/(nProf-1)
4212 4371 snr1 = numpy.sum(signal1/n1)/(nProf-1)
4213 4372 #jmax0 = MAX(signal0,maxp0)
4214 4373 #jmax1 = MAX(signal1,maxp1)
4215 4374 gamma = coh2[:,h]
4216 4375
4217 4376 indxs = (numpy.isfinite(list(gamma))==True).nonzero()
4218 4377
4219 4378 if len(indxs) >0:
4220 4379 if numpy.nanmean(gamma) > 0.07:
4221 4380 maxp0 = numpy.argmax(signal0*gamma)
4222 4381 maxp1 = numpy.argmax(signal1*gamma)
4223 4382 #print('usa gamma',numpy.nanmean(gamma))
4224 4383 else:
4225 4384 maxp0 = numpy.argmax(signal0)
4226 4385 maxp1 = numpy.argmax(signal1)
4227 4386 jvelr[h] = (absc[maxp0]+absc[maxp1])/2.
4228 4387 else: jvelr[h] = absc[0]
4229 4388 if snr0 > 0.1 and snr1 > 0.1: hvalid = numpy.concatenate((hvalid,h), axis=None)
4230 4389 #print(maxp0,absc[maxp0],snr0,jvelr[h])
4390 SIGNAL_0.append(signal0)
4391 SIGNAL_1.append(signal1)
4231 4392
4232 4393 if len(hvalid)> 1: fd0 = numpy.median(jvelr[hvalid[1:]])*-1
4233 4394 else: fd0 = numpy.nan
4234 4395 print(fd0)
4396 fd0n = [fd0]
4397 SIGNAL_0 = numpy.array(SIGNAL_0)
4398 SIGNAL_1 = numpy.array(SIGNAL_1)
4399 ### ---- Signal correction
4400
4401 diff = numpy.abs(dataOut.p03last[i] - fd0)
4402 if (filec != None) and (self.aux == 0) and (diff > 6):
4403 print('hace correccion de vr')
4404 try:
4405 maxs_0 = self.Vr_correction(SIGNAL_0)
4406 maxs_1 = self.Vr_correction(SIGNAL_1)
4407 fd0_aux = -1*(absc[maxs_0] + absc[maxs_1]) / 2
4408 if numpy.abs(dataOut.p03last[i] - fd0_aux ) > diff: print("Wrong correction omitted", fd0_aux)
4409 else: fd0 = fd0_aux; print("Changed fd0: ", fd0)
4410 except Exception as e:
4411 print("Error in correction processes skiped: ", e)
4412
4413 dataOut.p03last[i] = fd0
4414 ### ---
4415 fd0n = [fd0]
4235 4416 for h in range(nHeights):
4236 4417 d = data[:,h]
4237 4418 smooth = clean_num_aver[i+1,h] #dataOut.data_spc[:,1:nProf-0,:]
4238 4419 signalpn0 = (dataOut.data_spc[i*2,1:(nProf-0),h])/smooth
4239 4420 signalpn1 = (dataOut.data_spc[i*2+1,1:(nProf-0),h])/smooth
4240 4421 signal0 = signalpn0-n0
4241 4422 signal1 = signalpn1-n1
4242 4423 snr0 = numpy.sum(signal0/n0)/(nProf-1)
4243 4424 snr1 = numpy.sum(signal1/n1)/(nProf-1)
4244 4425
4245 4426 if snr0 > snrth and snr1 > snrth and clean_num_aver[i+1,h] > 0 :
4246 4427 #Covariance Matrix
4247 4428 D = numpy.diag(d**2)
4248 4429 ind = 0
4249 4430 for pairs in listComb:
4250 4431 #Coordinates in Covariance Matrix
4251 4432 x = pairs[0]
4252 4433 y = pairs[1]
4253 4434 #Channel Index
4254 4435 S12 = dataCross[ind,:,h]
4255 4436 D12 = numpy.diag(S12)
4256 4437 #Completing Covariance Matrix with Cross Spectras
4257 4438 D[x*N:(x+1)*N,y*N:(y+1)*N] = D12
4258 4439 D[y*N:(y+1)*N,x*N:(x+1)*N] = D12
4259 4440 ind += 1
4260 4441 diagD = numpy.zeros(256)
4261 4442
4262 4443 try:
4263 4444 Dinv=numpy.linalg.inv(D)
4264 4445 L=numpy.linalg.cholesky(Dinv)
4265 4446 except:
4266 4447 Dinv = D*numpy.nan
4267 4448 L= D*numpy.nan
4268 4449 LT=L.T
4269 4450
4270 4451 dp = numpy.dot(LT,d)
4271 4452 #Initial values
4272 4453 data_spc = dataOut.data_spc[coord,:,h]
4273 4454 w = data_spc/data_spc
4274 4455 if filec != None:
4275 4456 w = self.weightf.weightfit(w,tini.tm_year,tini.tm_yday,index,h,i)
4276 4457 if (h>6) and (error1[3]<25):
4277 4458 p0 = dataOut.data_param[i,:,h-1].copy()
4278 4459 else:
4279 4460 p0 = numpy.array(self.library.initialValuesFunction(data_spc*w, constants))# sin el i(data_spc, constants, i)
4280 4461 p0[3] = fd0
4281 4462 if filec != None:
4282 4463 p0 = self.weightf.Vrfit(p0,tini.tm_year,tini.tm_yday,index,h,i)
4283 4464
4284 4465 try:
4285 4466 #Least Squares
4286 4467 minp,covp,infodict,mesg,ier = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants),full_output=True)
4287 4468 #minp,covp = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants))
4288 4469 #Chi square error
4289 4470 error0 = numpy.sum(infodict['fvec']**2)/(2*N)
4290 4471 #Error with Jacobian
4291 4472 error1 = self.library.errorFunction(minp,constants,LT)
4292 4473
4293 4474 except:
4294 4475 minp = p0*numpy.nan
4295 4476 error0 = numpy.nan
4296 4477 error1 = p0*numpy.nan
4478 # s_sq = (self.__residFunction(minp,dp,LT,constants)).sum()/(len(dp)-len(p0))
4479 # covp = covp*s_sq
4480 # error = []
4481 # for ip in range(len(minp)):
4482 # try:
4483 # error.append(numpy.absolute(covp[ip][ip])**0.5)
4484 # except:
4485 # error.append( 0.00 )
4486 #if i==1 and h==11 and index == 139: print(p0, minp,data_spc)
4487 fd0n = numpy.concatenate((fd0n,minp[3]), axis=None)
4297 4488 else :
4298 4489 data_spc = dataOut.data_spc[coord,:,h]
4299 4490 p0 = numpy.array(self.library.initialValuesFunction(data_spc, constants))
4300 4491 minp = p0*numpy.nan
4301 4492 error0 = numpy.nan
4302 4493 error1 = p0*numpy.nan
4303 4494 if dataOut.data_param is None:
4304 4495 dataOut.data_param = numpy.zeros((nGroups, p0.size, nHeights))*numpy.nan
4305 4496 dataOut.data_error = numpy.zeros((nGroups, p0.size + 1, nHeights))*numpy.nan
4306 4497
4307 4498 dataOut.data_error[i,:,h] = numpy.hstack((error0,error1))
4308 4499 dataOut.data_param[i,:,h] = minp
4309 4500 dataOut.data_snr1_i[i*2,h] = numpy.sum(signalpn0/(nProf-1))/n0
4310 4501 dataOut.data_snr1_i[i*2+1,h] = numpy.sum(signalpn1/(nProf-1))/n1
4311
4502 #dataOut.smooth_i[i*2,h] = clean_num_aver[i+1,h]
4503 #print(fd0,dataOut.data_param[i,3,h])
4504 #print(fd0,dataOut.data_param[i,3,:])
4505 fd0n = fd0n[1:]
4506 dvr = abs(dataOut.data_param[i,3,:]-numpy.nanmedian(fd0n))
4507 indbad=numpy.where(dvr > 25)
4508 esf = 0
4509 if filec != None:
4510 esf = self.weightf.esffit(esf,tini.tm_year,tini.tm_yday,index)
4511 #print(indbad,'media ',numpy.nanmedian(fd0n), esf)
4512
4513 #plt.plot(abs(dataOut.data_param[i,3,:]-numpy.nanmedian(fd0n)),'o')
4514 #plt.plot(dataOut.data_param[i,3,:])
4515 #plt.ylim(-200,200)
4516 if esf == 0 :
4517 dataOut.data_param[i,3,indbad] = numpy.nanmedian(fd0n)
4518 print('corrige')
4519 #plt.plot(dataOut.data_param[i,3,:])
4520 #plt.show()
4312 4521 for ht in range(nHeights-1) :
4313 4522 smooth = coh_num_aver[i+1,ht] #datc[0,ht,0,beam]
4314 4523 dataOut.data_paramC[4*i,ht,1] = smooth
4315 4524 signalpn0 = (clean_coh_spectra[i*2 ,1:(nProf-0),ht])/smooth #coh_spectra
4316 4525 signalpn1 = (clean_coh_spectra[i*2+1,1:(nProf-0),ht])/smooth
4317 4526
4318 4527 val0 = (signalpn0 > 0).nonzero()
4319 4528 val0 = val0[0]
4320 4529
4321 4530 if len(val0) == 0 : val0_npoints = nProf
4322 4531 else : val0_npoints = len(val0)
4323 4532
4324 4533 val1 = (signalpn1 > 0).nonzero()
4325 4534 val1 = val1[0]
4326 4535 if len(val1) == 0 : val1_npoints = nProf
4327 4536 else : val1_npoints = len(val1)
4328 4537
4329 4538 dataOut.data_paramC[0+4*i,ht,0] = numpy.sum((signalpn0/val0_npoints))/n0
4330 4539 dataOut.data_paramC[1+4*i,ht,0] = numpy.sum((signalpn1/val1_npoints))/n1
4331 4540
4332 4541 signal0 = (signalpn0-n0)
4333 4542 vali = (signal0 < 0).nonzero()
4334 4543 vali = vali[0]
4335 4544 if len(vali) > 0 : signal0[vali] = 0
4336 4545 signal1 = (signalpn1-n1)
4337 4546 vali = (signal1 < 0).nonzero()
4338 4547 vali = vali[0]
4339 4548 if len(vali) > 0 : signal1[vali] = 0
4340 4549 snr0 = numpy.sum(signal0/n0)/(nProf-1)
4341 4550 snr1 = numpy.sum(signal1/n1)/(nProf-1)
4342 4551 doppler = absc[1:]
4343 4552 if snr0 >= snrth and snr1 >= snrth and smooth :
4344 4553 signalpn0_n0 = signalpn0
4345 4554 signalpn0_n0[val0] = signalpn0[val0] - n0
4346 4555 mom0 = self.moments(doppler,signalpn0-n0,nProf)
4347 4556
4348 4557 signalpn1_n1 = signalpn1
4349 4558 signalpn1_n1[val1] = signalpn1[val1] - n1
4350 4559 mom1 = self.moments(doppler,signalpn1_n1,nProf)
4351 4560 dataOut.data_paramC[2+4*i,ht,0] = (mom0[0]+mom1[0])/2.
4352 4561 dataOut.data_paramC[3+4*i,ht,0] = (mom0[1]+mom1[1])/2.
4353 4562
4354 4563 dataOut.data_spc = jspectra
4355 4564 dataOut.spc_noise = my_noises*nProf*M
4356 4565
4357 4566 if numpy.any(proc): dataOut.spc_noise = my_noises*nProf*M
4358 4567 if 0:
4359 4568 listChannels = groupArray.reshape((groupArray.size))
4360 4569 listChannels.sort()
4361 4570 # norm Este factor debe estar implementado para ploteo o grabado como metadata
4362 4571 # norm = dataOut.nProfiles * dataOut.nIncohInt * dataOut.nCohInt * dataOut.windowOfFilter
4363 4572 dataOut.data_snr = self.__getSNR(dataOut.data_spc[listChannels,:,:], my_noises[listChannels])
4364 4573 #print(dataOut.data_snr1_i)
4365 4574 # Adding coherent echoes from possible satellites.
4366 4575 #sat_spectra = numpy.zeros((nChan,nProf,nHei), dtype=float)
4367 4576 #sat_spectra = sat_spectra[*,*,anal_header.channels]
4368 4577 isat_spectra = numpy.zeros([2,int(nChan/2),nProf,nhei], dtype=float)
4369 4578
4370 4579 sat_fits = numpy.zeros([4,nhei], dtype=float)
4371 4580 noises = my_noises/nProf
4372 4581 #nchan2 = int(nChan/2)
4373 4582 for beam in range(int(nChan/2)-0) :
4374 4583 n0 = noises[2*beam]
4375 4584 n1 = noises[2*beam+1]
4376 4585 isat_spectra[0:2,beam,:,:] = dataOut.sat_spectra[2*beam +0:2*beam+2 ,:,:]
4377 4586
4378 4587 for ht in range(nhei-1) :
4379 4588 signalpn0 = isat_spectra[0,beam,:,ht]
4380 4589 signalpn0 = numpy.reshape(signalpn0,nProf)
4381 4590 signalpn1 = isat_spectra[1,beam,:,ht]
4382 4591 signalpn1 = numpy.reshape(signalpn1,nProf)
4383 4592
4384 4593 cval0 = len((signalpn0 > 0).nonzero()[0])
4385 4594 if cval0 == 0 : val0_npoints = nProf
4386 4595 else: val0_npoints = cval0
4387 4596
4388 4597 cval1 = len((signalpn1 > 0).nonzero()[0])
4389 4598 if cval1 == 0 : val1_npoints = nProf
4390 4599 else: val1_npoints = cval1
4391 4600
4392 4601 sat_fits[0+2*beam,ht] = numpy.sum(signalpn0/(val0_npoints*nProf))/n0
4393 4602 sat_fits[1+2*beam,ht] = numpy.sum(signalpn1/(val1_npoints*nProf))/n1
4394 4603
4395 4604 dataOut.sat_fits = sat_fits
4605 self.aux = 0
4396 4606 return dataOut
4397 4607
4398 4608 def __residFunction(self, p, dp, LT, constants):
4399 4609
4400 4610 fm = self.library.modelFunction(p, constants)
4401 4611 fmp=numpy.dot(LT,fm)
4402 4612 return dp-fmp
4403 4613
4404 4614 def __getSNR(self, z, noise, norm=1):
4405 4615
4406 4616 avg = numpy.average(z, axis=1)
4407 4617 SNR = (avg.T-noise)/noise
4408 4618 SNR = SNR.T
4409 4619 return SNR
4410 4620
4411 4621 def __chisq(self, p, chindex, hindex):
4412 4622 #similar to Resid but calculates CHI**2
4413 4623 [LT,d,fm]=setupLTdfm(p,chindex,hindex)
4414 4624 dp=numpy.dot(LT,d)
4415 4625 fmp=numpy.dot(LT,fm)
4416 4626 chisq=numpy.dot((dp-fmp).T,(dp-fmp))
4417 4627 return chisq
4418 4628
4419 4629 class WindProfiler(Operation):
4420 4630
4421 4631 __isConfig = False
4422 4632
4423 4633 __initime = None
4424 4634 __lastdatatime = None
4425 4635 __integrationtime = None
4426 4636
4427 4637 __buffer = None
4428 4638
4429 4639 __dataReady = False
4430 4640
4431 4641 __firstdata = None
4432 4642
4433 4643 n = None
4434 4644
4435 4645 def __init__(self):
4436 4646 Operation.__init__(self)
4437 4647
4438 4648 def __calculateCosDir(self, elev, azim):
4439 4649 zen = (90 - elev)*numpy.pi/180
4440 4650 azim = azim*numpy.pi/180
4441 4651 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
4442 4652 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
4443 4653
4444 4654 signX = numpy.sign(numpy.cos(azim))
4445 4655 signY = numpy.sign(numpy.sin(azim))
4446 4656
4447 4657 cosDirX = numpy.copysign(cosDirX, signX)
4448 4658 cosDirY = numpy.copysign(cosDirY, signY)
4449 4659 return cosDirX, cosDirY
4450 4660
4451 4661 def __calculateAngles(self, theta_x, theta_y, azimuth):
4452 4662
4453 4663 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
4454 4664 zenith_arr = numpy.arccos(dir_cosw)
4455 4665 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
4456 4666
4457 4667 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
4458 4668 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
4459 4669
4460 4670 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
4461 4671
4462 4672 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
4463 4673
4464 4674 if horOnly:
4465 4675 A = numpy.c_[dir_cosu,dir_cosv]
4466 4676 else:
4467 4677 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
4468 4678 A = numpy.asmatrix(A)
4469 4679 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
4470 4680
4471 4681 return A1
4472 4682
4473 4683 def __correctValues(self, heiRang, phi, velRadial, SNR):
4474 4684 listPhi = phi.tolist()
4475 4685 maxid = listPhi.index(max(listPhi))
4476 4686 minid = listPhi.index(min(listPhi))
4477 4687
4478 4688 rango = list(range(len(phi)))
4479 4689
4480 4690 heiRang1 = heiRang*math.cos(phi[maxid])
4481 4691 heiRangAux = heiRang*math.cos(phi[minid])
4482 4692 indOut = (heiRang1 < heiRangAux[0]).nonzero()
4483 4693 heiRang1 = numpy.delete(heiRang1,indOut)
4484 4694
4485 4695 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
4486 4696 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
4487 4697
4488 4698 for i in rango:
4489 4699 x = heiRang*math.cos(phi[i])
4490 4700 y1 = velRadial[i,:]
4491 4701 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
4492 4702
4493 4703 x1 = heiRang1
4494 4704 y11 = f1(x1)
4495 4705
4496 4706 y2 = SNR[i,:]
4497 4707 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
4498 4708 y21 = f2(x1)
4499 4709
4500 4710 velRadial1[i,:] = y11
4501 4711 SNR1[i,:] = y21
4502 4712
4503 4713 return heiRang1, velRadial1, SNR1
4504 4714
4505 4715 def __calculateVelUVW(self, A, velRadial):
4506 4716
4507 4717 #Operacion Matricial
4508 4718 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
4509 4719 velUVW[:,:] = numpy.dot(A,velRadial)
4510 4720
4511 4721
4512 4722 return velUVW
4513 4723
4514 4724 def techniqueDBS(self, kwargs):
4515 4725 """
4516 4726 Function that implements Doppler Beam Swinging (DBS) technique.
4517 4727
4518 4728 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
4519 4729 Direction correction (if necessary), Ranges and SNR
4520 4730
4521 4731 Output: Winds estimation (Zonal, Meridional and Vertical)
4522 4732
4523 4733 Parameters affected: Winds, height range, SNR
4524 4734 """
4525 4735 velRadial0 = kwargs['velRadial']
4526 4736 heiRang = kwargs['heightList']
4527 4737 SNR0 = kwargs['SNR']
4528 4738
4529 4739 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
4530 4740 theta_x = numpy.array(kwargs['dirCosx'])
4531 4741 theta_y = numpy.array(kwargs['dirCosy'])
4532 4742 else:
4533 4743 elev = numpy.array(kwargs['elevation'])
4534 4744 azim = numpy.array(kwargs['azimuth'])
4535 4745 theta_x, theta_y = self.__calculateCosDir(elev, azim)
4536 4746 azimuth = kwargs['correctAzimuth']
4537 4747 if 'horizontalOnly' in kwargs:
4538 4748 horizontalOnly = kwargs['horizontalOnly']
4539 4749 else: horizontalOnly = False
4540 4750 if 'correctFactor' in kwargs:
4541 4751 correctFactor = kwargs['correctFactor']
4542 4752 else: correctFactor = 1
4543 4753 if 'channelList' in kwargs:
4544 4754 channelList = kwargs['channelList']
4545 4755 if len(channelList) == 2:
4546 4756 horizontalOnly = True
4547 4757 arrayChannel = numpy.array(channelList)
4548 4758 param = param[arrayChannel,:,:]
4549 4759 theta_x = theta_x[arrayChannel]
4550 4760 theta_y = theta_y[arrayChannel]
4551 4761
4552 4762 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
4553 4763 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
4554 4764 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
4555 4765
4556 4766 #Calculo de Componentes de la velocidad con DBS
4557 4767 winds = self.__calculateVelUVW(A,velRadial1)
4558 4768
4559 4769 return winds, heiRang1, SNR1
4560 4770
4561 4771 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
4562 4772
4563 4773 nPairs = len(pairs_ccf)
4564 4774 posx = numpy.asarray(posx)
4565 4775 posy = numpy.asarray(posy)
4566 4776
4567 4777 #Rotacion Inversa para alinear con el azimuth
4568 4778 if azimuth!= None:
4569 4779 azimuth = azimuth*math.pi/180
4570 4780 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
4571 4781 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
4572 4782 else:
4573 4783 posx1 = posx
4574 4784 posy1 = posy
4575 4785
4576 4786 #Calculo de Distancias
4577 4787 distx = numpy.zeros(nPairs)
4578 4788 disty = numpy.zeros(nPairs)
4579 4789 dist = numpy.zeros(nPairs)
4580 4790 ang = numpy.zeros(nPairs)
4581 4791
4582 4792 for i in range(nPairs):
4583 4793 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
4584 4794 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
4585 4795 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
4586 4796 ang[i] = numpy.arctan2(disty[i],distx[i])
4587 4797
4588 4798 return distx, disty, dist, ang
4589 4799 #Calculo de Matrices
4590 4800
4591
4592 4801 def __calculateVelVer(self, phase, lagTRange, _lambda):
4593 4802
4594 4803 Ts = lagTRange[1] - lagTRange[0]
4595 4804 velW = -_lambda*phase/(4*math.pi*Ts)
4596 4805
4597 4806 return velW
4598 4807
4599 4808 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
4600 4809 nPairs = tau1.shape[0]
4601 4810 nHeights = tau1.shape[1]
4602 4811 vel = numpy.zeros((nPairs,3,nHeights))
4603 4812 dist1 = numpy.reshape(dist, (dist.size,1))
4604 4813
4605 4814 angCos = numpy.cos(ang)
4606 4815 angSin = numpy.sin(ang)
4607 4816
4608 4817 vel0 = dist1*tau1/(2*tau2**2)
4609 4818 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
4610 4819 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
4611 4820
4612 4821 ind = numpy.where(numpy.isinf(vel))
4613 4822 vel[ind] = numpy.nan
4614 4823
4615 4824 return vel
4616 4825
4617 4826 def techniqueSA(self, kwargs):
4618 4827
4619 4828 """
4620 4829 Function that implements Spaced Antenna (SA) technique.
4621 4830
4622 4831 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
4623 4832 Direction correction (if necessary), Ranges and SNR
4624 4833
4625 4834 Output: Winds estimation (Zonal, Meridional and Vertical)
4626 4835
4627 4836 Parameters affected: Winds
4628 4837 """
4629 4838 position_x = kwargs['positionX']
4630 4839 position_y = kwargs['positionY']
4631 4840 azimuth = kwargs['azimuth']
4632 4841
4633 4842 if 'correctFactor' in kwargs:
4634 4843 correctFactor = kwargs['correctFactor']
4635 4844 else:
4636 4845 correctFactor = 1
4637 4846
4638 4847 groupList = kwargs['groupList']
4639 4848 pairs_ccf = groupList[1]
4640 4849 tau = kwargs['tau']
4641 4850 _lambda = kwargs['_lambda']
4642 4851
4643 4852 #Cross Correlation pairs obtained
4644 4853
4645 4854 indtau = tau.shape[0]/2
4646 4855 tau1 = tau[:indtau,:]
4647 4856 tau2 = tau[indtau:-1,:]
4648 4857 phase1 = tau[-1,:]
4649 4858
4650 4859 #---------------------------------------------------------------------
4651 4860 #Metodo Directo
4652 4861 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
4653 4862 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
4654 4863 winds = stats.nanmean(winds, axis=0)
4655 4864 #---------------------------------------------------------------------
4656 4865 #Metodo General
4657 4866
4658 4867 #---------------------------------------------------------------------
4659 4868 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
4660 4869 winds = correctFactor*winds
4661 4870 return winds
4662 4871
4663 4872 def __checkTime(self, currentTime, paramInterval, outputInterval):
4664 4873
4665 4874 dataTime = currentTime + paramInterval
4666 4875 deltaTime = dataTime - self.__initime
4667 4876
4668 4877 if deltaTime >= outputInterval or deltaTime < 0:
4669 4878 self.__dataReady = True
4670 4879 return
4671 4880
4672 4881 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
4673 4882 '''
4674 4883 Function that implements winds estimation technique with detected meteors.
4675 4884
4676 4885 Input: Detected meteors, Minimum meteor quantity to wind estimation
4677 4886
4678 4887 Output: Winds estimation (Zonal and Meridional)
4679 4888
4680 4889 Parameters affected: Winds
4681 4890 '''
4682 4891 #Settings
4683 4892 nInt = (heightMax - heightMin)/2
4684 4893 nInt = int(nInt)
4685 4894 winds = numpy.zeros((2,nInt))*numpy.nan
4686 4895
4687 4896 #Filter errors
4688 4897 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
4689 4898 finalMeteor = arrayMeteor[error,:]
4690 4899
4691 4900 #Meteor Histogram
4692 4901 finalHeights = finalMeteor[:,2]
4693 4902 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
4694 4903 nMeteorsPerI = hist[0]
4695 4904 heightPerI = hist[1]
4696 4905
4697 4906 #Sort of meteors
4698 4907 indSort = finalHeights.argsort()
4699 4908 finalMeteor2 = finalMeteor[indSort,:]
4700 4909
4701 4910 # Calculating winds
4702 4911 ind1 = 0
4703 4912 ind2 = 0
4704 4913
4705 4914 for i in range(nInt):
4706 4915 nMet = nMeteorsPerI[i]
4707 4916 ind1 = ind2
4708 4917 ind2 = ind1 + nMet
4709 4918
4710 4919 meteorAux = finalMeteor2[ind1:ind2,:]
4711 4920
4712 4921 if meteorAux.shape[0] >= meteorThresh:
4713 4922 vel = meteorAux[:, 6]
4714 4923 zen = meteorAux[:, 4]*numpy.pi/180
4715 4924 azim = meteorAux[:, 3]*numpy.pi/180
4716 4925
4717 4926 n = numpy.cos(zen)
4718 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
4719 # l = m*numpy.tan(azim)
4720 4927 l = numpy.sin(zen)*numpy.sin(azim)
4721 4928 m = numpy.sin(zen)*numpy.cos(azim)
4722 4929
4723 4930 A = numpy.vstack((l, m)).transpose()
4724 4931 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
4725 4932 windsAux = numpy.dot(A1, vel)
4726 4933
4727 4934 winds[0,i] = windsAux[0]
4728 4935 winds[1,i] = windsAux[1]
4729 4936
4730 4937 return winds, heightPerI[:-1]
4731 4938
4732 4939 def techniqueNSM_SA(self, **kwargs):
4733 4940 metArray = kwargs['metArray']
4734 4941 heightList = kwargs['heightList']
4735 4942 timeList = kwargs['timeList']
4736 4943
4737 4944 rx_location = kwargs['rx_location']
4738 4945 groupList = kwargs['groupList']
4739 4946 azimuth = kwargs['azimuth']
4740 4947 dfactor = kwargs['dfactor']
4741 4948 k = kwargs['k']
4742 4949
4743 4950 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
4744 4951 d = dist*dfactor
4745 4952 #Phase calculation
4746 4953 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
4747 4954
4748 4955 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
4749 4956
4750 4957 velEst = numpy.zeros((heightList.size,2))*numpy.nan
4751 4958 azimuth1 = azimuth1*numpy.pi/180
4752 4959
4753 4960 for i in range(heightList.size):
4754 4961 h = heightList[i]
4755 4962 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
4756 4963 metHeight = metArray1[indH,:]
4757 4964 if metHeight.shape[0] >= 2:
4758 4965 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
4759 4966 iazim = metHeight[:,1].astype(int)
4760 4967 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
4761 4968 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
4762 4969 A = numpy.asmatrix(A)
4763 4970 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
4764 4971 velHor = numpy.dot(A1,velAux)
4765 4972
4766 4973 velEst[i,:] = numpy.squeeze(velHor)
4767 4974 return velEst
4768 4975
4769 4976 def __getPhaseSlope(self, metArray, heightList, timeList):
4770 4977 meteorList = []
4771 4978 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
4772 4979 #Putting back together the meteor matrix
4773 4980 utctime = metArray[:,0]
4774 4981 uniqueTime = numpy.unique(utctime)
4775 4982
4776 4983 phaseDerThresh = 0.5
4777 4984 ippSeconds = timeList[1] - timeList[0]
4778 4985 sec = numpy.where(timeList>1)[0][0]
4779 4986 nPairs = metArray.shape[1] - 6
4780 4987 nHeights = len(heightList)
4781 4988
4782 4989 for t in uniqueTime:
4783 4990 metArray1 = metArray[utctime==t,:]
4784 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
4785 4991 tmet = metArray1[:,1].astype(int)
4786 4992 hmet = metArray1[:,2].astype(int)
4787 4993
4788 4994 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
4789 4995 metPhase[:,:] = numpy.nan
4790 4996 metPhase[:,hmet,tmet] = metArray1[:,6:].T
4791 4997
4792 4998 #Delete short trails
4793 4999 metBool = ~numpy.isnan(metPhase[0,:,:])
4794 5000 heightVect = numpy.sum(metBool, axis = 1)
4795 5001 metBool[heightVect<sec,:] = False
4796 5002 metPhase[:,heightVect<sec,:] = numpy.nan
4797 5003
4798 5004 #Derivative
4799 5005 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
4800 5006 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
4801 5007 metPhase[phDerAux] = numpy.nan
4802 5008
4803 5009 #--------------------------METEOR DETECTION -----------------------------------------
4804 5010 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
4805 5011
4806 5012 for p in numpy.arange(nPairs):
4807 5013 phase = metPhase[p,:,:]
4808 5014 phDer = metDer[p,:,:]
4809 5015
4810 5016 for h in indMet:
4811 5017 height = heightList[h]
4812 5018 phase1 = phase[h,:] #82
4813 5019 phDer1 = phDer[h,:]
4814 5020
4815 5021 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
4816 5022
4817 5023 indValid = numpy.where(~numpy.isnan(phase1))[0]
4818 5024 initMet = indValid[0]
4819 5025 endMet = 0
4820 5026
4821 5027 for i in range(len(indValid)-1):
4822 5028
4823 5029 #Time difference
4824 5030 inow = indValid[i]
4825 5031 inext = indValid[i+1]
4826 5032 idiff = inext - inow
4827 5033 #Phase difference
4828 5034 phDiff = numpy.abs(phase1[inext] - phase1[inow])
4829 5035
4830 5036 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
4831 5037 sizeTrail = inow - initMet + 1
4832 5038 if sizeTrail>3*sec: #Too short meteors
4833 5039 x = numpy.arange(initMet,inow+1)*ippSeconds
4834 5040 y = phase1[initMet:inow+1]
4835 5041 ynnan = ~numpy.isnan(y)
4836 5042 x = x[ynnan]
4837 5043 y = y[ynnan]
4838 5044 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
4839 5045 ylin = x*slope + intercept
4840 5046 rsq = r_value**2
4841 5047 if rsq > 0.5:
4842 5048 vel = slope#*height*1000/(k*d)
4843 5049 estAux = numpy.array([utctime,p,height, vel, rsq])
4844 5050 meteorList.append(estAux)
4845 5051 initMet = inext
4846 5052 metArray2 = numpy.array(meteorList)
4847 5053
4848 5054 return metArray2
4849 5055
4850 5056 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
4851 5057
4852 5058 azimuth1 = numpy.zeros(len(pairslist))
4853 5059 dist = numpy.zeros(len(pairslist))
4854 5060
4855 5061 for i in range(len(rx_location)):
4856 5062 ch0 = pairslist[i][0]
4857 5063 ch1 = pairslist[i][1]
4858 5064
4859 5065 diffX = rx_location[ch0][0] - rx_location[ch1][0]
4860 5066 diffY = rx_location[ch0][1] - rx_location[ch1][1]
4861 5067 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
4862 5068 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
4863 5069
4864 5070 azimuth1 -= azimuth0
4865 5071 return azimuth1, dist
4866 5072
4867 5073 def techniqueNSM_DBS(self, **kwargs):
4868 5074 metArray = kwargs['metArray']
4869 5075 heightList = kwargs['heightList']
4870 5076 timeList = kwargs['timeList']
4871 5077 azimuth = kwargs['azimuth']
4872 5078 theta_x = numpy.array(kwargs['theta_x'])
4873 5079 theta_y = numpy.array(kwargs['theta_y'])
4874 5080
4875 5081 utctime = metArray[:,0]
4876 5082 cmet = metArray[:,1].astype(int)
4877 5083 hmet = metArray[:,3].astype(int)
4878 5084 SNRmet = metArray[:,4]
4879 5085 vmet = metArray[:,5]
4880 5086 spcmet = metArray[:,6]
4881 5087
4882 5088 nChan = numpy.max(cmet) + 1
4883 5089 nHeights = len(heightList)
4884 5090
4885 5091 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
4886 5092 hmet = heightList[hmet]
4887 5093 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
4888 5094
4889 5095 velEst = numpy.zeros((heightList.size,2))*numpy.nan
4890 5096
4891 5097 for i in range(nHeights - 1):
4892 5098 hmin = heightList[i]
4893 5099 hmax = heightList[i + 1]
4894 5100
4895 5101 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
4896 5102 indthisH = numpy.where(thisH)
4897 5103
4898 5104 if numpy.size(indthisH) > 3:
4899 5105
4900 5106 vel_aux = vmet[thisH]
4901 5107 chan_aux = cmet[thisH]
4902 5108 cosu_aux = dir_cosu[chan_aux]
4903 5109 cosv_aux = dir_cosv[chan_aux]
4904 5110 cosw_aux = dir_cosw[chan_aux]
4905 5111
4906 5112 nch = numpy.size(numpy.unique(chan_aux))
4907 5113 if nch > 1:
4908 5114 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
4909 5115 velEst[i,:] = numpy.dot(A,vel_aux)
4910 5116
4911 5117 return velEst
4912 5118
4913 5119 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
4914 5120
4915 param = dataOut.data_param
4916 #if dataOut.abscissaList != None:
5121 param = dataOut.moments ### LA VERSION ANTERIOR trabajaba con param = dataOut.data_param
4917 5122 if numpy.any(dataOut.abscissaList):
4918 5123 absc = dataOut.abscissaList[:-1]
4919 5124 # noise = dataOut.noise
4920 5125 heightList = dataOut.heightList
4921 5126 SNR = dataOut.data_snr
4922 5127
4923 5128 if technique == 'DBS':
4924 5129
4925 5130 kwargs['velRadial'] = param[:,1,:] #Radial velocity
4926 5131 kwargs['heightList'] = heightList
4927 5132 kwargs['SNR'] = SNR
4928 5133
4929 5134 dataOut.data_output, dataOut.heightList, dataOut.data_snr = self.techniqueDBS(kwargs) #DBS Function
4930 5135 dataOut.utctimeInit = dataOut.utctime
4931 5136 dataOut.outputInterval = dataOut.paramInterval
4932 5137
4933 5138 elif technique == 'SA':
4934 5139
4935 5140 #Parameters
4936 # position_x = kwargs['positionX']
4937 # position_y = kwargs['positionY']
4938 # azimuth = kwargs['azimuth']
4939 #
4940 # if kwargs.has_key('crosspairsList'):
4941 # pairs = kwargs['crosspairsList']
4942 # else:
4943 # pairs = None
4944 #
4945 # if kwargs.has_key('correctFactor'):
4946 # correctFactor = kwargs['correctFactor']
4947 # else:
4948 # correctFactor = 1
4949
4950 # tau = dataOut.data_param
4951 # _lambda = dataOut.C/dataOut.frequency
4952 # pairsList = dataOut.groupList
4953 # nChannels = dataOut.nChannels
4954
4955 5141 kwargs['groupList'] = dataOut.groupList
4956 5142 kwargs['tau'] = dataOut.data_param
4957 5143 kwargs['_lambda'] = dataOut.C/dataOut.frequency
4958 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
4959 5144 dataOut.data_output = self.techniqueSA(kwargs)
4960 5145 dataOut.utctimeInit = dataOut.utctime
4961 5146 dataOut.outputInterval = dataOut.timeInterval
4962 5147
4963 5148 elif technique == 'Meteors':
4964 5149 dataOut.flagNoData = True
4965 5150 self.__dataReady = False
4966 5151
4967 5152 if 'nHours' in kwargs:
4968 5153 nHours = kwargs['nHours']
4969 5154 else:
4970 5155 nHours = 1
4971 5156
4972 5157 if 'meteorsPerBin' in kwargs:
4973 5158 meteorThresh = kwargs['meteorsPerBin']
4974 5159 else:
4975 5160 meteorThresh = 6
4976 5161
4977 5162 if 'hmin' in kwargs:
4978 5163 hmin = kwargs['hmin']
4979 5164 else: hmin = 70
4980 5165 if 'hmax' in kwargs:
4981 5166 hmax = kwargs['hmax']
4982 5167 else: hmax = 110
4983 5168
4984 5169 dataOut.outputInterval = nHours*3600
4985 5170
4986 5171 if self.__isConfig == False:
4987 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
4988 5172 #Get Initial LTC time
4989 5173 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
4990 5174 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
4991 5175
4992 5176 self.__isConfig = True
4993 5177
4994 5178 if self.__buffer is None:
4995 5179 self.__buffer = dataOut.data_param
4996 5180 self.__firstdata = copy.copy(dataOut)
4997 5181
4998 5182 else:
4999 5183 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
5000 5184
5001 5185 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
5002 5186
5003 5187 if self.__dataReady:
5004 5188 dataOut.utctimeInit = self.__initime
5005 5189
5006 5190 self.__initime += dataOut.outputInterval #to erase time offset
5007 5191
5008 5192 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
5009 5193 dataOut.flagNoData = False
5010 5194 self.__buffer = None
5011 5195
5012 5196 elif technique == 'Meteors1':
5013 5197 dataOut.flagNoData = True
5014 5198 self.__dataReady = False
5015 5199
5016 5200 if 'nMins' in kwargs:
5017 5201 nMins = kwargs['nMins']
5018 5202 else: nMins = 20
5019 5203 if 'rx_location' in kwargs:
5020 5204 rx_location = kwargs['rx_location']
5021 5205 else: rx_location = [(0,1),(1,1),(1,0)]
5022 5206 if 'azimuth' in kwargs:
5023 5207 azimuth = kwargs['azimuth']
5024 5208 else: azimuth = 51.06
5025 5209 if 'dfactor' in kwargs:
5026 5210 dfactor = kwargs['dfactor']
5027 5211 if 'mode' in kwargs:
5028 5212 mode = kwargs['mode']
5029 5213 if 'theta_x' in kwargs:
5030 5214 theta_x = kwargs['theta_x']
5031 5215 if 'theta_y' in kwargs:
5032 5216 theta_y = kwargs['theta_y']
5033 5217 else: mode = 'SA'
5034 5218
5035 5219 #Borrar luego esto
5036 5220 if dataOut.groupList is None:
5037 5221 dataOut.groupList = [(0,1),(0,2),(1,2)]
5038 5222 groupList = dataOut.groupList
5039 5223 C = 3e8
5040 5224 freq = 50e6
5041 5225 lamb = C/freq
5042 5226 k = 2*numpy.pi/lamb
5043 5227
5044 5228 timeList = dataOut.abscissaList
5045 5229 heightList = dataOut.heightList
5046 5230
5047 5231 if self.__isConfig == False:
5048 5232 dataOut.outputInterval = nMins*60
5049 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
5050 5233 #Get Initial LTC time
5051 5234 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
5052 5235 minuteAux = initime.minute
5053 5236 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
5054 5237 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
5055 5238
5056 5239 self.__isConfig = True
5057 5240
5058 5241 if self.__buffer is None:
5059 5242 self.__buffer = dataOut.data_param
5060 5243 self.__firstdata = copy.copy(dataOut)
5061 5244
5062 5245 else:
5063 5246 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
5064 5247
5065 5248 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
5066 5249
5067 5250 if self.__dataReady:
5068 5251 dataOut.utctimeInit = self.__initime
5069 5252 self.__initime += dataOut.outputInterval #to erase time offset
5070 5253
5071 5254 metArray = self.__buffer
5072 5255 if mode == 'SA':
5073 5256 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
5074 5257 elif mode == 'DBS':
5075 5258 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
5076 5259 dataOut.data_output = dataOut.data_output.T
5077 5260 dataOut.flagNoData = False
5078 5261 self.__buffer = None
5079 5262
5080 return
5081
5082 class WindProfiler(Operation):
5083
5084 __isConfig = False
5085
5086 __initime = None
5087 __lastdatatime = None
5088 __integrationtime = None
5089
5090 __buffer = None
5091
5092 __dataReady = False
5093
5094 __firstdata = None
5263 return dataOut
5095 5264
5096 n = None
5265 class EWDriftsEstimation(Operation):
5097 5266
5098 5267 def __init__(self):
5099 5268 Operation.__init__(self)
5100 5269
5101 def __calculateCosDir(self, elev, azim):
5102 zen = (90 - elev)*numpy.pi/180
5103 azim = azim*numpy.pi/180
5104 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
5105 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
5106
5107 signX = numpy.sign(numpy.cos(azim))
5108 signY = numpy.sign(numpy.sin(azim))
5109
5110 cosDirX = numpy.copysign(cosDirX, signX)
5111 cosDirY = numpy.copysign(cosDirY, signY)
5112 return cosDirX, cosDirY
5113
5114 def __calculateAngles(self, theta_x, theta_y, azimuth):
5115
5116 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
5117 zenith_arr = numpy.arccos(dir_cosw)
5118 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
5119
5120 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
5121 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
5122
5123 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
5124
5125 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
5126
5127 if horOnly:
5128 A = numpy.c_[dir_cosu,dir_cosv]
5129 else:
5130 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
5131 A = numpy.asmatrix(A)
5132 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
5133
5134 return A1
5135
5136 5270 def __correctValues(self, heiRang, phi, velRadial, SNR):
5137 5271 listPhi = phi.tolist()
5138 5272 maxid = listPhi.index(max(listPhi))
5139 5273 minid = listPhi.index(min(listPhi))
5140 5274
5141 5275 rango = list(range(len(phi)))
5142
5143 5276 heiRang1 = heiRang*math.cos(phi[maxid])
5144 5277 heiRangAux = heiRang*math.cos(phi[minid])
5145 5278 indOut = (heiRang1 < heiRangAux[0]).nonzero()
5146 5279 heiRang1 = numpy.delete(heiRang1,indOut)
5147 5280
5148 5281 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
5149 5282 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
5150 5283
5151 5284 for i in rango:
5152 5285 x = heiRang*math.cos(phi[i])
5153 5286 y1 = velRadial[i,:]
5154 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
5155
5287 vali= (numpy.isfinite(y1)==True).nonzero()
5288 y1=y1[vali]
5289 x = x[vali]
5290 f1 = interpolate.interp1d(x,y1,kind = 'cubic',bounds_error=False)
5156 5291 x1 = heiRang1
5157 5292 y11 = f1(x1)
5158
5159 5293 y2 = SNR[i,:]
5160 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
5294 x = heiRang*math.cos(phi[i])
5295 vali= (y2 != -1).nonzero()
5296 y2 = y2[vali]
5297 x = x[vali]
5298 f2 = interpolate.interp1d(x,y2,kind = 'cubic',bounds_error=False)
5161 5299 y21 = f2(x1)
5162 5300
5163 5301 velRadial1[i,:] = y11
5164 5302 SNR1[i,:] = y21
5165 5303
5166 5304 return heiRang1, velRadial1, SNR1
5167 5305
5168 def __calculateVelUVW(self, A, velRadial):
5306 def run(self, dataOut, zenith, zenithCorrection,fileDrifts,beam_pos=None):
5307 dataOut.lat = -11.95
5308 dataOut.lon = -76.87
5309 dataOut.spcst = 0.00666
5310 dataOut.pl = 0.0003
5311 dataOut.cbadn = 3
5312 dataOut.inttms = 300
5313 if numpy.any(beam_pos) :
5314 dataOut.azw = beam_pos[0] # -115.687
5315 dataOut.elw = beam_pos[1] # 86.1095
5316 dataOut.aze = beam_pos[2] # 130.052
5317 dataOut.ele = beam_pos[3] # 87.6558
5318 dataOut.jro14 = numpy.log10(dataOut.spc_noise[0]/dataOut.normFactor)
5319 dataOut.jro15 = numpy.log10(dataOut.spc_noise[1]/dataOut.normFactor)
5320 dataOut.jro16 = numpy.log10(dataOut.spc_noise[2]/dataOut.normFactor)
5321 dataOut.nwlos = numpy.log10(dataOut.spc_noise[3]/dataOut.normFactor)
5169 5322
5170 #Operacion Matricial
5171 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
5172 velUVW[:,:] = numpy.dot(A,velRadial)
5323 heiRang = dataOut.heightList
5324 velRadial = dataOut.data_param[:,3,:]
5325 velRadialm = dataOut.data_param[:,2:4,:]*-1
5173 5326
5327 rbufc=dataOut.data_paramC[:,:,0]
5328 ebufc=dataOut.data_paramC[:,:,1]
5329 SNR = dataOut.data_snr1_i
5330 rbufi = dataOut.data_snr1_i
5331 velRerr = dataOut.data_error[:,4,:]
5332 range1 = dataOut.heightList
5333 nhei = len(range1)
5174 5334
5175 return velUVW
5335 sat_fits = dataOut.sat_fits
5176 5336
5177 def techniqueDBS(self, kwargs):
5178 """
5179 Function that implements Doppler Beam Swinging (DBS) technique.
5337 channels = dataOut.channelList
5338 nChan = len(channels)
5339 my_nbeams = nChan/2
5340 if my_nbeams == 2:
5341 moments=numpy.vstack(([velRadialm[0,:]],[velRadialm[0,:]],[velRadialm[1,:]],[velRadialm[1,:]]))
5342 else :
5343 moments=numpy.vstack(([velRadialm[0,:]],[velRadialm[0,:]]))
5344 dataOut.moments=moments
5345 #Incoherent
5346 smooth_w = dataOut.clean_num_aver[0,:]
5347 chisq_w = dataOut.data_error[0,0,:]
5348 p_w0 = rbufi[0,:]
5349 p_w1 = rbufi[1,:]
5180 5350
5181 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
5182 Direction correction (if necessary), Ranges and SNR
5351 # Coherent
5352 smooth_wC = ebufc[0,:]
5353 p_w0C = rbufc[0,:]
5354 p_w1C = rbufc[1,:]
5355 w_wC = rbufc[2,:]*-1 #*radial_sign(radial EQ 1)
5356 t_wC = rbufc[3,:]
5357 val = (numpy.isfinite(p_w0)==False).nonzero()
5358 p_w0[val]=0
5359 val = (numpy.isfinite(p_w1)==False).nonzero()
5360 p_w1[val]=0
5361 val = (numpy.isfinite(p_w0C)==False).nonzero()
5362 p_w0C[val]=0
5363 val = (numpy.isfinite(p_w1C)==False).nonzero()
5364 p_w1C[val]=0
5365 val = (numpy.isfinite(smooth_w)==False).nonzero()
5366 smooth_w[val]=0
5367 val = (numpy.isfinite(smooth_wC)==False).nonzero()
5368 smooth_wC[val]=0
5183 5369
5184 Output: Winds estimation (Zonal, Meridional and Vertical)
5370 p_w0_a = (p_w0*smooth_w+p_w0C*smooth_wC)/(smooth_w+smooth_wC)
5371 p_w1_a = (p_w1*smooth_w+p_w1C*smooth_wC)/(smooth_w+smooth_wC)
5185 5372
5186 Parameters affected: Winds, height range, SNR
5187 """
5188 velRadial0 = kwargs['velRadial']
5189 heiRang = kwargs['heightList']
5190 SNR0 = kwargs['SNR']
5373 if len(sat_fits) >0 :
5374 p_w0C = p_w0C + sat_fits[0,:]
5375 p_w1C = p_w1C + sat_fits[1,:]
5191 5376
5192 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
5193 theta_x = numpy.array(kwargs['dirCosx'])
5194 theta_y = numpy.array(kwargs['dirCosy'])
5377 if my_nbeams == 1:
5378 w = velRadial[0,:]
5379 winds = velRadial.copy()
5380 w_err = velRerr[0,:]
5381 werrtmp = numpy.where(numpy.isfinite(w)==True,w_err,numpy.nan)
5382 w_err = werrtmp.copy()
5383 u = w*numpy.nan
5384 u_err = w_err*numpy.nan
5385 p_e0 = p_w0*numpy.nan
5386 p_e1 = p_w1*numpy.nan
5387 #snr1 = 10*numpy.log10(SNR[0])
5388 if my_nbeams == 2:
5389
5390 zenith = numpy.array(zenith)
5391 zenith -= zenithCorrection
5392 zenith *= numpy.pi/180
5393 if zenithCorrection != 0 :
5394 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
5195 5395 else :
5196 elev = numpy.array(kwargs['elevation'])
5197 azim = numpy.array(kwargs['azimuth'])
5198 theta_x, theta_y = self.__calculateCosDir(elev, azim)
5199 azimuth = kwargs['correctAzimuth']
5200 if 'horizontalOnly' in kwargs:
5201 horizontalOnly = kwargs['horizontalOnly']
5202 else: horizontalOnly = False
5203 if 'correctFactor' in kwargs:
5204 correctFactor = kwargs['correctFactor']
5205 else: correctFactor = 1
5206 if 'channelList' in kwargs:
5207 channelList = kwargs['channelList']
5208 if len(channelList) == 2:
5209 horizontalOnly = True
5210 arrayChannel = numpy.array(channelList)
5211 param = param[arrayChannel,:,:]
5212 theta_x = theta_x[arrayChannel]
5213 theta_y = theta_y[arrayChannel]
5396 heiRang1 = heiRang
5397 velRadial1 = velRadial
5398 SNR1 = SNR
5214 5399
5215 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
5216 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
5217 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
5400 alp = zenith[0]
5401 bet = zenith[1]
5218 5402
5219 #Calculo de Componentes de la velocidad con DBS
5220 winds = self.__calculateVelUVW(A,velRadial1)
5403 w_w = velRadial1[0,:]
5404 w_e = velRadial1[1,:]
5405 w_w_err = velRerr[0,:]
5406 w_e_err = velRerr[1,:]
5407 smooth_e = dataOut.clean_num_aver[2,:]
5408 chisq_e = dataOut.data_error[1,0,:]
5409 p_e0 = rbufi[2,:]
5410 p_e1 = rbufi[3,:]
5221 5411
5222 return winds, heiRang1, SNR1
5412 tini=time.localtime(dataOut.utctime)
5223 5413
5224 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
5225
5226 nPairs = len(pairs_ccf)
5227 posx = numpy.asarray(posx)
5228 posy = numpy.asarray(posy)
5229
5230 #Rotacion Inversa para alinear con el azimuth
5231 if azimuth!= None:
5232 azimuth = azimuth*math.pi/180
5233 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
5234 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
5235 else:
5236 posx1 = posx
5237 posy1 = posy
5238
5239 #Calculo de Distancias
5240 distx = numpy.zeros(nPairs)
5241 disty = numpy.zeros(nPairs)
5242 dist = numpy.zeros(nPairs)
5243 ang = numpy.zeros(nPairs)
5244
5245 for i in range(nPairs):
5246 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
5247 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
5248 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
5249 ang[i] = numpy.arctan2(disty[i],distx[i])
5250
5251 return distx, disty, dist, ang
5252 #Calculo de Matrices
5253
5254 def __calculateVelVer(self, phase, lagTRange, _lambda):
5255
5256 Ts = lagTRange[1] - lagTRange[0]
5257 velW = -_lambda*phase/(4*math.pi*Ts)
5258
5259 return velW
5260
5261 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
5262 nPairs = tau1.shape[0]
5263 nHeights = tau1.shape[1]
5264 vel = numpy.zeros((nPairs,3,nHeights))
5265 dist1 = numpy.reshape(dist, (dist.size,1))
5266
5267 angCos = numpy.cos(ang)
5268 angSin = numpy.sin(ang)
5269
5270 vel0 = dist1*tau1/(2*tau2**2)
5271 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
5272 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
5273
5274 ind = numpy.where(numpy.isinf(vel))
5275 vel[ind] = numpy.nan
5276
5277 return vel
5278
5279 def techniqueSA(self, kwargs):
5280
5281 """
5282 Function that implements Spaced Antenna (SA) technique.
5283
5284 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
5285 Direction correction (if necessary), Ranges and SNR
5286
5287 Output: Winds estimation (Zonal, Meridional and Vertical)
5288
5289 Parameters affected: Winds
5290 """
5291 position_x = kwargs['positionX']
5292 position_y = kwargs['positionY']
5293 azimuth = kwargs['azimuth']
5294
5295 if 'correctFactor' in kwargs:
5296 correctFactor = kwargs['correctFactor']
5297 else:
5298 correctFactor = 1
5299
5300 groupList = kwargs['groupList']
5301 pairs_ccf = groupList[1]
5302 tau = kwargs['tau']
5303 _lambda = kwargs['_lambda']
5304
5305 #Cross Correlation pairs obtained
5306
5307 indtau = tau.shape[0]/2
5308 tau1 = tau[:indtau,:]
5309 tau2 = tau[indtau:-1,:]
5310 phase1 = tau[-1,:]
5311
5312 #---------------------------------------------------------------------
5313 #Metodo Directo
5314 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
5315 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
5316 winds = stats.nanmean(winds, axis=0)
5317 #---------------------------------------------------------------------
5318 #Metodo General
5319
5320 #---------------------------------------------------------------------
5321 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
5322 winds = correctFactor*winds
5323 return winds
5324
5325 def __checkTime(self, currentTime, paramInterval, outputInterval):
5326
5327 dataTime = currentTime + paramInterval
5328 deltaTime = dataTime - self.__initime
5329
5330 if deltaTime >= outputInterval or deltaTime < 0:
5331 self.__dataReady = True
5332 return
5333
5334 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
5335 '''
5336 Function that implements winds estimation technique with detected meteors.
5337
5338 Input: Detected meteors, Minimum meteor quantity to wind estimation
5339
5340 Output: Winds estimation (Zonal and Meridional)
5341
5342 Parameters affected: Winds
5343 '''
5344 #Settings
5345 nInt = (heightMax - heightMin)/2
5346 nInt = int(nInt)
5347 winds = numpy.zeros((2,nInt))*numpy.nan
5348
5349 #Filter errors
5350 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
5351 finalMeteor = arrayMeteor[error,:]
5352
5353 #Meteor Histogram
5354 finalHeights = finalMeteor[:,2]
5355 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
5356 nMeteorsPerI = hist[0]
5357 heightPerI = hist[1]
5358
5359 #Sort of meteors
5360 indSort = finalHeights.argsort()
5361 finalMeteor2 = finalMeteor[indSort,:]
5362
5363 # Calculating winds
5364 ind1 = 0
5365 ind2 = 0
5366
5367 for i in range(nInt):
5368 nMet = nMeteorsPerI[i]
5369 ind1 = ind2
5370 ind2 = ind1 + nMet
5371
5372 meteorAux = finalMeteor2[ind1:ind2,:]
5373
5374 if meteorAux.shape[0] >= meteorThresh:
5375 vel = meteorAux[:, 6]
5376 zen = meteorAux[:, 4]*numpy.pi/180
5377 azim = meteorAux[:, 3]*numpy.pi/180
5378
5379 n = numpy.cos(zen)
5380 l = numpy.sin(zen)*numpy.sin(azim)
5381 m = numpy.sin(zen)*numpy.cos(azim)
5382
5383 A = numpy.vstack((l, m)).transpose()
5384 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
5385 windsAux = numpy.dot(A1, vel)
5386
5387 winds[0,i] = windsAux[0]
5388 winds[1,i] = windsAux[1]
5389
5390 return winds, heightPerI[:-1]
5391
5392 def techniqueNSM_SA(self, **kwargs):
5393 metArray = kwargs['metArray']
5394 heightList = kwargs['heightList']
5395 timeList = kwargs['timeList']
5396
5397 rx_location = kwargs['rx_location']
5398 groupList = kwargs['groupList']
5399 azimuth = kwargs['azimuth']
5400 dfactor = kwargs['dfactor']
5401 k = kwargs['k']
5402
5403 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
5404 d = dist*dfactor
5405 #Phase calculation
5406 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
5407
5408 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
5409
5410 velEst = numpy.zeros((heightList.size,2))*numpy.nan
5411 azimuth1 = azimuth1*numpy.pi/180
5412
5413 for i in range(heightList.size):
5414 h = heightList[i]
5415 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
5416 metHeight = metArray1[indH,:]
5417 if metHeight.shape[0] >= 2:
5418 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
5419 iazim = metHeight[:,1].astype(int)
5420 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
5421 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
5422 A = numpy.asmatrix(A)
5423 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
5424 velHor = numpy.dot(A1,velAux)
5425
5426 velEst[i,:] = numpy.squeeze(velHor)
5427 return velEst
5428
5429 def __getPhaseSlope(self, metArray, heightList, timeList):
5430 meteorList = []
5431 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
5432 #Putting back together the meteor matrix
5433 utctime = metArray[:,0]
5434 uniqueTime = numpy.unique(utctime)
5435
5436 phaseDerThresh = 0.5
5437 ippSeconds = timeList[1] - timeList[0]
5438 sec = numpy.where(timeList>1)[0][0]
5439 nPairs = metArray.shape[1] - 6
5440 nHeights = len(heightList)
5441
5442 for t in uniqueTime:
5443 metArray1 = metArray[utctime==t,:]
5444 tmet = metArray1[:,1].astype(int)
5445 hmet = metArray1[:,2].astype(int)
5446
5447 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
5448 metPhase[:,:] = numpy.nan
5449 metPhase[:,hmet,tmet] = metArray1[:,6:].T
5450
5451 #Delete short trails
5452 metBool = ~numpy.isnan(metPhase[0,:,:])
5453 heightVect = numpy.sum(metBool, axis = 1)
5454 metBool[heightVect<sec,:] = False
5455 metPhase[:,heightVect<sec,:] = numpy.nan
5456
5457 #Derivative
5458 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
5459 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
5460 metPhase[phDerAux] = numpy.nan
5461
5462 #--------------------------METEOR DETECTION -----------------------------------------
5463 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
5464
5465 for p in numpy.arange(nPairs):
5466 phase = metPhase[p,:,:]
5467 phDer = metDer[p,:,:]
5468
5469 for h in indMet:
5470 height = heightList[h]
5471 phase1 = phase[h,:] #82
5472 phDer1 = phDer[h,:]
5473
5474 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
5475
5476 indValid = numpy.where(~numpy.isnan(phase1))[0]
5477 initMet = indValid[0]
5478 endMet = 0
5479
5480 for i in range(len(indValid)-1):
5481
5482 #Time difference
5483 inow = indValid[i]
5484 inext = indValid[i+1]
5485 idiff = inext - inow
5486 #Phase difference
5487 phDiff = numpy.abs(phase1[inext] - phase1[inow])
5488
5489 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
5490 sizeTrail = inow - initMet + 1
5491 if sizeTrail>3*sec: #Too short meteors
5492 x = numpy.arange(initMet,inow+1)*ippSeconds
5493 y = phase1[initMet:inow+1]
5494 ynnan = ~numpy.isnan(y)
5495 x = x[ynnan]
5496 y = y[ynnan]
5497 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
5498 ylin = x*slope + intercept
5499 rsq = r_value**2
5500 if rsq > 0.5:
5501 vel = slope#*height*1000/(k*d)
5502 estAux = numpy.array([utctime,p,height, vel, rsq])
5503 meteorList.append(estAux)
5504 initMet = inext
5505 metArray2 = numpy.array(meteorList)
5506
5507 return metArray2
5508
5509 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
5510
5511 azimuth1 = numpy.zeros(len(pairslist))
5512 dist = numpy.zeros(len(pairslist))
5513
5514 for i in range(len(rx_location)):
5515 ch0 = pairslist[i][0]
5516 ch1 = pairslist[i][1]
5517
5518 diffX = rx_location[ch0][0] - rx_location[ch1][0]
5519 diffY = rx_location[ch0][1] - rx_location[ch1][1]
5520 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
5521 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
5522
5523 azimuth1 -= azimuth0
5524 return azimuth1, dist
5525
5526 def techniqueNSM_DBS(self, **kwargs):
5527 metArray = kwargs['metArray']
5528 heightList = kwargs['heightList']
5529 timeList = kwargs['timeList']
5530 azimuth = kwargs['azimuth']
5531 theta_x = numpy.array(kwargs['theta_x'])
5532 theta_y = numpy.array(kwargs['theta_y'])
5533
5534 utctime = metArray[:,0]
5535 cmet = metArray[:,1].astype(int)
5536 hmet = metArray[:,3].astype(int)
5537 SNRmet = metArray[:,4]
5538 vmet = metArray[:,5]
5539 spcmet = metArray[:,6]
5540
5541 nChan = numpy.max(cmet) + 1
5542 nHeights = len(heightList)
5543
5544 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
5545 hmet = heightList[hmet]
5546 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
5547
5548 velEst = numpy.zeros((heightList.size,2))*numpy.nan
5549
5550 for i in range(nHeights - 1):
5551 hmin = heightList[i]
5552 hmax = heightList[i + 1]
5553
5554 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
5555 indthisH = numpy.where(thisH)
5556
5557 if numpy.size(indthisH) > 3:
5558
5559 vel_aux = vmet[thisH]
5560 chan_aux = cmet[thisH]
5561 cosu_aux = dir_cosu[chan_aux]
5562 cosv_aux = dir_cosv[chan_aux]
5563 cosw_aux = dir_cosw[chan_aux]
5564
5565 nch = numpy.size(numpy.unique(chan_aux))
5566 if nch > 1:
5567 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
5568 velEst[i,:] = numpy.dot(A,vel_aux)
5569
5570 return velEst
5571
5572 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
5573
5574 param = dataOut.moments
5575 if numpy.any(dataOut.abscissaList):
5576 absc = dataOut.abscissaList[:-1]
5577 # noise = dataOut.noise
5578 heightList = dataOut.heightList
5579 SNR = dataOut.data_snr
5580
5581 if technique == 'DBS':
5582
5583 kwargs['velRadial'] = param[:,1,:] #Radial velocity
5584 kwargs['heightList'] = heightList
5585 kwargs['SNR'] = SNR
5586
5587 dataOut.data_output, dataOut.heightList, dataOut.data_snr = self.techniqueDBS(kwargs) #DBS Function
5588 dataOut.utctimeInit = dataOut.utctime
5589 dataOut.outputInterval = dataOut.paramInterval
5590
5591 elif technique == 'SA':
5592
5593 #Parameters
5594 kwargs['groupList'] = dataOut.groupList
5595 kwargs['tau'] = dataOut.data_param
5596 kwargs['_lambda'] = dataOut.C/dataOut.frequency
5597 dataOut.data_output = self.techniqueSA(kwargs)
5598 dataOut.utctimeInit = dataOut.utctime
5599 dataOut.outputInterval = dataOut.timeInterval
5600
5601 elif technique == 'Meteors':
5602 dataOut.flagNoData = True
5603 self.__dataReady = False
5604
5605 if 'nHours' in kwargs:
5606 nHours = kwargs['nHours']
5607 else:
5608 nHours = 1
5609
5610 if 'meteorsPerBin' in kwargs:
5611 meteorThresh = kwargs['meteorsPerBin']
5612 else:
5613 meteorThresh = 6
5614
5615 if 'hmin' in kwargs:
5616 hmin = kwargs['hmin']
5617 else: hmin = 70
5618 if 'hmax' in kwargs:
5619 hmax = kwargs['hmax']
5620 else: hmax = 110
5621
5622 dataOut.outputInterval = nHours*3600
5623
5624 if self.__isConfig == False:
5625 #Get Initial LTC time
5626 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
5627 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
5628
5629 self.__isConfig = True
5630
5631 if self.__buffer is None:
5632 self.__buffer = dataOut.data_param
5633 self.__firstdata = copy.copy(dataOut)
5634
5635 else:
5636 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
5637
5638 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
5639
5640 if self.__dataReady:
5641 dataOut.utctimeInit = self.__initime
5642
5643 self.__initime += dataOut.outputInterval #to erase time offset
5644
5645 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
5646 dataOut.flagNoData = False
5647 self.__buffer = None
5648
5649 elif technique == 'Meteors1':
5650 dataOut.flagNoData = True
5651 self.__dataReady = False
5652
5653 if 'nMins' in kwargs:
5654 nMins = kwargs['nMins']
5655 else: nMins = 20
5656 if 'rx_location' in kwargs:
5657 rx_location = kwargs['rx_location']
5658 else: rx_location = [(0,1),(1,1),(1,0)]
5659 if 'azimuth' in kwargs:
5660 azimuth = kwargs['azimuth']
5661 else: azimuth = 51.06
5662 if 'dfactor' in kwargs:
5663 dfactor = kwargs['dfactor']
5664 if 'mode' in kwargs:
5665 mode = kwargs['mode']
5666 if 'theta_x' in kwargs:
5667 theta_x = kwargs['theta_x']
5668 if 'theta_y' in kwargs:
5669 theta_y = kwargs['theta_y']
5670 else: mode = 'SA'
5671
5672 #Borrar luego esto
5673 if dataOut.groupList is None:
5674 dataOut.groupList = [(0,1),(0,2),(1,2)]
5675 groupList = dataOut.groupList
5676 C = 3e8
5677 freq = 50e6
5678 lamb = C/freq
5679 k = 2*numpy.pi/lamb
5680
5681 timeList = dataOut.abscissaList
5682 heightList = dataOut.heightList
5683
5684 if self.__isConfig == False:
5685 dataOut.outputInterval = nMins*60
5686 #Get Initial LTC time
5687 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
5688 minuteAux = initime.minute
5689 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
5690 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
5691
5692 self.__isConfig = True
5693
5694 if self.__buffer is None:
5695 self.__buffer = dataOut.data_param
5696 self.__firstdata = copy.copy(dataOut)
5697
5698 else:
5699 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
5700
5701 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
5702
5703 if self.__dataReady:
5704 dataOut.utctimeInit = self.__initime
5705 self.__initime += dataOut.outputInterval #to erase time offset
5706
5707 metArray = self.__buffer
5708 if mode == 'SA':
5709 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
5710 elif mode == 'DBS':
5711 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
5712 dataOut.data_output = dataOut.data_output.T
5713 dataOut.flagNoData = False
5714 self.__buffer = None
5715
5716 return dataOut
5717
5718 class EWDriftsEstimation(Operation):
5719
5720 def __init__(self):
5721 Operation.__init__(self)
5722
5723 def __correctValues(self, heiRang, phi, velRadial, SNR):
5724 listPhi = phi.tolist()
5725 maxid = listPhi.index(max(listPhi))
5726 minid = listPhi.index(min(listPhi))
5727
5728 rango = list(range(len(phi)))
5729 heiRang1 = heiRang*math.cos(phi[maxid])
5730 heiRangAux = heiRang*math.cos(phi[minid])
5731 indOut = (heiRang1 < heiRangAux[0]).nonzero()
5732 heiRang1 = numpy.delete(heiRang1,indOut)
5733
5734 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
5735 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
5736
5737 for i in rango:
5738 x = heiRang*math.cos(phi[i])
5739 y1 = velRadial[i,:]
5740 vali= (numpy.isfinite(y1)==True).nonzero()
5741 y1=y1[vali]
5742 x = x[vali]
5743 f1 = interpolate.interp1d(x,y1,kind = 'cubic',bounds_error=False)
5744 x1 = heiRang1
5745 y11 = f1(x1)
5746 y2 = SNR[i,:]
5747 x = heiRang*math.cos(phi[i])
5748 vali= (y2 != -1).nonzero()
5749 y2 = y2[vali]
5750 x = x[vali]
5751 f2 = interpolate.interp1d(x,y2,kind = 'cubic',bounds_error=False)
5752 y21 = f2(x1)
5753
5754 velRadial1[i,:] = y11
5755 SNR1[i,:] = y21
5756
5757 return heiRang1, velRadial1, SNR1
5758
5759 def run(self, dataOut, zenith, zenithCorrection,fileDrifts):
5760
5761 dataOut.lat = -11.95
5762 dataOut.lon = -76.87
5763 dataOut.spcst = 0.00666
5764 dataOut.pl = 0.0003
5765 dataOut.cbadn = 3
5766 dataOut.inttms = 300
5767 dataOut.azw = -115.687
5768 dataOut.elw = 86.1095
5769 dataOut.aze = 130.052
5770 dataOut.ele = 87.6558
5771 dataOut.jro14 = numpy.log10(dataOut.spc_noise[0]/dataOut.normFactor)
5772 dataOut.jro15 = numpy.log10(dataOut.spc_noise[1]/dataOut.normFactor)
5773 dataOut.jro16 = numpy.log10(dataOut.spc_noise[2]/dataOut.normFactor)
5774 dataOut.nwlos = numpy.log10(dataOut.spc_noise[3]/dataOut.normFactor)
5775
5776 heiRang = dataOut.heightList
5777 velRadial = dataOut.data_param[:,3,:]
5778 velRadialm = dataOut.data_param[:,2:4,:]*-1
5779
5780 rbufc=dataOut.data_paramC[:,:,0]
5781 ebufc=dataOut.data_paramC[:,:,1]
5782 SNR = dataOut.data_snr1_i
5783 rbufi = dataOut.data_snr1_i
5784 velRerr = dataOut.data_error[:,4,:]
5785 range1 = dataOut.heightList
5786 nhei = len(range1)
5787
5788 sat_fits = dataOut.sat_fits
5789
5790 channels = dataOut.channelList
5791 nChan = len(channels)
5792 my_nbeams = nChan/2
5793 if my_nbeams == 2:
5794 moments=numpy.vstack(([velRadialm[0,:]],[velRadialm[0,:]],[velRadialm[1,:]],[velRadialm[1,:]]))
5795 else :
5796 moments=numpy.vstack(([velRadialm[0,:]],[velRadialm[0,:]]))
5797 dataOut.moments=moments
5798 #Incoherent
5799 smooth_w = dataOut.clean_num_aver[0,:]
5800 chisq_w = dataOut.data_error[0,0,:]
5801 p_w0 = rbufi[0,:]
5802 p_w1 = rbufi[1,:]
5803
5804 # Coherent
5805 smooth_wC = ebufc[0,:]
5806 p_w0C = rbufc[0,:]
5807 p_w1C = rbufc[1,:]
5808 w_wC = rbufc[2,:]*-1 #*radial_sign(radial EQ 1)
5809 t_wC = rbufc[3,:]
5810 val = (numpy.isfinite(p_w0)==False).nonzero()
5811 p_w0[val]=0
5812 val = (numpy.isfinite(p_w1)==False).nonzero()
5813 p_w1[val]=0
5814 val = (numpy.isfinite(p_w0C)==False).nonzero()
5815 p_w0C[val]=0
5816 val = (numpy.isfinite(p_w1C)==False).nonzero()
5817 p_w1C[val]=0
5818 val = (numpy.isfinite(smooth_w)==False).nonzero()
5819 smooth_w[val]=0
5820 val = (numpy.isfinite(smooth_wC)==False).nonzero()
5821 smooth_wC[val]=0
5822
5823 #p_w0 = (p_w0*smooth_w+p_w0C*smooth_wC)/(smooth_w+smooth_wC)
5824 #p_w1 = (p_w1*smooth_w+p_w1C*smooth_wC)/(smooth_w+smooth_wC)
5825
5826 if len(sat_fits) >0 :
5827 p_w0C = p_w0C + sat_fits[0,:]
5828 p_w1C = p_w1C + sat_fits[1,:]
5829
5830 if my_nbeams == 1:
5831 w = velRadial[0,:]
5832 winds = velRadial.copy()
5833 w_err = velRerr[0,:]
5834 u = w*numpy.nan
5835 u_err = w_err*numpy.nan
5836 p_e0 = p_w0*numpy.nan
5837 p_e1 = p_w1*numpy.nan
5838 #snr1 = 10*numpy.log10(SNR[0])
5839 if my_nbeams == 2:
5840
5841 zenith = numpy.array(zenith)
5842 zenith -= zenithCorrection
5843 zenith *= numpy.pi/180
5844 if zenithCorrection != 0 :
5845 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
5846 else :
5847 heiRang1 = heiRang
5848 velRadial1 = velRadial
5849 SNR1 = SNR
5850
5851 alp = zenith[0]
5852 bet = zenith[1]
5853
5854 w_w = velRadial1[0,:]
5855 w_e = velRadial1[1,:]
5856 w_w_err = velRerr[0,:]
5857 w_e_err = velRerr[1,:]
5858 smooth_e = dataOut.clean_num_aver[2,:]
5859 chisq_e = dataOut.data_error[1,0,:]
5860 p_e0 = rbufi[2,:]
5861 p_e1 = rbufi[3,:]
5862
5863 tini=time.localtime(dataOut.utctime)
5864
5865 if tini[3] >= 6 and tini[3] < 18 :
5866 w_wtmp = numpy.where(numpy.isfinite(w_wC)==True,w_wC,w_w)
5867 w_w_errtmp = numpy.where(numpy.isfinite(w_wC)==True,numpy.nan,w_w_err)
5868 else:
5869 w_wtmp = numpy.where(numpy.isfinite(w_wC)==True,w_wC,w_w)
5870 w_wtmp = numpy.where(range1 > 200,w_w,w_wtmp)
5871 w_w_errtmp = numpy.where(numpy.isfinite(w_wC)==True,numpy.nan,w_w_err)
5872 w_w_errtmp = numpy.where(range1 > 200,w_w_err,w_w_errtmp)
5873 w_w = w_wtmp
5874 w_w_err = w_w_errtmp
5414 if tini[3] >= 6 and tini[3] < 18 :
5415 w_wtmp = numpy.where(numpy.isfinite(w_wC)==True,w_wC,w_w)
5416 w_w_errtmp = numpy.where(numpy.isfinite(w_wC)==True,numpy.nan,w_w_err)
5417 else:
5418 w_wtmp = numpy.where(numpy.isfinite(w_wC)==True,w_wC,w_w)
5419 w_wtmp = numpy.where(range1 > 200,w_w,w_wtmp)
5420 w_w_errtmp = numpy.where(numpy.isfinite(w_wC)==True,numpy.nan,w_w_err)
5421 w_w_errtmp = numpy.where(range1 > 200,w_w_err,w_w_errtmp)
5422 w_w = w_wtmp
5423 w_w_err = w_w_errtmp
5875 5424
5876 5425 #if my_nbeams == 2:
5877 5426 smooth_eC=ebufc[4,:]
5878 5427 p_e0C = rbufc[4,:]
5879 5428 p_e1C = rbufc[5,:]
5880 5429 w_eC = rbufc[6,:]*-1
5881 5430 t_eC = rbufc[7,:]
5882 5431 val = (numpy.isfinite(p_e0)==False).nonzero()
5883 5432 p_e0[val]=0
5884 5433 val = (numpy.isfinite(p_e1)==False).nonzero()
5885 5434 p_e1[val]=0
5886 5435 val = (numpy.isfinite(p_e0C)==False).nonzero()
5887 5436 p_e0C[val]=0
5888 5437 val = (numpy.isfinite(p_e1C)==False).nonzero()
5889 5438 p_e1C[val]=0
5890 5439 val = (numpy.isfinite(smooth_e)==False).nonzero()
5891 5440 smooth_e[val]=0
5892 5441 val = (numpy.isfinite(smooth_eC)==False).nonzero()
5893 5442 smooth_eC[val]=0
5894 #p_e0 = (p_e0*smooth_e+p_e0C*smooth_eC)/(smooth_e+smooth_eC)
5895 #p_e1 = (p_e1*smooth_e+p_e1C*smooth_eC)/(smooth_e+smooth_eC)
5896
5443 p_e0_a = (p_e0*smooth_e+p_e0C*smooth_eC)/(smooth_e+smooth_eC)
5444 p_e1_a = (p_e1*smooth_e+p_e1C*smooth_eC)/(smooth_e+smooth_eC)
5445 #print(w_e,w_eC,p_e0C,sat_fits[2,:])
5897 5446 if len(sat_fits) >0 :
5898 5447 p_e0C = p_e0C + sat_fits[2,:]
5899 5448 p_e1C = p_e1C + sat_fits[3,:]
5900 5449
5901 5450 if tini[3] >= 6 and tini[3] < 18 :
5902 5451 w_etmp = numpy.where(numpy.isfinite(w_eC)==True,w_eC,w_e)
5903 5452 w_e_errtmp = numpy.where(numpy.isfinite(w_eC)==True,numpy.nan,w_e_err)
5904 5453 else:
5905 5454 w_etmp = numpy.where(numpy.isfinite(w_eC)==True,w_eC,w_e)
5906 5455 w_etmp = numpy.where(range1 > 200,w_e,w_etmp)
5907 5456 w_e_errtmp = numpy.where(numpy.isfinite(w_eC)==True,numpy.nan,w_e_err)
5908 5457 w_e_errtmp = numpy.where(range1 > 200,w_e_err,w_e_errtmp)
5909 5458 w_e = w_etmp
5910 5459 w_e_err = w_e_errtmp
5911 5460
5912 5461 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
5913 5462 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
5914 5463
5915 5464 w_err = numpy.sqrt((w_w_err*numpy.sin(bet))**2.+(w_e_err*numpy.sin(alp))**2.)/ numpy.absolute(numpy.cos(alp)*numpy.sin(bet)-numpy.cos(bet)*numpy.sin(alp))
5916 5465 u_err = numpy.sqrt((w_w_err*numpy.cos(bet))**2.+(w_e_err*numpy.cos(alp))**2.)/ numpy.absolute(numpy.cos(alp)*numpy.sin(bet)-numpy.cos(bet)*numpy.sin(alp))
5917 5466
5467 #wtmp = numpy.where(w < -100 ,numpy.nan,w)
5468 wtmp = numpy.where(abs(w) > 100 ,numpy.nan,w)
5469 werrtmp = numpy.where(abs(w_err) > 100 ,numpy.nan,w_err)
5470 werrtmp = numpy.where(numpy.isfinite(wtmp)==True,werrtmp,numpy.nan)
5471 #wtmp = numpy.where(numpy.isfinite(werrtmp)==True,wtmp,numpy.nan)
5472
5473 #utmp = numpy.where(u < -500,numpy.nan,u)
5474 utmp = numpy.where(abs(u) > 500 ,numpy.nan,u)
5475 uerrtmp = numpy.where(abs(u_err) > 500 ,numpy.nan,u_err)
5476 uerrtmp = numpy.where(numpy.isfinite(utmp)==True,uerrtmp,numpy.nan)
5477 #utmp = numpy.where(numpy.isfinite(uerrtmp)==True,utmp,numpy.nan)
5478 w= wtmp.copy()
5479 u= utmp.copy()
5480 w_err= werrtmp.copy()
5481 u_err= uerrtmp.copy()
5482
5918 5483 winds = numpy.vstack((w,u))
5919 5484 dataOut.heightList = heiRang1
5920 5485 #snr1 = 10*numpy.log10(SNR1[0])
5921 5486 dataOut.data_output = winds
5922 5487 range1 = dataOut.heightList
5923 5488 nhei = len(range1)
5924 5489 #print('alt ',range1*numpy.sin(86.1*numpy.pi/180))
5925 5490 #print(numpy.min([dataOut.eldir7,dataOut.eldir8]))
5926 5491 galt = range1*numpy.sin(numpy.min([dataOut.elw,dataOut.ele])*numpy.pi/180.)
5927 dataOut.params = numpy.vstack((range1,galt,w,w_err,u,u_err,w_w,w_w_err,w_e,w_e_err,numpy.log10(p_w0),numpy.log10(p_w0C),numpy.log10(p_w1),numpy.log10(p_w1C),numpy.log10(p_e0),numpy.log10(p_e0C),numpy.log10(p_e1),numpy.log10(p_e1C),chisq_w,chisq_e))
5492 dataOut.params = numpy.vstack((range1,galt,w,w_err,u,u_err,w_w,w_w_err,w_e,w_e_err,numpy.log10(p_w0),numpy.log10(p_w0C),numpy.log10(p_w1),numpy.log10(p_w1C),numpy.log10(p_e0),numpy.log10(p_e0C),numpy.log10(p_e1),numpy.log10(p_e1C),chisq_w,chisq_e,numpy.log10(p_w0_a),numpy.log10(p_w1_a),numpy.log10(p_e0_a),numpy.log10(p_e1_a)))
5928 5493 #snr1 = 10*numpy.log10(SNR1[0])
5929 5494 #print(min(snr1), max(snr1))
5930 5495 snr1 = numpy.vstack((p_w0,p_w1,p_e0,p_e1))
5931 5496 snr1db = 10*numpy.log10(snr1[0])
5932 5497
5933 5498 #dataOut.data_snr1 = numpy.reshape(snr1,(1,snr1.shape[0]))
5934 5499 dataOut.data_snr1 = numpy.reshape(snr1db,(1,snr1db.shape[0]))
5935 5500 dataOut.utctimeInit = dataOut.utctime
5936 5501 dataOut.outputInterval = dataOut.timeInterval
5937 5502
5938 5503 hei_aver0 = 218
5939 5504 jrange = 450 #900 para HA drifts
5940 5505 deltah = 15.0 #dataOut.spacing(0) 25 HAD
5941 5506 h0 = 0.0 #dataOut.first_height(0)
5942 5507
5943 5508 range1 = numpy.arange(nhei) * deltah + h0
5944 5509 jhei = (range1 >= hei_aver0).nonzero()
5945 5510 if len(jhei[0]) > 0 :
5946 5511 h0_index = jhei[0][0] # Initial height for getting averages 218km
5947 5512
5948 5513 mynhei = 7
5949 5514 nhei_avg = int(jrange/deltah)
5950 5515 h_avgs = int(nhei_avg/mynhei)
5951 5516 nhei_avg = h_avgs*(mynhei-1)+mynhei
5952 5517
5953 5518 navgs = numpy.zeros(mynhei,dtype='float')
5954 5519 delta_h = numpy.zeros(mynhei,dtype='float')
5955 5520 range_aver = numpy.zeros(mynhei,dtype='float')
5956 5521 for ih in range( mynhei-1 ):
5957 5522 range_aver[ih] = numpy.sum(range1[h0_index+h_avgs*ih:h0_index+h_avgs*(ih+1)-0])/h_avgs
5958 5523 navgs[ih] = h_avgs
5959 5524 delta_h[ih] = deltah*h_avgs
5960 5525
5961 5526 range_aver[mynhei-1] = numpy.sum(range1[h0_index:h0_index+6*h_avgs-0])/(6*h_avgs)
5962 5527 navgs[mynhei-1] = 6*h_avgs
5963 5528 delta_h[mynhei-1] = deltah*6*h_avgs
5964 5529
5965 5530 wA = w[h0_index:h0_index+nhei_avg-0]
5966 5531 wA_err = w_err[h0_index:h0_index+nhei_avg-0]
5967 5532 for i in range(5) :
5968 5533 vals = wA[i*h_avgs:(i+1)*h_avgs-0]
5969 5534 errs = wA_err[i*h_avgs:(i+1)*h_avgs-0]
5970 5535 avg = numpy.nansum(vals/errs**2.)/numpy.nansum(1./errs**2.)
5971 5536 sigma = numpy.sqrt(1./numpy.nansum(1./errs**2.))
5972 5537 wA[6*h_avgs+i] = avg
5973 5538 wA_err[6*h_avgs+i] = sigma
5974 5539
5975 5540 vals = wA[0:6*h_avgs-0]
5976 5541 errs=wA_err[0:6*h_avgs-0]
5977 5542 avg = numpy.nansum(vals/errs**2.)/numpy.nansum(1./errs**2)
5978 5543 sigma = numpy.sqrt(1./numpy.nansum(1./errs**2.))
5979 5544 wA[nhei_avg-1] = avg
5980 5545 wA_err[nhei_avg-1] = sigma
5981 5546
5982 5547 wA = wA[6*h_avgs:nhei_avg-0]
5983 5548 wA_err=wA_err[6*h_avgs:nhei_avg-0]
5984 5549 if my_nbeams == 2 :
5985 5550 uA = u[h0_index:h0_index+nhei_avg]
5986 5551 uA_err=u_err[h0_index:h0_index+nhei_avg]
5987 5552
5988 5553 for i in range(5) :
5989 5554 vals = uA[i*h_avgs:(i+1)*h_avgs-0]
5990 5555 errs=uA_err[i*h_avgs:(i+1)*h_avgs-0]
5991 5556 avg = numpy.nansum(vals/errs**2.)/numpy.nansum(1./errs**2.)
5992 5557 sigma = numpy.sqrt(1./numpy.nansum(1./errs**2.))
5993 5558 uA[6*h_avgs+i] = avg
5994 5559 uA_err[6*h_avgs+i]=sigma
5995 5560
5996 5561 vals = uA[0:6*h_avgs-0]
5997 5562 errs = uA_err[0:6*h_avgs-0]
5998 5563 avg = numpy.nansum(vals/errs**2.)/numpy.nansum(1./errs**2.)
5999 5564 sigma = numpy.sqrt(1./numpy.nansum(1./errs**2.))
6000 5565 uA[nhei_avg-1] = avg
6001 5566 uA_err[nhei_avg-1] = sigma
6002 5567 uA = uA[6*h_avgs:nhei_avg-0]
6003 5568 uA_err = uA_err[6*h_avgs:nhei_avg-0]
6004 5569 dataOut.drifts_avg = numpy.vstack((wA,uA))
6005 5570
6006 5571 if my_nbeams == 1: dataOut.drifts_avg = wA
6007 5572 #deltahavg= wA*0.0+deltah
6008 5573 dataOut.range = range1
6009 5574 galtavg = range_aver*numpy.sin(numpy.min([dataOut.elw,dataOut.ele])*numpy.pi/180.)
6010 5575 dataOut.params_avg = numpy.vstack((wA,wA_err,uA,uA_err,range_aver,galtavg,delta_h))
6011 5576
6012 #print('comparando dim de avg ',wA.shape,deltahavg.shape,range_aver.shape)
5577 '''
6013 5578 tini=time.localtime(dataOut.utctime)
6014 5579 datefile= str(tini[0]).zfill(4)+str(tini[1]).zfill(2)+str(tini[2]).zfill(2)
6015 5580 nfile = fileDrifts+'/jro'+datefile+'drifts_sch3.txt'
6016
5581 #nfile = '/home/pcondor/Database/ewdriftsschain2019/jro'+datefile+'drifts_sch3.txt'
5582 #print(len(dataOut.drifts_avg),dataOut.drifts_avg.shape)
6017 5583 f1 = open(nfile,'a')
6018 5584 datedriftavg=str(tini[0])+' '+str(tini[1])+' '+str(tini[2])+' '+str(tini[3])+' '+str(tini[4])
6019 5585 driftavgstr=str(dataOut.drifts_avg)
6020 5586 numpy.savetxt(f1,numpy.column_stack([tini[0],tini[1],tini[2],tini[3],tini[4]]),fmt='%4i')
6021 5587 numpy.savetxt(f1,numpy.reshape(range_aver,(1,len(range_aver))) ,fmt='%10.2f')
5588 #numpy.savetxt(f1,numpy.reshape(dataOut.drifts_avg,(7,len(dataOut.drifts_avg))) ,fmt='%10.2f')
6022 5589 numpy.savetxt(f1,dataOut.drifts_avg[:,:],fmt='%10.2f')
6023 5590 f1.close()
6024
5591 '''
5592 '''
6025 5593 swfile = fileDrifts+'/jro'+datefile+'drifts_sw.txt'
6026 5594 f1 = open(swfile,'a')
6027 5595 numpy.savetxt(f1,numpy.column_stack([tini[0],tini[1],tini[2],tini[3],tini[4]]),fmt='%4i')
6028 5596 numpy.savetxt(f1,numpy.reshape(heiRang,(1,len(heiRang))),fmt='%10.2f')
6029 5597 numpy.savetxt(f1,dataOut.data_param[:,0,:],fmt='%10.2f')
6030 5598 f1.close()
6031 dataOut.heightListtmp = dataOut.heightList
6032 5599 '''
5600 dataOut.heightListtmp = dataOut.heightList
5601
6033 5602 #Envio data de drifts a mysql
6034 5603 fechad = str(tini[0]).zfill(4)+'-'+str(tini[1]).zfill(2)+'-'+str(tini[2]).zfill(2)+' '+str(tini[3]).zfill(2)+':'+str(tini[4]).zfill(2)+':'+str(0).zfill(2)
6035 5604 mydb = mysql.connector.connect(
6036 host="10.10.110.213",
5605 host="10.10.110.205",
6037 5606 user="user_clima",
6038 5607 password="5D.bh(B2)Y_wRNz9",
6039 5608 database="clima_espacial"
6040 5609 )
6041 5610
6042 5611 mycursor = mydb.cursor()
6043 5612 #mycursor.execute("CREATE TABLE drifts_vertical (id INT AUTO_INCREMENT PRIMARY KEY, fecha DATETIME(6), Vertical FLOAT(10,2))")
6044 5613
6045 5614 sql = "INSERT INTO drifts_vertical (datetime, value) VALUES (%s, %s)"
6046 5615 if numpy.isfinite(dataOut.drifts_avg[0,6]): vdql = dataOut.drifts_avg[0,6]
6047 5616 else : vdql = 999
6048 5617 val = (fechad, vdql)
6049 5618 mycursor.execute(sql, val)
6050 5619 mydb.commit()
6051 5620 sql = "INSERT INTO drifts_zonal (datetime, value) VALUES (%s, %s)"
6052 5621 if numpy.isfinite(dataOut.drifts_avg[1,6]): zdql = dataOut.drifts_avg[1,6]
6053 5622 else : zdql = 999
6054 5623 val = (fechad, zdql)
6055 5624 mycursor.execute(sql, val)
6056 5625 mydb.commit()
6057 5626
6058 5627 print(mycursor.rowcount, "record inserted.")
6059 '''
5628
6060 5629 return dataOut
6061 5630
6062 5631 class setHeightDrifts(Operation):
6063 5632
6064 5633 def __init__(self):
6065 5634 Operation.__init__(self)
6066 5635 def run(self, dataOut):
6067 5636 #print('h inicial ',dataOut.heightList,dataOut.heightListtmp)
6068 5637 dataOut.heightList = dataOut.heightListtmp
6069 5638 #print('regresa H ',dataOut.heightList)
6070 5639 return dataOut
6071 5640 class setHeightDriftsavg(Operation):
6072 5641
6073 5642 def __init__(self):
6074 5643 Operation.__init__(self)
6075 5644 def run(self, dataOut):
6076 5645 #print('h inicial ',dataOut.heightList)
6077 5646 dataOut.heightList = dataOut.params_avg[4]
6078 5647 #print('cambia H ',dataOut.params_avg[4],dataOut.heightList)
6079 5648 return dataOut
6080 5649
6081 5650 #--------------- Non Specular Meteor ----------------
6082 5651
6083 5652 class NonSpecularMeteorDetection(Operation):
6084 5653
6085 5654 def run(self, dataOut, mode, SNRthresh=8, phaseDerThresh=0.5, cohThresh=0.8, allData = False):
6086 5655 data_acf = dataOut.data_pre[0]
6087 5656 data_ccf = dataOut.data_pre[1]
6088 5657 pairsList = dataOut.groupList[1]
6089 5658
6090 5659 lamb = dataOut.C/dataOut.frequency
6091 5660 tSamp = dataOut.ippSeconds*dataOut.nCohInt
6092 5661 paramInterval = dataOut.paramInterval
6093 5662
6094 5663 nChannels = data_acf.shape[0]
6095 5664 nLags = data_acf.shape[1]
6096 5665 nProfiles = data_acf.shape[2]
6097 5666 nHeights = dataOut.nHeights
6098 5667 nCohInt = dataOut.nCohInt
6099 5668 sec = numpy.round(nProfiles/dataOut.paramInterval)
6100 5669 heightList = dataOut.heightList
6101 5670 ippSeconds = dataOut.ippSeconds*dataOut.nCohInt*dataOut.nAvg
6102 5671 utctime = dataOut.utctime
6103 5672
6104 5673 dataOut.abscissaList = numpy.arange(0,paramInterval+ippSeconds,ippSeconds)
6105 5674
6106 5675 #------------------------ SNR --------------------------------------
6107 5676 power = data_acf[:,0,:,:].real
6108 5677 noise = numpy.zeros(nChannels)
6109 5678 SNR = numpy.zeros(power.shape)
6110 5679 for i in range(nChannels):
6111 5680 noise[i] = hildebrand_sekhon(power[i,:], nCohInt)
6112 5681 SNR[i] = (power[i]-noise[i])/noise[i]
6113 5682 SNRm = numpy.nanmean(SNR, axis = 0)
6114 5683 SNRdB = 10*numpy.log10(SNR)
6115 5684
6116 5685 if mode == 'SA':
6117 5686 dataOut.groupList = dataOut.groupList[1]
6118 5687 nPairs = data_ccf.shape[0]
6119 5688 #---------------------- Coherence and Phase --------------------------
6120 5689 phase = numpy.zeros(data_ccf[:,0,:,:].shape)
6121 5690 coh1 = numpy.zeros(data_ccf[:,0,:,:].shape)
6122 5691
6123 5692 for p in range(nPairs):
6124 5693 ch0 = pairsList[p][0]
6125 5694 ch1 = pairsList[p][1]
6126 5695 ccf = data_ccf[p,0,:,:]/numpy.sqrt(data_acf[ch0,0,:,:]*data_acf[ch1,0,:,:])
6127 5696 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
6128 5697 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
6129 5698 coh = numpy.nanmax(coh1, axis = 0)
6130 5699 #---------------------- Radial Velocity ----------------------------
6131 5700 phaseAux = numpy.mean(numpy.angle(data_acf[:,1,:,:]), axis = 0)
6132 5701 velRad = phaseAux*lamb/(4*numpy.pi*tSamp)
6133 5702
6134 5703 if allData:
6135 5704 boolMetFin = ~numpy.isnan(SNRm)
6136 5705 else:
6137 5706 #------------------------ Meteor mask ---------------------------------
6138 5707
6139 5708 #Coherence mask
6140 5709 boolMet1 = coh > 0.75
6141 5710 struc = numpy.ones((30,1))
6142 5711 boolMet1 = ndimage.morphology.binary_dilation(boolMet1, structure=struc)
6143 5712
6144 5713 #Derivative mask
6145 5714 derPhase = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
6146 5715 boolMet2 = derPhase < 0.2
6147 5716 boolMet2 = ndimage.median_filter(boolMet2,size=5)
6148 5717 boolMet2 = numpy.vstack((boolMet2,numpy.full((1,nHeights), True, dtype=bool)))
6149 5718 boolMetFin = boolMet1&boolMet2
6150 5719 #Creating data_param
6151 5720 coordMet = numpy.where(boolMetFin)
6152 5721
6153 5722 tmet = coordMet[0]
6154 5723 hmet = coordMet[1]
6155 5724
6156 5725 data_param = numpy.zeros((tmet.size, 6 + nPairs))
6157 5726 data_param[:,0] = utctime
6158 5727 data_param[:,1] = tmet
6159 5728 data_param[:,2] = hmet
6160 5729 data_param[:,3] = SNRm[tmet,hmet]
6161 5730 data_param[:,4] = velRad[tmet,hmet]
6162 5731 data_param[:,5] = coh[tmet,hmet]
6163 5732 data_param[:,6:] = phase[:,tmet,hmet].T
6164 5733
6165 5734 elif mode == 'DBS':
6166 5735 dataOut.groupList = numpy.arange(nChannels)
6167 5736
6168 5737 #Radial Velocities
6169 5738 phase = numpy.angle(data_acf[:,1,:,:])
6170 5739 velRad = phase*lamb/(4*numpy.pi*tSamp)
6171 5740
6172 5741 #Spectral width
6173 5742 acf1 = data_acf[:,1,:,:]
6174 5743 acf2 = data_acf[:,2,:,:]
6175 5744
6176 5745 spcWidth = (lamb/(2*numpy.sqrt(6)*numpy.pi*tSamp))*numpy.sqrt(numpy.log(acf1/acf2))
6177 5746 if allData:
6178 5747 boolMetFin = ~numpy.isnan(SNRdB)
6179 5748 else:
6180 5749 #SNR
6181 5750 boolMet1 = (SNRdB>SNRthresh) #SNR mask
6182 5751 boolMet1 = ndimage.median_filter(boolMet1, size=(1,5,5))
6183 5752
6184 5753 #Radial velocity
6185 5754 boolMet2 = numpy.abs(velRad) < 20
6186 5755 boolMet2 = ndimage.median_filter(boolMet2, (1,5,5))
6187 5756
6188 5757 #Spectral Width
6189 5758 boolMet3 = spcWidth < 30
6190 5759 boolMet3 = ndimage.median_filter(boolMet3, (1,5,5))
6191 5760 boolMetFin = boolMet1&boolMet2&boolMet3
6192 5761
6193 5762 #Creating data_param
6194 5763 coordMet = numpy.where(boolMetFin)
6195 5764
6196 5765 cmet = coordMet[0]
6197 5766 tmet = coordMet[1]
6198 5767 hmet = coordMet[2]
6199 5768
6200 5769 data_param = numpy.zeros((tmet.size, 7))
6201 5770 data_param[:,0] = utctime
6202 5771 data_param[:,1] = cmet
6203 5772 data_param[:,2] = tmet
6204 5773 data_param[:,3] = hmet
6205 5774 data_param[:,4] = SNR[cmet,tmet,hmet].T
6206 5775 data_param[:,5] = velRad[cmet,tmet,hmet].T
6207 5776 data_param[:,6] = spcWidth[cmet,tmet,hmet].T
6208 5777
6209 5778 if len(data_param) == 0:
6210 5779 dataOut.flagNoData = True
6211 5780 else:
6212 5781 dataOut.data_param = data_param
6213 5782
6214 5783 def __erase_small(self, binArray, threshX, threshY):
6215 5784 labarray, numfeat = ndimage.measurements.label(binArray)
6216 5785 binArray1 = numpy.copy(binArray)
6217 5786
6218 5787 for i in range(1,numfeat + 1):
6219 5788 auxBin = (labarray==i)
6220 5789 auxSize = auxBin.sum()
6221 5790
6222 5791 x,y = numpy.where(auxBin)
6223 5792 widthX = x.max() - x.min()
6224 5793 widthY = y.max() - y.min()
6225 5794
6226 5795 #width X: 3 seg -> 12.5*3
6227 5796 #width Y:
6228 5797
6229 5798 if (auxSize < 50) or (widthX < threshX) or (widthY < threshY):
6230 5799 binArray1[auxBin] = False
6231 5800
6232 5801 return binArray1
6233 5802
6234 5803 #--------------- Specular Meteor ----------------
6235 5804
6236 5805 class SMDetection(Operation):
6237 5806 '''
6238 5807 Function DetectMeteors()
6239 5808 Project developed with paper:
6240 5809 HOLDSWORTH ET AL. 2004
6241 5810
6242 5811 Input:
6243 5812 self.dataOut.data_pre
6244 5813
6245 5814 centerReceiverIndex: From the channels, which is the center receiver
6246 5815
6247 5816 hei_ref: Height reference for the Beacon signal extraction
6248 5817 tauindex:
6249 5818 predefinedPhaseShifts: Predefined phase offset for the voltge signals
6250 5819
6251 5820 cohDetection: Whether to user Coherent detection or not
6252 5821 cohDet_timeStep: Coherent Detection calculation time step
6253 5822 cohDet_thresh: Coherent Detection phase threshold to correct phases
6254 5823
6255 5824 noise_timeStep: Noise calculation time step
6256 5825 noise_multiple: Noise multiple to define signal threshold
6257 5826
6258 5827 multDet_timeLimit: Multiple Detection Removal time limit in seconds
6259 5828 multDet_rangeLimit: Multiple Detection Removal range limit in km
6260 5829
6261 5830 phaseThresh: Maximum phase difference between receiver to be consider a meteor
6262 5831 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
6263 5832
6264 5833 hmin: Minimum Height of the meteor to use it in the further wind estimations
6265 5834 hmax: Maximum Height of the meteor to use it in the further wind estimations
6266 5835 azimuth: Azimuth angle correction
6267 5836
6268 5837 Affected:
6269 5838 self.dataOut.data_param
6270 5839
6271 5840 Rejection Criteria (Errors):
6272 5841 0: No error; analysis OK
6273 5842 1: SNR < SNR threshold
6274 5843 2: angle of arrival (AOA) ambiguously determined
6275 5844 3: AOA estimate not feasible
6276 5845 4: Large difference in AOAs obtained from different antenna baselines
6277 5846 5: echo at start or end of time series
6278 5847 6: echo less than 5 examples long; too short for analysis
6279 5848 7: echo rise exceeds 0.3s
6280 5849 8: echo decay time less than twice rise time
6281 5850 9: large power level before echo
6282 5851 10: large power level after echo
6283 5852 11: poor fit to amplitude for estimation of decay time
6284 5853 12: poor fit to CCF phase variation for estimation of radial drift velocity
6285 5854 13: height unresolvable echo: not valid height within 70 to 110 km
6286 5855 14: height ambiguous echo: more then one possible height within 70 to 110 km
6287 5856 15: radial drift velocity or projected horizontal velocity exceeds 200 m/s
6288 5857 16: oscilatory echo, indicating event most likely not an underdense echo
6289 5858
6290 5859 17: phase difference in meteor Reestimation
6291 5860
6292 5861 Data Storage:
6293 5862 Meteors for Wind Estimation (8):
6294 5863 Utc Time | Range Height
6295 5864 Azimuth Zenith errorCosDir
6296 5865 VelRad errorVelRad
6297 5866 Phase0 Phase1 Phase2 Phase3
6298 5867 TypeError
6299 5868
6300 5869 '''
6301 5870
6302 5871 def run(self, dataOut, hei_ref = None, tauindex = 0,
6303 5872 phaseOffsets = None,
6304 5873 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
6305 5874 noise_timeStep = 4, noise_multiple = 4,
6306 5875 multDet_timeLimit = 1, multDet_rangeLimit = 3,
6307 5876 phaseThresh = 20, SNRThresh = 5,
6308 5877 hmin = 50, hmax=150, azimuth = 0,
6309 5878 channelPositions = None) :
6310 5879
6311 5880
6312 5881 #Getting Pairslist
6313 5882 if channelPositions is None:
6314 5883 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
6315 5884 meteorOps = SMOperations()
6316 5885 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
6317 5886 heiRang = dataOut.heightList
6318 5887 #Get Beacon signal - No Beacon signal anymore
6319 5888 #****************REMOVING HARDWARE PHASE DIFFERENCES***************
6320 5889 # see if the user put in pre defined phase shifts
6321 5890 voltsPShift = dataOut.data_pre.copy()
6322 5891
6323 5892 #******************END OF REMOVING HARDWARE PHASE DIFFERENCES*********
6324 5893
6325 5894 #Remove DC
6326 5895 voltsDC = numpy.mean(voltsPShift,1)
6327 5896 voltsDC = numpy.mean(voltsDC,1)
6328 5897 for i in range(voltsDC.shape[0]):
6329 5898 voltsPShift[i] = voltsPShift[i] - voltsDC[i]
6330 5899
6331 5900 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
6332 5901
6333 5902 #************ FIND POWER OF DATA W/COH OR NON COH DETECTION (3.4) **********
6334 5903 #Coherent Detection
6335 5904 if cohDetection:
6336 5905 #use coherent detection to get the net power
6337 5906 cohDet_thresh = cohDet_thresh*numpy.pi/180
6338 5907 voltsPShift = self.__coherentDetection(voltsPShift, cohDet_timeStep, dataOut.timeInterval, pairslist0, cohDet_thresh)
6339 5908
6340 5909 #Non-coherent detection!
6341 5910 powerNet = numpy.nansum(numpy.abs(voltsPShift[:,:,:])**2,0)
6342 5911 #********** END OF COH/NON-COH POWER CALCULATION**********************
6343 5912
6344 5913 #********** FIND THE NOISE LEVEL AND POSSIBLE METEORS ****************
6345 5914 #Get noise
6346 5915 noise, noise1 = self.__getNoise(powerNet, noise_timeStep, dataOut.timeInterval)
6347 5916 #Get signal threshold
6348 5917 signalThresh = noise_multiple*noise
6349 5918 #Meteor echoes detection
6350 5919 listMeteors = self.__findMeteors(powerNet, signalThresh)
6351 5920 #******* END OF NOISE LEVEL AND POSSIBLE METEORS CACULATION **********
6352 5921
6353 5922 #************** REMOVE MULTIPLE DETECTIONS (3.5) ***************************
6354 5923 #Parameters
6355 5924 heiRange = dataOut.heightList
6356 5925 rangeInterval = heiRange[1] - heiRange[0]
6357 5926 rangeLimit = multDet_rangeLimit/rangeInterval
6358 5927 timeLimit = multDet_timeLimit/dataOut.timeInterval
6359 5928 #Multiple detection removals
6360 5929 listMeteors1 = self.__removeMultipleDetections(listMeteors, rangeLimit, timeLimit)
6361 5930 #************ END OF REMOVE MULTIPLE DETECTIONS **********************
6362 5931
6363 5932 #********************* METEOR REESTIMATION (3.7, 3.8, 3.9, 3.10) ********************
6364 5933 #Parameters
6365 5934 phaseThresh = phaseThresh*numpy.pi/180
6366 5935 thresh = [phaseThresh, noise_multiple, SNRThresh]
6367 5936 #Meteor reestimation (Errors N 1, 6, 12, 17)
6368 5937 listMeteors2, listMeteorsPower, listMeteorsVolts = self.__meteorReestimation(listMeteors1, voltsPShift, pairslist0, thresh, noise, dataOut.timeInterval, dataOut.frequency)
6369 5938 #Estimation of decay times (Errors N 7, 8, 11)
6370 5939 listMeteors3 = self.__estimateDecayTime(listMeteors2, listMeteorsPower, dataOut.timeInterval, dataOut.frequency)
6371 5940 #******************* END OF METEOR REESTIMATION *******************
6372 5941
6373 5942 #********************* METEOR PARAMETERS CALCULATION (3.11, 3.12, 3.13) **************************
6374 5943 #Calculating Radial Velocity (Error N 15)
6375 5944 radialStdThresh = 10
6376 5945 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
6377 5946
6378 5947 if len(listMeteors4) > 0:
6379 5948 #Setting New Array
6380 5949 date = dataOut.utctime
6381 5950 arrayParameters = self.__setNewArrays(listMeteors4, date, heiRang)
6382 5951
6383 5952 #Correcting phase offset
6384 5953 if phaseOffsets != None:
6385 5954 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
6386 5955 arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
6387 5956
6388 5957 #Second Pairslist
6389 5958 pairsList = []
6390 5959 pairx = (0,1)
6391 5960 pairy = (2,3)
6392 5961 pairsList.append(pairx)
6393 5962 pairsList.append(pairy)
6394 5963
6395 5964 jph = numpy.array([0,0,0,0])
6396 5965 h = (hmin,hmax)
6397 5966 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
6398 5967 dataOut.data_param = arrayParameters
6399 5968
6400 5969 if arrayParameters is None:
6401 5970 dataOut.flagNoData = True
6402 5971 else:
6403 5972 dataOut.flagNoData = True
6404 5973
6405 5974 return
6406 5975
6407 5976 def __getHardwarePhaseDiff(self, voltage0, pairslist, newheis, n):
6408 5977
6409 5978 minIndex = min(newheis[0])
6410 5979 maxIndex = max(newheis[0])
6411 5980
6412 5981 voltage = voltage0[:,:,minIndex:maxIndex+1]
6413 5982 nLength = voltage.shape[1]/n
6414 5983 nMin = 0
6415 5984 nMax = 0
6416 5985 phaseOffset = numpy.zeros((len(pairslist),n))
6417 5986
6418 5987 for i in range(n):
6419 5988 nMax += nLength
6420 5989 phaseCCF = -numpy.angle(self.__calculateCCF(voltage[:,nMin:nMax,:], pairslist, [0]))
6421 5990 phaseCCF = numpy.mean(phaseCCF, axis = 2)
6422 5991 phaseOffset[:,i] = phaseCCF.transpose()
6423 5992 nMin = nMax
6424 5993
6425 5994 #Remove Outliers
6426 5995 factor = 2
6427 5996 wt = phaseOffset - signal.medfilt(phaseOffset,(1,5))
6428 5997 dw = numpy.std(wt,axis = 1)
6429 5998 dw = dw.reshape((dw.size,1))
6430 5999 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
6431 6000 phaseOffset[ind] = numpy.nan
6432 6001 phaseOffset = stats.nanmean(phaseOffset, axis=1)
6433 6002
6434 6003 return phaseOffset
6435 6004
6436 6005 def __shiftPhase(self, data, phaseShift):
6437 6006 #this will shift the phase of a complex number
6438 6007 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
6439 6008 return dataShifted
6440 6009
6441 6010 def __estimatePhaseDifference(self, array, pairslist):
6442 6011 nChannel = array.shape[0]
6443 6012 nHeights = array.shape[2]
6444 6013 numPairs = len(pairslist)
6445 6014 phaseCCF = numpy.angle(self.__calculateCCF(array, pairslist, [-2,-1,0,1,2]))
6446 6015
6447 6016 #Correct phases
6448 6017 derPhaseCCF = phaseCCF[:,1:,:] - phaseCCF[:,0:-1,:]
6449 6018 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
6450 6019
6451 6020 if indDer[0].shape[0] > 0:
6452 6021 for i in range(indDer[0].shape[0]):
6453 6022 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i],indDer[2][i]])
6454 6023 phaseCCF[indDer[0][i],indDer[1][i]+1:,:] += signo*2*numpy.pi
6455 6024
6456 6025 #Linear
6457 6026 phaseInt = numpy.zeros((numPairs,1))
6458 6027 angAllCCF = phaseCCF[:,[0,1,3,4],0]
6459 6028 for j in range(numPairs):
6460 6029 fit = stats.linregress([-2,-1,1,2],angAllCCF[j,:])
6461 6030 phaseInt[j] = fit[1]
6462 6031 #Phase Differences
6463 6032 phaseDiff = phaseInt - phaseCCF[:,2,:]
6464 6033 phaseArrival = phaseInt.reshape(phaseInt.size)
6465 6034
6466 6035 #Dealias
6467 6036 phaseArrival = numpy.angle(numpy.exp(1j*phaseArrival))
6468 6037
6469 6038 return phaseDiff, phaseArrival
6470 6039
6471 6040 def __coherentDetection(self, volts, timeSegment, timeInterval, pairslist, thresh):
6472 6041 #this function will run the coherent detection used in Holdworth et al. 2004 and return the net power
6473 6042 #find the phase shifts of each channel over 1 second intervals
6474 6043 #only look at ranges below the beacon signal
6475 6044 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
6476 6045 numBlocks = int(volts.shape[1]/numProfPerBlock)
6477 6046 numHeights = volts.shape[2]
6478 6047 nChannel = volts.shape[0]
6479 6048 voltsCohDet = volts.copy()
6480 6049
6481 6050 pairsarray = numpy.array(pairslist)
6482 6051 indSides = pairsarray[:,1]
6483 6052 listBlocks = numpy.array_split(volts, numBlocks, 1)
6484 6053
6485 6054 startInd = 0
6486 6055 endInd = 0
6487 6056
6488 6057 for i in range(numBlocks):
6489 6058 startInd = endInd
6490 6059 endInd = endInd + listBlocks[i].shape[1]
6491 6060
6492 6061 arrayBlock = listBlocks[i]
6493 6062
6494 6063 #Estimate the Phase Difference
6495 6064 phaseDiff, aux = self.__estimatePhaseDifference(arrayBlock, pairslist)
6496 6065 #Phase Difference RMS
6497 6066 arrayPhaseRMS = numpy.abs(phaseDiff)
6498 6067 phaseRMSaux = numpy.sum(arrayPhaseRMS < thresh,0)
6499 6068 indPhase = numpy.where(phaseRMSaux==4)
6500 6069 #Shifting
6501 6070 if indPhase[0].shape[0] > 0:
6502 6071 for j in range(indSides.size):
6503 6072 arrayBlock[indSides[j],:,indPhase] = self.__shiftPhase(arrayBlock[indSides[j],:,indPhase], phaseDiff[j,indPhase].transpose())
6504 6073 voltsCohDet[:,startInd:endInd,:] = arrayBlock
6505 6074
6506 6075 return voltsCohDet
6507 6076
6508 6077 def __calculateCCF(self, volts, pairslist ,laglist):
6509 6078
6510 6079 nHeights = volts.shape[2]
6511 6080 nPoints = volts.shape[1]
6512 6081 voltsCCF = numpy.zeros((len(pairslist), len(laglist), nHeights),dtype = 'complex')
6513 6082
6514 6083 for i in range(len(pairslist)):
6515 6084 volts1 = volts[pairslist[i][0]]
6516 6085 volts2 = volts[pairslist[i][1]]
6517 6086
6518 6087 for t in range(len(laglist)):
6519 6088 idxT = laglist[t]
6520 6089 if idxT >= 0:
6521 6090 vStacked = numpy.vstack((volts2[idxT:,:],
6522 6091 numpy.zeros((idxT, nHeights),dtype='complex')))
6523 6092 else:
6524 6093 vStacked = numpy.vstack((numpy.zeros((-idxT, nHeights),dtype='complex'),
6525 6094 volts2[:(nPoints + idxT),:]))
6526 6095 voltsCCF[i,t,:] = numpy.sum((numpy.conjugate(volts1)*vStacked),axis=0)
6527 6096
6528 6097 vStacked = None
6529 6098 return voltsCCF
6530 6099
6531 6100 def __getNoise(self, power, timeSegment, timeInterval):
6532 6101 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
6533 6102 numBlocks = int(power.shape[0]/numProfPerBlock)
6534 6103 numHeights = power.shape[1]
6535 6104
6536 6105 listPower = numpy.array_split(power, numBlocks, 0)
6537 6106 noise = numpy.zeros((power.shape[0], power.shape[1]))
6538 6107 noise1 = numpy.zeros((power.shape[0], power.shape[1]))
6539 6108
6540 6109 startInd = 0
6541 6110 endInd = 0
6542 6111
6543 6112 for i in range(numBlocks): #split por canal
6544 6113 startInd = endInd
6545 6114 endInd = endInd + listPower[i].shape[0]
6546 6115
6547 6116 arrayBlock = listPower[i]
6548 6117 noiseAux = numpy.mean(arrayBlock, 0)
6549 6118 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
6550 6119
6551 6120 noiseAux1 = numpy.mean(arrayBlock)
6552 6121 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
6553 6122
6554 6123 return noise, noise1
6555 6124
6556 6125 def __findMeteors(self, power, thresh):
6557 6126 nProf = power.shape[0]
6558 6127 nHeights = power.shape[1]
6559 6128 listMeteors = []
6560 6129
6561 6130 for i in range(nHeights):
6562 6131 powerAux = power[:,i]
6563 6132 threshAux = thresh[:,i]
6564 6133
6565 6134 indUPthresh = numpy.where(powerAux > threshAux)[0]
6566 6135 indDNthresh = numpy.where(powerAux <= threshAux)[0]
6567 6136
6568 6137 j = 0
6569 6138
6570 6139 while (j < indUPthresh.size - 2):
6571 6140 if (indUPthresh[j + 2] == indUPthresh[j] + 2):
6572 6141 indDNAux = numpy.where(indDNthresh > indUPthresh[j])
6573 6142 indDNthresh = indDNthresh[indDNAux]
6574 6143
6575 6144 if (indDNthresh.size > 0):
6576 6145 indEnd = indDNthresh[0] - 1
6577 6146 indInit = indUPthresh[j]
6578 6147
6579 6148 meteor = powerAux[indInit:indEnd + 1]
6580 6149 indPeak = meteor.argmax() + indInit
6581 6150 FLA = sum(numpy.conj(meteor)*numpy.hstack((meteor[1:],0)))
6582 6151
6583 6152 listMeteors.append(numpy.array([i,indInit,indPeak,indEnd,FLA])) #CHEQUEAR!!!!!
6584 6153 j = numpy.where(indUPthresh == indEnd)[0] + 1
6585 6154 else: j+=1
6586 6155 else: j+=1
6587 6156
6588 6157 return listMeteors
6589 6158
6590 6159 def __removeMultipleDetections(self,listMeteors, rangeLimit, timeLimit):
6591 6160
6592 6161 arrayMeteors = numpy.asarray(listMeteors)
6593 6162 listMeteors1 = []
6594 6163
6595 6164 while arrayMeteors.shape[0] > 0:
6596 6165 FLAs = arrayMeteors[:,4]
6597 6166 maxFLA = FLAs.argmax()
6598 6167 listMeteors1.append(arrayMeteors[maxFLA,:])
6599 6168
6600 6169 MeteorInitTime = arrayMeteors[maxFLA,1]
6601 6170 MeteorEndTime = arrayMeteors[maxFLA,3]
6602 6171 MeteorHeight = arrayMeteors[maxFLA,0]
6603 6172
6604 6173 #Check neighborhood
6605 6174 maxHeightIndex = MeteorHeight + rangeLimit
6606 6175 minHeightIndex = MeteorHeight - rangeLimit
6607 6176 minTimeIndex = MeteorInitTime - timeLimit
6608 6177 maxTimeIndex = MeteorEndTime + timeLimit
6609 6178
6610 6179 #Check Heights
6611 6180 indHeight = numpy.logical_and(arrayMeteors[:,0] >= minHeightIndex, arrayMeteors[:,0] <= maxHeightIndex)
6612 6181 indTime = numpy.logical_and(arrayMeteors[:,3] >= minTimeIndex, arrayMeteors[:,1] <= maxTimeIndex)
6613 6182 indBoth = numpy.where(numpy.logical_and(indTime,indHeight))
6614 6183
6615 6184 arrayMeteors = numpy.delete(arrayMeteors, indBoth, axis = 0)
6616 6185
6617 6186 return listMeteors1
6618 6187
6619 6188 def __meteorReestimation(self, listMeteors, volts, pairslist, thresh, noise, timeInterval,frequency):
6620 6189 numHeights = volts.shape[2]
6621 6190 nChannel = volts.shape[0]
6622 6191
6623 6192 thresholdPhase = thresh[0]
6624 6193 thresholdNoise = thresh[1]
6625 6194 thresholdDB = float(thresh[2])
6626 6195
6627 6196 thresholdDB1 = 10**(thresholdDB/10)
6628 6197 pairsarray = numpy.array(pairslist)
6629 6198 indSides = pairsarray[:,1]
6630 6199
6631 6200 pairslist1 = list(pairslist)
6632 6201 pairslist1.append((0,1))
6633 6202 pairslist1.append((3,4))
6634 6203
6635 6204 listMeteors1 = []
6636 6205 listPowerSeries = []
6637 6206 listVoltageSeries = []
6638 6207 #volts has the war data
6639 6208
6640 6209 if frequency == 30e6:
6641 6210 timeLag = 45*10**-3
6642 6211 else:
6643 6212 timeLag = 15*10**-3
6644 6213 lag = numpy.ceil(timeLag/timeInterval)
6645 6214
6646 6215 for i in range(len(listMeteors)):
6647 6216
6648 6217 ###################### 3.6 - 3.7 PARAMETERS REESTIMATION #########################
6649 6218 meteorAux = numpy.zeros(16)
6650 6219
6651 6220 #Loading meteor Data (mHeight, mStart, mPeak, mEnd)
6652 6221 mHeight = listMeteors[i][0]
6653 6222 mStart = listMeteors[i][1]
6654 6223 mPeak = listMeteors[i][2]
6655 6224 mEnd = listMeteors[i][3]
6656 6225
6657 6226 #get the volt data between the start and end times of the meteor
6658 6227 meteorVolts = volts[:,mStart:mEnd+1,mHeight]
6659 6228 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
6660 6229
6661 6230 #3.6. Phase Difference estimation
6662 6231 phaseDiff, aux = self.__estimatePhaseDifference(meteorVolts, pairslist)
6663 6232
6664 6233 #3.7. Phase difference removal & meteor start, peak and end times reestimated
6665 6234 #meteorVolts0.- all Channels, all Profiles
6666 6235 meteorVolts0 = volts[:,:,mHeight]
6667 6236 meteorThresh = noise[:,mHeight]*thresholdNoise
6668 6237 meteorNoise = noise[:,mHeight]
6669 6238 meteorVolts0[indSides,:] = self.__shiftPhase(meteorVolts0[indSides,:], phaseDiff) #Phase Shifting
6670 6239 powerNet0 = numpy.nansum(numpy.abs(meteorVolts0)**2, axis = 0) #Power
6671 6240
6672 6241 #Times reestimation
6673 6242 mStart1 = numpy.where(powerNet0[:mPeak] < meteorThresh[:mPeak])[0]
6674 6243 if mStart1.size > 0:
6675 6244 mStart1 = mStart1[-1] + 1
6676 6245
6677 6246 else:
6678 6247 mStart1 = mPeak
6679 6248
6680 6249 mEnd1 = numpy.where(powerNet0[mPeak:] < meteorThresh[mPeak:])[0][0] + mPeak - 1
6681 6250 mEndDecayTime1 = numpy.where(powerNet0[mPeak:] < meteorNoise[mPeak:])[0]
6682 6251 if mEndDecayTime1.size == 0:
6683 6252 mEndDecayTime1 = powerNet0.size
6684 6253 else:
6685 6254 mEndDecayTime1 = mEndDecayTime1[0] + mPeak - 1
6686 6255
6687 6256 #meteorVolts1.- all Channels, from start to end
6688 6257 meteorVolts1 = meteorVolts0[:,mStart1:mEnd1 + 1]
6689 6258 meteorVolts2 = meteorVolts0[:,mPeak + lag:mEnd1 + 1]
6690 6259 if meteorVolts2.shape[1] == 0:
6691 6260 meteorVolts2 = meteorVolts0[:,mPeak:mEnd1 + 1]
6692 6261 meteorVolts1 = meteorVolts1.reshape(meteorVolts1.shape[0], meteorVolts1.shape[1], 1)
6693 6262 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1], 1)
6694 6263 ##################### END PARAMETERS REESTIMATION #########################
6695 6264
6696 6265 ##################### 3.8 PHASE DIFFERENCE REESTIMATION ########################
6697 6266 if meteorVolts2.shape[1] > 0:
6698 6267 #Phase Difference re-estimation
6699 6268 phaseDiff1, phaseDiffint = self.__estimatePhaseDifference(meteorVolts2, pairslist1) #Phase Difference Estimation
6700 6269 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1])
6701 6270 phaseDiff11 = numpy.reshape(phaseDiff1, (phaseDiff1.shape[0],1))
6702 6271 meteorVolts2[indSides,:] = self.__shiftPhase(meteorVolts2[indSides,:], phaseDiff11[0:4]) #Phase Shifting
6703 6272
6704 6273 #Phase Difference RMS
6705 6274 phaseRMS1 = numpy.sqrt(numpy.mean(numpy.square(phaseDiff1)))
6706 6275 powerNet1 = numpy.nansum(numpy.abs(meteorVolts1[:,:])**2,0)
6707 6276 #Data from Meteor
6708 6277 mPeak1 = powerNet1.argmax() + mStart1
6709 6278 mPeakPower1 = powerNet1.max()
6710 6279 noiseAux = sum(noise[mStart1:mEnd1 + 1,mHeight])
6711 6280 mSNR1 = (sum(powerNet1)-noiseAux)/noiseAux
6712 6281 Meteor1 = numpy.array([mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1])
6713 6282 Meteor1 = numpy.hstack((Meteor1,phaseDiffint))
6714 6283 PowerSeries = powerNet0[mStart1:mEndDecayTime1 + 1]
6715 6284 #Vectorize
6716 6285 meteorAux[0:7] = [mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1]
6717 6286 meteorAux[7:11] = phaseDiffint[0:4]
6718 6287
6719 6288 #Rejection Criterions
6720 6289 if phaseRMS1 > thresholdPhase: #Error Number 17: Phase variation
6721 6290 meteorAux[-1] = 17
6722 6291 elif mSNR1 < thresholdDB1: #Error Number 1: SNR < threshold dB
6723 6292 meteorAux[-1] = 1
6724 6293
6725 6294
6726 6295 else:
6727 6296 meteorAux[0:4] = [mHeight, mStart, mPeak, mEnd]
6728 6297 meteorAux[-1] = 6 #Error Number 6: echo less than 5 samples long; too short for analysis
6729 6298 PowerSeries = 0
6730 6299
6731 6300 listMeteors1.append(meteorAux)
6732 6301 listPowerSeries.append(PowerSeries)
6733 6302 listVoltageSeries.append(meteorVolts1)
6734 6303
6735 6304 return listMeteors1, listPowerSeries, listVoltageSeries
6736 6305
6737 6306 def __estimateDecayTime(self, listMeteors, listPower, timeInterval, frequency):
6738 6307
6739 6308 threshError = 10
6740 6309 #Depending if it is 30 or 50 MHz
6741 6310 if frequency == 30e6:
6742 6311 timeLag = 45*10**-3
6743 6312 else:
6744 6313 timeLag = 15*10**-3
6745 6314 lag = numpy.ceil(timeLag/timeInterval)
6746 6315
6747 6316 listMeteors1 = []
6748 6317
6749 6318 for i in range(len(listMeteors)):
6750 6319 meteorPower = listPower[i]
6751 6320 meteorAux = listMeteors[i]
6752 6321
6753 6322 if meteorAux[-1] == 0:
6754 6323
6755 6324 try:
6756 6325 indmax = meteorPower.argmax()
6757 6326 indlag = indmax + lag
6758 6327
6759 6328 y = meteorPower[indlag:]
6760 6329 x = numpy.arange(0, y.size)*timeLag
6761 6330
6762 6331 #first guess
6763 6332 a = y[0]
6764 6333 tau = timeLag
6765 6334 #exponential fit
6766 6335 popt, pcov = optimize.curve_fit(self.__exponential_function, x, y, p0 = [a, tau])
6767 6336 y1 = self.__exponential_function(x, *popt)
6768 6337 #error estimation
6769 6338 error = sum((y - y1)**2)/(numpy.var(y)*(y.size - popt.size))
6770 6339
6771 6340 decayTime = popt[1]
6772 6341 riseTime = indmax*timeInterval
6773 6342 meteorAux[11:13] = [decayTime, error]
6774 6343
6775 6344 #Table items 7, 8 and 11
6776 6345 if (riseTime > 0.3): #Number 7: Echo rise exceeds 0.3s
6777 6346 meteorAux[-1] = 7
6778 6347 elif (decayTime < 2*riseTime) : #Number 8: Echo decay time less than than twice rise time
6779 6348 meteorAux[-1] = 8
6780 6349 if (error > threshError): #Number 11: Poor fit to amplitude for estimation of decay time
6781 6350 meteorAux[-1] = 11
6782 6351
6783 6352
6784 6353 except:
6785 6354 meteorAux[-1] = 11
6786 6355
6787 6356
6788 6357 listMeteors1.append(meteorAux)
6789 6358
6790 6359 return listMeteors1
6791 6360
6792 6361 #Exponential Function
6793 6362
6794 6363 def __exponential_function(self, x, a, tau):
6795 6364 y = a*numpy.exp(-x/tau)
6796 6365 return y
6797 6366
6798 6367 def __getRadialVelocity(self, listMeteors, listVolts, radialStdThresh, pairslist, timeInterval):
6799 6368
6800 6369 pairslist1 = list(pairslist)
6801 6370 pairslist1.append((0,1))
6802 6371 pairslist1.append((3,4))
6803 6372 numPairs = len(pairslist1)
6804 6373 #Time Lag
6805 6374 timeLag = 45*10**-3
6806 6375 c = 3e8
6807 6376 lag = numpy.ceil(timeLag/timeInterval)
6808 6377 freq = 30e6
6809 6378
6810 6379 listMeteors1 = []
6811 6380
6812 6381 for i in range(len(listMeteors)):
6813 6382 meteorAux = listMeteors[i]
6814 6383 if meteorAux[-1] == 0:
6815 6384 mStart = listMeteors[i][1]
6816 6385 mPeak = listMeteors[i][2]
6817 6386 mLag = mPeak - mStart + lag
6818 6387
6819 6388 #get the volt data between the start and end times of the meteor
6820 6389 meteorVolts = listVolts[i]
6821 6390 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
6822 6391
6823 6392 #Get CCF
6824 6393 allCCFs = self.__calculateCCF(meteorVolts, pairslist1, [-2,-1,0,1,2])
6825 6394
6826 6395 #Method 2
6827 6396 slopes = numpy.zeros(numPairs)
6828 6397 time = numpy.array([-2,-1,1,2])*timeInterval
6829 6398 angAllCCF = numpy.angle(allCCFs[:,[0,1,3,4],0])
6830 6399
6831 6400 #Correct phases
6832 6401 derPhaseCCF = angAllCCF[:,1:] - angAllCCF[:,0:-1]
6833 6402 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
6834 6403
6835 6404 if indDer[0].shape[0] > 0:
6836 6405 for i in range(indDer[0].shape[0]):
6837 6406 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i]])
6838 6407 angAllCCF[indDer[0][i],indDer[1][i]+1:] += signo*2*numpy.pi
6839 6408
6840 6409 for j in range(numPairs):
6841 6410 fit = stats.linregress(time, angAllCCF[j,:])
6842 6411 slopes[j] = fit[0]
6843 6412
6844 6413 #Remove Outlier
6845 6414 radialVelocity = -numpy.mean(slopes)*(0.25/numpy.pi)*(c/freq)
6846 6415 radialError = numpy.std(slopes)*(0.25/numpy.pi)*(c/freq)
6847 6416 meteorAux[-2] = radialError
6848 6417 meteorAux[-3] = radialVelocity
6849 6418
6850 6419 #Setting Error
6851 6420 #Number 15: Radial Drift velocity or projected horizontal velocity exceeds 200 m/s
6852 6421 if numpy.abs(radialVelocity) > 200:
6853 6422 meteorAux[-1] = 15
6854 6423 #Number 12: Poor fit to CCF variation for estimation of radial drift velocity
6855 6424 elif radialError > radialStdThresh:
6856 6425 meteorAux[-1] = 12
6857 6426
6858 6427 listMeteors1.append(meteorAux)
6859 6428 return listMeteors1
6860 6429
6861 6430 def __setNewArrays(self, listMeteors, date, heiRang):
6862 6431
6863 6432 #New arrays
6864 6433 arrayMeteors = numpy.array(listMeteors)
6865 6434 arrayParameters = numpy.zeros((len(listMeteors), 13))
6866 6435
6867 6436 #Date inclusion
6868 6437 arrayDate = numpy.tile(date, (len(listMeteors)))
6869 6438
6870 6439 #Meteor array
6871 6440 #Parameters Array
6872 6441 arrayParameters[:,0] = arrayDate #Date
6873 6442 arrayParameters[:,1] = heiRang[arrayMeteors[:,0].astype(int)] #Range
6874 6443 arrayParameters[:,6:8] = arrayMeteors[:,-3:-1] #Radial velocity and its error
6875 6444 arrayParameters[:,8:12] = arrayMeteors[:,7:11] #Phases
6876 6445 arrayParameters[:,-1] = arrayMeteors[:,-1] #Error
6877 6446
6878 6447
6879 6448 return arrayParameters
6880 6449
6881 6450 class CorrectSMPhases(Operation):
6882 6451
6883 6452 def run(self, dataOut, phaseOffsets, hmin = 50, hmax = 150, azimuth = 45, channelPositions = None):
6884 6453
6885 6454 arrayParameters = dataOut.data_param
6886 6455 pairsList = []
6887 6456 pairx = (0,1)
6888 6457 pairy = (2,3)
6889 6458 pairsList.append(pairx)
6890 6459 pairsList.append(pairy)
6891 6460 jph = numpy.zeros(4)
6892 6461
6893 6462 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
6894 6463 # arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
6895 6464 arrayParameters[:,8:12] = numpy.angle(numpy.exp(1j*(arrayParameters[:,8:12] + phaseOffsets)))
6896 6465
6897 6466 meteorOps = SMOperations()
6898 6467 if channelPositions is None:
6899 6468 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
6900 6469 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
6901 6470
6902 6471 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
6903 6472 h = (hmin,hmax)
6904 6473
6905 6474 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
6906 6475
6907 6476 dataOut.data_param = arrayParameters
6908 6477 return
6909 6478
6910 6479 class SMPhaseCalibration(Operation):
6911 6480
6912 6481 __buffer = None
6913 6482
6914 6483 __initime = None
6915 6484
6916 6485 __dataReady = False
6917 6486
6918 6487 __isConfig = False
6919 6488
6920 6489 def __checkTime(self, currentTime, initTime, paramInterval, outputInterval):
6921 6490
6922 6491 dataTime = currentTime + paramInterval
6923 6492 deltaTime = dataTime - initTime
6924 6493
6925 6494 if deltaTime >= outputInterval or deltaTime < 0:
6926 6495 return True
6927 6496
6928 6497 return False
6929 6498
6930 6499 def __getGammas(self, pairs, d, phases):
6931 6500 gammas = numpy.zeros(2)
6932 6501
6933 6502 for i in range(len(pairs)):
6934 6503
6935 6504 pairi = pairs[i]
6936 6505
6937 6506 phip3 = phases[:,pairi[0]]
6938 6507 d3 = d[pairi[0]]
6939 6508 phip2 = phases[:,pairi[1]]
6940 6509 d2 = d[pairi[1]]
6941 6510 #Calculating gamma
6942 6511 jgamma = -phip2*d3/d2 - phip3
6943 6512 jgamma = numpy.angle(numpy.exp(1j*jgamma))
6944 6513
6945 6514 #Revised distribution
6946 6515 jgammaArray = numpy.hstack((jgamma,jgamma+0.5*numpy.pi,jgamma-0.5*numpy.pi))
6947 6516
6948 6517 #Histogram
6949 6518 nBins = 64
6950 6519 rmin = -0.5*numpy.pi
6951 6520 rmax = 0.5*numpy.pi
6952 6521 phaseHisto = numpy.histogram(jgammaArray, bins=nBins, range=(rmin,rmax))
6953 6522
6954 6523 meteorsY = phaseHisto[0]
6955 6524 phasesX = phaseHisto[1][:-1]
6956 6525 width = phasesX[1] - phasesX[0]
6957 6526 phasesX += width/2
6958 6527
6959 6528 #Gaussian aproximation
6960 6529 bpeak = meteorsY.argmax()
6961 6530 peak = meteorsY.max()
6962 6531 jmin = bpeak - 5
6963 6532 jmax = bpeak + 5 + 1
6964 6533
6965 6534 if jmin<0:
6966 6535 jmin = 0
6967 6536 jmax = 6
6968 6537 elif jmax > meteorsY.size:
6969 6538 jmin = meteorsY.size - 6
6970 6539 jmax = meteorsY.size
6971 6540
6972 6541 x0 = numpy.array([peak,bpeak,50])
6973 6542 coeff = optimize.leastsq(self.__residualFunction, x0, args=(meteorsY[jmin:jmax], phasesX[jmin:jmax]))
6974 6543
6975 6544 #Gammas
6976 6545 gammas[i] = coeff[0][1]
6977 6546
6978 6547 return gammas
6979 6548
6980 6549 def __residualFunction(self, coeffs, y, t):
6981 6550
6982 6551 return y - self.__gauss_function(t, coeffs)
6983 6552
6984 6553 def __gauss_function(self, t, coeffs):
6985 6554
6986 6555 return coeffs[0]*numpy.exp(-0.5*((t - coeffs[1]) / coeffs[2])**2)
6987 6556
6988 6557 def __getPhases(self, azimuth, h, pairsList, d, gammas, meteorsArray):
6989 6558 meteorOps = SMOperations()
6990 6559 nchan = 4
6991 6560 pairx = pairsList[0] #x es 0
6992 6561 pairy = pairsList[1] #y es 1
6993 6562 center_xangle = 0
6994 6563 center_yangle = 0
6995 6564 range_angle = numpy.array([10*numpy.pi,numpy.pi,numpy.pi/2,numpy.pi/4])
6996 6565 ntimes = len(range_angle)
6997 6566
6998 6567 nstepsx = 20
6999 6568 nstepsy = 20
7000 6569
7001 6570 for iz in range(ntimes):
7002 6571 min_xangle = -range_angle[iz]/2 + center_xangle
7003 6572 max_xangle = range_angle[iz]/2 + center_xangle
7004 6573 min_yangle = -range_angle[iz]/2 + center_yangle
7005 6574 max_yangle = range_angle[iz]/2 + center_yangle
7006 6575
7007 6576 inc_x = (max_xangle-min_xangle)/nstepsx
7008 6577 inc_y = (max_yangle-min_yangle)/nstepsy
7009 6578
7010 6579 alpha_y = numpy.arange(nstepsy)*inc_y + min_yangle
7011 6580 alpha_x = numpy.arange(nstepsx)*inc_x + min_xangle
7012 6581 penalty = numpy.zeros((nstepsx,nstepsy))
7013 6582 jph_array = numpy.zeros((nchan,nstepsx,nstepsy))
7014 6583 jph = numpy.zeros(nchan)
7015 6584
7016 6585 # Iterations looking for the offset
7017 6586 for iy in range(int(nstepsy)):
7018 6587 for ix in range(int(nstepsx)):
7019 6588 d3 = d[pairsList[1][0]]
7020 6589 d2 = d[pairsList[1][1]]
7021 6590 d5 = d[pairsList[0][0]]
7022 6591 d4 = d[pairsList[0][1]]
7023 6592
7024 6593 alp2 = alpha_y[iy] #gamma 1
7025 6594 alp4 = alpha_x[ix] #gamma 0
7026 6595
7027 6596 alp3 = -alp2*d3/d2 - gammas[1]
7028 6597 alp5 = -alp4*d5/d4 - gammas[0]
7029 6598 jph[pairsList[0][1]] = alp4
7030 6599 jph[pairsList[0][0]] = alp5
7031 6600 jph[pairsList[1][0]] = alp3
7032 6601 jph[pairsList[1][1]] = alp2
7033 6602 jph_array[:,ix,iy] = jph
7034 6603 meteorsArray1 = meteorOps.getMeteorParams(meteorsArray, azimuth, h, pairsList, d, jph)
7035 6604 error = meteorsArray1[:,-1]
7036 6605 ind1 = numpy.where(error==0)[0]
7037 6606 penalty[ix,iy] = ind1.size
7038 6607
7039 6608 i,j = numpy.unravel_index(penalty.argmax(), penalty.shape)
7040 6609 phOffset = jph_array[:,i,j]
7041 6610
7042 6611 center_xangle = phOffset[pairx[1]]
7043 6612 center_yangle = phOffset[pairy[1]]
7044 6613
7045 6614 phOffset = numpy.angle(numpy.exp(1j*jph_array[:,i,j]))
7046 6615 phOffset = phOffset*180/numpy.pi
7047 6616 return phOffset
7048 6617
7049 6618
7050 6619 def run(self, dataOut, hmin, hmax, channelPositions=None, nHours = 1):
7051 6620
7052 6621 dataOut.flagNoData = True
7053 6622 self.__dataReady = False
7054 6623 dataOut.outputInterval = nHours*3600
7055 6624
7056 6625 if self.__isConfig == False:
7057 6626 #Get Initial LTC time
7058 6627 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
7059 6628 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
7060 6629
7061 6630 self.__isConfig = True
7062 6631
7063 6632 if self.__buffer is None:
7064 6633 self.__buffer = dataOut.data_param.copy()
7065 6634
7066 6635 else:
7067 6636 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
7068 6637
7069 6638 self.__dataReady = self.__checkTime(dataOut.utctime, self.__initime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
7070 6639
7071 6640 if self.__dataReady:
7072 6641 dataOut.utctimeInit = self.__initime
7073 6642 self.__initime += dataOut.outputInterval #to erase time offset
7074 6643
7075 6644 freq = dataOut.frequency
7076 6645 c = dataOut.C #m/s
7077 6646 lamb = c/freq
7078 6647 k = 2*numpy.pi/lamb
7079 6648 azimuth = 0
7080 6649 h = (hmin, hmax)
7081 6650
7082 6651 if channelPositions is None:
7083 6652 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
7084 6653 meteorOps = SMOperations()
7085 6654 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
7086 6655
7087 6656 #Checking correct order of pairs
7088 6657 pairs = []
7089 6658 if distances[1] > distances[0]:
7090 6659 pairs.append((1,0))
7091 6660 else:
7092 6661 pairs.append((0,1))
7093 6662
7094 6663 if distances[3] > distances[2]:
7095 6664 pairs.append((3,2))
7096 6665 else:
7097 6666 pairs.append((2,3))
7098 6667
7099 6668 meteorsArray = self.__buffer
7100 6669 error = meteorsArray[:,-1]
7101 6670 boolError = (error==0)|(error==3)|(error==4)|(error==13)|(error==14)
7102 6671 ind1 = numpy.where(boolError)[0]
7103 6672 meteorsArray = meteorsArray[ind1,:]
7104 6673 meteorsArray[:,-1] = 0
7105 6674 phases = meteorsArray[:,8:12]
7106 6675
7107 6676 #Calculate Gammas
7108 6677 gammas = self.__getGammas(pairs, distances, phases)
7109 6678 #Calculate Phases
7110 6679 phasesOff = self.__getPhases(azimuth, h, pairs, distances, gammas, meteorsArray)
7111 6680 phasesOff = phasesOff.reshape((1,phasesOff.size))
7112 6681 dataOut.data_output = -phasesOff
7113 6682 dataOut.flagNoData = False
7114 6683 self.__buffer = None
7115 6684
7116 6685
7117 6686 return
7118 6687
7119 6688 class SMOperations():
7120 6689
7121 6690 def __init__(self):
7122 6691
7123 6692 return
7124 6693
7125 6694 def getMeteorParams(self, arrayParameters0, azimuth, h, pairsList, distances, jph):
7126 6695
7127 6696 arrayParameters = arrayParameters0.copy()
7128 6697 hmin = h[0]
7129 6698 hmax = h[1]
7130 6699
7131 6700 #Calculate AOA (Error N 3, 4)
7132 6701 #JONES ET AL. 1998
7133 6702 AOAthresh = numpy.pi/8
7134 6703 error = arrayParameters[:,-1]
7135 6704 phases = -arrayParameters[:,8:12] + jph
7136 6705 arrayParameters[:,3:6], arrayParameters[:,-1] = self.__getAOA(phases, pairsList, distances, error, AOAthresh, azimuth)
7137 6706
7138 6707 #Calculate Heights (Error N 13 and 14)
7139 6708 error = arrayParameters[:,-1]
7140 6709 Ranges = arrayParameters[:,1]
7141 6710 zenith = arrayParameters[:,4]
7142 6711 arrayParameters[:,2], arrayParameters[:,-1] = self.__getHeights(Ranges, zenith, error, hmin, hmax)
7143 6712
7144 6713 #----------------------- Get Final data ------------------------------------
7145 6714
7146 6715 return arrayParameters
7147 6716
7148 6717 def __getAOA(self, phases, pairsList, directions, error, AOAthresh, azimuth):
7149 6718
7150 6719 arrayAOA = numpy.zeros((phases.shape[0],3))
7151 6720 cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList,directions)
7152 6721
7153 6722 arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
7154 6723 cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
7155 6724 arrayAOA[:,2] = cosDirError
7156 6725
7157 6726 azimuthAngle = arrayAOA[:,0]
7158 6727 zenithAngle = arrayAOA[:,1]
7159 6728
7160 6729 #Setting Error
7161 6730 indError = numpy.where(numpy.logical_or(error == 3, error == 4))[0]
7162 6731 error[indError] = 0
7163 6732 #Number 3: AOA not fesible
7164 6733 indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
7165 6734 error[indInvalid] = 3
7166 6735 #Number 4: Large difference in AOAs obtained from different antenna baselines
7167 6736 indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
7168 6737 error[indInvalid] = 4
7169 6738 return arrayAOA, error
7170 6739
7171 6740 def __getDirectionCosines(self, arrayPhase, pairsList, distances):
7172 6741
7173 6742 #Initializing some variables
7174 6743 ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
7175 6744 ang_aux = ang_aux.reshape(1,ang_aux.size)
7176 6745
7177 6746 cosdir = numpy.zeros((arrayPhase.shape[0],2))
7178 6747 cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
7179 6748
7180 6749
7181 6750 for i in range(2):
7182 6751 ph0 = arrayPhase[:,pairsList[i][0]]
7183 6752 ph1 = arrayPhase[:,pairsList[i][1]]
7184 6753 d0 = distances[pairsList[i][0]]
7185 6754 d1 = distances[pairsList[i][1]]
7186 6755
7187 6756 ph0_aux = ph0 + ph1
7188 6757 ph0_aux = numpy.angle(numpy.exp(1j*ph0_aux))
7189 6758 #First Estimation
7190 6759 cosdir0[:,i] = (ph0_aux)/(2*numpy.pi*(d0 - d1))
7191 6760
7192 6761 #Most-Accurate Second Estimation
7193 6762 phi1_aux = ph0 - ph1
7194 6763 phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
7195 6764 #Direction Cosine 1
7196 6765 cosdir1 = (phi1_aux + ang_aux)/(2*numpy.pi*(d0 + d1))
7197 6766
7198 6767 #Searching the correct Direction Cosine
7199 6768 cosdir0_aux = cosdir0[:,i]
7200 6769 cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
7201 6770 #Minimum Distance
7202 6771 cosDiff = (cosdir1 - cosdir0_aux)**2
7203 6772 indcos = cosDiff.argmin(axis = 1)
7204 6773 #Saving Value obtained
7205 6774 cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
7206 6775
7207 6776 return cosdir0, cosdir
7208 6777
7209 6778 def __calculateAOA(self, cosdir, azimuth):
7210 6779 cosdirX = cosdir[:,0]
7211 6780 cosdirY = cosdir[:,1]
7212 6781
7213 6782 zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
7214 6783 azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth#0 deg north, 90 deg east
7215 6784 angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
7216 6785
7217 6786 return angles
7218 6787
7219 6788 def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
7220 6789
7221 6790 Ramb = 375 #Ramb = c/(2*PRF)
7222 6791 Re = 6371 #Earth Radius
7223 6792 heights = numpy.zeros(Ranges.shape)
7224 6793
7225 6794 R_aux = numpy.array([0,1,2])*Ramb
7226 6795 R_aux = R_aux.reshape(1,R_aux.size)
7227 6796
7228 6797 Ranges = Ranges.reshape(Ranges.size,1)
7229 6798
7230 6799 Ri = Ranges + R_aux
7231 6800 hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
7232 6801
7233 6802 #Check if there is a height between 70 and 110 km
7234 6803 h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
7235 6804 ind_h = numpy.where(h_bool == 1)[0]
7236 6805
7237 6806 hCorr = hi[ind_h, :]
7238 6807 ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
7239 6808
7240 6809 hCorr = hi[ind_hCorr][:len(ind_h)]
7241 6810 heights[ind_h] = hCorr
7242 6811
7243 6812 #Setting Error
7244 6813 #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
7245 6814 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
7246 6815 indError = numpy.where(numpy.logical_or(error == 13, error == 14))[0]
7247 6816 error[indError] = 0
7248 6817 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
7249 6818 error[indInvalid2] = 14
7250 6819 indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
7251 6820 error[indInvalid1] = 13
7252 6821
7253 6822 return heights, error
7254 6823
7255 6824 def getPhasePairs(self, channelPositions):
7256 6825 chanPos = numpy.array(channelPositions)
7257 6826 listOper = list(itertools.combinations(list(range(5)),2))
7258 6827
7259 6828 distances = numpy.zeros(4)
7260 6829 axisX = []
7261 6830 axisY = []
7262 6831 distX = numpy.zeros(3)
7263 6832 distY = numpy.zeros(3)
7264 6833 ix = 0
7265 6834 iy = 0
7266 6835
7267 6836 pairX = numpy.zeros((2,2))
7268 6837 pairY = numpy.zeros((2,2))
7269 6838
7270 6839 for i in range(len(listOper)):
7271 6840 pairi = listOper[i]
7272 6841
7273 6842 posDif = numpy.abs(chanPos[pairi[0],:] - chanPos[pairi[1],:])
7274 6843
7275 6844 if posDif[0] == 0:
7276 6845 axisY.append(pairi)
7277 6846 distY[iy] = posDif[1]
7278 6847 iy += 1
7279 6848 elif posDif[1] == 0:
7280 6849 axisX.append(pairi)
7281 6850 distX[ix] = posDif[0]
7282 6851 ix += 1
7283 6852
7284 6853 for i in range(2):
7285 6854 if i==0:
7286 6855 dist0 = distX
7287 6856 axis0 = axisX
7288 6857 else:
7289 6858 dist0 = distY
7290 6859 axis0 = axisY
7291 6860
7292 6861 side = numpy.argsort(dist0)[:-1]
7293 6862 axis0 = numpy.array(axis0)[side,:]
7294 6863 chanC = int(numpy.intersect1d(axis0[0,:], axis0[1,:])[0])
7295 6864 axis1 = numpy.unique(numpy.reshape(axis0,4))
7296 6865 side = axis1[axis1 != chanC]
7297 6866 diff1 = chanPos[chanC,i] - chanPos[side[0],i]
7298 6867 diff2 = chanPos[chanC,i] - chanPos[side[1],i]
7299 6868 if diff1<0:
7300 6869 chan2 = side[0]
7301 6870 d2 = numpy.abs(diff1)
7302 6871 chan1 = side[1]
7303 6872 d1 = numpy.abs(diff2)
7304 6873 else:
7305 6874 chan2 = side[1]
7306 6875 d2 = numpy.abs(diff2)
7307 6876 chan1 = side[0]
7308 6877 d1 = numpy.abs(diff1)
7309 6878
7310 6879 if i==0:
7311 6880 chanCX = chanC
7312 6881 chan1X = chan1
7313 6882 chan2X = chan2
7314 6883 distances[0:2] = numpy.array([d1,d2])
7315 6884 else:
7316 6885 chanCY = chanC
7317 6886 chan1Y = chan1
7318 6887 chan2Y = chan2
7319 6888 distances[2:4] = numpy.array([d1,d2])
7320
7321 6889 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
7322 6890
7323 6891 return pairslist, distances
7324 6892
7325 6893 class IGRFModel(Operation):
7326 6894 '''
7327 6895 Written by R. Flores
7328 6896 '''
7329 6897 """Operation to calculate Geomagnetic parameters.
7330 6898
7331 6899 Parameters:
7332 6900 -----------
7333 6901 None
7334 6902
7335 6903 Example
7336 6904 --------
7337 6905
7338 6906 op = proc_unit.addOperation(name='IGRFModel', optype='other')
7339 6907
7340 6908 """
7341 6909
7342 6910 def __init__(self, **kwargs):
7343 6911
7344 6912 Operation.__init__(self, **kwargs)
7345 6913
7346 6914 self.aux=1
7347 6915
7348 6916 def run(self,dataOut):
7349 6917
7350 6918 try:
7351 6919 from schainpy.model.proc import mkfact_short_2020_2
7352 6920 except:
7353 6921 log.warning('You should install "mkfact_short_2020" module to process IGRF Model')
7354 6922
7355 6923 if self.aux==1:
7356 6924
7357 6925 #dataOut.TimeBlockSeconds_First_Time=time.mktime(time.strptime(dataOut.TimeBlockDate))
7358 6926 #### we do not use dataOut.datatime.ctime() because it's the time of the second (next) block
7359 6927 dataOut.TimeBlockSeconds_First_Time=dataOut.TimeBlockSeconds
7360 6928 dataOut.bd_time=time.gmtime(dataOut.TimeBlockSeconds_First_Time)
7361 6929 dataOut.year=dataOut.bd_time.tm_year+(dataOut.bd_time.tm_yday-1)/364.0
7362 6930 dataOut.ut=dataOut.bd_time.tm_hour+dataOut.bd_time.tm_min/60.0+dataOut.bd_time.tm_sec/3600.0
7363 6931
7364 6932 self.aux=0
7365 6933 dh = dataOut.heightList[1]-dataOut.heightList[0]
7366 6934 #dataOut.h=numpy.arange(0.0,15.0*dataOut.MAXNRANGENDT,15.0,dtype='float32')
7367 6935 dataOut.h=numpy.arange(0.0,dh*dataOut.MAXNRANGENDT,dh,dtype='float32')
7368 6936 dataOut.bfm=numpy.zeros(dataOut.MAXNRANGENDT,dtype='float32')
7369 6937 dataOut.bfm=numpy.array(dataOut.bfm,order='F')
7370 6938 dataOut.thb=numpy.zeros(dataOut.MAXNRANGENDT,dtype='float32')
7371 6939 dataOut.thb=numpy.array(dataOut.thb,order='F')
7372 6940 dataOut.bki=numpy.zeros(dataOut.MAXNRANGENDT,dtype='float32')
7373 6941 dataOut.bki=numpy.array(dataOut.bki,order='F')
7374 6942
7375 6943 mkfact_short_2020_2.mkfact(dataOut.year,dataOut.h,dataOut.bfm,dataOut.thb,dataOut.bki,dataOut.MAXNRANGENDT)
7376 6944
7377 6945 return dataOut
7378 6946
7379 6947 class MergeProc(ProcessingUnit):
7380 6948
7381 6949 def __init__(self):
7382 6950 ProcessingUnit.__init__(self)
7383 6951
7384 6952 def run(self, attr_data, attr_data_2 = None, attr_data_3 = None, attr_data_4 = None, attr_data_5 = None, mode=0):
7385 6953
7386 6954 self.dataOut = getattr(self, self.inputs[0])
7387 6955 data_inputs = [getattr(self, attr) for attr in self.inputs]
7388 6956
7389 6957 if mode==0:
7390 6958 data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs])
7391 6959 setattr(self.dataOut, attr_data, data)
7392 6960
7393 6961 if mode==1: #Hybrid
7394 6962 #data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs],axis=1)
7395 6963 #setattr(self.dataOut, attr_data, data)
7396 6964 setattr(self.dataOut, 'dataLag_spc', [getattr(data, attr_data) for data in data_inputs][0])
7397 6965 setattr(self.dataOut, 'dataLag_spc_LP', [getattr(data, attr_data) for data in data_inputs][1])
7398 6966 setattr(self.dataOut, 'dataLag_cspc', [getattr(data, attr_data_2) for data in data_inputs][0])
7399 6967 setattr(self.dataOut, 'dataLag_cspc_LP', [getattr(data, attr_data_2) for data in data_inputs][1])
7400 6968 #setattr(self.dataOut, 'nIncohInt', [getattr(data, attr_data_3) for data in data_inputs][0])
7401 6969 #setattr(self.dataOut, 'nIncohInt_LP', [getattr(data, attr_data_3) for data in data_inputs][1])
7402 6970 '''
7403 6971 print(self.dataOut.dataLag_spc_LP.shape)
7404 6972 print(self.dataOut.dataLag_cspc_LP.shape)
7405 6973 exit(1)
7406 6974 '''
7407 6975
7408 6976 #self.dataOut.dataLag_spc_LP = numpy.transpose(self.dataOut.dataLag_spc_LP[0],(2,0,1))
7409 6977 #self.dataOut.dataLag_cspc_LP = numpy.transpose(self.dataOut.dataLag_cspc_LP,(3,1,2,0))
7410 6978 '''
7411 6979 print("Merge")
7412 6980 print(numpy.shape(self.dataOut.dataLag_spc))
7413 6981 print(numpy.shape(self.dataOut.dataLag_spc_LP))
7414 6982 print(numpy.shape(self.dataOut.dataLag_cspc))
7415 6983 print(numpy.shape(self.dataOut.dataLag_cspc_LP))
7416 6984 exit(1)
7417 6985 '''
7418 6986 #print(numpy.sum(self.dataOut.dataLag_spc_LP[2,:,164])/128)
7419 6987 #print(numpy.sum(self.dataOut.dataLag_cspc_LP[0,:,30,1])/128)
7420 6988 #exit(1)
7421 6989 #print(self.dataOut.NDP)
7422 6990 #print(self.dataOut.nNoiseProfiles)
7423 6991
7424 6992 #self.dataOut.nIncohInt_LP = 128
7425 6993 self.dataOut.nProfiles_LP = 128#self.dataOut.nIncohInt_LP
7426 6994 self.dataOut.nIncohInt_LP = self.dataOut.nIncohInt
7427 6995 self.dataOut.NLAG = 16
7428 6996 self.dataOut.NRANGE = 200
7429 6997 self.dataOut.NSCAN = 128
7430 6998 #print(numpy.shape(self.dataOut.data_spc))
7431 6999
7432 7000 #exit(1)
7433 7001
7434 7002 if mode==2: #HAE 2022
7435 7003 data = numpy.sum([getattr(data, attr_data) for data in data_inputs],axis=0)
7436 7004 setattr(self.dataOut, attr_data, data)
7437 7005
7438 7006 self.dataOut.nIncohInt *= 2
7439 7007 #meta = self.dataOut.getFreqRange(1)/1000.
7440 7008 self.dataOut.freqRange = self.dataOut.getFreqRange(1)/1000.
7441 7009
7442 7010 #exit(1)
7443 7011
7444 7012 if mode==4: #Hybrid LP-SSheightProfiles
7445 7013 #data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs],axis=1)
7446 7014 #setattr(self.dataOut, attr_data, data)
7447 7015 setattr(self.dataOut, 'dataLag_spc', getattr(data_inputs[0], attr_data)) #DP
7448 7016 setattr(self.dataOut, 'dataLag_cspc', getattr(data_inputs[0], attr_data_2)) #DP
7449 7017 setattr(self.dataOut, 'dataLag_spc_LP', getattr(data_inputs[1], attr_data_3)) #LP
7450 7018 #setattr(self.dataOut, 'dataLag_cspc_LP', getattr(data_inputs[1], attr_data_4)) #LP
7451 7019 #setattr(self.dataOut, 'data_acf', getattr(data_inputs[1], attr_data_5)) #LP
7452 7020 setattr(self.dataOut, 'data_acf', getattr(data_inputs[1], attr_data_5)) #LP
7453 7021 #print("Merge data_acf: ",self.dataOut.data_acf.shape)
7454 7022
7455 7023 #self.dataOut.nIncohInt_LP = 128
7456 7024 #self.dataOut.nProfiles_LP = 128#self.dataOut.nIncohInt_LP
7457 7025 self.dataOut.nProfiles_LP = 16#28#self.dataOut.nIncohInt_LP
7458 7026 self.dataOut.nProfiles_LP = self.dataOut.data_acf.shape[1]#28#self.dataOut.nIncohInt_LP
7459 7027 self.dataOut.NSCAN = 128
7460 7028 self.dataOut.nIncohInt_LP = self.dataOut.nIncohInt*self.dataOut.NSCAN
7461 7029 #print("sahpi",self.dataOut.nIncohInt_LP)
7462 7030 #exit(1)
7463 7031 self.dataOut.NLAG = 16
7464 7032 self.dataOut.NLAG = self.dataOut.data_acf.shape[1]
7465 7033 self.dataOut.NRANGE = self.dataOut.data_acf.shape[-1]
7466 7034
7467 7035 #print(numpy.shape(self.dataOut.data_spc))
7468 7036
7469 7037 #exit(1)
7470 7038 if mode==5:
7471 7039 data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs])
7472 7040 setattr(self.dataOut, attr_data, data)
7473 7041 data = numpy.concatenate([getattr(data, attr_data_2) for data in data_inputs])
7474 7042 setattr(self.dataOut, attr_data_2, data)
7475 7043
7476 7044 if mode==6: #Hybrid Spectra-Voltage
7477 7045 #data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs],axis=1)
7478 7046 #setattr(self.dataOut, attr_data, data)
7479 7047 setattr(self.dataOut, 'dataLag_spc', getattr(data_inputs[1], attr_data)) #DP
7480 7048 setattr(self.dataOut, 'dataLag_cspc', getattr(data_inputs[1], attr_data_2)) #DP
7481 7049 setattr(self.dataOut, 'output_LP_integrated', getattr(data_inputs[0], attr_data_3)) #LP
7482 7050 #setattr(self.dataOut, 'dataLag_cspc_LP', getattr(data_inputs[1], attr_data_4)) #LP
7483 7051 #setattr(self.dataOut, 'data_acf', getattr(data_inputs[1], attr_data_5)) #LP
7484 7052 #setattr(self.dataOut, 'data_acf', getattr(data_inputs[1], attr_data_5)) #LP
7485 7053 #print("Merge data_acf: ",self.dataOut.data_acf.shape)
7486 7054 #print(self.dataOut.NSCAN)
7487 7055 self.dataOut.nIncohInt = int(self.dataOut.NAVG * self.dataOut.nint)
7488 7056 #print(self.dataOut.dataLag_spc.shape)
7489 7057 self.dataOut.nProfiles = self.dataOut.nProfiles_DP = self.dataOut.dataLag_spc.shape[1]
7490 7058 '''
7491 7059 #self.dataOut.nIncohInt_LP = 128
7492 7060 #self.dataOut.nProfiles_LP = 128#self.dataOut.nIncohInt_LP
7493 7061 self.dataOut.nProfiles_LP = 16#28#self.dataOut.nIncohInt_LP
7494 7062 self.dataOut.nProfiles_LP = self.dataOut.data_acf.shape[1]#28#self.dataOut.nIncohInt_LP
7495 7063 self.dataOut.NSCAN = 128
7496 7064 self.dataOut.nIncohInt_LP = self.dataOut.nIncohInt*self.dataOut.NSCAN
7497 7065 #print("sahpi",self.dataOut.nIncohInt_LP)
7498 7066 #exit(1)
7499 7067 self.dataOut.NLAG = 16
7500 7068 self.dataOut.NLAG = self.dataOut.data_acf.shape[1]
7501 7069 self.dataOut.NRANGE = self.dataOut.data_acf.shape[-1]
7502 7070 '''
7503 7071 #print(numpy.shape(self.dataOut.data_spc))
7504 7072 #print("*************************GOOD*************************")
7505 7073 #exit(1)
7506 7074
7507 7075 if mode==11: #MST ISR
7508 7076 #data = numpy.concatenate([getattr(data, attr_data) for data in data_inputs],axis=1)
7509 7077 #setattr(self.dataOut, attr_data, data)
7510 7078 #setattr(self.dataOut, 'ph2', [getattr(data, attr_data) for data in data_inputs][1])
7511 7079 #setattr(self.dataOut, 'dphi', [getattr(data, attr_data_2) for data in data_inputs][1])
7512 7080 #setattr(self.dataOut, 'sdp2', [getattr(data, attr_data_3) for data in data_inputs][1])
7513 7081
7514 7082 setattr(self.dataOut, 'ph2', getattr(data_inputs[1], attr_data)) #DP
7515 7083 setattr(self.dataOut, 'dphi', getattr(data_inputs[1], attr_data_2)) #DP
7516 7084 setattr(self.dataOut, 'sdp2', getattr(data_inputs[1], attr_data_3)) #DP
7517 7085
7518 7086 print("MST Density", numpy.shape(self.dataOut.ph2))
7519 7087 print("cf MST: ", self.dataOut.cf)
7520 7088 #exit(1)
7521 7089 #print("MST Density", self.dataOut.ph2[116:283])
7522 7090 print("MST Density", self.dataOut.ph2[80:120])
7523 7091 print("MST dPhi", self.dataOut.dphi[80:120])
7524 7092 self.dataOut.ph2 *= self.dataOut.cf#0.0008136899
7525 7093 #print("MST Density", self.dataOut.ph2[116:283])
7526 7094 self.dataOut.sdp2 *= 0#self.dataOut.cf#0.0008136899
7527 7095 #print("MST Density", self.dataOut.ph2[116:283])
7528 7096 print("MST Density", self.dataOut.ph2[80:120])
7529 7097 self.dataOut.NSHTS = int(numpy.shape(self.dataOut.ph2)[0])
7530 7098 dH = self.dataOut.heightList[1]-self.dataOut.heightList[0]
7531 7099 dH /= self.dataOut.windowOfFilter
7532 7100 self.dataOut.heightList = numpy.arange(0,self.dataOut.NSHTS)*dH + dH
7533 7101 #print("heightList: ", self.dataOut.heightList)
7534 7102 self.dataOut.NDP = self.dataOut.NSHTS
7535 7103 #exit(1)
7536 7104 #print(self.dataOut.heightList)
7537 7105
7538 7106 class MST_Den_Conv(Operation):
7539 7107 '''
7540 7108 Written by R. Flores
7541 7109 '''
7542 7110 """Operation to calculate Geomagnetic parameters.
7543 7111
7544 7112 Parameters:
7545 7113 -----------
7546 7114 None
7547 7115
7548 7116 Example
7549 7117 --------
7550 7118
7551 7119 op = proc_unit.addOperation(name='MST_Den_Conv', optype='other')
7552 7120
7553 7121 """
7554 7122
7555 7123 def __init__(self, **kwargs):
7556 7124
7557 7125 Operation.__init__(self, **kwargs)
7558 7126
7559 7127 def run(self,dataOut):
7560 7128
7561 7129 dataOut.PowDen = numpy.zeros((1,dataOut.NDP))
7562 7130 dataOut.PowDen[0] = numpy.copy(dataOut.ph2[:dataOut.NDP])
7563 7131
7564 7132 dataOut.FarDen = numpy.zeros((1,dataOut.NDP))
7565 7133 dataOut.FarDen[0] = numpy.copy(dataOut.dphi[:dataOut.NDP])
7566 7134 print("pow den shape", numpy.shape(dataOut.PowDen))
7567 7135 print("far den shape", numpy.shape(dataOut.FarDen))
7568 7136 return dataOut
7569 7137
7570 7138 class addTxPower(Operation):
7571 7139 '''
7572 7140 Transmited power level integrated in the dataOut ->AMISR
7573 7141 resolution 1 min
7574 7142 The power files have the pattern power_YYYYMMDD.csv
7575 7143 '''
7576 7144 __slots__ =('isConfig','dataDatetimes','txPowers')
7577 7145 def __init__(self):
7578 7146
7579 7147 Operation.__init__(self)
7580 7148 self.isConfig = False
7581 7149 self.dataDatetimes = []
7582 7150 self.txPowers = []
7583 7151
7584 7152 def setup(self, powerFile, dutyCycle):
7585 7153 if not os.path.isfile(powerFile):
7586 7154 raise schainpy.admin.SchainError('There is no file named :{}'.format(powerFile))
7587 7155 return
7588 7156
7589 7157 with open(powerFile, newline='') as pfile:
7590 7158 reader = csv.reader(pfile, delimiter=',', quotechar='|')
7591 7159 next(reader)
7592 7160 for row in reader:
7593 7161 #'2022-10-25 00:00:00'
7594 7162 self.dataDatetimes.append(datetime.datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S"))
7595 7163 self.txPowers.append(float(row[1])/dutyCycle)
7596 7164 self.isConfig = True
7597 7165
7598 7166 def run(self, dataOut, path, DS=0.05):
7599 7167
7600 7168 #dataOut.flagNoData = True
7601 7169
7602 7170 if not(self.isConfig):
7603 7171 self.setup(path, DS)
7604 7172
7605 7173 dataDate = datetime.datetime.utcfromtimestamp(dataOut.utctime).replace(second=0, microsecond=0)#no seconds
7606 7174 try:
7607 7175 indx = self.dataDatetimes.index(dataDate)
7608 7176 dataOut.txPower = self.txPowers[indx]
7609 7177 except:
7610 7178 log.warning("No power available for the datetime {}, setting power to 0 w", self.name)
7611 7179 dataOut.txPower = 0
7612 7180
7613 7181 return dataOut No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now