##// END OF EJS Templates
jrodata se cambio los atrituos de pulsepair,jroplot_voltage se cambio el ploteo de la potencial y la senal, jroIO_simulator se anadio la modificacion de bloquesporarchivo y perfilesporbloque,jro_proc_voltage se corrigio el calculo de noise con remocion DC y se asignaron nuevos nombres al dataOut, jroproc_parameters se anadio los nuevos atributos del dataOut jroproc_voltage pulsepair,test_sim0009.py es el nuevo test de escritura
avaldez -
r1311:816ce18b0db1 v3-devel-julio
parent child
Show More
@@ -1,1399 +1,1434
1 1 '''
2 2
3 3 $Author: murco $
4 4 $Id: JROData.py 173 2012-11-20 15:06:21Z murco $
5 5 '''
6 6
7 7 import copy
8 8 import numpy
9 9 import datetime
10 10 import json
11 11
12 12 import schainpy.admin
13 13 from schainpy.utils import log
14 14 from .jroheaderIO import SystemHeader, RadarControllerHeader
15 15 from schainpy.model.data import _noise
16 16
17 17
18 18 def getNumpyDtype(dataTypeCode):
19 19
20 20 if dataTypeCode == 0:
21 21 numpyDtype = numpy.dtype([('real', '<i1'), ('imag', '<i1')])
22 22 elif dataTypeCode == 1:
23 23 numpyDtype = numpy.dtype([('real', '<i2'), ('imag', '<i2')])
24 24 elif dataTypeCode == 2:
25 25 numpyDtype = numpy.dtype([('real', '<i4'), ('imag', '<i4')])
26 26 elif dataTypeCode == 3:
27 27 numpyDtype = numpy.dtype([('real', '<i8'), ('imag', '<i8')])
28 28 elif dataTypeCode == 4:
29 29 numpyDtype = numpy.dtype([('real', '<f4'), ('imag', '<f4')])
30 30 elif dataTypeCode == 5:
31 31 numpyDtype = numpy.dtype([('real', '<f8'), ('imag', '<f8')])
32 32 else:
33 33 raise ValueError('dataTypeCode was not defined')
34 34
35 35 return numpyDtype
36 36
37 37
38 38 def getDataTypeCode(numpyDtype):
39 39
40 40 if numpyDtype == numpy.dtype([('real', '<i1'), ('imag', '<i1')]):
41 41 datatype = 0
42 42 elif numpyDtype == numpy.dtype([('real', '<i2'), ('imag', '<i2')]):
43 43 datatype = 1
44 44 elif numpyDtype == numpy.dtype([('real', '<i4'), ('imag', '<i4')]):
45 45 datatype = 2
46 46 elif numpyDtype == numpy.dtype([('real', '<i8'), ('imag', '<i8')]):
47 47 datatype = 3
48 48 elif numpyDtype == numpy.dtype([('real', '<f4'), ('imag', '<f4')]):
49 49 datatype = 4
50 50 elif numpyDtype == numpy.dtype([('real', '<f8'), ('imag', '<f8')]):
51 51 datatype = 5
52 52 else:
53 53 datatype = None
54 54
55 55 return datatype
56 56
57 57
58 58 def hildebrand_sekhon(data, navg):
59 59 """
60 60 This method is for the objective determination of the noise level in Doppler spectra. This
61 61 implementation technique is based on the fact that the standard deviation of the spectral
62 62 densities is equal to the mean spectral density for white Gaussian noise
63 63
64 64 Inputs:
65 65 Data : heights
66 66 navg : numbers of averages
67 67
68 68 Return:
69 69 mean : noise's level
70 70 """
71 71
72 72 sortdata = numpy.sort(data, axis=None)
73 73 '''
74 74 lenOfData = len(sortdata)
75 75 nums_min = lenOfData*0.2
76 76
77 77 if nums_min <= 5:
78 78
79 79 nums_min = 5
80 80
81 81 sump = 0.
82 82 sumq = 0.
83 83
84 84 j = 0
85 85 cont = 1
86 86
87 87 while((cont == 1)and(j < lenOfData)):
88 88
89 89 sump += sortdata[j]
90 90 sumq += sortdata[j]**2
91 91
92 92 if j > nums_min:
93 93 rtest = float(j)/(j-1) + 1.0/navg
94 94 if ((sumq*j) > (rtest*sump**2)):
95 95 j = j - 1
96 96 sump = sump - sortdata[j]
97 97 sumq = sumq - sortdata[j]**2
98 98 cont = 0
99 99
100 100 j += 1
101 101
102 102 lnoise = sump / j
103 103 '''
104 104 return _noise.hildebrand_sekhon(sortdata, navg)
105 105
106 106
107 107 class Beam:
108 108
109 109 def __init__(self):
110 110 self.codeList = []
111 111 self.azimuthList = []
112 112 self.zenithList = []
113 113
114 114
115 115 class GenericData(object):
116 116
117 117 flagNoData = True
118 118
119 119 def copy(self, inputObj=None):
120 120
121 121 if inputObj == None:
122 122 return copy.deepcopy(self)
123 123
124 124 for key in list(inputObj.__dict__.keys()):
125 125
126 126 attribute = inputObj.__dict__[key]
127 127
128 128 # If this attribute is a tuple or list
129 129 if type(inputObj.__dict__[key]) in (tuple, list):
130 130 self.__dict__[key] = attribute[:]
131 131 continue
132 132
133 133 # If this attribute is another object or instance
134 134 if hasattr(attribute, '__dict__'):
135 135 self.__dict__[key] = attribute.copy()
136 136 continue
137 137
138 138 self.__dict__[key] = inputObj.__dict__[key]
139 139
140 140 def deepcopy(self):
141 141
142 142 return copy.deepcopy(self)
143 143
144 144 def isEmpty(self):
145 145
146 146 return self.flagNoData
147 147
148 148 def isReady(self):
149 149
150 150 return not self.flagNoData
151 151
152 152
153 153 class JROData(GenericData):
154 154
155 155 # m_BasicHeader = BasicHeader()
156 156 # m_ProcessingHeader = ProcessingHeader()
157 157
158 158 systemHeaderObj = SystemHeader()
159 159 radarControllerHeaderObj = RadarControllerHeader()
160 160 # data = None
161 161 type = None
162 162 datatype = None # dtype but in string
163 163 # dtype = None
164 164 # nChannels = None
165 165 # nHeights = None
166 166 nProfiles = None
167 167 heightList = None
168 168 channelList = None
169 169 flagDiscontinuousBlock = False
170 170 useLocalTime = False
171 171 utctime = None
172 172 timeZone = None
173 173 dstFlag = None
174 174 errorCount = None
175 175 blocksize = None
176 176 # nCode = None
177 177 # nBaud = None
178 178 # code = None
179 179 flagDecodeData = False # asumo q la data no esta decodificada
180 180 flagDeflipData = False # asumo q la data no esta sin flip
181 181 flagShiftFFT = False
182 182 # ippSeconds = None
183 183 # timeInterval = None
184 184 nCohInt = None
185 185 # noise = None
186 186 windowOfFilter = 1
187 187 # Speed of ligth
188 188 C = 3e8
189 189 frequency = 49.92e6
190 190 realtime = False
191 191 beacon_heiIndexList = None
192 192 last_block = None
193 193 blocknow = None
194 194 azimuth = None
195 195 zenith = None
196 196 beam = Beam()
197 197 profileIndex = None
198 198 error = None
199 199 data = None
200 200 nmodes = None
201 201
202 202 def __str__(self):
203 203
204 204 return '{} - {}'.format(self.type, self.getDatatime())
205 205
206 206 def getNoise(self):
207 207
208 208 raise NotImplementedError
209 209
210 210 def getNChannels(self):
211 211
212 212 return len(self.channelList)
213 213
214 214 def getChannelIndexList(self):
215 215
216 216 return list(range(self.nChannels))
217 217
218 218 def getNHeights(self):
219 219
220 220 return len(self.heightList)
221 221
222 222 def getHeiRange(self, extrapoints=0):
223 223
224 224 heis = self.heightList
225 225 # deltah = self.heightList[1] - self.heightList[0]
226 226 #
227 227 # heis.append(self.heightList[-1])
228 228
229 229 return heis
230 230
231 231 def getDeltaH(self):
232 232
233 233 delta = self.heightList[1] - self.heightList[0]
234 234
235 235 return delta
236 236
237 237 def getltctime(self):
238 238
239 239 if self.useLocalTime:
240 240 return self.utctime - self.timeZone * 60
241 241
242 242 return self.utctime
243 243
244 244 def getDatatime(self):
245 245
246 246 datatimeValue = datetime.datetime.utcfromtimestamp(self.ltctime)
247 247 return datatimeValue
248 248
249 249 def getTimeRange(self):
250 250
251 251 datatime = []
252 252
253 253 datatime.append(self.ltctime)
254 254 datatime.append(self.ltctime + self.timeInterval + 1)
255 255
256 256 datatime = numpy.array(datatime)
257 257
258 258 return datatime
259 259
260 260 def getFmaxTimeResponse(self):
261 261
262 262 period = (10**-6) * self.getDeltaH() / (0.15)
263 263
264 264 PRF = 1. / (period * self.nCohInt)
265 265
266 266 fmax = PRF
267 267
268 268 return fmax
269 269
270 270 def getFmax(self):
271 271 PRF = 1. / (self.ippSeconds * self.nCohInt)
272 272
273 273 fmax = PRF
274 274 return fmax
275 275
276 276 def getVmax(self):
277 277
278 278 _lambda = self.C / self.frequency
279 279
280 280 vmax = self.getFmax() * _lambda / 2
281 281
282 282 return vmax
283 283
284 284 def get_ippSeconds(self):
285 285 '''
286 286 '''
287 287 return self.radarControllerHeaderObj.ippSeconds
288 288
289 289 def set_ippSeconds(self, ippSeconds):
290 290 '''
291 291 '''
292 292
293 293 self.radarControllerHeaderObj.ippSeconds = ippSeconds
294 294
295 295 return
296 296
297 297 def get_dtype(self):
298 298 '''
299 299 '''
300 300 return getNumpyDtype(self.datatype)
301 301
302 302 def set_dtype(self, numpyDtype):
303 303 '''
304 304 '''
305 305
306 306 self.datatype = getDataTypeCode(numpyDtype)
307 307
308 308 def get_code(self):
309 309 '''
310 310 '''
311 311 return self.radarControllerHeaderObj.code
312 312
313 313 def set_code(self, code):
314 314 '''
315 315 '''
316 316 self.radarControllerHeaderObj.code = code
317 317
318 318 return
319 319
320 320 def get_ncode(self):
321 321 '''
322 322 '''
323 323 return self.radarControllerHeaderObj.nCode
324 324
325 325 def set_ncode(self, nCode):
326 326 '''
327 327 '''
328 328 self.radarControllerHeaderObj.nCode = nCode
329 329
330 330 return
331 331
332 332 def get_nbaud(self):
333 333 '''
334 334 '''
335 335 return self.radarControllerHeaderObj.nBaud
336 336
337 337 def set_nbaud(self, nBaud):
338 338 '''
339 339 '''
340 340 self.radarControllerHeaderObj.nBaud = nBaud
341 341
342 342 return
343 343
344 344 nChannels = property(getNChannels, "I'm the 'nChannel' property.")
345 345 channelIndexList = property(
346 346 getChannelIndexList, "I'm the 'channelIndexList' property.")
347 347 nHeights = property(getNHeights, "I'm the 'nHeights' property.")
348 348 #noise = property(getNoise, "I'm the 'nHeights' property.")
349 349 datatime = property(getDatatime, "I'm the 'datatime' property")
350 350 ltctime = property(getltctime, "I'm the 'ltctime' property")
351 351 ippSeconds = property(get_ippSeconds, set_ippSeconds)
352 352 dtype = property(get_dtype, set_dtype)
353 353 # timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
354 354 code = property(get_code, set_code)
355 355 nCode = property(get_ncode, set_ncode)
356 356 nBaud = property(get_nbaud, set_nbaud)
357 357
358 358
359 359 class Voltage(JROData):
360 360
361 361 # data es un numpy array de 2 dmensiones (canales, alturas)
362 data = None
363 data_intensity = None
364 data_velocity = None
365 data_specwidth = None
362 data = None
363 dataPP_POW = None
364 dataPP_DOP = None
365 dataPP_WIDTH = None
366 dataPP_SNR = None
367
366 368 def __init__(self):
367 369 '''
368 370 Constructor
369 371 '''
370 372
371 373 self.useLocalTime = True
372 374 self.radarControllerHeaderObj = RadarControllerHeader()
373 375 self.systemHeaderObj = SystemHeader()
374 376 self.type = "Voltage"
375 377 self.data = None
376 378 # self.dtype = None
377 379 # self.nChannels = 0
378 380 # self.nHeights = 0
379 381 self.nProfiles = None
380 382 self.heightList = None
381 383 self.channelList = None
382 384 # self.channelIndexList = None
383 385 self.flagNoData = True
384 386 self.flagDiscontinuousBlock = False
385 387 self.utctime = None
386 388 self.timeZone = None
387 389 self.dstFlag = None
388 390 self.errorCount = None
389 391 self.nCohInt = None
390 392 self.blocksize = None
391 393 self.flagDecodeData = False # asumo q la data no esta decodificada
392 394 self.flagDeflipData = False # asumo q la data no esta sin flip
393 395 self.flagShiftFFT = False
394 396 self.flagDataAsBlock = False # Asumo que la data es leida perfil a perfil
395 397 self.profileIndex = 0
396 398
397 399 def getNoisebyHildebrand(self, channel=None):
398 400 """
399 401 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
400 402
401 403 Return:
402 404 noiselevel
403 405 """
404 406
405 407 if channel != None:
406 408 data = self.data[channel]
407 409 nChannels = 1
408 410 else:
409 411 data = self.data
410 412 nChannels = self.nChannels
411 413
412 414 noise = numpy.zeros(nChannels)
413 415 power = data * numpy.conjugate(data)
414 416
415 417 for thisChannel in range(nChannels):
416 418 if nChannels == 1:
417 419 daux = power[:].real
418 420 else:
419 421 daux = power[thisChannel, :].real
420 422 noise[thisChannel] = hildebrand_sekhon(daux, self.nCohInt)
421 423
422 424 return noise
423 425
426 def getNoisebyHildebrandDC(self, channel=None,DC=0):
427 """
428 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
429
430 Return:
431 noiselevel
432 """
433
434 if channel != None:
435 data = self.data[channel]-DC
436 nChannels = 1
437 else:
438 data = self.data
439 nChannels = self.nChannels
440
441 noise = numpy.zeros(nChannels)
442 power = data * numpy.conjugate(data)
443
444 for thisChannel in range(nChannels):
445 if nChannels == 1:
446 daux = power[:].real
447 else:
448 daux = power[thisChannel, :].real
449 noise[thisChannel] = hildebrand_sekhon(daux, self.nCohInt)
450
451 return noise
452
453
454
424 455 def getNoise(self, type=1, channel=None):
425 456
426 457 if type == 1:
427 458 noise = self.getNoisebyHildebrand(channel)
428 459
429 460 return noise
430 461
431 462 def getPower(self, channel=None):
432 463
433 464 if channel != None:
434 465 data = self.data[channel]
435 466 else:
436 467 data = self.data
437 468
438 469 power = data * numpy.conjugate(data)
439 470 powerdB = 10 * numpy.log10(power.real)
440 471 powerdB = numpy.squeeze(powerdB)
441 472
442 473 return powerdB
443 474
444 475 def getTimeInterval(self):
445 476
446 477 timeInterval = self.ippSeconds * self.nCohInt
447 478
448 479 return timeInterval
449 480
450 481 noise = property(getNoise, "I'm the 'nHeights' property.")
451 482 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
452 483
453 484
454 485 class Spectra(JROData):
455 486
456 487 # data spc es un numpy array de 2 dmensiones (canales, perfiles, alturas)
457 488 data_spc = None
458 489 # data cspc es un numpy array de 2 dmensiones (canales, pares, alturas)
459 490 data_cspc = None
460 491 # data dc es un numpy array de 2 dmensiones (canales, alturas)
461 492 data_dc = None
462 493 # data power
463 494 data_pwr = None
464 495 nFFTPoints = None
465 496 # nPairs = None
466 497 pairsList = None
467 498 nIncohInt = None
468 499 wavelength = None # Necesario para cacular el rango de velocidad desde la frecuencia
469 500 nCohInt = None # se requiere para determinar el valor de timeInterval
470 501 ippFactor = None
471 502 profileIndex = 0
472 503 plotting = "spectra"
473 504
474 505 def __init__(self):
475 506 '''
476 507 Constructor
477 508 '''
478 509
479 510 self.useLocalTime = True
480 511 self.radarControllerHeaderObj = RadarControllerHeader()
481 512 self.systemHeaderObj = SystemHeader()
482 513 self.type = "Spectra"
483 514 # self.data = None
484 515 # self.dtype = None
485 516 # self.nChannels = 0
486 517 # self.nHeights = 0
487 518 self.nProfiles = None
488 519 self.heightList = None
489 520 self.channelList = None
490 521 # self.channelIndexList = None
491 522 self.pairsList = None
492 523 self.flagNoData = True
493 524 self.flagDiscontinuousBlock = False
494 525 self.utctime = None
495 526 self.nCohInt = None
496 527 self.nIncohInt = None
497 528 self.blocksize = None
498 529 self.nFFTPoints = None
499 530 self.wavelength = None
500 531 self.flagDecodeData = False # asumo q la data no esta decodificada
501 532 self.flagDeflipData = False # asumo q la data no esta sin flip
502 533 self.flagShiftFFT = False
503 534 self.ippFactor = 1
504 535 #self.noise = None
505 536 self.beacon_heiIndexList = []
506 537 self.noise_estimation = None
507 538
508 539 def getNoisebyHildebrand(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
509 540 """
510 541 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
511 542
512 543 Return:
513 544 noiselevel
514 545 """
515 546
516 547 noise = numpy.zeros(self.nChannels)
517 548
518 549 for channel in range(self.nChannels):
519 550 daux = self.data_spc[channel,
520 551 xmin_index:xmax_index, ymin_index:ymax_index]
521 552 noise[channel] = hildebrand_sekhon(daux, self.nIncohInt)
522 553
523 554 return noise
524 555
525 556 def getNoise(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
526 557
527 558 if self.noise_estimation is not None:
528 559 # this was estimated by getNoise Operation defined in jroproc_spectra.py
529 560 return self.noise_estimation
530 561 else:
531 562 noise = self.getNoisebyHildebrand(
532 563 xmin_index, xmax_index, ymin_index, ymax_index)
533 564 return noise
534 565
535 566 def getFreqRangeTimeResponse(self, extrapoints=0):
536 567
537 568 deltafreq = self.getFmaxTimeResponse() / (self.nFFTPoints * self.ippFactor)
538 569 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.) - deltafreq / 2
539 570
540 571 return freqrange
541 572
542 573 def getAcfRange(self, extrapoints=0):
543 574
544 575 deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor))
545 576 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
546 577
547 578 return freqrange
548 579
549 580 def getFreqRange(self, extrapoints=0):
550 581
551 582 deltafreq = self.getFmax() / (self.nFFTPoints * self.ippFactor)
552 583 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
553 584
554 585 return freqrange
555 586
556 587 def getVelRange(self, extrapoints=0):
557 588
558 589 deltav = self.getVmax() / (self.nFFTPoints * self.ippFactor)
559 590 velrange = deltav * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.)
560 591
561 592 if self.nmodes:
562 593 return velrange/self.nmodes
563 594 else:
564 595 return velrange
565 596
566 597 def getNPairs(self):
567 598
568 599 return len(self.pairsList)
569 600
570 601 def getPairsIndexList(self):
571 602
572 603 return list(range(self.nPairs))
573 604
574 605 def getNormFactor(self):
575 606
576 607 pwcode = 1
577 608
578 609 if self.flagDecodeData:
579 610 pwcode = numpy.sum(self.code[0]**2)
580 611 #normFactor = min(self.nFFTPoints,self.nProfiles)*self.nIncohInt*self.nCohInt*pwcode*self.windowOfFilter
581 612 normFactor = self.nProfiles * self.nIncohInt * self.nCohInt * pwcode * self.windowOfFilter
582 613
583 614 return normFactor
584 615
585 616 def getFlagCspc(self):
586 617
587 618 if self.data_cspc is None:
588 619 return True
589 620
590 621 return False
591 622
592 623 def getFlagDc(self):
593 624
594 625 if self.data_dc is None:
595 626 return True
596 627
597 628 return False
598 629
599 630 def getTimeInterval(self):
600 631
601 632 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt * self.nProfiles * self.ippFactor
602 633 if self.nmodes:
603 634 return self.nmodes*timeInterval
604 635 else:
605 636 return timeInterval
606 637
607 638 def getPower(self):
608 639
609 640 factor = self.normFactor
610 641 z = self.data_spc / factor
611 642 z = numpy.where(numpy.isfinite(z), z, numpy.NAN)
612 643 avg = numpy.average(z, axis=1)
613 644
614 645 return 10 * numpy.log10(avg)
615 646
616 647 def getCoherence(self, pairsList=None, phase=False):
617 648
618 649 z = []
619 650 if pairsList is None:
620 651 pairsIndexList = self.pairsIndexList
621 652 else:
622 653 pairsIndexList = []
623 654 for pair in pairsList:
624 655 if pair not in self.pairsList:
625 656 raise ValueError("Pair %s is not in dataOut.pairsList" % (
626 657 pair))
627 658 pairsIndexList.append(self.pairsList.index(pair))
628 659 for i in range(len(pairsIndexList)):
629 660 pair = self.pairsList[pairsIndexList[i]]
630 661 ccf = numpy.average(self.data_cspc[pairsIndexList[i], :, :], axis=0)
631 662 powa = numpy.average(self.data_spc[pair[0], :, :], axis=0)
632 663 powb = numpy.average(self.data_spc[pair[1], :, :], axis=0)
633 664 avgcoherenceComplex = ccf / numpy.sqrt(powa * powb)
634 665 if phase:
635 666 data = numpy.arctan2(avgcoherenceComplex.imag,
636 667 avgcoherenceComplex.real) * 180 / numpy.pi
637 668 else:
638 669 data = numpy.abs(avgcoherenceComplex)
639 670
640 671 z.append(data)
641 672
642 673 return numpy.array(z)
643 674
644 675 def setValue(self, value):
645 676
646 677 print("This property should not be initialized")
647 678
648 679 return
649 680
650 681 nPairs = property(getNPairs, setValue, "I'm the 'nPairs' property.")
651 682 pairsIndexList = property(
652 683 getPairsIndexList, setValue, "I'm the 'pairsIndexList' property.")
653 684 normFactor = property(getNormFactor, setValue,
654 685 "I'm the 'getNormFactor' property.")
655 686 flag_cspc = property(getFlagCspc, setValue)
656 687 flag_dc = property(getFlagDc, setValue)
657 688 noise = property(getNoise, setValue, "I'm the 'nHeights' property.")
658 689 timeInterval = property(getTimeInterval, setValue,
659 690 "I'm the 'timeInterval' property")
660 691
661 692
662 693 class SpectraHeis(Spectra):
663 694
664 695 data_spc = None
665 696 data_cspc = None
666 697 data_dc = None
667 698 nFFTPoints = None
668 699 # nPairs = None
669 700 pairsList = None
670 701 nCohInt = None
671 702 nIncohInt = None
672 703
673 704 def __init__(self):
674 705
675 706 self.radarControllerHeaderObj = RadarControllerHeader()
676 707
677 708 self.systemHeaderObj = SystemHeader()
678 709
679 710 self.type = "SpectraHeis"
680 711
681 712 # self.dtype = None
682 713
683 714 # self.nChannels = 0
684 715
685 716 # self.nHeights = 0
686 717
687 718 self.nProfiles = None
688 719
689 720 self.heightList = None
690 721
691 722 self.channelList = None
692 723
693 724 # self.channelIndexList = None
694 725
695 726 self.flagNoData = True
696 727
697 728 self.flagDiscontinuousBlock = False
698 729
699 730 # self.nPairs = 0
700 731
701 732 self.utctime = None
702 733
703 734 self.blocksize = None
704 735
705 736 self.profileIndex = 0
706 737
707 738 self.nCohInt = 1
708 739
709 740 self.nIncohInt = 1
710 741
711 742 def getNormFactor(self):
712 743 pwcode = 1
713 744 if self.flagDecodeData:
714 745 pwcode = numpy.sum(self.code[0]**2)
715 746
716 747 normFactor = self.nIncohInt * self.nCohInt * pwcode
717 748
718 749 return normFactor
719 750
720 751 def getTimeInterval(self):
721 752
722 753 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
723 754
724 755 return timeInterval
725 756
726 757 normFactor = property(getNormFactor, "I'm the 'getNormFactor' property.")
727 758 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
728 759
729 760
730 761 class Fits(JROData):
731 762
732 763 heightList = None
733 764 channelList = None
734 765 flagNoData = True
735 766 flagDiscontinuousBlock = False
736 767 useLocalTime = False
737 768 utctime = None
738 769 timeZone = None
739 770 # ippSeconds = None
740 771 # timeInterval = None
741 772 nCohInt = None
742 773 nIncohInt = None
743 774 noise = None
744 775 windowOfFilter = 1
745 776 # Speed of ligth
746 777 C = 3e8
747 778 frequency = 49.92e6
748 779 realtime = False
749 780
750 781 def __init__(self):
751 782
752 783 self.type = "Fits"
753 784
754 785 self.nProfiles = None
755 786
756 787 self.heightList = None
757 788
758 789 self.channelList = None
759 790
760 791 # self.channelIndexList = None
761 792
762 793 self.flagNoData = True
763 794
764 795 self.utctime = None
765 796
766 797 self.nCohInt = 1
767 798
768 799 self.nIncohInt = 1
769 800
770 801 self.useLocalTime = True
771 802
772 803 self.profileIndex = 0
773 804
774 805 # self.utctime = None
775 806 # self.timeZone = None
776 807 # self.ltctime = None
777 808 # self.timeInterval = None
778 809 # self.header = None
779 810 # self.data_header = None
780 811 # self.data = None
781 812 # self.datatime = None
782 813 # self.flagNoData = False
783 814 # self.expName = ''
784 815 # self.nChannels = None
785 816 # self.nSamples = None
786 817 # self.dataBlocksPerFile = None
787 818 # self.comments = ''
788 819 #
789 820
790 821 def getltctime(self):
791 822
792 823 if self.useLocalTime:
793 824 return self.utctime - self.timeZone * 60
794 825
795 826 return self.utctime
796 827
797 828 def getDatatime(self):
798 829
799 830 datatime = datetime.datetime.utcfromtimestamp(self.ltctime)
800 831 return datatime
801 832
802 833 def getTimeRange(self):
803 834
804 835 datatime = []
805 836
806 837 datatime.append(self.ltctime)
807 838 datatime.append(self.ltctime + self.timeInterval)
808 839
809 840 datatime = numpy.array(datatime)
810 841
811 842 return datatime
812 843
813 844 def getHeiRange(self):
814 845
815 846 heis = self.heightList
816 847
817 848 return heis
818 849
819 850 def getNHeights(self):
820 851
821 852 return len(self.heightList)
822 853
823 854 def getNChannels(self):
824 855
825 856 return len(self.channelList)
826 857
827 858 def getChannelIndexList(self):
828 859
829 860 return list(range(self.nChannels))
830 861
831 862 def getNoise(self, type=1):
832 863
833 864 #noise = numpy.zeros(self.nChannels)
834 865
835 866 if type == 1:
836 867 noise = self.getNoisebyHildebrand()
837 868
838 869 if type == 2:
839 870 noise = self.getNoisebySort()
840 871
841 872 if type == 3:
842 873 noise = self.getNoisebyWindow()
843 874
844 875 return noise
845 876
846 877 def getTimeInterval(self):
847 878
848 879 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
849 880
850 881 return timeInterval
851 882
852 883 def get_ippSeconds(self):
853 884 '''
854 885 '''
855 886 return self.ipp_sec
856 887
857 888
858 889 datatime = property(getDatatime, "I'm the 'datatime' property")
859 890 nHeights = property(getNHeights, "I'm the 'nHeights' property.")
860 891 nChannels = property(getNChannels, "I'm the 'nChannel' property.")
861 892 channelIndexList = property(
862 893 getChannelIndexList, "I'm the 'channelIndexList' property.")
863 894 noise = property(getNoise, "I'm the 'nHeights' property.")
864 895
865 896 ltctime = property(getltctime, "I'm the 'ltctime' property")
866 897 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
867 898 ippSeconds = property(get_ippSeconds, '')
868 899
869 900 class Correlation(JROData):
870 901
871 902 noise = None
872 903 SNR = None
873 904 #--------------------------------------------------
874 905 mode = None
875 906 split = False
876 907 data_cf = None
877 908 lags = None
878 909 lagRange = None
879 910 pairsList = None
880 911 normFactor = None
881 912 #--------------------------------------------------
882 913 # calculateVelocity = None
883 914 nLags = None
884 915 nPairs = None
885 916 nAvg = None
886 917
887 918 def __init__(self):
888 919 '''
889 920 Constructor
890 921 '''
891 922 self.radarControllerHeaderObj = RadarControllerHeader()
892 923
893 924 self.systemHeaderObj = SystemHeader()
894 925
895 926 self.type = "Correlation"
896 927
897 928 self.data = None
898 929
899 930 self.dtype = None
900 931
901 932 self.nProfiles = None
902 933
903 934 self.heightList = None
904 935
905 936 self.channelList = None
906 937
907 938 self.flagNoData = True
908 939
909 940 self.flagDiscontinuousBlock = False
910 941
911 942 self.utctime = None
912 943
913 944 self.timeZone = None
914 945
915 946 self.dstFlag = None
916 947
917 948 self.errorCount = None
918 949
919 950 self.blocksize = None
920 951
921 952 self.flagDecodeData = False # asumo q la data no esta decodificada
922 953
923 954 self.flagDeflipData = False # asumo q la data no esta sin flip
924 955
925 956 self.pairsList = None
926 957
927 958 self.nPoints = None
928 959
929 960 def getPairsList(self):
930 961
931 962 return self.pairsList
932 963
933 964 def getNoise(self, mode=2):
934 965
935 966 indR = numpy.where(self.lagR == 0)[0][0]
936 967 indT = numpy.where(self.lagT == 0)[0][0]
937 968
938 969 jspectra0 = self.data_corr[:, :, indR, :]
939 970 jspectra = copy.copy(jspectra0)
940 971
941 972 num_chan = jspectra.shape[0]
942 973 num_hei = jspectra.shape[2]
943 974
944 975 freq_dc = jspectra.shape[1] / 2
945 976 ind_vel = numpy.array([-2, -1, 1, 2]) + freq_dc
946 977
947 978 if ind_vel[0] < 0:
948 979 ind_vel[list(range(0, 1))] = ind_vel[list(
949 980 range(0, 1))] + self.num_prof
950 981
951 982 if mode == 1:
952 983 jspectra[:, freq_dc, :] = (
953 984 jspectra[:, ind_vel[1], :] + jspectra[:, ind_vel[2], :]) / 2 # CORRECCION
954 985
955 986 if mode == 2:
956 987
957 988 vel = numpy.array([-2, -1, 1, 2])
958 989 xx = numpy.zeros([4, 4])
959 990
960 991 for fil in range(4):
961 992 xx[fil, :] = vel[fil]**numpy.asarray(list(range(4)))
962 993
963 994 xx_inv = numpy.linalg.inv(xx)
964 995 xx_aux = xx_inv[0, :]
965 996
966 997 for ich in range(num_chan):
967 998 yy = jspectra[ich, ind_vel, :]
968 999 jspectra[ich, freq_dc, :] = numpy.dot(xx_aux, yy)
969 1000
970 1001 junkid = jspectra[ich, freq_dc, :] <= 0
971 1002 cjunkid = sum(junkid)
972 1003
973 1004 if cjunkid.any():
974 1005 jspectra[ich, freq_dc, junkid.nonzero()] = (
975 1006 jspectra[ich, ind_vel[1], junkid] + jspectra[ich, ind_vel[2], junkid]) / 2
976 1007
977 1008 noise = jspectra0[:, freq_dc, :] - jspectra[:, freq_dc, :]
978 1009
979 1010 return noise
980 1011
981 1012 def getTimeInterval(self):
982 1013
983 1014 timeInterval = self.ippSeconds * self.nCohInt * self.nProfiles
984 1015
985 1016 return timeInterval
986 1017
987 1018 def splitFunctions(self):
988 1019
989 1020 pairsList = self.pairsList
990 1021 ccf_pairs = []
991 1022 acf_pairs = []
992 1023 ccf_ind = []
993 1024 acf_ind = []
994 1025 for l in range(len(pairsList)):
995 1026 chan0 = pairsList[l][0]
996 1027 chan1 = pairsList[l][1]
997 1028
998 1029 # Obteniendo pares de Autocorrelacion
999 1030 if chan0 == chan1:
1000 1031 acf_pairs.append(chan0)
1001 1032 acf_ind.append(l)
1002 1033 else:
1003 1034 ccf_pairs.append(pairsList[l])
1004 1035 ccf_ind.append(l)
1005 1036
1006 1037 data_acf = self.data_cf[acf_ind]
1007 1038 data_ccf = self.data_cf[ccf_ind]
1008 1039
1009 1040 return acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf
1010 1041
1011 1042 def getNormFactor(self):
1012 1043 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.splitFunctions()
1013 1044 acf_pairs = numpy.array(acf_pairs)
1014 1045 normFactor = numpy.zeros((self.nPairs, self.nHeights))
1015 1046
1016 1047 for p in range(self.nPairs):
1017 1048 pair = self.pairsList[p]
1018 1049
1019 1050 ch0 = pair[0]
1020 1051 ch1 = pair[1]
1021 1052
1022 1053 ch0_max = numpy.max(data_acf[acf_pairs == ch0, :, :], axis=1)
1023 1054 ch1_max = numpy.max(data_acf[acf_pairs == ch1, :, :], axis=1)
1024 1055 normFactor[p, :] = numpy.sqrt(ch0_max * ch1_max)
1025 1056
1026 1057 return normFactor
1027 1058
1028 1059 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
1029 1060 normFactor = property(getNormFactor, "I'm the 'normFactor property'")
1030 1061
1031 1062
1032 1063 class Parameters(Spectra):
1033 1064
1034 1065 experimentInfo = None # Information about the experiment
1035 1066 # Information from previous data
1036 1067 inputUnit = None # Type of data to be processed
1037 1068 operation = None # Type of operation to parametrize
1038 1069 # normFactor = None #Normalization Factor
1039 1070 groupList = None # List of Pairs, Groups, etc
1040 1071 # Parameters
1041 1072 data_param = None # Parameters obtained
1042 1073 data_pre = None # Data Pre Parametrization
1043 1074 data_SNR = None # Signal to Noise Ratio
1044 1075 # heightRange = None #Heights
1045 1076 abscissaList = None # Abscissa, can be velocities, lags or time
1046 1077 # noise = None #Noise Potency
1047 1078 utctimeInit = None # Initial UTC time
1048 1079 paramInterval = None # Time interval to calculate Parameters in seconds
1049 1080 useLocalTime = True
1050 1081 # Fitting
1051 1082 data_error = None # Error of the estimation
1052 1083 constants = None
1053 1084 library = None
1054 1085 # Output signal
1055 1086 outputInterval = None # Time interval to calculate output signal in seconds
1056 1087 data_output = None # Out signal
1057 1088 nAvg = None
1058 1089 noise_estimation = None
1059 1090 GauSPC = None # Fit gaussian SPC
1060 1091
1061 1092 def __init__(self):
1062 1093 '''
1063 1094 Constructor
1064 1095 '''
1065 1096 self.radarControllerHeaderObj = RadarControllerHeader()
1066 1097
1067 1098 self.systemHeaderObj = SystemHeader()
1068 1099
1069 1100 self.type = "Parameters"
1070 1101
1071 1102 def getTimeRange1(self, interval):
1072 1103
1073 1104 datatime = []
1074 1105
1075 1106 if self.useLocalTime:
1076 1107 time1 = self.utctimeInit - self.timeZone * 60
1077 1108 else:
1078 1109 time1 = self.utctimeInit
1079 1110
1080 1111 datatime.append(time1)
1081 1112 datatime.append(time1 + interval)
1082 1113 datatime = numpy.array(datatime)
1083 1114
1084 1115 return datatime
1085 1116
1086 1117 def getTimeInterval(self):
1087 1118
1088 1119 if hasattr(self, 'timeInterval1'):
1089 1120 return self.timeInterval1
1090 1121 else:
1091 1122 return self.paramInterval
1092 1123
1093 1124 def setValue(self, value):
1094 1125
1095 1126 print("This property should not be initialized")
1096 1127
1097 1128 return
1098 1129
1099 1130 def getNoise(self):
1100 1131
1101 1132 return self.spc_noise
1102 1133
1103 1134 timeInterval = property(getTimeInterval)
1104 1135 noise = property(getNoise, setValue, "I'm the 'Noise' property.")
1105 1136
1106 1137
1107 1138 class PlotterData(object):
1108 1139 '''
1109 1140 Object to hold data to be plotted
1110 1141 '''
1111 1142
1112 1143 MAXNUMX = 200
1113 1144 MAXNUMY = 200
1114 1145
1115 1146 def __init__(self, code, throttle_value, exp_code, buffering=True, snr=False):
1116 1147
1117 1148 self.key = code
1118 1149 self.throttle = throttle_value
1119 1150 self.exp_code = exp_code
1120 1151 self.buffering = buffering
1121 1152 self.ready = False
1122 1153 self.flagNoData = False
1123 1154 self.localtime = False
1124 1155 self.data = {}
1125 1156 self.meta = {}
1126 1157 self.__times = []
1127 1158 self.__heights = []
1128 1159
1129 1160 if 'snr' in code:
1130 1161 self.plottypes = ['snr']
1131 1162 elif code == 'spc':
1132 1163 self.plottypes = ['spc', 'noise', 'rti']
1133 1164 elif code == 'rti':
1134 1165 self.plottypes = ['noise', 'rti']
1135 1166 else:
1136 1167 self.plottypes = [code]
1137 1168
1138 1169 if 'snr' not in self.plottypes and snr:
1139 1170 self.plottypes.append('snr')
1140 1171
1141 1172 for plot in self.plottypes:
1142 1173 self.data[plot] = {}
1143 1174
1144 1175
1145 1176 def __str__(self):
1146 1177 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
1147 1178 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
1148 1179
1149 1180 def __len__(self):
1150 1181 return len(self.__times)
1151 1182
1152 1183 def __getitem__(self, key):
1153 1184
1154 1185 if key not in self.data:
1155 1186 raise KeyError(log.error('Missing key: {}'.format(key)))
1156 1187 if 'spc' in key or not self.buffering:
1157 1188 ret = self.data[key]
1158 1189 elif 'scope' in key:
1159 1190 ret = numpy.array(self.data[key][float(self.tm)])
1160 1191 else:
1161 1192 ret = numpy.array([self.data[key][x] for x in self.times])
1162 1193 if ret.ndim > 1:
1163 1194 ret = numpy.swapaxes(ret, 0, 1)
1164 1195 return ret
1165 1196
1166 1197 def __contains__(self, key):
1167 1198 return key in self.data
1168 1199
1169 1200 def setup(self):
1170 1201 '''
1171 1202 Configure object
1172 1203 '''
1173 1204 self.type = ''
1174 1205 self.ready = False
1175 1206 self.data = {}
1176 1207 self.__times = []
1177 1208 self.__heights = []
1178 1209 self.__all_heights = set()
1179 1210 for plot in self.plottypes:
1180 1211 if 'snr' in plot:
1181 1212 plot = 'snr'
1182 1213 elif 'spc_moments' == plot:
1183 1214 plot = 'moments'
1184 1215 self.data[plot] = {}
1185 1216
1186 1217 if 'spc' in self.data or 'rti' in self.data or 'cspc' in self.data or 'moments' in self.data:
1187 1218 self.data['noise'] = {}
1188 1219 self.data['rti'] = {}
1189 1220 if 'noise' not in self.plottypes:
1190 1221 self.plottypes.append('noise')
1191 1222 if 'rti' not in self.plottypes:
1192 1223 self.plottypes.append('rti')
1193 1224
1194 1225 def shape(self, key):
1195 1226 '''
1196 1227 Get the shape of the one-element data for the given key
1197 1228 '''
1198 1229
1199 1230 if len(self.data[key]):
1200 1231 if 'spc' in key or not self.buffering:
1201 1232 return self.data[key].shape
1202 1233 return self.data[key][self.__times[0]].shape
1203 1234 return (0,)
1204 1235
1205 1236 def update(self, dataOut, tm):
1206 1237 '''
1207 1238 Update data object with new dataOut
1208 1239 '''
1209 1240 if tm in self.__times:
1210 1241 return
1211 1242 self.profileIndex = dataOut.profileIndex
1212 1243 self.tm = tm
1213 1244 self.type = dataOut.type
1214 1245 self.parameters = getattr(dataOut, 'parameters', [])
1215 1246
1216 1247 if hasattr(dataOut, 'meta'):
1217 1248 self.meta.update(dataOut.meta)
1218 1249
1219 1250 if hasattr(dataOut, 'pairsList'):
1220 1251 self.pairs = dataOut.pairsList
1221 1252
1222 1253 self.interval = dataOut.getTimeInterval()
1223 1254 self.localtime = dataOut.useLocalTime
1224 1255 if True in ['spc' in ptype for ptype in self.plottypes]:
1225 1256 self.xrange = (dataOut.getFreqRange(1)/1000.,
1226 1257 dataOut.getAcfRange(1), dataOut.getVelRange(1))
1227 1258 self.factor = dataOut.normFactor
1228 1259 self.__heights.append(dataOut.heightList)
1229 1260 self.__all_heights.update(dataOut.heightList)
1230 1261 self.__times.append(tm)
1231 1262 for plot in self.plottypes:
1232 1263 if plot in ('spc', 'spc_moments', 'spc_cut'):
1233 1264 z = dataOut.data_spc/dataOut.normFactor
1234 1265 buffer = 10*numpy.log10(z)
1235 1266 if plot == 'cspc':
1236 1267 z = dataOut.data_spc/dataOut.normFactor
1237 1268 buffer = (dataOut.data_spc, dataOut.data_cspc)
1238 1269 if plot == 'noise':
1239 1270 buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
1240 1271 if plot in ('rti', 'spcprofile'):
1241 1272 buffer = dataOut.getPower()
1242 1273 if plot == 'snr_db':
1243 1274 buffer = dataOut.data_SNR
1244 1275 if plot == 'snr':
1245 1276 buffer = 10*numpy.log10(dataOut.data_SNR)
1246 1277 if plot == 'dop':
1247 1278 buffer = dataOut.data_DOP
1248 1279 if plot == 'pow':
1249 1280 buffer = 10*numpy.log10(dataOut.data_POW)
1250 1281 if plot == 'width':
1251 1282 buffer = dataOut.data_WIDTH
1252 1283 if plot == 'coh':
1253 1284 buffer = dataOut.getCoherence()
1254 1285 if plot == 'phase':
1255 1286 buffer = dataOut.getCoherence(phase=True)
1256 1287 if plot == 'output':
1257 1288 buffer = dataOut.data_output
1258 1289 if plot == 'param':
1259 1290 buffer = dataOut.data_param
1260 1291 if plot == 'scope':
1261 1292 buffer = dataOut.data
1262 1293 self.flagDataAsBlock = dataOut.flagDataAsBlock
1263 1294 self.nProfiles = dataOut.nProfiles
1264 1295 if plot == 'pp_power':
1265 buffer = dataOut.data_intensity
1296 buffer = dataOut.dataPP_POWER
1297 self.flagDataAsBlock = dataOut.flagDataAsBlock
1298 self.nProfiles = dataOut.nProfiles
1299 if plot == 'pp_signal':
1300 buffer = dataOut.dataPP_POW
1266 1301 self.flagDataAsBlock = dataOut.flagDataAsBlock
1267 1302 self.nProfiles = dataOut.nProfiles
1268 1303 if plot == 'pp_velocity':
1269 buffer = dataOut.data_velocity
1304 buffer = dataOut.dataPP_DOP
1270 1305 self.flagDataAsBlock = dataOut.flagDataAsBlock
1271 1306 self.nProfiles = dataOut.nProfiles
1272 1307 if plot == 'pp_specwidth':
1273 buffer = dataOut.data_specwidth
1308 buffer = dataOut.dataPP_WIDTH
1274 1309 self.flagDataAsBlock = dataOut.flagDataAsBlock
1275 1310 self.nProfiles = dataOut.nProfiles
1276 1311
1277 1312 if plot == 'spc':
1278 1313 self.data['spc'] = buffer
1279 1314 elif plot == 'cspc':
1280 1315 self.data['spc'] = buffer[0]
1281 1316 self.data['cspc'] = buffer[1]
1282 1317 elif plot == 'spc_moments':
1283 1318 self.data['spc'] = buffer
1284 1319 self.data['moments'][tm] = dataOut.moments
1285 1320 else:
1286 1321 if self.buffering:
1287 1322 self.data[plot][tm] = buffer
1288 1323 else:
1289 1324 self.data[plot] = buffer
1290 1325
1291 1326 if dataOut.channelList is None:
1292 1327 self.channels = range(buffer.shape[0])
1293 1328 else:
1294 1329 self.channels = dataOut.channelList
1295 1330
1296 1331 if buffer is None:
1297 1332 self.flagNoData = True
1298 1333 raise schainpy.admin.SchainWarning('Attribute data_{} is empty'.format(self.key))
1299 1334
1300 1335 def normalize_heights(self):
1301 1336 '''
1302 1337 Ensure same-dimension of the data for different heighList
1303 1338 '''
1304 1339
1305 1340 H = numpy.array(list(self.__all_heights))
1306 1341 H.sort()
1307 1342 for key in self.data:
1308 1343 shape = self.shape(key)[:-1] + H.shape
1309 1344 for tm, obj in list(self.data[key].items()):
1310 1345 h = self.__heights[self.__times.index(tm)]
1311 1346 if H.size == h.size:
1312 1347 continue
1313 1348 index = numpy.where(numpy.in1d(H, h))[0]
1314 1349 dummy = numpy.zeros(shape) + numpy.nan
1315 1350 if len(shape) == 2:
1316 1351 dummy[:, index] = obj
1317 1352 else:
1318 1353 dummy[index] = obj
1319 1354 self.data[key][tm] = dummy
1320 1355
1321 1356 self.__heights = [H for tm in self.__times]
1322 1357
1323 1358 def jsonify(self, plot_name, plot_type, decimate=False):
1324 1359 '''
1325 1360 Convert data to json
1326 1361 '''
1327 1362
1328 1363 tm = self.times[-1]
1329 1364 dy = int(self.heights.size/self.MAXNUMY) + 1
1330 1365 if self.key in ('spc', 'cspc') or not self.buffering:
1331 1366 dx = int(self.data[self.key].shape[1]/self.MAXNUMX) + 1
1332 1367 data = self.roundFloats(
1333 1368 self.data[self.key][::, ::dx, ::dy].tolist())
1334 1369 else:
1335 1370 if self.key is 'noise':
1336 1371 data = [[x] for x in self.roundFloats(self.data[self.key][tm].tolist())]
1337 1372 else:
1338 1373 data = self.roundFloats(self.data[self.key][tm][::, ::dy].tolist())
1339 1374
1340 1375 meta = {}
1341 1376 ret = {
1342 1377 'plot': plot_name,
1343 1378 'code': self.exp_code,
1344 1379 'time': float(tm),
1345 1380 'data': data,
1346 1381 }
1347 1382 meta['type'] = plot_type
1348 1383 meta['interval'] = float(self.interval)
1349 1384 meta['localtime'] = self.localtime
1350 1385 meta['yrange'] = self.roundFloats(self.heights[::dy].tolist())
1351 1386 if 'spc' in self.data or 'cspc' in self.data:
1352 1387 meta['xrange'] = self.roundFloats(self.xrange[2][::dx].tolist())
1353 1388 else:
1354 1389 meta['xrange'] = []
1355 1390
1356 1391 meta.update(self.meta)
1357 1392 ret['metadata'] = meta
1358 1393 return json.dumps(ret)
1359 1394
1360 1395 @property
1361 1396 def times(self):
1362 1397 '''
1363 1398 Return the list of times of the current data
1364 1399 '''
1365 1400
1366 1401 ret = numpy.array(self.__times)
1367 1402 ret.sort()
1368 1403 return ret
1369 1404
1370 1405 @property
1371 1406 def min_time(self):
1372 1407 '''
1373 1408 Return the minimun time value
1374 1409 '''
1375 1410
1376 1411 return self.times[0]
1377 1412
1378 1413 @property
1379 1414 def max_time(self):
1380 1415 '''
1381 1416 Return the maximun time value
1382 1417 '''
1383 1418
1384 1419 return self.times[-1]
1385 1420
1386 1421 @property
1387 1422 def heights(self):
1388 1423 '''
1389 1424 Return the list of heights of the current data
1390 1425 '''
1391 1426
1392 1427 return numpy.array(self.__heights[-1])
1393 1428
1394 1429 @staticmethod
1395 1430 def roundFloats(obj):
1396 1431 if isinstance(obj, list):
1397 1432 return list(map(PlotterData.roundFloats, obj))
1398 1433 elif isinstance(obj, float):
1399 1434 return round(obj, 2)
@@ -1,276 +1,302
1 1 '''
2 2 Created on Jul 9, 2014
3 3
4 4 @author: roj-idl71
5 5 '''
6 6 import os
7 7 import datetime
8 8 import numpy
9 9
10 10 from schainpy.model.graphics.jroplot_base import Plot, plt
11 11
12 12
13 13 class ScopePlot(Plot):
14 14
15 15 '''
16 16 Plot for Scope
17 17 '''
18 18
19 19 CODE = 'scope'
20 20 plot_name = 'Scope'
21 21 plot_type = 'scatter'
22 22
23 23 def setup(self):
24 24
25 25 self.xaxis = 'Range (Km)'
26 26 self.ncols = 1
27 27 self.nrows = 1
28 28 self.nplots = 1
29 29 self.ylabel = 'Intensity [dB]'
30 30 self.titles = ['Scope']
31 31 self.colorbar = False
32 32 self.width = 6
33 33 self.height = 4
34 34
35 35 def plot_iq(self, x, y, channelIndexList, thisDatetime, wintitle):
36 36
37 37 yreal = y[channelIndexList,:].real
38 38 yimag = y[channelIndexList,:].imag
39 39 title = wintitle + " Scope: %s" %(thisDatetime.strftime("%d-%b-%Y"))
40 40 self.xlabel = "Range (Km)"
41 41 self.ylabel = "Intensity - IQ"
42 42
43 43 self.y = yreal
44 44 self.x = x
45 45 self.xmin = min(x)
46 46 self.xmax = max(x)
47 47
48 48
49 49 self.titles[0] = title
50 50
51 51 for i,ax in enumerate(self.axes):
52 52 title = "Channel %d" %(i)
53 53 if ax.firsttime:
54 54 ax.plt_r = ax.plot(x, yreal[i,:], color='b')[0]
55 55 ax.plt_i = ax.plot(x, yimag[i,:], color='r')[0]
56 56 else:
57 57 ax.plt_r.set_data(x, yreal[i,:])
58 58 ax.plt_i.set_data(x, yimag[i,:])
59 59
60 60 def plot_power(self, x, y, channelIndexList, thisDatetime, wintitle):
61 61 y = y[channelIndexList,:] * numpy.conjugate(y[channelIndexList,:])
62 62 yreal = y.real
63 63 yreal = 10*numpy.log10(yreal)
64 64 self.y = yreal
65 65 title = wintitle + " Scope: %s" %(thisDatetime.strftime("%d-%b-%Y"))
66 66 self.xlabel = "Range (Km)"
67 67 self.ylabel = "Intensity"
68 68 self.xmin = min(x)
69 69 self.xmax = max(x)
70 70
71 71
72 72 self.titles[0] = title
73 73
74 74 for i,ax in enumerate(self.axes):
75 75 title = "Channel %d" %(i)
76 76
77 77 ychannel = yreal[i,:]
78 78
79 79 if ax.firsttime:
80 80 ax.plt_r = ax.plot(x, ychannel)[0]
81 81 else:
82 82 #pass
83 83 ax.plt_r.set_data(x, ychannel)
84 84
85 85 def plot_weatherpower(self, x, y, channelIndexList, thisDatetime, wintitle):
86 86
87 87
88 88 y = y[channelIndexList,:]
89 89 yreal = y.real
90 90 yreal = 10*numpy.log10(yreal)
91 91 self.y = yreal
92 92 title = wintitle + " Scope: %s" %(thisDatetime.strftime("%d-%b-%Y %H:%M:%S"))
93 93 self.xlabel = "Range (Km)"
94 94 self.ylabel = "Intensity"
95 95 self.xmin = min(x)
96 96 self.xmax = max(x)
97 97
98 98 self.titles[0] =title
99 99 for i,ax in enumerate(self.axes):
100 100 title = "Channel %d" %(i)
101 101
102 102 ychannel = yreal[i,:]
103 103
104 104 if ax.firsttime:
105 105 ax.plt_r = ax.plot(x, ychannel)[0]
106 106 else:
107 107 #pass
108 108 ax.plt_r.set_data(x, ychannel)
109 109
110 110 def plot_weathervelocity(self, x, y, channelIndexList, thisDatetime, wintitle):
111 111
112 112 x = x[channelIndexList,:]
113 113 yreal = y
114 114 self.y = yreal
115 115 title = wintitle + " Scope: %s" %(thisDatetime.strftime("%d-%b-%Y %H:%M:%S"))
116 116 self.xlabel = "Velocity (m/s)"
117 117 self.ylabel = "Range (Km)"
118 118 self.xmin = numpy.min(x)
119 119 self.xmax = numpy.max(x)
120 120 self.titles[0] =title
121 121 for i,ax in enumerate(self.axes):
122 122 title = "Channel %d" %(i)
123 123 xchannel = x[i,:]
124 124 if ax.firsttime:
125 125 ax.plt_r = ax.plot(xchannel, yreal)[0]
126 126 else:
127 127 #pass
128 128 ax.plt_r.set_data(xchannel, yreal)
129 129
130 130 def plot_weatherspecwidth(self, x, y, channelIndexList, thisDatetime, wintitle):
131 131
132 132 x = x[channelIndexList,:]
133 133 yreal = y
134 134 self.y = yreal
135 135 title = wintitle + " Scope: %s" %(thisDatetime.strftime("%d-%b-%Y %H:%M:%S"))
136 136 self.xlabel = "width "
137 137 self.ylabel = "Range (Km)"
138 138 self.xmin = numpy.min(x)
139 139 self.xmax = numpy.max(x)
140 140 self.titles[0] =title
141 141 for i,ax in enumerate(self.axes):
142 142 title = "Channel %d" %(i)
143 143 xchannel = x[i,:]
144 144 if ax.firsttime:
145 145 ax.plt_r = ax.plot(xchannel, yreal)[0]
146 146 else:
147 147 #pass
148 148 ax.plt_r.set_data(xchannel, yreal)
149 149
150 150 def plot(self):
151 151 if self.channels:
152 152 channels = self.channels
153 153 else:
154 154 channels = self.data.channels
155 155
156 156 thisDatetime = datetime.datetime.utcfromtimestamp(self.data.times[-1])
157 157 if self.CODE == "pp_power":
158 158 scope = self.data['pp_power']
159 elif self.CODE == "pp_signal":
160 scope = self.data["pp_signal"]
159 161 elif self.CODE == "pp_velocity":
160 162 scope = self.data["pp_velocity"]
161 163 elif self.CODE == "pp_specwidth":
162 164 scope = self.data["pp_specwidth"]
163 165 else:
164 166 scope =self.data["scope"]
165 167
166 168 if self.data.flagDataAsBlock:
167 169
168 170 for i in range(self.data.nProfiles):
169 171
170 172 wintitle1 = " [Profile = %d] " %i
171 173 if self.CODE =="scope":
172 174 if self.type == "power":
173 175 self.plot_power(self.data.heights,
174 176 scope[:,i,:],
175 177 channels,
176 178 thisDatetime,
177 179 wintitle1
178 180 )
179 181
180 182 if self.type == "iq":
181 183 self.plot_iq(self.data.heights,
182 184 scope[:,i,:],
183 185 channels,
184 186 thisDatetime,
185 187 wintitle1
186 188 )
187 189 if self.CODE=="pp_power":
188 190 self.plot_weatherpower(self.data.heights,
189 191 scope[:,i,:],
190 192 channels,
191 193 thisDatetime,
192 194 wintitle
193 195 )
196 if self.CODE=="pp_signal":
197 self.plot_weatherpower(self.data.heights,
198 scope[:,i,:],
199 channels,
200 thisDatetime,
201 wintitle
202 )
194 203 if self.CODE=="pp_velocity":
195 204 self.plot_weathervelocity(scope[:,i,:],
196 205 self.data.heights,
197 206 channels,
198 207 thisDatetime,
199 208 wintitle
200 209 )
201 210 if self.CODE=="pp_spcwidth":
202 211 self.plot_weatherspecwidth(scope[:,i,:],
203 212 self.data.heights,
204 213 channels,
205 214 thisDatetime,
206 215 wintitle
207 216 )
208 217 else:
209 218 wintitle = " [Profile = %d] " %self.data.profileIndex
210 219 if self.CODE== "scope":
211 220 if self.type == "power":
212 221 self.plot_power(self.data.heights,
213 222 scope,
214 223 channels,
215 224 thisDatetime,
216 225 wintitle
217 226 )
218 227
219 228 if self.type == "iq":
220 229 self.plot_iq(self.data.heights,
221 230 scope,
222 231 channels,
223 232 thisDatetime,
224 233 wintitle
225 234 )
226 235 if self.CODE=="pp_power":
227 236 self.plot_weatherpower(self.data.heights,
228 237 scope,
229 238 channels,
230 239 thisDatetime,
231 240 wintitle
232 241 )
242 if self.CODE=="pp_signal":
243 self.plot_weatherpower(self.data.heights,
244 scope,
245 channels,
246 thisDatetime,
247 wintitle
248 )
233 249 if self.CODE=="pp_velocity":
234 250 self.plot_weathervelocity(scope,
235 251 self.data.heights,
236 252 channels,
237 253 thisDatetime,
238 254 wintitle
239 255 )
240 256 if self.CODE=="pp_specwidth":
241 257 self.plot_weatherspecwidth(scope,
242 258 self.data.heights,
243 259 channels,
244 260 thisDatetime,
245 261 wintitle
246 262 )
247 263
248 264
249 265
250 266 class PulsepairPowerPlot(ScopePlot):
251 267 '''
252 Plot for
268 Plot for P= S+N
253 269 '''
254 270
255 271 CODE = 'pp_power'
256 272 plot_name = 'PulsepairPower'
257 273 plot_type = 'scatter'
258 274 buffering = False
259 275
260 276 class PulsepairVelocityPlot(ScopePlot):
261 277 '''
262 Plot for
278 Plot for VELOCITY
263 279 '''
264 280 CODE = 'pp_velocity'
265 281 plot_name = 'PulsepairVelocity'
266 282 plot_type = 'scatter'
267 283 buffering = False
268 284
269 285 class PulsepairSpecwidthPlot(ScopePlot):
270 286 '''
271 Plot for
287 Plot for WIDTH
272 288 '''
273 289 CODE = 'pp_specwidth'
274 290 plot_name = 'PulsepairSpecwidth'
275 291 plot_type = 'scatter'
276 292 buffering = False
293
294 class PulsepairSignalPlot(ScopePlot):
295 '''
296 Plot for S
297 '''
298
299 CODE = 'pp_signal'
300 plot_name = 'PulsepairSignal'
301 plot_type = 'scatter'
302 buffering = False
@@ -1,512 +1,519
1 1 import numpy,math,random,time
2 2 #---------------1 Heredamos JRODatareader
3 3 from schainpy.model.io.jroIO_base import *
4 4 #---------------2 Heredamos las propiedades de ProcessingUnit
5 5 from schainpy.model.proc.jroproc_base import ProcessingUnit,Operation,MPDecorator
6 6 #---------------3 Importaremos las clases BascicHeader, SystemHeader, RadarControlHeader, ProcessingHeader
7 7 from schainpy.model.data.jroheaderIO import PROCFLAG, BasicHeader,SystemHeader,RadarControllerHeader, ProcessingHeader
8 8 #---------------4 Importaremos el objeto Voltge
9 9 from schainpy.model.data.jrodata import Voltage
10 10
11 11 class SimulatorReader(JRODataReader, ProcessingUnit):
12 12 incIntFactor = 1
13 13 nFFTPoints = 0
14 14 FixPP_IncInt = 1
15 15 FixRCP_IPP = 1000
16 16 FixPP_CohInt = 1
17 17 Tau_0 = 250
18 18 AcqH0_0 = 70
19 19 H0 = AcqH0_0
20 20 AcqDH_0 = 1.25
21 21 DH0 = AcqDH_0
22 22 Bauds = 32
23 23 BaudWidth = None
24 24 FixRCP_TXA = 40
25 25 FixRCP_TXB = 70
26 26 fAngle = 2.0*math.pi*(1/16)
27 27 DC_level = 500
28 28 stdev = 8
29 29 Num_Codes = 2
30 30 #code0 = numpy.array([1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1])
31 31 #code1 = numpy.array([1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,1,1,1,0,0,0,1,0])
32 32 #Dyn_snCode = numpy.array([Num_Codes,Bauds])
33 33 Dyn_snCode = None
34 34 Samples = 200
35 35 channels = 2
36 36 pulses = None
37 37 Reference = None
38 38 pulse_size = None
39 39 prof_gen = None
40 40 Fdoppler = 100
41 41 Hdoppler = 36
42 42 Adoppler = 300
43 43 frequency = 9345
44 44 nTotalReadFiles = 1000
45 45
46 46 def __init__(self):
47 47 """
48 48 Inicializador de la clases SimulatorReader para
49 49 generar datos de voltage simulados.
50 50 Input:
51 51 dataOut: Objeto de la clase Voltage.
52 52 Este Objeto sera utilizado apra almacenar
53 53 un perfil de datos cada vez qe se haga
54 54 un requerimiento (getData)
55 55 """
56 56 ProcessingUnit.__init__(self)
57 57 print(" [ START ] init - Metodo Simulator Reader")
58 58
59 59 self.isConfig = False
60 60 self.basicHeaderObj = BasicHeader(LOCALTIME)
61 61 self.systemHeaderObj = SystemHeader()
62 62 self.radarControllerHeaderObj = RadarControllerHeader()
63 63 self.processingHeaderObj = ProcessingHeader()
64 64 self.profileIndex = 2**32-1
65 65 self.dataOut = Voltage()
66 66 #code0 = numpy.array([1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1])
67 67 code0 = numpy.array([1,1,1,-1,1,1,-1,1,1,1,1,-1,-1,-1,1,-1,1,1,1,-1,1,1,-1,1,-1,-1,-1,1,1,1,-1,1])
68 68 #code1 = numpy.array([1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,1,1,1,0,0,0,1,0])
69 69 code1 = numpy.array([1,1,1,-1,1,1,-1,1,1,1,1,-1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,1,1,-1,-1,-1,1,-1])
70 70 #self.Dyn_snCode = numpy.array([code0,code1])
71 71 self.Dyn_snCode = None
72 72
73 73 def set_kwargs(self, **kwargs):
74 74 for key, value in kwargs.items():
75 75 setattr(self, key, value)
76 76
77 77 def __hasNotDataInBuffer(self):
78 78
79 79 if self.profileIndex >= self.processingHeaderObj.profilesPerBlock* self.nTxs:
80 80 if self.nReadBlocks>0:
81 81 tmp = self.dataOut.utctime
82 82 tmp_utc = int(self.dataOut.utctime)
83 83 tmp_milisecond = int((tmp-tmp_utc)*1000)
84 84 self.basicHeaderObj.utc = tmp_utc
85 85 self.basicHeaderObj.miliSecond= tmp_milisecond
86 86 return 1
87 87 return 0
88 88
89 89 def setNextFile(self):
90 90 """Set the next file to be readed open it and parse de file header"""
91 91
92 92 if (self.nReadBlocks >= self.processingHeaderObj.dataBlocksPerFile):
93 93 self.nReadFiles=self.nReadFiles+1
94 94 if self.nReadFiles > self.nTotalReadFiles:
95 95 self.flagNoMoreFiles=1
96 96 raise schainpy.admin.SchainWarning('No more files to read')
97 97
98 98 print('------------------- [Opening file] ------------------------------',self.nReadFiles)
99 99 self.nReadBlocks = 0
100 100 #if self.nReadBlocks==0:
101 101 # self.readFirstHeader()
102 102
103 103 def __setNewBlock(self):
104 104 self.setNextFile()
105 105 if self.flagIsNewFile:
106 106 return 1
107 107
108 108 def readNextBlock(self):
109 109 while True:
110 110 self.__setNewBlock()
111 111 if not(self.readBlock()):
112 112 return 0
113 113 self.getBasicHeader()
114 114 break
115 115 if self.verbose:
116 116 print("[Reading] Block No. %d/%d -> %s" %(self.nReadBlocks,
117 117 self.processingHeaderObj.dataBlocksPerFile,
118 118 self.dataOut.datatime.ctime()) )
119 119 return 1
120 120
121 121 def getFirstHeader(self):
122 122 self.getBasicHeader()
123 123 self.dataOut.processingHeaderObj = self.processingHeaderObj.copy()
124 124 self.dataOut.systemHeaderObj = self.systemHeaderObj.copy()
125 125 self.dataOut.radarControllerHeaderObj = self.radarControllerHeaderObj.copy()
126 126 self.dataOut.dtype = self.dtype
127 127
128 128 self.dataOut.nProfiles = self.processingHeaderObj.profilesPerBlock
129 129 self.dataOut.heightList = numpy.arange(self.processingHeaderObj.nHeights) * self.processingHeaderObj.deltaHeight + self.processingHeaderObj.firstHeight
130 130 self.dataOut.channelList = list(range(self.systemHeaderObj.nChannels))
131 131 self.dataOut.nCohInt = self.processingHeaderObj.nCohInt
132 132 # asumo q la data no esta decodificada
133 133 self.dataOut.flagDecodeData = self.processingHeaderObj.flag_decode
134 134 # asumo q la data no esta sin flip
135 135 self.dataOut.flagDeflipData = self.processingHeaderObj.flag_deflip
136 136 self.dataOut.flagShiftFFT = self.processingHeaderObj.shif_fft
137 137 self.dataOut.frequency = self.frequency
138 138
139 139 def getBasicHeader(self):
140 140 self.dataOut.utctime = self.basicHeaderObj.utc + self.basicHeaderObj.miliSecond / \
141 141 1000. + self.profileIndex * self.radarControllerHeaderObj.ippSeconds
142 142
143 143 self.dataOut.flagDiscontinuousBlock = self.flagDiscontinuousBlock
144 144 self.dataOut.timeZone = self.basicHeaderObj.timeZone
145 145 self.dataOut.dstFlag = self.basicHeaderObj.dstFlag
146 146 self.dataOut.errorCount = self.basicHeaderObj.errorCount
147 147 self.dataOut.useLocalTime = self.basicHeaderObj.useLocalTime
148 148 self.dataOut.ippSeconds = self.radarControllerHeaderObj.ippSeconds / self.nTxs
149 149
150 150 def readFirstHeader(self):
151 151
152 152 datatype = int(numpy.log2((self.processingHeaderObj.processFlags &
153 153 PROCFLAG.DATATYPE_MASK)) - numpy.log2(PROCFLAG.DATATYPE_CHAR))
154 154 if datatype == 0:
155 155 datatype_str = numpy.dtype([('real', '<i1'), ('imag', '<i1')])
156 156 elif datatype == 1:
157 157 datatype_str = numpy.dtype([('real', '<i2'), ('imag', '<i2')])
158 158 elif datatype == 2:
159 159 datatype_str = numpy.dtype([('real', '<i4'), ('imag', '<i4')])
160 160 elif datatype == 3:
161 161 datatype_str = numpy.dtype([('real', '<i8'), ('imag', '<i8')])
162 162 elif datatype == 4:
163 163 datatype_str = numpy.dtype([('real', '<f4'), ('imag', '<f4')])
164 164 elif datatype == 5:
165 165 datatype_str = numpy.dtype([('real', '<f8'), ('imag', '<f8')])
166 166 else:
167 167 raise ValueError('Data type was not defined')
168 168
169 169 self.dtype = datatype_str
170 170
171 171
172 172 def set_RCH(self, expType=2, nTx=1,ipp=None, txA=0, txB=0,
173 173 nWindows=None, nHeights=None, firstHeight=None, deltaHeight=None,
174 174 numTaus=0, line6Function=0, line5Function=0, fClock=None,
175 175 prePulseBefore=0, prePulseAfter=0,
176 176 codeType=0, nCode=0, nBaud=0, code=None,
177 177 flip1=0, flip2=0,Taus=0):
178 178 self.radarControllerHeaderObj.expType = expType
179 179 self.radarControllerHeaderObj.nTx = nTx
180 180 self.radarControllerHeaderObj.ipp = float(ipp)
181 181 self.radarControllerHeaderObj.txA = float(txA)
182 182 self.radarControllerHeaderObj.txB = float(txB)
183 183 self.radarControllerHeaderObj.rangeIpp = b'A\n'#ipp
184 184 self.radarControllerHeaderObj.rangeTxA = b''
185 185 self.radarControllerHeaderObj.rangeTxB = b''
186 186
187 187 self.radarControllerHeaderObj.nHeights = int(nHeights)
188 188 self.radarControllerHeaderObj.firstHeight = numpy.array([firstHeight])
189 189 self.radarControllerHeaderObj.deltaHeight = numpy.array([deltaHeight])
190 190 self.radarControllerHeaderObj.samplesWin = numpy.array([nHeights])
191 191
192 192
193 193 self.radarControllerHeaderObj.nWindows = nWindows
194 194 self.radarControllerHeaderObj.numTaus = numTaus
195 195 self.radarControllerHeaderObj.codeType = codeType
196 196 self.radarControllerHeaderObj.line6Function = line6Function
197 197 self.radarControllerHeaderObj.line5Function = line5Function
198 198 #self.radarControllerHeaderObj.fClock = fClock
199 199 self.radarControllerHeaderObj.prePulseBefore= prePulseBefore
200 200 self.radarControllerHeaderObj.prePulseAfter = prePulseAfter
201 201
202 202 self.radarControllerHeaderObj.flip1 = flip1
203 203 self.radarControllerHeaderObj.flip2 = flip2
204 204
205 205 self.radarControllerHeaderObj.code_size = 0
206 206 if self.radarControllerHeaderObj.codeType != 0:
207 207 self.radarControllerHeaderObj.nCode = nCode
208 208 self.radarControllerHeaderObj.nBaud = nBaud
209 209 self.radarControllerHeaderObj.code = code
210 210 self.radarControllerHeaderObj.code_size = int(numpy.ceil(nBaud / 32.)) * nCode * 4
211 211
212 212 if fClock is None and deltaHeight is not None:
213 213 self.fClock = 0.15 / (deltaHeight * 1e-6)
214 214 self.radarControllerHeaderObj.fClock = self.fClock
215 215 if numTaus==0:
216 216 self.radarControllerHeaderObj.Taus = numpy.array(0,'<f4')
217 217 else:
218 218 self.radarControllerHeaderObj.Taus = numpy.array(Taus,'<f4')
219 219
220 220 def set_PH(self, dtype=0, blockSize=0, profilesPerBlock=0,
221 221 dataBlocksPerFile=0, nWindows=0, processFlags=0, nCohInt=0,
222 222 nIncohInt=0, totalSpectra=0, nHeights=0, firstHeight=0,
223 223 deltaHeight=0, samplesWin=0, spectraComb=0, nCode=0,
224 224 code=0, nBaud=None, shif_fft=False, flag_dc=False,
225 225 flag_cspc=False, flag_decode=False, flag_deflip=False):
226 226
227 227 self.processingHeaderObj.dtype = dtype
228 228 self.processingHeaderObj.profilesPerBlock = profilesPerBlock
229 229 self.processingHeaderObj.dataBlocksPerFile = dataBlocksPerFile
230 230 self.processingHeaderObj.nWindows = nWindows
231 231 self.processingHeaderObj.processFlags = processFlags
232 232 self.processingHeaderObj.nCohInt = nCohInt
233 233 self.processingHeaderObj.nIncohInt = nIncohInt
234 234 self.processingHeaderObj.totalSpectra = totalSpectra
235 235
236 236 self.processingHeaderObj.nHeights = int(nHeights)
237 237 self.processingHeaderObj.firstHeight = firstHeight#numpy.array([firstHeight])#firstHeight
238 238 self.processingHeaderObj.deltaHeight = deltaHeight#numpy.array([deltaHeight])#deltaHeight
239 239 self.processingHeaderObj.samplesWin = nHeights#numpy.array([nHeights])#nHeights
240 240
241 241 def set_BH(self, utc = 0, miliSecond = 0, timeZone = 0):
242 242 self.basicHeaderObj.utc = utc
243 243 self.basicHeaderObj.miliSecond = miliSecond
244 244 self.basicHeaderObj.timeZone = timeZone
245 245
246 246 def set_SH(self, nSamples=0, nProfiles=0, nChannels=0, adcResolution=14, pciDioBusWidth=32):
247 247 #self.systemHeaderObj.size = size
248 248 self.systemHeaderObj.nSamples = nSamples
249 249 self.systemHeaderObj.nProfiles = nProfiles
250 250 self.systemHeaderObj.nChannels = nChannels
251 251 self.systemHeaderObj.adcResolution = adcResolution
252 252 self.systemHeaderObj.pciDioBusWidth = pciDioBusWidth
253 253
254 254 def init_acquisition(self):
255 255
256 256 if self.nFFTPoints != 0:
257 257 self.incIntFactor = m_nProfilesperBlock/self.nFFTPoints
258 258 if (self.FixPP_IncInt > self.incIntFactor):
259 259 self.incIntFactor = self.FixPP_IncInt/ self.incIntFactor
260 260 elif(self.FixPP_IncInt< self.incIntFactor):
261 261 print("False alert...")
262 262
263 263 ProfilesperBlock = self.processingHeaderObj.profilesPerBlock
264 264
265 265 self.timeperblock =int(((self.FixRCP_IPP
266 266 *ProfilesperBlock
267 267 *self.FixPP_CohInt
268 268 *self.incIntFactor)
269 269 /150.0)
270 270 *0.9
271 271 +0.5)
272 272 # para cada canal
273 273 self.profiles = ProfilesperBlock*self.FixPP_CohInt
274 274 self.profiles = ProfilesperBlock
275 275 self.Reference = int((self.Tau_0-self.AcqH0_0)/(self.AcqDH_0)+0.5)
276 276 self.BaudWidth = int((self.FixRCP_TXA/self.AcqDH_0)/self.Bauds + 0.5 )
277 277
278 278 if (self.BaudWidth==0):
279 279 self.BaudWidth=1
280 280
281 281 def init_pulse(self,Num_Codes=Num_Codes,Bauds=Bauds,BaudWidth=BaudWidth,Dyn_snCode=Dyn_snCode):
282 282
283 283 Num_Codes = Num_Codes
284 284 Bauds = Bauds
285 285 BaudWidth = BaudWidth
286 286 Dyn_snCode = Dyn_snCode
287 287
288 288 if Dyn_snCode:
289 289 print("EXISTE")
290 290 else:
291 291 print("No existe")
292 292
293 293 if Dyn_snCode: # if Bauds:
294 294 pulses = list(range(0,Num_Codes))
295 295 num_codes = Num_Codes
296 296 for i in range(num_codes):
297 297 pulse_size = Bauds*BaudWidth
298 298 pulses[i] = numpy.zeros(pulse_size)
299 299 for j in range(Bauds):
300 300 for k in range(BaudWidth):
301 301 pulses[i][j*BaudWidth+k] = int(Dyn_snCode[i][j]*600)
302 302 else:
303 303 print("sin code")
304 304 pulses = list(range(1))
305 305 if self.AcqDH_0>0.149:
306 306 pulse_size = int(self.FixRCP_TXB/0.15+0.5)
307 307 else:
308 308 pulse_size = int((self.FixRCP_TXB/self.AcqDH_0)+0.5) #0.0375
309 309 pulses[0] = numpy.ones(pulse_size)
310 310 pulses = 600*pulses[0]
311 311
312 312 return pulses,pulse_size
313 313
314 314 def jro_GenerateBlockOfData(self,Samples=Samples,DC_level= DC_level,stdev=stdev,
315 315 Reference= Reference,pulses= pulses,
316 316 Num_Codes= Num_Codes,pulse_size=pulse_size,
317 317 prof_gen= prof_gen,H0 = H0,DH0=DH0,
318 318 Adoppler=Adoppler,Fdoppler= Fdoppler,Hdoppler=Hdoppler):
319 319 Samples = Samples
320 320 DC_level = DC_level
321 321 stdev = stdev
322 322 m_nR = Reference
323 323 pulses = pulses
324 324 num_codes = Num_Codes
325 325 ps = pulse_size
326 326 prof_gen = prof_gen
327 327 channels = self.channels
328 328 H0 = H0
329 329 DH0 = DH0
330 330 ippSec = self.radarControllerHeaderObj.ippSeconds
331 331 Fdoppler = self.Fdoppler
332 332 Hdoppler = self.Hdoppler
333 333 Adoppler = self.Adoppler
334 334
335 335 self.datablock = numpy.zeros([channels,prof_gen,Samples],dtype= numpy.complex64)
336 336 for i in range(channels):
337 337 for k in range(prof_gen):
338 338 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·NOISEΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
339 339 Noise_r = numpy.random.normal(DC_level,stdev,Samples)
340 340 Noise_i = numpy.random.normal(DC_level,stdev,Samples)
341 341 Noise = numpy.zeros(Samples,dtype=complex)
342 342 Noise.real = Noise_r
343 343 Noise.imag = Noise_i
344 344 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·PULSOSΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
345 345 Pulso = numpy.zeros(pulse_size,dtype=complex)
346 346 Pulso.real = pulses[k%num_codes]
347 347 Pulso.imag = pulses[k%num_codes]
348 348 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· PULSES+NOISEΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·
349 349 InBuffer = numpy.zeros(Samples,dtype=complex)
350 350 InBuffer[m_nR:m_nR+ps] = Pulso
351 351 InBuffer = InBuffer+Noise
352 352 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· ANGLE Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
353 353 InBuffer.real[m_nR:m_nR+ps] = InBuffer.real[m_nR:m_nR+ps]*(math.cos( self.fAngle)*5)
354 354 InBuffer.imag[m_nR:m_nR+ps] = InBuffer.imag[m_nR:m_nR+ps]*(math.sin( self.fAngle)*5)
355 355 InBuffer=InBuffer
356 356 self.datablock[i][k]= InBuffer
357 357
358 358 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·DOPPLER SIGNAL...............................................
359 359 time_vec = numpy.linspace(0,(prof_gen-1)*ippSec,int(prof_gen))+self.nReadBlocks*ippSec*prof_gen+(self.nReadFiles-1)*ippSec*prof_gen
360 360 fd = Fdoppler #+(600.0/120)*self.nReadBlocks
361 361 d_signal = Adoppler*numpy.array(numpy.exp(1.0j*2.0*math.pi*fd*time_vec),dtype=numpy.complex64)
362 362 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·SeΓ±al con ancho espectralΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
363 #specw_sig = numpy.linspace(-149,150,300)
364 #w = 8
365 #A = 20
366 #specw_sig = specw_sig/w
367 #specw_sig = numpy.sinc(specw_sig)
368 #specw_sig = A*numpy.array(specw_sig,dtype=numpy.complex64)
363 if prof_gen%2==0:
364 min = int(prof_gen/2.0-1.0)
365 max = int(prof_gen/2.0)
366 else:
367 min = int(prof_gen/2.0)
368 max = int(prof_gen/2.0)
369 specw_sig = numpy.linspace(-min,max,prof_gen)
370 w = 4
371 A = 20
372 specw_sig = specw_sig/w
373 specw_sig = numpy.sinc(specw_sig)
374 specw_sig = A*numpy.array(specw_sig,dtype=numpy.complex64)
369 375 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· DATABLOCK + DOPPLERΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
370 376 HD=int(Hdoppler/self.AcqDH_0)
371 377 for i in range(12):
372 378 self.datablock[0,:,HD+i]=self.datablock[0,:,HD+i]+ d_signal# RESULT
373 379 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· DATABLOCK + DOPPLER*Sinc(x)Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
374 #HD=int(Hdoppler/self.AcqDH_0)
375 #HD=int(HD/2)
376 #for i in range(12):
377 # self.datablock[0,:,HD+i]=self.datablock[0,:,HD+i]+ specw_sig*d_signal# RESULT
380 HD=int(Hdoppler/self.AcqDH_0)
381 HD=int(HD/2)
382 for i in range(12):
383 self.datablock[0,:,HD+i]=self.datablock[0,:,HD+i]+ specw_sig*d_signal# RESULT
378 384
379 385 def readBlock(self):
380 386
381 387 self.jro_GenerateBlockOfData(Samples= self.samples,DC_level=self.DC_level,
382 388 stdev=self.stdev,Reference= self.Reference,
383 389 pulses = self.pulses,Num_Codes=self.Num_Codes,
384 390 pulse_size=self.pulse_size,prof_gen=self.profiles,
385 391 H0=self.H0,DH0=self.DH0)
386 392
387 393 self.profileIndex = 0
388 394 self.flagIsNewFile = 0
389 395 self.flagIsNewBlock = 1
390 396 self.nTotalBlocks += 1
391 397 self.nReadBlocks += 1
392 398
393 399 return 1
394 400
395 401
396 402 def getData(self):
397 403 if self.flagNoMoreFiles:
398 404 self.dataOut.flagNodata = True
399 405 return 0
400 406 self.flagDiscontinuousBlock = 0
401 407 self.flagIsNewBlock = 0
402 408 if self.__hasNotDataInBuffer(): # aqui es verdad
403 409 if not(self.readNextBlock()): # return 1 y por eso el if not salta a getBasic Header
404 410 return 0
405 411 self.getFirstHeader() # atributo
406 412
407 413 if not self.getByBlock:
408 414 self.dataOut.flagDataAsBlock = False
409 415 self.dataOut.data = self.datablock[:, self.profileIndex, :]
410 416 self.dataOut.profileIndex = self.profileIndex
411 417 self.profileIndex += 1
412 418 else:
413 419 pass
414 420 self.dataOut.flagNoData = False
415 421 self.getBasicHeader()
416 422 self.dataOut.realtime = self.online
417 423 return self.dataOut.data
418 424
419 425
420 426 def setup(self,frequency=49.92e6,incIntFactor= 1, nFFTPoints = 0, FixPP_IncInt=1,FixRCP_IPP=1000,
421 427 FixPP_CohInt= 1,Tau_0= 250,AcqH0_0 = 70 ,AcqDH_0=1.25, Bauds= 32,
422 428 FixRCP_TXA = 40, FixRCP_TXB = 50, fAngle = 2.0*math.pi*(1/16),DC_level= 50,
423 429 stdev= 8,Num_Codes = 1 , Dyn_snCode = None, samples=200,
424 channels=2,Fdoppler=20,Hdoppler=36,Adoppler=500,nTotalReadFiles=10000,
430 channels=2,Fdoppler=20,Hdoppler=36,Adoppler=500,
431 profilesPerBlock=300,dataBlocksPerFile=120,nTotalReadFiles=10000,
425 432 **kwargs):
426 433
427 434 self.set_kwargs(**kwargs)
428 435 self.nReadBlocks = 0
429 436 self.nReadFiles = 1
430 437 print('------------------- [Opening file: ] ------------------------------',self.nReadFiles)
431 438
432 439 tmp = time.time()
433 440 tmp_utc = int(tmp)
434 441 tmp_milisecond = int((tmp-tmp_utc)*1000)
435 442 print(" SETUP -basicHeaderObj.utc",datetime.datetime.utcfromtimestamp(tmp))
436 443 if Dyn_snCode is None:
437 444 Num_Codes=1
438 445 Bauds =1
439 446
440 447
441 448
442 449 self.set_BH(utc= tmp_utc,miliSecond= tmp_milisecond,timeZone=300 )
443 450 self.set_RCH( expType=0, nTx=150,ipp=FixRCP_IPP, txA=FixRCP_TXA, txB= FixRCP_TXB,
444 451 nWindows=1 , nHeights=samples, firstHeight=AcqH0_0, deltaHeight=AcqDH_0,
445 452 numTaus=1, line6Function=0, line5Function=0, fClock=None,
446 453 prePulseBefore=0, prePulseAfter=0,
447 454 codeType=0, nCode=Num_Codes, nBaud=32, code=Dyn_snCode,
448 455 flip1=0, flip2=0,Taus=Tau_0)
449 456
450 self.set_PH(dtype=0, blockSize=0, profilesPerBlock=300,
451 dataBlocksPerFile=120, nWindows=1, processFlags=numpy.array([1024]), nCohInt=1,
457 self.set_PH(dtype=0, blockSize=0, profilesPerBlock=profilesPerBlock,
458 dataBlocksPerFile=dataBlocksPerFile, nWindows=1, processFlags=numpy.array([1024]), nCohInt=1,
452 459 nIncohInt=1, totalSpectra=0, nHeights=samples, firstHeight=AcqH0_0,
453 460 deltaHeight=AcqDH_0, samplesWin=samples, spectraComb=0, nCode=0,
454 461 code=0, nBaud=None, shif_fft=False, flag_dc=False,
455 462 flag_cspc=False, flag_decode=False, flag_deflip=False)
456 463
457 self.set_SH(nSamples=samples, nProfiles=300, nChannels=channels)
464 self.set_SH(nSamples=samples, nProfiles=profilesPerBlock, nChannels=channels)
458 465
459 466 self.readFirstHeader()
460 467
461 468 self.frequency = frequency
462 469 self.incIntFactor = incIntFactor
463 470 self.nFFTPoints = nFFTPoints
464 471 self.FixPP_IncInt = FixPP_IncInt
465 472 self.FixRCP_IPP = FixRCP_IPP
466 473 self.FixPP_CohInt = FixPP_CohInt
467 474 self.Tau_0 = Tau_0
468 475 self.AcqH0_0 = AcqH0_0
469 476 self.H0 = AcqH0_0
470 477 self.AcqDH_0 = AcqDH_0
471 478 self.DH0 = AcqDH_0
472 479 self.Bauds = Bauds
473 480 self.FixRCP_TXA = FixRCP_TXA
474 481 self.FixRCP_TXB = FixRCP_TXB
475 482 self.fAngle = fAngle
476 483 self.DC_level = DC_level
477 484 self.stdev = stdev
478 485 self.Num_Codes = Num_Codes
479 486 self.Dyn_snCode = Dyn_snCode
480 487 self.samples = samples
481 488 self.channels = channels
482 489 self.profiles = None
483 490 self.m_nReference = None
484 491 self.Baudwidth = None
485 492 self.Fdoppler = Fdoppler
486 493 self.Hdoppler = Hdoppler
487 494 self.Adoppler = Adoppler
488 495 self.nTotalReadFiles = int(nTotalReadFiles)
489 496
490 497 print("IPP ", self.FixRCP_IPP)
491 498 print("Tau_0 ",self.Tau_0)
492 499 print("AcqH0_0",self.AcqH0_0)
493 500 print("samples,window ",self.samples)
494 501 print("AcqDH_0",AcqDH_0)
495 502 print("FixRCP_TXA",self.FixRCP_TXA)
496 503 print("FixRCP_TXB",self.FixRCP_TXB)
497 504 print("Dyn_snCode",Dyn_snCode)
498 505 print("Fdoppler", Fdoppler)
499 506 print("Hdoppler",Hdoppler)
500 507 print("Vdopplermax",Fdoppler*(3.0e8/self.frequency)/2.0)
501 508 print("nTotalReadFiles", nTotalReadFiles)
502 509
503 510 self.init_acquisition()
504 511 self.pulses,self.pulse_size=self.init_pulse(Num_Codes=self.Num_Codes,Bauds=self.Bauds,BaudWidth=self.BaudWidth,Dyn_snCode=Dyn_snCode)
505 512 print(" [ END ] - SETUP metodo")
506 513 return
507 514
508 515 def run(self,**kwargs): # metodo propio
509 516 if not(self.isConfig):
510 517 self.setup(**kwargs)
511 518 self.isConfig = True
512 519 self.getData()
This diff has been collapsed as it changes many lines, (2143 lines changed) Show them Hide them
@@ -1,3987 +1,4002
1 1 import numpy
2 2 import math
3 3 from scipy import optimize, interpolate, signal, stats, ndimage
4 4 import scipy
5 5 import re
6 6 import datetime
7 7 import copy
8 8 import sys
9 9 import importlib
10 10 import itertools
11 from multiprocessing import Pool, TimeoutError
11 from multiprocessing import Pool, TimeoutError
12 12 from multiprocessing.pool import ThreadPool
13 13 import time
14 14
15 15 from scipy.optimize import fmin_l_bfgs_b #optimize with bounds on state papameters
16 from .jroproc_base import ProcessingUnit, Operation, MPDecorator
16 from .jroproc_base import ProcessingUnit, Operation, MPDecorator
17 17 from schainpy.model.data.jrodata import Parameters, hildebrand_sekhon
18 18 from scipy import asarray as ar,exp
19 19 from scipy.optimize import curve_fit
20 20 from schainpy.utils import log
21 21 import warnings
22 22 from numpy import NaN
23 23 from scipy.optimize.optimize import OptimizeWarning
24 24 warnings.filterwarnings('ignore')
25 25
26 26 import matplotlib.pyplot as plt
27 27
28 28 SPEED_OF_LIGHT = 299792458
29 29
30 30
31 31 '''solving pickling issue'''
32 32
33 33 def _pickle_method(method):
34 34 func_name = method.__func__.__name__
35 35 obj = method.__self__
36 36 cls = method.__self__.__class__
37 37 return _unpickle_method, (func_name, obj, cls)
38 38
39 39 def _unpickle_method(func_name, obj, cls):
40 40 for cls in cls.mro():
41 41 try:
42 42 func = cls.__dict__[func_name]
43 43 except KeyError:
44 44 pass
45 45 else:
46 46 break
47 47 return func.__get__(obj, cls)
48 48
49 49
50 50 class ParametersProc(ProcessingUnit):
51
51
52 52 METHODS = {}
53 53 nSeconds = None
54 54
55 55 def __init__(self):
56 56 ProcessingUnit.__init__(self)
57
57
58 58 # self.objectDict = {}
59 59 self.buffer = None
60 60 self.firstdatatime = None
61 61 self.profIndex = 0
62 62 self.dataOut = Parameters()
63 63 self.setupReq = False #Agregar a todas las unidades de proc
64 64
65 65 def __updateObjFromInput(self):
66
66
67 67 self.dataOut.inputUnit = self.dataIn.type
68
68
69 69 self.dataOut.timeZone = self.dataIn.timeZone
70 70 self.dataOut.dstFlag = self.dataIn.dstFlag
71 71 self.dataOut.errorCount = self.dataIn.errorCount
72 72 self.dataOut.useLocalTime = self.dataIn.useLocalTime
73
73
74 74 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
75 75 self.dataOut.systemHeaderObj = self.dataIn.systemHeaderObj.copy()
76 76 self.dataOut.channelList = self.dataIn.channelList
77 77 self.dataOut.heightList = self.dataIn.heightList
78 78 self.dataOut.dtype = numpy.dtype([('real','<f4'),('imag','<f4')])
79 79 # self.dataOut.nHeights = self.dataIn.nHeights
80 80 # self.dataOut.nChannels = self.dataIn.nChannels
81 81 self.dataOut.nBaud = self.dataIn.nBaud
82 82 self.dataOut.nCode = self.dataIn.nCode
83 83 self.dataOut.code = self.dataIn.code
84 84 # self.dataOut.nProfiles = self.dataOut.nFFTPoints
85 85 self.dataOut.flagDiscontinuousBlock = self.dataIn.flagDiscontinuousBlock
86 86 # self.dataOut.utctime = self.firstdatatime
87 87 self.dataOut.utctime = self.dataIn.utctime
88 88 self.dataOut.flagDecodeData = self.dataIn.flagDecodeData #asumo q la data esta decodificada
89 89 self.dataOut.flagDeflipData = self.dataIn.flagDeflipData #asumo q la data esta sin flip
90 90 self.dataOut.nCohInt = self.dataIn.nCohInt
91 91 # self.dataOut.nIncohInt = 1
92 92 self.dataOut.ippSeconds = self.dataIn.ippSeconds
93 93 # self.dataOut.windowOfFilter = self.dataIn.windowOfFilter
94 94 self.dataOut.timeInterval1 = self.dataIn.timeInterval
95 self.dataOut.heightList = self.dataIn.getHeiRange()
95 self.dataOut.heightList = self.dataIn.getHeiRange()
96 96 self.dataOut.frequency = self.dataIn.frequency
97 97 # self.dataOut.noise = self.dataIn.noise
98
98
99 99 def run(self):
100 100
101 101
102 102
103 103 #---------------------- Voltage Data ---------------------------
104
104
105 105 if self.dataIn.type == "Voltage":
106 106
107 107 self.__updateObjFromInput()
108 108 self.dataOut.data_pre = self.dataIn.data.copy()
109 109 self.dataOut.flagNoData = False
110 110 self.dataOut.utctimeInit = self.dataIn.utctime
111 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
111
112 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
113 if hasattr(self.dataIn, 'dataPP_POW'):
114 self.dataOut.dataPP_POW = self.dataIn.dataPP_POW
115
116 if hasattr(self.dataIn, 'dataPP_POWER'):
117 self.dataOut.dataPP_POWER = self.dataIn.dataPP_POWER
118
119 if hasattr(self.dataIn, 'dataPP_DOP'):
120 self.dataOut.dataPP_DOP = self.dataIn.dataPP_DOP
121
122 if hasattr(self.dataIn, 'dataPP_SNR'):
123 self.dataOut.dataPP_SNR = self.dataIn.dataPP_SNR
124
125 if hasattr(self.dataIn, 'dataPP_WIDTH'):
126 self.dataOut.dataPP_WIDTH = self.dataIn.dataPP_WIDTH
127
112 128 return
113
129
114 130 #---------------------- Spectra Data ---------------------------
115
131
116 132 if self.dataIn.type == "Spectra":
117 133
118 134 self.dataOut.data_pre = (self.dataIn.data_spc, self.dataIn.data_cspc)
119 135 self.dataOut.data_spc = self.dataIn.data_spc
120 136 self.dataOut.data_cspc = self.dataIn.data_cspc
121 137 self.dataOut.nProfiles = self.dataIn.nProfiles
122 138 self.dataOut.nIncohInt = self.dataIn.nIncohInt
123 139 self.dataOut.nFFTPoints = self.dataIn.nFFTPoints
124 140 self.dataOut.ippFactor = self.dataIn.ippFactor
125 141 self.dataOut.abscissaList = self.dataIn.getVelRange(1)
126 142 self.dataOut.spc_noise = self.dataIn.getNoise()
127 143 self.dataOut.spc_range = (self.dataIn.getFreqRange(1) , self.dataIn.getAcfRange(1) , self.dataIn.getVelRange(1))
128 144 # self.dataOut.normFactor = self.dataIn.normFactor
129 self.dataOut.pairsList = self.dataIn.pairsList
145 self.dataOut.pairsList = self.dataIn.pairsList
130 146 self.dataOut.groupList = self.dataIn.pairsList
131 self.dataOut.flagNoData = False
132
147 self.dataOut.flagNoData = False
148
133 149 if hasattr(self.dataIn, 'ChanDist'): #Distances of receiver channels
134 150 self.dataOut.ChanDist = self.dataIn.ChanDist
135 else: self.dataOut.ChanDist = None
136
151 else: self.dataOut.ChanDist = None
152
137 153 #if hasattr(self.dataIn, 'VelRange'): #Velocities range
138 154 # self.dataOut.VelRange = self.dataIn.VelRange
139 155 #else: self.dataOut.VelRange = None
140
156
141 157 if hasattr(self.dataIn, 'RadarConst'): #Radar Constant
142 158 self.dataOut.RadarConst = self.dataIn.RadarConst
143
159
144 160 if hasattr(self.dataIn, 'NPW'): #NPW
145 161 self.dataOut.NPW = self.dataIn.NPW
146
162
147 163 if hasattr(self.dataIn, 'COFA'): #COFA
148 164 self.dataOut.COFA = self.dataIn.COFA
149
150
151
165
166
167
152 168 #---------------------- Correlation Data ---------------------------
153
169
154 170 if self.dataIn.type == "Correlation":
155 171 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.dataIn.splitFunctions()
156
172
157 173 self.dataOut.data_pre = (self.dataIn.data_cf[acf_ind,:], self.dataIn.data_cf[ccf_ind,:,:])
158 174 self.dataOut.normFactor = (self.dataIn.normFactor[acf_ind,:], self.dataIn.normFactor[ccf_ind,:])
159 175 self.dataOut.groupList = (acf_pairs, ccf_pairs)
160
176
161 177 self.dataOut.abscissaList = self.dataIn.lagRange
162 178 self.dataOut.noise = self.dataIn.noise
163 179 self.dataOut.data_SNR = self.dataIn.SNR
164 180 self.dataOut.flagNoData = False
165 181 self.dataOut.nAvg = self.dataIn.nAvg
166
182
167 183 #---------------------- Parameters Data ---------------------------
168
184
169 185 if self.dataIn.type == "Parameters":
170 186 self.dataOut.copy(self.dataIn)
171 187 self.dataOut.flagNoData = False
172
188
173 189 return True
174
190
175 191 self.__updateObjFromInput()
176 192 self.dataOut.utctimeInit = self.dataIn.utctime
177 193 self.dataOut.paramInterval = self.dataIn.timeInterval
178
194
179 195 return
180 196
181 197
182 198 def target(tups):
183
199
184 200 obj, args = tups
185
201
186 202 return obj.FitGau(args)
187
188
203
204
189 205 class SpectralFilters(Operation):
190
206
191 207 '''This class allows the Rainfall / Wind Selection for CLAIRE RADAR
192
208
193 209 LimitR : It is the limit in m/s of Rainfall
194 210 LimitW : It is the limit in m/s for Winds
195
211
196 212 Input:
197
213
198 214 self.dataOut.data_pre : SPC and CSPC
199 215 self.dataOut.spc_range : To select wind and rainfall velocities
200
216
201 217 Affected:
202
218
203 219 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
204 self.dataOut.spcparam_range : Used in SpcParamPlot
220 self.dataOut.spcparam_range : Used in SpcParamPlot
205 221 self.dataOut.SPCparam : Used in PrecipitationProc
206
207
222
223
208 224 '''
209
225
210 226 def __init__(self):
211 227 Operation.__init__(self)
212 228 self.i=0
213
214 def run(self, dataOut, PositiveLimit=1.5, NegativeLimit=2.5):
215
216
217 #Limite de vientos
229
230 def run(self, dataOut, PositiveLimit=1.5, NegativeLimit=2.5):
231
232
233 #Limite de vientos
218 234 LimitR = PositiveLimit
219 235 LimitN = NegativeLimit
220
236
221 237 self.spc = dataOut.data_pre[0].copy()
222 238 self.cspc = dataOut.data_pre[1].copy()
223
239
224 240 self.Num_Hei = self.spc.shape[2]
225 241 self.Num_Bin = self.spc.shape[1]
226 242 self.Num_Chn = self.spc.shape[0]
227
243
228 244 VelRange = dataOut.spc_range[2]
229 245 TimeRange = dataOut.spc_range[1]
230 246 FrecRange = dataOut.spc_range[0]
231
247
232 248 Vmax= 2*numpy.max(dataOut.spc_range[2])
233 249 Tmax= 2*numpy.max(dataOut.spc_range[1])
234 250 Fmax= 2*numpy.max(dataOut.spc_range[0])
235
251
236 252 Breaker1R=VelRange[numpy.abs(VelRange-(-LimitN)).argmin()]
237 253 Breaker1R=numpy.where(VelRange == Breaker1R)
238
239 Delta = self.Num_Bin/2 - Breaker1R[0]
240
241
254
255 Delta = self.Num_Bin/2 - Breaker1R[0]
256
257
242 258 '''Reacomodando SPCrange'''
243 259
244 260 VelRange=numpy.roll(VelRange,-(int(self.Num_Bin/2)) ,axis=0)
245
261
246 262 VelRange[-(int(self.Num_Bin/2)):]+= Vmax
247
263
248 264 FrecRange=numpy.roll(FrecRange,-(int(self.Num_Bin/2)),axis=0)
249
265
250 266 FrecRange[-(int(self.Num_Bin/2)):]+= Fmax
251
267
252 268 TimeRange=numpy.roll(TimeRange,-(int(self.Num_Bin/2)),axis=0)
253
269
254 270 TimeRange[-(int(self.Num_Bin/2)):]+= Tmax
255
271
256 272 ''' ------------------ '''
257
273
258 274 Breaker2R=VelRange[numpy.abs(VelRange-(LimitR)).argmin()]
259 275 Breaker2R=numpy.where(VelRange == Breaker2R)
260
261
276
277
262 278 SPCroll = numpy.roll(self.spc,-(int(self.Num_Bin/2)) ,axis=1)
263
279
264 280 SPCcut = SPCroll.copy()
265 281 for i in range(self.Num_Chn):
266
282
267 283 SPCcut[i,0:int(Breaker2R[0]),:] = dataOut.noise[i]
268 284 SPCcut[i,-int(Delta):,:] = dataOut.noise[i]
269
285
270 286 SPCcut[i]=SPCcut[i]- dataOut.noise[i]
271 287 SPCcut[ numpy.where( SPCcut<0 ) ] = 1e-20
272
288
273 289 SPCroll[i]=SPCroll[i]-dataOut.noise[i]
274 290 SPCroll[ numpy.where( SPCroll<0 ) ] = 1e-20
275
291
276 292 SPC_ch1 = SPCroll
277
293
278 294 SPC_ch2 = SPCcut
279
295
280 296 SPCparam = (SPC_ch1, SPC_ch2, self.spc)
281 dataOut.SPCparam = numpy.asarray(SPCparam)
282
283
297 dataOut.SPCparam = numpy.asarray(SPCparam)
298
299
284 300 dataOut.spcparam_range=numpy.zeros([self.Num_Chn,self.Num_Bin+1])
285
301
286 302 dataOut.spcparam_range[2]=VelRange
287 303 dataOut.spcparam_range[1]=TimeRange
288 304 dataOut.spcparam_range[0]=FrecRange
289 305 return dataOut
290
306
291 307 class GaussianFit(Operation):
292
308
293 309 '''
294 Function that fit of one and two generalized gaussians (gg) based
295 on the PSD shape across an "power band" identified from a cumsum of
310 Function that fit of one and two generalized gaussians (gg) based
311 on the PSD shape across an "power band" identified from a cumsum of
296 312 the measured spectrum - noise.
297
313
298 314 Input:
299 315 self.dataOut.data_pre : SelfSpectra
300
316
301 317 Output:
302 318 self.dataOut.SPCparam : SPC_ch1, SPC_ch2
303
319
304 320 '''
305 321 def __init__(self):
306 322 Operation.__init__(self)
307 323 self.i=0
308
309
324
325
310 326 def run(self, dataOut, num_intg=7, pnoise=1., SNRlimit=-9): #num_intg: Incoherent integrations, pnoise: Noise, vel_arr: range of velocities, similar to the ftt points
311 327 """This routine will find a couple of generalized Gaussians to a power spectrum
312 328 input: spc
313 329 output:
314 330 Amplitude0,shift0,width0,p0,Amplitude1,shift1,width1,p1,noise
315 331 """
316
332
317 333 self.spc = dataOut.data_pre[0].copy()
318 334 self.Num_Hei = self.spc.shape[2]
319 335 self.Num_Bin = self.spc.shape[1]
320 336 self.Num_Chn = self.spc.shape[0]
321 337 Vrange = dataOut.abscissaList
322
338
323 339 GauSPC = numpy.empty([self.Num_Chn,self.Num_Bin,self.Num_Hei])
324 340 SPC_ch1 = numpy.empty([self.Num_Bin,self.Num_Hei])
325 341 SPC_ch2 = numpy.empty([self.Num_Bin,self.Num_Hei])
326 342 SPC_ch1[:] = numpy.NaN
327 343 SPC_ch2[:] = numpy.NaN
328 344
329
345
330 346 start_time = time.time()
331
347
332 348 noise_ = dataOut.spc_noise[0].copy()
333
334
335 pool = Pool(processes=self.Num_Chn)
349
350
351 pool = Pool(processes=self.Num_Chn)
336 352 args = [(Vrange, Ch, pnoise, noise_, num_intg, SNRlimit) for Ch in range(self.Num_Chn)]
337 objs = [self for __ in range(self.Num_Chn)]
338 attrs = list(zip(objs, args))
353 objs = [self for __ in range(self.Num_Chn)]
354 attrs = list(zip(objs, args))
339 355 gauSPC = pool.map(target, attrs)
340 356 dataOut.SPCparam = numpy.asarray(SPCparam)
341
357
342 358 ''' Parameters:
343 359 1. Amplitude
344 360 2. Shift
345 361 3. Width
346 362 4. Power
347 363 '''
348
364
349 365 def FitGau(self, X):
350
366
351 367 Vrange, ch, pnoise, noise_, num_intg, SNRlimit = X
352
368
353 369 SPCparam = []
354 370 SPC_ch1 = numpy.empty([self.Num_Bin,self.Num_Hei])
355 371 SPC_ch2 = numpy.empty([self.Num_Bin,self.Num_Hei])
356 372 SPC_ch1[:] = 0#numpy.NaN
357 373 SPC_ch2[:] = 0#numpy.NaN
358
359
360
374
375
376
361 377 for ht in range(self.Num_Hei):
362
363
378
379
364 380 spc = numpy.asarray(self.spc)[ch,:,ht]
365
381
366 382 #############################################
367 383 # normalizing spc and noise
368 384 # This part differs from gg1
369 385 spc_norm_max = max(spc)
370 386 #spc = spc / spc_norm_max
371 387 pnoise = pnoise #/ spc_norm_max
372 388 #############################################
373
389
374 390 fatspectra=1.0
375
391
376 392 wnoise = noise_ #/ spc_norm_max
377 393 #wnoise,stdv,i_max,index =enoise(spc,num_intg) #noise estimate using Hildebrand Sekhon, only wnoise is used
378 #if wnoise>1.1*pnoise: # to be tested later
394 #if wnoise>1.1*pnoise: # to be tested later
379 395 # wnoise=pnoise
380 noisebl=wnoise*0.9;
396 noisebl=wnoise*0.9;
381 397 noisebh=wnoise*1.1
382 398 spc=spc-wnoise
383
399
384 400 minx=numpy.argmin(spc)
385 #spcs=spc.copy()
401 #spcs=spc.copy()
386 402 spcs=numpy.roll(spc,-minx)
387 403 cum=numpy.cumsum(spcs)
388 404 tot_noise=wnoise * self.Num_Bin #64;
389
405
390 406 snr = sum(spcs)/tot_noise
391 407 snrdB=10.*numpy.log10(snr)
392
408
393 409 if snrdB < SNRlimit :
394 410 snr = numpy.NaN
395 411 SPC_ch1[:,ht] = 0#numpy.NaN
396 412 SPC_ch1[:,ht] = 0#numpy.NaN
397 413 SPCparam = (SPC_ch1,SPC_ch2)
398 414 continue
399
400
415
416
401 417 #if snrdB<-18 or numpy.isnan(snrdB) or num_intg<4:
402 418 # return [None,]*4,[None,]*4,None,snrdB,None,None,[None,]*5,[None,]*9,None
403
404 cummax=max(cum);
419
420 cummax=max(cum);
405 421 epsi=0.08*fatspectra # cumsum to narrow down the energy region
406 cumlo=cummax*epsi;
422 cumlo=cummax*epsi;
407 423 cumhi=cummax*(1-epsi)
408 424 powerindex=numpy.array(numpy.where(numpy.logical_and(cum>cumlo, cum<cumhi))[0])
409
410
425
426
411 427 if len(powerindex) < 1:# case for powerindex 0
412 428 continue
413 429 powerlo=powerindex[0]
414 430 powerhi=powerindex[-1]
415 431 powerwidth=powerhi-powerlo
416
432
417 433 firstpeak=powerlo+powerwidth/10.# first gaussian energy location
418 434 secondpeak=powerhi-powerwidth/10.#second gaussian energy location
419 435 midpeak=(firstpeak+secondpeak)/2.
420 436 firstamp=spcs[int(firstpeak)]
421 437 secondamp=spcs[int(secondpeak)]
422 438 midamp=spcs[int(midpeak)]
423
439
424 440 x=numpy.arange( self.Num_Bin )
425 441 y_data=spc+wnoise
426
442
427 443 ''' single Gaussian '''
428 444 shift0=numpy.mod(midpeak+minx, self.Num_Bin )
429 445 width0=powerwidth/4.#Initialization entire power of spectrum divided by 4
430 446 power0=2.
431 447 amplitude0=midamp
432 448 state0=[shift0,width0,amplitude0,power0,wnoise]
433 449 bnds=(( 0,(self.Num_Bin-1) ),(1,powerwidth),(0,None),(0.5,3.),(noisebl,noisebh))
434 450 lsq1=fmin_l_bfgs_b(self.misfit1,state0,args=(y_data,x,num_intg),bounds=bnds,approx_grad=True)
435
436 chiSq1=lsq1[1];
437 451
438
452 chiSq1=lsq1[1];
453
454
439 455 if fatspectra<1.0 and powerwidth<4:
440 456 choice=0
441 457 Amplitude0=lsq1[0][2]
442 458 shift0=lsq1[0][0]
443 459 width0=lsq1[0][1]
444 460 p0=lsq1[0][3]
445 461 Amplitude1=0.
446 462 shift1=0.
447 463 width1=0.
448 464 p1=0.
449 465 noise=lsq1[0][4]
450 466 #return (numpy.array([shift0,width0,Amplitude0,p0]),
451 467 # numpy.array([shift1,width1,Amplitude1,p1]),noise,snrdB,chiSq1,6.,sigmas1,[None,]*9,choice)
452
468
453 469 ''' two gaussians '''
454 470 #shift0=numpy.mod(firstpeak+minx,64); shift1=numpy.mod(secondpeak+minx,64)
455 shift0=numpy.mod(firstpeak+minx, self.Num_Bin );
471 shift0=numpy.mod(firstpeak+minx, self.Num_Bin );
456 472 shift1=numpy.mod(secondpeak+minx, self.Num_Bin )
457 width0=powerwidth/6.;
473 width0=powerwidth/6.;
458 474 width1=width0
459 power0=2.;
475 power0=2.;
460 476 power1=power0
461 amplitude0=firstamp;
477 amplitude0=firstamp;
462 478 amplitude1=secondamp
463 479 state0=[shift0,width0,amplitude0,power0,shift1,width1,amplitude1,power1,wnoise]
464 480 #bnds=((0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
465 481 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))
466 482 #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))
467
483
468 484 lsq2 = fmin_l_bfgs_b( self.misfit2 , state0 , args=(y_data,x,num_intg) , bounds=bnds , approx_grad=True )
469
470
471 chiSq2=lsq2[1];
472
473
474
485
486
487 chiSq2=lsq2[1];
488
489
490
475 491 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)
476
492
477 493 if snrdB>-12: # when SNR is strong pick the peak with least shift (LOS velocity) error
478 494 if oneG:
479 495 choice=0
480 496 else:
481 497 w1=lsq2[0][1]; w2=lsq2[0][5]
482 498 a1=lsq2[0][2]; a2=lsq2[0][6]
483 499 p1=lsq2[0][3]; p2=lsq2[0][7]
484 s1=(2**(1+1./p1))*scipy.special.gamma(1./p1)/p1;
500 s1=(2**(1+1./p1))*scipy.special.gamma(1./p1)/p1;
485 501 s2=(2**(1+1./p2))*scipy.special.gamma(1./p2)/p2;
486 502 gp1=a1*w1*s1; gp2=a2*w2*s2 # power content of each ggaussian with proper p scaling
487
503
488 504 if gp1>gp2:
489 505 if a1>0.7*a2:
490 506 choice=1
491 507 else:
492 508 choice=2
493 509 elif gp2>gp1:
494 510 if a2>0.7*a1:
495 511 choice=2
496 512 else:
497 513 choice=1
498 514 else:
499 515 choice=numpy.argmax([a1,a2])+1
500 516 #else:
501 517 #choice=argmin([std2a,std2b])+1
502
518
503 519 else: # with low SNR go to the most energetic peak
504 520 choice=numpy.argmax([lsq1[0][2]*lsq1[0][1],lsq2[0][2]*lsq2[0][1],lsq2[0][6]*lsq2[0][5]])
505
506
507 shift0=lsq2[0][0];
521
522
523 shift0=lsq2[0][0];
508 524 vel0=Vrange[0] + shift0*(Vrange[1]-Vrange[0])
509 shift1=lsq2[0][4];
525 shift1=lsq2[0][4];
510 526 vel1=Vrange[0] + shift1*(Vrange[1]-Vrange[0])
511
527
512 528 max_vel = 1.0
513
529
514 530 #first peak will be 0, second peak will be 1
515 531 if vel0 > -1.0 and vel0 < max_vel : #first peak is in the correct range
516 532 shift0=lsq2[0][0]
517 533 width0=lsq2[0][1]
518 534 Amplitude0=lsq2[0][2]
519 535 p0=lsq2[0][3]
520
536
521 537 shift1=lsq2[0][4]
522 538 width1=lsq2[0][5]
523 539 Amplitude1=lsq2[0][6]
524 540 p1=lsq2[0][7]
525 noise=lsq2[0][8]
541 noise=lsq2[0][8]
526 542 else:
527 543 shift1=lsq2[0][0]
528 544 width1=lsq2[0][1]
529 545 Amplitude1=lsq2[0][2]
530 546 p1=lsq2[0][3]
531
547
532 548 shift0=lsq2[0][4]
533 549 width0=lsq2[0][5]
534 550 Amplitude0=lsq2[0][6]
535 p0=lsq2[0][7]
536 noise=lsq2[0][8]
537
551 p0=lsq2[0][7]
552 noise=lsq2[0][8]
553
538 554 if Amplitude0<0.05: # in case the peak is noise
539 shift0,width0,Amplitude0,p0 = [0,0,0,0]#4*[numpy.NaN]
555 shift0,width0,Amplitude0,p0 = [0,0,0,0]#4*[numpy.NaN]
540 556 if Amplitude1<0.05:
541 shift1,width1,Amplitude1,p1 = [0,0,0,0]#4*[numpy.NaN]
542
543
557 shift1,width1,Amplitude1,p1 = [0,0,0,0]#4*[numpy.NaN]
558
559
544 560 SPC_ch1[:,ht] = noise + Amplitude0*numpy.exp(-0.5*(abs(x-shift0))/width0)**p0
545 561 SPC_ch2[:,ht] = noise + Amplitude1*numpy.exp(-0.5*(abs(x-shift1))/width1)**p1
546 562 SPCparam = (SPC_ch1,SPC_ch2)
547
548
563
564
549 565 return GauSPC
550
566
551 567 def y_model1(self,x,state):
552 568 shift0,width0,amplitude0,power0,noise=state
553 569 model0=amplitude0*numpy.exp(-0.5*abs((x-shift0)/width0)**power0)
554
570
555 571 model0u=amplitude0*numpy.exp(-0.5*abs((x-shift0- self.Num_Bin )/width0)**power0)
556
572
557 573 model0d=amplitude0*numpy.exp(-0.5*abs((x-shift0+ self.Num_Bin )/width0)**power0)
558 574 return model0+model0u+model0d+noise
559
560 def y_model2(self,x,state): #Equation for two generalized Gaussians with Nyquist
575
576 def y_model2(self,x,state): #Equation for two generalized Gaussians with Nyquist
561 577 shift0,width0,amplitude0,power0,shift1,width1,amplitude1,power1,noise=state
562 578 model0=amplitude0*numpy.exp(-0.5*abs((x-shift0)/width0)**power0)
563
579
564 580 model0u=amplitude0*numpy.exp(-0.5*abs((x-shift0- self.Num_Bin )/width0)**power0)
565
581
566 582 model0d=amplitude0*numpy.exp(-0.5*abs((x-shift0+ self.Num_Bin )/width0)**power0)
567 583 model1=amplitude1*numpy.exp(-0.5*abs((x-shift1)/width1)**power1)
568
584
569 585 model1u=amplitude1*numpy.exp(-0.5*abs((x-shift1- self.Num_Bin )/width1)**power1)
570
586
571 587 model1d=amplitude1*numpy.exp(-0.5*abs((x-shift1+ self.Num_Bin )/width1)**power1)
572 588 return model0+model0u+model0d+model1+model1u+model1d+noise
573
574 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.
589
590 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.
575 591
576 592 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model1(x,state)))**2)#/(64-5.) # /(64-5.) can be commented
577
593
578 594 def misfit2(self,state,y_data,x,num_intg):
579 595 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model2(x,state)))**2)#/(64-9.)
580
581
596
597
582 598
583 599 class PrecipitationProc(Operation):
584
600
585 601 '''
586 602 Operator that estimates Reflectivity factor (Z), and estimates rainfall Rate (R)
587
588 Input:
603
604 Input:
589 605 self.dataOut.data_pre : SelfSpectra
590
591 Output:
592
593 self.dataOut.data_output : Reflectivity factor, rainfall Rate
594
595
596 Parameters affected:
606
607 Output:
608
609 self.dataOut.data_output : Reflectivity factor, rainfall Rate
610
611
612 Parameters affected:
597 613 '''
598
614
599 615 def __init__(self):
600 616 Operation.__init__(self)
601 617 self.i=0
602
603
618
619
604 620 def gaus(self,xSamples,Amp,Mu,Sigma):
605 621 return ( Amp / ((2*numpy.pi)**0.5 * Sigma) ) * numpy.exp( -( xSamples - Mu )**2 / ( 2 * (Sigma**2) ))
606
607
608
622
623
624
609 625 def Moments(self, ySamples, xSamples):
610 626 Pot = numpy.nansum( ySamples ) # Potencia, momento 0
611 627 yNorm = ySamples / Pot
612
628
613 629 Vr = numpy.nansum( yNorm * xSamples ) # Velocidad radial, mu, corrimiento doppler, primer momento
614 Sigma2 = abs(numpy.nansum( yNorm * ( xSamples - Vr )**2 )) # Segundo Momento
630 Sigma2 = abs(numpy.nansum( yNorm * ( xSamples - Vr )**2 )) # Segundo Momento
615 631 Desv = Sigma2**0.5 # Desv. Estandar, Ancho espectral
616
617 return numpy.array([Pot, Vr, Desv])
618
619 def run(self, dataOut, radar=None, Pt=5000, Gt=295.1209, Gr=70.7945, Lambda=0.6741, aL=2.5118,
632
633 return numpy.array([Pot, Vr, Desv])
634
635 def run(self, dataOut, radar=None, Pt=5000, Gt=295.1209, Gr=70.7945, Lambda=0.6741, aL=2.5118,
620 636 tauW=4e-06, ThetaT=0.1656317, ThetaR=0.36774087, Km = 0.93, Altitude=3350):
621
622
637
638
623 639 Velrange = dataOut.spcparam_range[2]
624 640 FrecRange = dataOut.spcparam_range[0]
625
641
626 642 dV= Velrange[1]-Velrange[0]
627 643 dF= FrecRange[1]-FrecRange[0]
628
644
629 645 if radar == "MIRA35C" :
630
646
631 647 self.spc = dataOut.data_pre[0].copy()
632 648 self.Num_Hei = self.spc.shape[2]
633 649 self.Num_Bin = self.spc.shape[1]
634 650 self.Num_Chn = self.spc.shape[0]
635 651 Ze = self.dBZeMODE2(dataOut)
636
652
637 653 else:
638
654
639 655 self.spc = dataOut.SPCparam[1].copy() #dataOut.data_pre[0].copy() #
640
656
641 657 """NOTA SE DEBE REMOVER EL RANGO DEL PULSO TX"""
642
643 self.spc[:,:,0:7]= numpy.NaN
644
658
659 self.spc[:,:,0:7]= numpy.NaN
660
645 661 """##########################################"""
646
662
647 663 self.Num_Hei = self.spc.shape[2]
648 664 self.Num_Bin = self.spc.shape[1]
649 665 self.Num_Chn = self.spc.shape[0]
650
666
651 667 ''' Se obtiene la constante del RADAR '''
652
668
653 669 self.Pt = Pt
654 670 self.Gt = Gt
655 671 self.Gr = Gr
656 672 self.Lambda = Lambda
657 673 self.aL = aL
658 674 self.tauW = tauW
659 675 self.ThetaT = ThetaT
660 676 self.ThetaR = ThetaR
661
677
662 678 Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
663 679 Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * tauW * numpy.pi * ThetaT * ThetaR)
664 680 RadarConstant = 10e-26 * Numerator / Denominator #
665
681
666 682 ''' ============================= '''
667
668 self.spc[0] = (self.spc[0]-dataOut.noise[0])
669 self.spc[1] = (self.spc[1]-dataOut.noise[1])
670 self.spc[2] = (self.spc[2]-dataOut.noise[2])
671
683
684 self.spc[0] = (self.spc[0]-dataOut.noise[0])
685 self.spc[1] = (self.spc[1]-dataOut.noise[1])
686 self.spc[2] = (self.spc[2]-dataOut.noise[2])
687
672 688 self.spc[ numpy.where(self.spc < 0)] = 0
673
674 SPCmean = (numpy.mean(self.spc,0) - numpy.mean(dataOut.noise))
689
690 SPCmean = (numpy.mean(self.spc,0) - numpy.mean(dataOut.noise))
675 691 SPCmean[ numpy.where(SPCmean < 0)] = 0
676
692
677 693 ETAn = numpy.zeros([self.Num_Bin,self.Num_Hei])
678 694 ETAv = numpy.zeros([self.Num_Bin,self.Num_Hei])
679 695 ETAd = numpy.zeros([self.Num_Bin,self.Num_Hei])
680
696
681 697 Pr = SPCmean[:,:]
682
698
683 699 VelMeteoro = numpy.mean(SPCmean,axis=0)
684
700
685 701 D_range = numpy.zeros([self.Num_Bin,self.Num_Hei])
686 702 SIGMA = numpy.zeros([self.Num_Bin,self.Num_Hei])
687 703 N_dist = numpy.zeros([self.Num_Bin,self.Num_Hei])
688 704 V_mean = numpy.zeros(self.Num_Hei)
689 705 del_V = numpy.zeros(self.Num_Hei)
690 706 Z = numpy.zeros(self.Num_Hei)
691 707 Ze = numpy.zeros(self.Num_Hei)
692 708 RR = numpy.zeros(self.Num_Hei)
693
709
694 710 Range = dataOut.heightList*1000.
695
711
696 712 for R in range(self.Num_Hei):
697
713
698 714 h = Range[R] + Altitude #Range from ground to radar pulse altitude
699 715 del_V[R] = 1 + 3.68 * 10**-5 * h + 1.71 * 10**-9 * h**2 #Density change correction for velocity
700
716
701 717 D_range[:,R] = numpy.log( (9.65 - (Velrange[0:self.Num_Bin] / del_V[R])) / 10.3 ) / -0.6 #Diameter range [m]x10**-3
702
718
703 719 '''NOTA: ETA(n) dn = ETA(f) df
704
720
705 721 dn = 1 Diferencial de muestreo
706 722 df = ETA(n) / ETA(f)
707
723
708 724 '''
709
725
710 726 ETAn[:,R] = RadarConstant * Pr[:,R] * (Range[R] )**2 #Reflectivity (ETA)
711
727
712 728 ETAv[:,R]=ETAn[:,R]/dV
713
729
714 730 ETAd[:,R]=ETAv[:,R]*6.18*exp(-0.6*D_range[:,R])
715
731
716 732 SIGMA[:,R] = Km * (D_range[:,R] * 1e-3 )**6 * numpy.pi**5 / Lambda**4 #Equivalent Section of drops (sigma)
717
718 N_dist[:,R] = ETAn[:,R] / SIGMA[:,R]
719
733
734 N_dist[:,R] = ETAn[:,R] / SIGMA[:,R]
735
720 736 DMoments = self.Moments(Pr[:,R], Velrange[0:self.Num_Bin])
721
737
722 738 try:
723 739 popt01,pcov = curve_fit(self.gaus, Velrange[0:self.Num_Bin] , Pr[:,R] , p0=DMoments)
724 except:
740 except:
725 741 popt01=numpy.zeros(3)
726 742 popt01[1]= DMoments[1]
727
743
728 744 if popt01[1]<0 or popt01[1]>20:
729 745 popt01[1]=numpy.NaN
730
731
746
747
732 748 V_mean[R]=popt01[1]
733
749
734 750 Z[R] = numpy.nansum( N_dist[:,R] * (D_range[:,R])**6 )#*10**-18
735
751
736 752 RR[R] = 0.0006*numpy.pi * numpy.nansum( D_range[:,R]**3 * N_dist[:,R] * Velrange[0:self.Num_Bin] ) #Rainfall rate
737
753
738 754 Ze[R] = (numpy.nansum( ETAn[:,R]) * Lambda**4) / ( 10**-18*numpy.pi**5 * Km)
739
740
741
755
756
757
742 758 RR2 = (Z/200)**(1/1.6)
743 759 dBRR = 10*numpy.log10(RR)
744 760 dBRR2 = 10*numpy.log10(RR2)
745
761
746 762 dBZe = 10*numpy.log10(Ze)
747 763 dBZ = 10*numpy.log10(Z)
748
764
749 765 dataOut.data_output = RR[8]
750 766 dataOut.data_param = numpy.ones([3,self.Num_Hei])
751 767 dataOut.channelList = [0,1,2]
752
768
753 769 dataOut.data_param[0]=dBZ
754 770 dataOut.data_param[1]=V_mean
755 771 dataOut.data_param[2]=RR
756 772
757 773 return dataOut
758
774
759 775 def dBZeMODE2(self, dataOut): # Processing for MIRA35C
760
776
761 777 NPW = dataOut.NPW
762 778 COFA = dataOut.COFA
763
779
764 780 SNR = numpy.array([self.spc[0,:,:] / NPW[0]]) #, self.spc[1,:,:] / NPW[1]])
765 781 RadarConst = dataOut.RadarConst
766 782 #frequency = 34.85*10**9
767
783
768 784 ETA = numpy.zeros(([self.Num_Chn ,self.Num_Hei]))
769 785 data_output = numpy.ones([self.Num_Chn , self.Num_Hei])*numpy.NaN
770
786
771 787 ETA = numpy.sum(SNR,1)
772
788
773 789 ETA = numpy.where(ETA is not 0. , ETA, numpy.NaN)
774
790
775 791 Ze = numpy.ones([self.Num_Chn, self.Num_Hei] )
776
792
777 793 for r in range(self.Num_Hei):
778
794
779 795 Ze[0,r] = ( ETA[0,r] ) * COFA[0,r][0] * RadarConst * ((r/5000.)**2)
780 796 #Ze[1,r] = ( ETA[1,r] ) * COFA[1,r][0] * RadarConst * ((r/5000.)**2)
781
797
782 798 return Ze
783
799
784 800 # def GetRadarConstant(self):
785 #
786 # """
801 #
802 # """
787 803 # Constants:
788 #
804 #
789 805 # Pt: Transmission Power dB 5kW 5000
790 806 # Gt: Transmission Gain dB 24.7 dB 295.1209
791 807 # Gr: Reception Gain dB 18.5 dB 70.7945
792 808 # Lambda: Wavelenght m 0.6741 m 0.6741
793 809 # aL: Attenuation loses dB 4dB 2.5118
794 810 # tauW: Width of transmission pulse s 4us 4e-6
795 811 # ThetaT: Transmission antenna bean angle rad 0.1656317 rad 0.1656317
796 812 # ThetaR: Reception antenna beam angle rad 0.36774087 rad 0.36774087
797 #
813 #
798 814 # """
799 #
815 #
800 816 # Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
801 817 # Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * TauW * numpy.pi * ThetaT * TheraR)
802 818 # RadarConstant = Numerator / Denominator
803 #
819 #
804 820 # return RadarConstant
805
806
807
808 class FullSpectralAnalysis(Operation):
809
821
822
823
824 class FullSpectralAnalysis(Operation):
825
810 826 """
811 827 Function that implements Full Spectral Analysis technique.
812
813 Input:
828
829 Input:
814 830 self.dataOut.data_pre : SelfSpectra and CrossSpectra data
815 831 self.dataOut.groupList : Pairlist of channels
816 832 self.dataOut.ChanDist : Physical distance between receivers
817
818
819 Output:
820
821 self.dataOut.data_output : Zonal wind, Meridional wind and Vertical wind
822
823
833
834
835 Output:
836
837 self.dataOut.data_output : Zonal wind, Meridional wind and Vertical wind
838
839
824 840 Parameters affected: Winds, height range, SNR
825
841
826 842 """
827 843 def run(self, dataOut, Xi01=None, Xi02=None, Xi12=None, Eta01=None, Eta02=None, Eta12=None, SNRlimit=7, minheight=None, maxheight=None):
828
829 self.indice=int(numpy.random.rand()*1000)
830
844
845 self.indice=int(numpy.random.rand()*1000)
846
831 847 spc = dataOut.data_pre[0].copy()
832 848 cspc = dataOut.data_pre[1]
833
849
834 850 """Erick: NOTE THE RANGE OF THE PULSE TX MUST BE REMOVED"""
835 851
836 852 SNRspc = spc.copy()
837 853 SNRspc[:,:,0:7]= numpy.NaN
838
854
839 855 """##########################################"""
840
841
856
857
842 858 nChannel = spc.shape[0]
843 859 nProfiles = spc.shape[1]
844 860 nHeights = spc.shape[2]
845
861
846 862 # first_height = 0.75 #km (ref: data header 20170822)
847 863 # resolution_height = 0.075 #km
848 864 '''
849 865 finding height range. check this when radar parameters are changed!
850 866 '''
851 867 if maxheight is not None:
852 868 # range_max = math.ceil((maxheight - first_height) / resolution_height) # theoretical
853 869 range_max = math.ceil(13.26 * maxheight - 3) # empirical, works better
854 870 else:
855 871 range_max = nHeights
856 872 if minheight is not None:
857 873 # range_min = int((minheight - first_height) / resolution_height) # theoretical
858 874 range_min = int(13.26 * minheight - 5) # empirical, works better
859 875 if range_min < 0:
860 876 range_min = 0
861 877 else:
862 878 range_min = 0
863 879
864 880 pairsList = dataOut.groupList
865 881 if dataOut.ChanDist is not None :
866 882 ChanDist = dataOut.ChanDist
867 883 else:
868 884 ChanDist = numpy.array([[Xi01, Eta01],[Xi02,Eta02],[Xi12,Eta12]])
869
885
870 886 FrecRange = dataOut.spc_range[0]
871
887
872 888 data_SNR=numpy.zeros([nProfiles])
873 889 noise = dataOut.noise
874
890
875 891 dataOut.data_SNR = (numpy.mean(SNRspc,axis=1)- noise[0]) / noise[0]
876
892
877 893 dataOut.data_SNR[numpy.where( dataOut.data_SNR <0 )] = 1e-20
878
879
894
895
880 896 data_output=numpy.ones([spc.shape[0],spc.shape[2]])*numpy.NaN
881
897
882 898 velocityX=[]
883 899 velocityY=[]
884 velocityV=[]
885
900 velocityV=[]
901
886 902 dbSNR = 10*numpy.log10(dataOut.data_SNR)
887 903 dbSNR = numpy.average(dbSNR,0)
888
904
889 905 '''***********************************************WIND ESTIMATION**************************************'''
890
906
891 907 for Height in range(nHeights):
892
893 if Height >= range_min and Height < range_max:
894 # error_code unused, yet maybe useful for future analysis.
908
909 if Height >= range_min and Height < range_max:
910 # error_code unused, yet maybe useful for future analysis.
895 911 [Vzon,Vmer,Vver, error_code] = self.WindEstimation(spc[:,:,Height], cspc[:,:,Height], pairsList, ChanDist, Height, noise, dataOut.spc_range, dbSNR[Height], SNRlimit)
896 912 else:
897 913 Vzon,Vmer,Vver = 0., 0., numpy.NaN
898
899
914
915
900 916 if abs(Vzon) < 100. and abs(Vzon) > 0. and abs(Vmer) < 100. and abs(Vmer) > 0.:
901 917 velocityX=numpy.append(velocityX, Vzon)
902 918 velocityY=numpy.append(velocityY, -Vmer)
903 919
904 920 else:
905 921 velocityX=numpy.append(velocityX, numpy.NaN)
906 922 velocityY=numpy.append(velocityY, numpy.NaN)
907
923
908 924 if dbSNR[Height] > SNRlimit:
909 925 velocityV=numpy.append(velocityV, -Vver) # reason for this minus sign -> convention? (taken from Ericks version)
910 926 else:
911 927 velocityV=numpy.append(velocityV, numpy.NaN)
912
913
928
929
914 930 '''Change the numpy.array (velocityX) sign when trying to process BLTR data (Erick)'''
915 data_output[0] = numpy.array(velocityX)
916 data_output[1] = numpy.array(velocityY)
931 data_output[0] = numpy.array(velocityX)
932 data_output[1] = numpy.array(velocityY)
917 933 data_output[2] = velocityV
918
919
934
935
920 936 dataOut.data_output = data_output
921
937
922 938 return dataOut
923
939
924 940
925 941 def moving_average(self,x, N=2):
926 942 """ convolution for smoothenig data. note that last N-1 values are convolution with zeroes """
927 943 return numpy.convolve(x, numpy.ones((N,))/N)[(N-1):]
928
944
929 945 def gaus(self,xSamples,Amp,Mu,Sigma):
930 946 return ( Amp / ((2*numpy.pi)**0.5 * Sigma) ) * numpy.exp( -( xSamples - Mu )**2 / ( 2 * (Sigma**2) ))
931
947
932 948 def Moments(self, ySamples, xSamples):
933 '''***
949 '''***
934 950 Variables corresponding to moments of distribution.
935 951 Also used as initial coefficients for curve_fit.
936 952 Vr was corrected. Only a velocity when x is velocity, of course.
937 953 ***'''
938 954 Pot = numpy.nansum( ySamples ) # Potencia, momento 0
939 955 yNorm = ySamples / Pot
940 956 x_range = (numpy.max(xSamples)-numpy.min(xSamples))
941 957 Vr = numpy.nansum( yNorm * xSamples )*x_range/len(xSamples) # Velocidad radial, mu, corrimiento doppler, primer momento
942 Sigma2 = abs(numpy.nansum( yNorm * ( xSamples - Vr )**2 )) # Segundo Momento
958 Sigma2 = abs(numpy.nansum( yNorm * ( xSamples - Vr )**2 )) # Segundo Momento
943 959 Desv = Sigma2**0.5 # Desv. Estandar, Ancho espectral
944
960
945 961 return numpy.array([Pot, Vr, Desv])
946 962
947 963 def StopWindEstimation(self, error_code):
948 964 '''
949 965 the wind calculation and returns zeros
950 966 '''
951 967 Vzon = 0
952 968 Vmer = 0
953 969 Vver = numpy.nan
954 970 return Vzon, Vmer, Vver, error_code
955 971
956 972 def AntiAliasing(self, interval, maxstep):
957 """
973 """
958 974 function to prevent errors from aliased values when computing phaseslope
959 975 """
960 976 antialiased = numpy.zeros(len(interval))*0.0
961 977 copyinterval = interval.copy()
962 978
963 979 antialiased[0] = copyinterval[0]
964 980
965 981 for i in range(1,len(antialiased)):
966 982
967 step = interval[i] - interval[i-1]
968
983 step = interval[i] - interval[i-1]
984
969 985 if step > maxstep:
970 986 copyinterval -= 2*numpy.pi
971 987 antialiased[i] = copyinterval[i]
972 988
973 989 elif step < maxstep*(-1):
974 990 copyinterval += 2*numpy.pi
975 991 antialiased[i] = copyinterval[i]
976
992
977 993 else:
978 994 antialiased[i] = copyinterval[i].copy()
979 995
980 996 return antialiased
981 997
982 998 def WindEstimation(self, spc, cspc, pairsList, ChanDist, Height, noise, AbbsisaRange, dbSNR, SNRlimit):
983 999 """
984 1000 Function that Calculates Zonal, Meridional and Vertical wind velocities.
985 1001 Initial Version by E. Bocanegra updated by J. Zibell until Nov. 2019.
986 1002
987 1003 Input:
988 1004 spc, cspc : self spectra and cross spectra data. In Briggs notation something like S_i*(S_i)_conj, (S_j)_conj respectively.
989 1005 pairsList : Pairlist of channels
990 1006 ChanDist : array of xi_ij and eta_ij
991 1007 Height : height at which data is processed
992 1008 noise : noise in [channels] format for specific height
993 1009 Abbsisarange : range of the frequencies or velocities
994 1010 dbSNR, SNRlimit : signal to noise ratio in db, lower limit
995 1011
996 1012 Output:
997 1013 Vzon, Vmer, Vver : wind velocities
998 1014 error_code : int that states where code is terminated
999 1015
1000 1016 0 : no error detected
1001 1017 1 : Gaussian of mean spc exceeds widthlimit
1002 1018 2 : no Gaussian of mean spc found
1003 1019 3 : SNR to low or velocity to high -> prec. e.g.
1004 1020 4 : at least one Gaussian of cspc exceeds widthlimit
1005 1021 5 : zero out of three cspc Gaussian fits converged
1006 6 : phase slope fit could not be found
1022 6 : phase slope fit could not be found
1007 1023 7 : arrays used to fit phase have different length
1008 1024 8 : frequency range is either too short (len <= 5) or very long (> 30% of cspc)
1009 1025
1010 1026 """
1011 1027
1012 1028 error_code = 0
1013
1029
1014 1030
1015 1031 SPC_Samples = numpy.ones([spc.shape[0],spc.shape[1]]) # for normalized spc values for one height
1016 1032 phase = numpy.ones([spc.shape[0],spc.shape[1]]) # phase between channels
1017 1033 CSPC_Samples = numpy.ones([spc.shape[0],spc.shape[1]],dtype=numpy.complex_) # for normalized cspc values
1018 1034 PhaseSlope = numpy.zeros(spc.shape[0]) # slope of the phases, channelwise
1019 1035 PhaseInter = numpy.ones(spc.shape[0]) # intercept to the slope of the phases, channelwise
1020 xFrec = AbbsisaRange[0][0:spc.shape[1]] # frequency range
1036 xFrec = AbbsisaRange[0][0:spc.shape[1]] # frequency range
1021 1037 xVel = AbbsisaRange[2][0:spc.shape[1]] # velocity range
1022 1038 SPCav = numpy.average(spc, axis=0)-numpy.average(noise) # spc[0]-noise[0]
1023
1039
1024 1040 SPCmoments_vel = self.Moments(SPCav, xVel ) # SPCmoments_vel[1] corresponds to vertical velocity and is used to determine if signal corresponds to wind (if .. <3)
1025 1041 CSPCmoments = []
1026
1042
1027 1043
1028 1044 '''Getting Eij and Nij'''
1029 1045
1030 1046 Xi01, Xi02, Xi12 = ChanDist[:,0]
1031 1047 Eta01, Eta02, Eta12 = ChanDist[:,1]
1032 1048
1033 1049 # update nov 19
1034 1050 widthlimit = 7 # maximum width in Hz of the gaussian, empirically determined. Anything above 10 is unrealistic, often values between 1 and 5 correspond to proper fits.
1035 1051
1036 1052 '''************************* SPC is normalized ********************************'''
1037 1053
1038 1054 spc_norm = spc.copy() # need copy() because untouched spc is needed for normalization of cspc below
1039 1055 spc_norm = numpy.where(numpy.isfinite(spc_norm), spc_norm, numpy.NAN)
1040 1056
1041 for i in range(spc.shape[0]):
1042
1057 for i in range(spc.shape[0]):
1058
1043 1059 spc_sub = spc_norm[i,:] - noise[i] # spc not smoothed here or in previous version.
1044 1060
1045 1061 Factor_Norm = 2*numpy.max(xFrec) / numpy.count_nonzero(~numpy.isnan(spc_sub)) # usually = Freq range / nfft
1046 normalized_spc = spc_sub / (numpy.nansum(numpy.abs(spc_sub)) * Factor_Norm)
1047
1062 normalized_spc = spc_sub / (numpy.nansum(numpy.abs(spc_sub)) * Factor_Norm)
1063
1048 1064 xSamples = xFrec # the frequency range is taken
1049 1065 SPC_Samples[i] = normalized_spc # Normalized SPC values are taken
1050 1066
1051 1067 '''********************** FITTING MEAN SPC GAUSSIAN **********************'''
1052 1068
1053 1069 """ the gaussian of the mean: first subtract noise, then normalize. this is legal because
1054 1070 you only fit the curve and don't need the absolute value of height for calculation,
1055 1071 only for estimation of width. for normalization of cross spectra, you need initial,
1056 1072 unnormalized self-spectra With noise.
1057 1073
1058 Technically, you don't even need to normalize the self-spectra, as you only need the
1074 Technically, you don't even need to normalize the self-spectra, as you only need the
1059 1075 width of the peak. However, it was left this way. Note that the normalization has a flaw:
1060 1076 due to subtraction of the noise, some values are below zero. Raw "spc" values should be
1061 1077 >= 0, as it is the modulus squared of the signals (complex * it's conjugate)
1062 1078 """
1063 1079
1064 SPCMean = numpy.average(SPC_Samples, axis=0)
1065
1080 SPCMean = numpy.average(SPC_Samples, axis=0)
1081
1066 1082 popt = [1e-10,0,1e-10]
1067 1083 SPCMoments = self.Moments(SPCMean, xSamples)
1068 1084
1069 if dbSNR > SNRlimit and numpy.abs(SPCmoments_vel[1]) < 3:
1085 if dbSNR > SNRlimit and numpy.abs(SPCmoments_vel[1]) < 3:
1070 1086 try:
1071 1087 popt,pcov = curve_fit(self.gaus,xSamples,SPCMean,p0=SPCMoments)#, bounds=(-numpy.inf, [numpy.inf, numpy.inf, 10])). Setting bounds does not make the code faster but only keeps the fit from finding the minimum.
1072 1088 if popt[2] > widthlimit: # CONDITION
1073 1089 return self.StopWindEstimation(error_code = 1)
1074 1090
1075 1091 FitGauss = self.gaus(xSamples,*popt)
1076
1092
1077 1093 except :#RuntimeError:
1078 1094 return self.StopWindEstimation(error_code = 2)
1079 1095
1080 1096 else:
1081 1097 return self.StopWindEstimation(error_code = 3)
1082
1098
1083 1099
1084 1100
1085 1101 '''***************************** CSPC Normalization *************************
1086 1102 new section:
1087 1103 The Spc spectra are used to normalize the crossspectra. Peaks from precipitation
1088 influence the norm which is not desired. First, a range is identified where the
1089 wind peak is estimated -> sum_wind is sum of those frequencies. Next, the area
1090 around it gets cut off and values replaced by mean determined by the boundary
1104 influence the norm which is not desired. First, a range is identified where the
1105 wind peak is estimated -> sum_wind is sum of those frequencies. Next, the area
1106 around it gets cut off and values replaced by mean determined by the boundary
1091 1107 data -> sum_noise (spc is not normalized here, thats why the noise is important)
1092 1108
1093 1109 The sums are then added and multiplied by range/datapoints, because you need
1094 1110 an integral and not a sum for normalization.
1095
1096 A norm is found according to Briggs 92.
1111
1112 A norm is found according to Briggs 92.
1097 1113 '''
1098 1114
1099 1115 radarWavelength = 0.6741 # meters
1100 count_limit_freq = numpy.abs(popt[1]) + widthlimit # Hz, m/s can be also used if velocity is desired abscissa.
1116 count_limit_freq = numpy.abs(popt[1]) + widthlimit # Hz, m/s can be also used if velocity is desired abscissa.
1101 1117 # count_limit_freq = numpy.max(xFrec)
1102 1118
1103 1119 channel_integrals = numpy.zeros(3)
1104 1120
1105 1121 for i in range(spc.shape[0]):
1106 1122 '''
1107 1123 find the point in array corresponding to count_limit frequency.
1108 1124 sum over all frequencies in the range around zero Hz @ math.ceil(N_freq/2)
1109 1125 '''
1110 1126 N_freq = numpy.count_nonzero(~numpy.isnan(spc[i,:]))
1111 count_limit_int = int(math.ceil( count_limit_freq / numpy.max(xFrec) * (N_freq / 2) )) # gives integer point
1127 count_limit_int = int(math.ceil( count_limit_freq / numpy.max(xFrec) * (N_freq / 2) )) # gives integer point
1112 1128 sum_wind = numpy.nansum( spc[i, (math.ceil(N_freq/2) - count_limit_int) : (math.ceil(N_freq / 2) + count_limit_int)] ) #N_freq/2 is where frequency (velocity) is zero, i.e. middle of spectrum.
1113 1129 sum_noise = (numpy.mean(spc[i, :4]) + numpy.mean(spc[i, -6:-2]))/2.0 * (N_freq - 2*count_limit_int)
1114 1130 channel_integrals[i] = (sum_noise + sum_wind) * (2*numpy.max(xFrec) / N_freq)
1115
1131
1116 1132
1117 1133 cross_integrals_peak = numpy.zeros(3)
1118 1134 # cross_integrals_totalrange = numpy.zeros(3)
1119 1135
1120 1136 for i in range(spc.shape[0]):
1121 1137
1122 1138 cspc_norm = cspc[i,:].copy() # cspc not smoothed here or in previous version
1123 1139
1124 1140 chan_index0 = pairsList[i][0]
1125 1141 chan_index1 = pairsList[i][1]
1126 1142
1127 1143 cross_integrals_peak[i] = channel_integrals[chan_index0]*channel_integrals[chan_index1]
1128 normalized_cspc = cspc_norm / numpy.sqrt(cross_integrals_peak[i])
1144 normalized_cspc = cspc_norm / numpy.sqrt(cross_integrals_peak[i])
1129 1145 CSPC_Samples[i] = normalized_cspc
1130 1146
1131 1147 ''' Finding cross integrals without subtracting any peaks:'''
1132 1148 # FactorNorm0 = 2*numpy.max(xFrec) / numpy.count_nonzero(~numpy.isnan(spc[chan_index0,:]))
1133 1149 # FactorNorm1 = 2*numpy.max(xFrec) / numpy.count_nonzero(~numpy.isnan(spc[chan_index1,:]))
1134 # cross_integrals_totalrange[i] = (numpy.nansum(spc[chan_index0,:])) * FactorNorm0 * (numpy.nansum(spc[chan_index1,:])) * FactorNorm1
1135 # normalized_cspc = cspc_norm / numpy.sqrt(cross_integrals_totalrange[i])
1150 # cross_integrals_totalrange[i] = (numpy.nansum(spc[chan_index0,:])) * FactorNorm0 * (numpy.nansum(spc[chan_index1,:])) * FactorNorm1
1151 # normalized_cspc = cspc_norm / numpy.sqrt(cross_integrals_totalrange[i])
1136 1152 # CSPC_Samples[i] = normalized_cspc
1137
1138
1153
1154
1139 1155 phase[i] = numpy.arctan2(CSPC_Samples[i].imag, CSPC_Samples[i].real)
1140 1156
1141 1157
1142 1158 CSPCmoments = numpy.vstack([self.Moments(numpy.abs(CSPC_Samples[0]), xSamples),
1143 1159 self.Moments(numpy.abs(CSPC_Samples[1]), xSamples),
1144 1160 self.Moments(numpy.abs(CSPC_Samples[2]), xSamples)])
1145
1161
1146 1162
1147 1163 '''***Sorting out NaN entries***'''
1148 1164 CSPCMask01 = numpy.abs(CSPC_Samples[0])
1149 1165 CSPCMask02 = numpy.abs(CSPC_Samples[1])
1150 1166 CSPCMask12 = numpy.abs(CSPC_Samples[2])
1151
1167
1152 1168 mask01 = ~numpy.isnan(CSPCMask01)
1153 1169 mask02 = ~numpy.isnan(CSPCMask02)
1154 1170 mask12 = ~numpy.isnan(CSPCMask12)
1155
1171
1156 1172 CSPCMask01 = CSPCMask01[mask01]
1157 1173 CSPCMask02 = CSPCMask02[mask02]
1158 1174 CSPCMask12 = CSPCMask12[mask12]
1159 1175
1160
1161 popt01, popt02, popt12 = [1e-10,1e-10,1e-10], [1e-10,1e-10,1e-10] ,[1e-10,1e-10,1e-10]
1176
1177 popt01, popt02, popt12 = [1e-10,1e-10,1e-10], [1e-10,1e-10,1e-10] ,[1e-10,1e-10,1e-10]
1162 1178 FitGauss01, FitGauss02, FitGauss12 = numpy.empty(len(xSamples))*0, numpy.empty(len(xSamples))*0, numpy.empty(len(xSamples))*0
1163
1179
1164 1180 '''*******************************FIT GAUSS CSPC************************************'''
1165 1181
1166 try:
1182 try:
1167 1183 popt01,pcov = curve_fit(self.gaus,xSamples[mask01],numpy.abs(CSPCMask01),p0=CSPCmoments[0])
1168 1184 if popt01[2] > widthlimit: # CONDITION
1169 1185 return self.StopWindEstimation(error_code = 4)
1170 1186
1171 1187 popt02,pcov = curve_fit(self.gaus,xSamples[mask02],numpy.abs(CSPCMask02),p0=CSPCmoments[1])
1172 1188 if popt02[2] > widthlimit: # CONDITION
1173 1189 return self.StopWindEstimation(error_code = 4)
1174 1190
1175 1191 popt12,pcov = curve_fit(self.gaus,xSamples[mask12],numpy.abs(CSPCMask12),p0=CSPCmoments[2])
1176 1192 if popt12[2] > widthlimit: # CONDITION
1177 1193 return self.StopWindEstimation(error_code = 4)
1178 1194
1179 1195 FitGauss01 = self.gaus(xSamples, *popt01)
1180 1196 FitGauss02 = self.gaus(xSamples, *popt02)
1181 1197 FitGauss12 = self.gaus(xSamples, *popt12)
1182 1198
1183 1199 except:
1184 1200 return self.StopWindEstimation(error_code = 5)
1185 1201
1186 1202
1187 1203 '''************* Getting Fij ***************'''
1188 1204
1189
1190 #Punto en Eje X de la Gaussiana donde se encuentra el centro -- x-axis point of the gaussian where the center is located
1191 # -> PointGauCenter
1192 GaussCenter = popt[1]
1205
1206 #Punto en Eje X de la Gaussiana donde se encuentra el centro -- x-axis point of the gaussian where the center is located
1207 # -> PointGauCenter
1208 GaussCenter = popt[1]
1193 1209 ClosestCenter = xSamples[numpy.abs(xSamples-GaussCenter).argmin()]
1194 1210 PointGauCenter = numpy.where(xSamples==ClosestCenter)[0][0]
1195
1211
1196 1212 #Punto e^-1 hubicado en la Gaussiana -- point where e^-1 is located in the gaussian
1197 1213 PeMinus1 = numpy.max(FitGauss) * numpy.exp(-1)
1198 1214 FijClosest = FitGauss[numpy.abs(FitGauss-PeMinus1).argmin()] # El punto mas cercano a "Peminus1" dentro de "FitGauss"
1199 1215 PointFij = numpy.where(FitGauss==FijClosest)[0][0]
1200 1216
1201 1217 Fij = numpy.abs(xSamples[PointFij] - xSamples[PointGauCenter])
1202
1218
1203 1219 '''********** Taking frequency ranges from mean SPCs **********'''
1204
1220
1205 1221 #GaussCenter = popt[1] #Primer momento 01
1206 1222 GauWidth = popt[2] * 3/2 #Ancho de banda de Gau01 -- Bandwidth of Gau01 TODO why *3/2?
1207 1223 Range = numpy.empty(2)
1208 1224 Range[0] = GaussCenter - GauWidth
1209 Range[1] = GaussCenter + GauWidth
1225 Range[1] = GaussCenter + GauWidth
1210 1226 #Punto en Eje X de la Gaussiana donde se encuentra ancho de banda (min:max) -- Point in x-axis where the bandwidth is located (min:max)
1211 1227 ClosRangeMin = xSamples[numpy.abs(xSamples-Range[0]).argmin()]
1212 1228 ClosRangeMax = xSamples[numpy.abs(xSamples-Range[1]).argmin()]
1213
1229
1214 1230 PointRangeMin = numpy.where(xSamples==ClosRangeMin)[0][0]
1215 1231 PointRangeMax = numpy.where(xSamples==ClosRangeMax)[0][0]
1216
1232
1217 1233 Range = numpy.array([ PointRangeMin, PointRangeMax ])
1218
1234
1219 1235 FrecRange = xFrec[ Range[0] : Range[1] ]
1220 1236
1221
1222 '''************************** Getting Phase Slope ***************************'''
1223
1224 for i in range(1,3): # Changed to only compute two
1225
1237
1238 '''************************** Getting Phase Slope ***************************'''
1239
1240 for i in range(1,3): # Changed to only compute two
1241
1226 1242 if len(FrecRange) > 5 and len(FrecRange) < spc.shape[1] * 0.3:
1227 1243 # PhaseRange=self.moving_average(phase[i,Range[0]:Range[1]],N=1) #used before to smooth phase with N=3
1228 1244 PhaseRange = phase[i,Range[0]:Range[1]].copy()
1229
1245
1230 1246 mask = ~numpy.isnan(FrecRange) & ~numpy.isnan(PhaseRange)
1231
1247
1232 1248
1233 1249 if len(FrecRange) == len(PhaseRange):
1234
1235 try:
1250
1251 try:
1236 1252 slope, intercept, _, _, _ = stats.linregress(FrecRange[mask], self.AntiAliasing(PhaseRange[mask], 4.5))
1237 1253 PhaseSlope[i] = slope
1238 1254 PhaseInter[i] = intercept
1239 1255
1240 1256 except:
1241 1257 return self.StopWindEstimation(error_code = 6)
1242 1258
1243 1259 else:
1244 1260 return self.StopWindEstimation(error_code = 7)
1245
1261
1246 1262 else:
1247 1263 return self.StopWindEstimation(error_code = 8)
1248
1249
1250
1264
1265
1266
1251 1267 '''*** Constants A-H correspond to the convention as in Briggs and Vincent 1992 ***'''
1252 1268
1253 1269 '''Getting constant C'''
1254 1270 cC=(Fij*numpy.pi)**2
1255
1271
1256 1272 '''****** Getting constants F and G ******'''
1257 1273 MijEijNij = numpy.array([[Xi02,Eta02], [Xi12,Eta12]])
1258 1274 MijResult0 = (-PhaseSlope[1] * cC) / (2*numpy.pi)
1259 MijResult1 = (-PhaseSlope[2] * cC) / (2*numpy.pi)
1275 MijResult1 = (-PhaseSlope[2] * cC) / (2*numpy.pi)
1260 1276 MijResults = numpy.array([MijResult0,MijResult1])
1261 (cF,cG) = numpy.linalg.solve(MijEijNij, MijResults)
1262
1277 (cF,cG) = numpy.linalg.solve(MijEijNij, MijResults)
1278
1263 1279 '''****** Getting constants A, B and H ******'''
1264 W01 = numpy.nanmax( FitGauss01 )
1265 W02 = numpy.nanmax( FitGauss02 )
1266 W12 = numpy.nanmax( FitGauss12 )
1267
1280 W01 = numpy.nanmax( FitGauss01 )
1281 W02 = numpy.nanmax( FitGauss02 )
1282 W12 = numpy.nanmax( FitGauss12 )
1283
1268 1284 WijResult0 = ((cF * Xi01 + cG * Eta01)**2)/cC - numpy.log(W01 / numpy.sqrt(numpy.pi / cC))
1269 1285 WijResult1 = ((cF * Xi02 + cG * Eta02)**2)/cC - numpy.log(W02 / numpy.sqrt(numpy.pi / cC))
1270 1286 WijResult2 = ((cF * Xi12 + cG * Eta12)**2)/cC - numpy.log(W12 / numpy.sqrt(numpy.pi / cC))
1271
1287
1272 1288 WijResults = numpy.array([WijResult0, WijResult1, WijResult2])
1273
1274 WijEijNij = numpy.array([ [Xi01**2, Eta01**2, 2*Xi01*Eta01] , [Xi02**2, Eta02**2, 2*Xi02*Eta02] , [Xi12**2, Eta12**2, 2*Xi12*Eta12] ])
1289
1290 WijEijNij = numpy.array([ [Xi01**2, Eta01**2, 2*Xi01*Eta01] , [Xi02**2, Eta02**2, 2*Xi02*Eta02] , [Xi12**2, Eta12**2, 2*Xi12*Eta12] ])
1275 1291 (cA,cB,cH) = numpy.linalg.solve(WijEijNij, WijResults)
1276
1292
1277 1293 VxVy = numpy.array([[cA,cH],[cH,cB]])
1278 1294 VxVyResults = numpy.array([-cF,-cG])
1279 1295 (Vx,Vy) = numpy.linalg.solve(VxVy, VxVyResults)
1280
1296
1281 1297 Vzon = Vy
1282 1298 Vmer = Vx
1283
1299
1284 1300 # Vmag=numpy.sqrt(Vzon**2+Vmer**2) # unused
1285 1301 # Vang=numpy.arctan2(Vmer,Vzon) # unused
1286 1302
1287
1303
1288 1304 ''' using frequency as abscissa. Due to three channels, the offzenith angle is zero
1289 1305 and Vrad equal to Vver. formula taken from Briggs 92, figure 4.
1290 1306 '''
1291 1307 if numpy.abs( popt[1] ) < 3.5 and len(FrecRange) > 4:
1292 1308 Vver = 0.5 * radarWavelength * popt[1] * 100 # *100 to get cm (/s)
1293 1309 else:
1294 1310 Vver = numpy.NaN
1295 1311
1296 1312 error_code = 0
1297 1313
1298 return Vzon, Vmer, Vver, error_code
1314 return Vzon, Vmer, Vver, error_code
1299 1315
1300 1316
1301 1317 class SpectralMoments(Operation):
1302
1318
1303 1319 '''
1304 1320 Function SpectralMoments()
1305
1321
1306 1322 Calculates moments (power, mean, standard deviation) and SNR of the signal
1307
1323
1308 1324 Type of dataIn: Spectra
1309
1325
1310 1326 Configuration Parameters:
1311
1327
1312 1328 dirCosx : Cosine director in X axis
1313 1329 dirCosy : Cosine director in Y axis
1314
1330
1315 1331 elevation :
1316 1332 azimuth :
1317
1333
1318 1334 Input:
1319 channelList : simple channel list to select e.g. [2,3,7]
1335 channelList : simple channel list to select e.g. [2,3,7]
1320 1336 self.dataOut.data_pre : Spectral data
1321 1337 self.dataOut.abscissaList : List of frequencies
1322 1338 self.dataOut.noise : Noise level per channel
1323
1339
1324 1340 Affected:
1325 1341 self.dataOut.moments : Parameters per channel
1326 1342 self.dataOut.data_SNR : SNR per channel
1327
1343
1328 1344 '''
1329
1345
1330 1346 def run(self, dataOut):
1331
1347
1332 1348 data = dataOut.data_pre[0]
1333 1349 absc = dataOut.abscissaList[:-1]
1334 1350 noise = dataOut.noise
1335 1351 nChannel = data.shape[0]
1336 1352 data_param = numpy.zeros((nChannel, 4, data.shape[2]))
1337 1353
1338 1354 for ind in range(nChannel):
1339 1355 data_param[ind,:,:] = self.__calculateMoments( data[ind,:,:] , absc , noise[ind] )
1340
1356
1341 1357 dataOut.moments = data_param[:,1:,:]
1342 1358 dataOut.data_SNR = data_param[:,0]
1343 1359 dataOut.data_POW = data_param[:,1]
1344 1360 dataOut.data_DOP = data_param[:,2]
1345 1361 dataOut.data_WIDTH = data_param[:,3]
1346 1362
1347 1363 return dataOut
1348
1349 def __calculateMoments(self, oldspec, oldfreq, n0,
1364
1365 def __calculateMoments(self, oldspec, oldfreq, n0,
1350 1366 nicoh = None, graph = None, smooth = None, type1 = None, fwindow = None, snrth = None, dc = None, aliasing = None, oldfd = None, wwauto = None):
1351
1367
1352 1368 if (nicoh is None): nicoh = 1
1353 if (graph is None): graph = 0
1369 if (graph is None): graph = 0
1354 1370 if (smooth is None): smooth = 0
1355 1371 elif (self.smooth < 3): smooth = 0
1356 1372
1357 1373 if (type1 is None): type1 = 0
1358 1374 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
1359 1375 if (snrth is None): snrth = -3
1360 1376 if (dc is None): dc = 0
1361 1377 if (aliasing is None): aliasing = 0
1362 1378 if (oldfd is None): oldfd = 0
1363 1379 if (wwauto is None): wwauto = 0
1364
1380
1365 1381 if (n0 < 1.e-20): n0 = 1.e-20
1366
1382
1367 1383 freq = oldfreq
1368 1384 vec_power = numpy.zeros(oldspec.shape[1])
1369 1385 vec_fd = numpy.zeros(oldspec.shape[1])
1370 1386 vec_w = numpy.zeros(oldspec.shape[1])
1371 1387 vec_snr = numpy.zeros(oldspec.shape[1])
1372
1388
1373 1389 # oldspec = numpy.ma.masked_invalid(oldspec)
1374
1390
1375 1391 for ind in range(oldspec.shape[1]):
1376
1392
1377 1393 spec = oldspec[:,ind]
1378 1394 aux = spec*fwindow
1379 1395 max_spec = aux.max()
1380 1396 m = aux.tolist().index(max_spec)
1381
1382 #Smooth
1397
1398 #Smooth
1383 1399 if (smooth == 0):
1384 1400 spec2 = spec
1385 1401 else:
1386 1402 spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
1387
1403
1388 1404 # Calculo de Momentos
1389 1405 bb = spec2[numpy.arange(m,spec2.size)]
1390 1406 bb = (bb<n0).nonzero()
1391 1407 bb = bb[0]
1392
1408
1393 1409 ss = spec2[numpy.arange(0,m + 1)]
1394 1410 ss = (ss<n0).nonzero()
1395 1411 ss = ss[0]
1396
1412
1397 1413 if (bb.size == 0):
1398 1414 bb0 = spec.size - 1 - m
1399 else:
1415 else:
1400 1416 bb0 = bb[0] - 1
1401 1417 if (bb0 < 0):
1402 1418 bb0 = 0
1403
1419
1404 1420 if (ss.size == 0):
1405 1421 ss1 = 1
1406 1422 else:
1407 1423 ss1 = max(ss) + 1
1408
1424
1409 1425 if (ss1 > m):
1410 1426 ss1 = m
1411
1412 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
1413
1427
1428 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
1429
1414 1430 power = ((spec2[valid] - n0) * fwindow[valid]).sum()
1415 1431 fd = ((spec2[valid]- n0)*freq[valid] * fwindow[valid]).sum() / power
1416 1432 w = numpy.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum() / power)
1417 1433 snr = (spec2.mean()-n0)/n0
1418 if (snr < 1.e-20) :
1434 if (snr < 1.e-20) :
1419 1435 snr = 1.e-20
1420
1436
1421 1437 vec_power[ind] = power
1422 1438 vec_fd[ind] = fd
1423 1439 vec_w[ind] = w
1424 1440 vec_snr[ind] = snr
1425 1441
1426 1442 return numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
1427
1443
1428 1444 #------------------ Get SA Parameters --------------------------
1429
1445
1430 1446 def GetSAParameters(self):
1431 1447 #SA en frecuencia
1432 1448 pairslist = self.dataOut.groupList
1433 1449 num_pairs = len(pairslist)
1434
1450
1435 1451 vel = self.dataOut.abscissaList
1436 1452 spectra = self.dataOut.data_pre
1437 1453 cspectra = self.dataIn.data_cspc
1438 delta_v = vel[1] - vel[0]
1439
1454 delta_v = vel[1] - vel[0]
1455
1440 1456 #Calculating the power spectrum
1441 1457 spc_pow = numpy.sum(spectra, 3)*delta_v
1442 1458 #Normalizing Spectra
1443 1459 norm_spectra = spectra/spc_pow
1444 1460 #Calculating the norm_spectra at peak
1445 max_spectra = numpy.max(norm_spectra, 3)
1446
1461 max_spectra = numpy.max(norm_spectra, 3)
1462
1447 1463 #Normalizing Cross Spectra
1448 1464 norm_cspectra = numpy.zeros(cspectra.shape)
1449
1465
1450 1466 for i in range(num_chan):
1451 1467 norm_cspectra[i,:,:] = cspectra[i,:,:]/numpy.sqrt(spc_pow[pairslist[i][0],:]*spc_pow[pairslist[i][1],:])
1452
1468
1453 1469 max_cspectra = numpy.max(norm_cspectra,2)
1454 1470 max_cspectra_index = numpy.argmax(norm_cspectra, 2)
1455
1471
1456 1472 for i in range(num_pairs):
1457 1473 cspc_par[i,:,:] = __calculateMoments(norm_cspectra)
1458 1474 #------------------- Get Lags ----------------------------------
1459
1475
1460 1476 class SALags(Operation):
1461 1477 '''
1462 1478 Function GetMoments()
1463 1479
1464 1480 Input:
1465 1481 self.dataOut.data_pre
1466 1482 self.dataOut.abscissaList
1467 1483 self.dataOut.noise
1468 1484 self.dataOut.normFactor
1469 1485 self.dataOut.data_SNR
1470 1486 self.dataOut.groupList
1471 1487 self.dataOut.nChannels
1472
1488
1473 1489 Affected:
1474 1490 self.dataOut.data_param
1475
1491
1476 1492 '''
1477 def run(self, dataOut):
1493 def run(self, dataOut):
1478 1494 data_acf = dataOut.data_pre[0]
1479 1495 data_ccf = dataOut.data_pre[1]
1480 1496 normFactor_acf = dataOut.normFactor[0]
1481 1497 normFactor_ccf = dataOut.normFactor[1]
1482 1498 pairs_acf = dataOut.groupList[0]
1483 1499 pairs_ccf = dataOut.groupList[1]
1484
1500
1485 1501 nHeights = dataOut.nHeights
1486 1502 absc = dataOut.abscissaList
1487 1503 noise = dataOut.noise
1488 1504 SNR = dataOut.data_SNR
1489 1505 nChannels = dataOut.nChannels
1490 1506 # pairsList = dataOut.groupList
1491 1507 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairsList, nChannels)
1492 1508
1493 1509 for l in range(len(pairs_acf)):
1494 1510 data_acf[l,:,:] = data_acf[l,:,:]/normFactor_acf[l,:]
1495
1511
1496 1512 for l in range(len(pairs_ccf)):
1497 1513 data_ccf[l,:,:] = data_ccf[l,:,:]/normFactor_ccf[l,:]
1498
1514
1499 1515 dataOut.data_param = numpy.zeros((len(pairs_ccf)*2 + 1, nHeights))
1500 1516 dataOut.data_param[:-1,:] = self.__calculateTaus(data_acf, data_ccf, absc)
1501 1517 dataOut.data_param[-1,:] = self.__calculateLag1Phase(data_acf, absc)
1502 1518 return
1503
1519
1504 1520 # def __getPairsAutoCorr(self, pairsList, nChannels):
1505 #
1521 #
1506 1522 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1507 #
1508 # for l in range(len(pairsList)):
1523 #
1524 # for l in range(len(pairsList)):
1509 1525 # firstChannel = pairsList[l][0]
1510 1526 # secondChannel = pairsList[l][1]
1511 #
1512 # #Obteniendo pares de Autocorrelacion
1527 #
1528 # #Obteniendo pares de Autocorrelacion
1513 1529 # if firstChannel == secondChannel:
1514 1530 # pairsAutoCorr[firstChannel] = int(l)
1515 #
1531 #
1516 1532 # pairsAutoCorr = pairsAutoCorr.astype(int)
1517 #
1533 #
1518 1534 # pairsCrossCorr = range(len(pairsList))
1519 1535 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1520 #
1536 #
1521 1537 # return pairsAutoCorr, pairsCrossCorr
1522
1538
1523 1539 def __calculateTaus(self, data_acf, data_ccf, lagRange):
1524
1540
1525 1541 lag0 = data_acf.shape[1]/2
1526 1542 #Funcion de Autocorrelacion
1527 1543 mean_acf = stats.nanmean(data_acf, axis = 0)
1528
1544
1529 1545 #Obtencion Indice de TauCross
1530 1546 ind_ccf = data_ccf.argmax(axis = 1)
1531 1547 #Obtencion Indice de TauAuto
1532 1548 ind_acf = numpy.zeros(ind_ccf.shape,dtype = 'int')
1533 1549 ccf_lag0 = data_ccf[:,lag0,:]
1534
1550
1535 1551 for i in range(ccf_lag0.shape[0]):
1536 1552 ind_acf[i,:] = numpy.abs(mean_acf - ccf_lag0[i,:]).argmin(axis = 0)
1537
1553
1538 1554 #Obtencion de TauCross y TauAuto
1539 1555 tau_ccf = lagRange[ind_ccf]
1540 1556 tau_acf = lagRange[ind_acf]
1541
1557
1542 1558 Nan1, Nan2 = numpy.where(tau_ccf == lagRange[0])
1543
1559
1544 1560 tau_ccf[Nan1,Nan2] = numpy.nan
1545 1561 tau_acf[Nan1,Nan2] = numpy.nan
1546 1562 tau = numpy.vstack((tau_ccf,tau_acf))
1547
1563
1548 1564 return tau
1549
1565
1550 1566 def __calculateLag1Phase(self, data, lagTRange):
1551 1567 data1 = stats.nanmean(data, axis = 0)
1552 1568 lag1 = numpy.where(lagTRange == 0)[0][0] + 1
1553 1569
1554 1570 phase = numpy.angle(data1[lag1,:])
1555
1571
1556 1572 return phase
1557
1573
1558 1574 class SpectralFitting(Operation):
1559 1575 '''
1560 1576 Function GetMoments()
1561
1577
1562 1578 Input:
1563 1579 Output:
1564 1580 Variables modified:
1565 1581 '''
1566
1567 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None):
1568
1569
1582
1583 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None):
1584
1585
1570 1586 if path != None:
1571 1587 sys.path.append(path)
1572 1588 self.dataOut.library = importlib.import_module(file)
1573
1589
1574 1590 #To be inserted as a parameter
1575 1591 groupArray = numpy.array(groupList)
1576 # groupArray = numpy.array([[0,1],[2,3]])
1592 # groupArray = numpy.array([[0,1],[2,3]])
1577 1593 self.dataOut.groupList = groupArray
1578
1594
1579 1595 nGroups = groupArray.shape[0]
1580 1596 nChannels = self.dataIn.nChannels
1581 1597 nHeights=self.dataIn.heightList.size
1582
1598
1583 1599 #Parameters Array
1584 1600 self.dataOut.data_param = None
1585
1601
1586 1602 #Set constants
1587 1603 constants = self.dataOut.library.setConstants(self.dataIn)
1588 1604 self.dataOut.constants = constants
1589 1605 M = self.dataIn.normFactor
1590 1606 N = self.dataIn.nFFTPoints
1591 1607 ippSeconds = self.dataIn.ippSeconds
1592 1608 K = self.dataIn.nIncohInt
1593 1609 pairsArray = numpy.array(self.dataIn.pairsList)
1594
1610
1595 1611 #List of possible combinations
1596 1612 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
1597 1613 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
1598
1614
1599 1615 if getSNR:
1600 1616 listChannels = groupArray.reshape((groupArray.size))
1601 1617 listChannels.sort()
1602 1618 noise = self.dataIn.getNoise()
1603 1619 self.dataOut.data_SNR = self.__getSNR(self.dataIn.data_spc[listChannels,:,:], noise[listChannels])
1604
1605 for i in range(nGroups):
1620
1621 for i in range(nGroups):
1606 1622 coord = groupArray[i,:]
1607
1623
1608 1624 #Input data array
1609 1625 data = self.dataIn.data_spc[coord,:,:]/(M*N)
1610 1626 data = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
1611
1627
1612 1628 #Cross Spectra data array for Covariance Matrixes
1613 1629 ind = 0
1614 1630 for pairs in listComb:
1615 1631 pairsSel = numpy.array([coord[x],coord[y]])
1616 1632 indCross[ind] = int(numpy.where(numpy.all(pairsArray == pairsSel, axis = 1))[0][0])
1617 1633 ind += 1
1618 1634 dataCross = self.dataIn.data_cspc[indCross,:,:]/(M*N)
1619 1635 dataCross = dataCross**2/K
1620
1636
1621 1637 for h in range(nHeights):
1622
1638
1623 1639 #Input
1624 1640 d = data[:,h]
1625 1641
1626 1642 #Covariance Matrix
1627 1643 D = numpy.diag(d**2/K)
1628 1644 ind = 0
1629 1645 for pairs in listComb:
1630 1646 #Coordinates in Covariance Matrix
1631 x = pairs[0]
1647 x = pairs[0]
1632 1648 y = pairs[1]
1633 1649 #Channel Index
1634 1650 S12 = dataCross[ind,:,h]
1635 1651 D12 = numpy.diag(S12)
1636 1652 #Completing Covariance Matrix with Cross Spectras
1637 1653 D[x*N:(x+1)*N,y*N:(y+1)*N] = D12
1638 1654 D[y*N:(y+1)*N,x*N:(x+1)*N] = D12
1639 1655 ind += 1
1640 1656 Dinv=numpy.linalg.inv(D)
1641 1657 L=numpy.linalg.cholesky(Dinv)
1642 1658 LT=L.T
1643 1659
1644 1660 dp = numpy.dot(LT,d)
1645
1661
1646 1662 #Initial values
1647 1663 data_spc = self.dataIn.data_spc[coord,:,h]
1648
1664
1649 1665 if (h>0)and(error1[3]<5):
1650 1666 p0 = self.dataOut.data_param[i,:,h-1]
1651 1667 else:
1652 1668 p0 = numpy.array(self.dataOut.library.initialValuesFunction(data_spc, constants, i))
1653
1669
1654 1670 try:
1655 1671 #Least Squares
1656 1672 minp,covp,infodict,mesg,ier = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants),full_output=True)
1657 1673 # minp,covp = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants))
1658 1674 #Chi square error
1659 1675 error0 = numpy.sum(infodict['fvec']**2)/(2*N)
1660 1676 #Error with Jacobian
1661 1677 error1 = self.dataOut.library.errorFunction(minp,constants,LT)
1662 1678 except:
1663 1679 minp = p0*numpy.nan
1664 1680 error0 = numpy.nan
1665 1681 error1 = p0*numpy.nan
1666
1682
1667 1683 #Save
1668 1684 if self.dataOut.data_param is None:
1669 1685 self.dataOut.data_param = numpy.zeros((nGroups, p0.size, nHeights))*numpy.nan
1670 1686 self.dataOut.data_error = numpy.zeros((nGroups, p0.size + 1, nHeights))*numpy.nan
1671
1687
1672 1688 self.dataOut.data_error[i,:,h] = numpy.hstack((error0,error1))
1673 1689 self.dataOut.data_param[i,:,h] = minp
1674 1690 return
1675
1691
1676 1692 def __residFunction(self, p, dp, LT, constants):
1677 1693
1678 1694 fm = self.dataOut.library.modelFunction(p, constants)
1679 1695 fmp=numpy.dot(LT,fm)
1680
1696
1681 1697 return dp-fmp
1682 1698
1683 1699 def __getSNR(self, z, noise):
1684
1700
1685 1701 avg = numpy.average(z, axis=1)
1686 1702 SNR = (avg.T-noise)/noise
1687 1703 SNR = SNR.T
1688 1704 return SNR
1689
1705
1690 1706 def __chisq(p,chindex,hindex):
1691 1707 #similar to Resid but calculates CHI**2
1692 1708 [LT,d,fm]=setupLTdfm(p,chindex,hindex)
1693 1709 dp=numpy.dot(LT,d)
1694 1710 fmp=numpy.dot(LT,fm)
1695 1711 chisq=numpy.dot((dp-fmp).T,(dp-fmp))
1696 1712 return chisq
1697
1713
1698 1714 class WindProfiler(Operation):
1699
1715
1700 1716 __isConfig = False
1701
1717
1702 1718 __initime = None
1703 1719 __lastdatatime = None
1704 1720 __integrationtime = None
1705
1721
1706 1722 __buffer = None
1707
1723
1708 1724 __dataReady = False
1709
1725
1710 1726 __firstdata = None
1711
1727
1712 1728 n = None
1713
1714 def __init__(self):
1729
1730 def __init__(self):
1715 1731 Operation.__init__(self)
1716
1732
1717 1733 def __calculateCosDir(self, elev, azim):
1718 1734 zen = (90 - elev)*numpy.pi/180
1719 1735 azim = azim*numpy.pi/180
1720 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
1736 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
1721 1737 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
1722
1738
1723 1739 signX = numpy.sign(numpy.cos(azim))
1724 1740 signY = numpy.sign(numpy.sin(azim))
1725
1741
1726 1742 cosDirX = numpy.copysign(cosDirX, signX)
1727 1743 cosDirY = numpy.copysign(cosDirY, signY)
1728 1744 return cosDirX, cosDirY
1729
1745
1730 1746 def __calculateAngles(self, theta_x, theta_y, azimuth):
1731
1747
1732 1748 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
1733 1749 zenith_arr = numpy.arccos(dir_cosw)
1734 1750 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
1735
1751
1736 1752 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
1737 1753 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
1738
1754
1739 1755 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
1740 1756
1741 1757 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
1742
1743 #
1758
1759 #
1744 1760 if horOnly:
1745 1761 A = numpy.c_[dir_cosu,dir_cosv]
1746 1762 else:
1747 1763 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
1748 1764 A = numpy.asmatrix(A)
1749 1765 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
1750 1766
1751 1767 return A1
1752 1768
1753 1769 def __correctValues(self, heiRang, phi, velRadial, SNR):
1754 1770 listPhi = phi.tolist()
1755 1771 maxid = listPhi.index(max(listPhi))
1756 1772 minid = listPhi.index(min(listPhi))
1757
1758 rango = list(range(len(phi)))
1773
1774 rango = list(range(len(phi)))
1759 1775 # rango = numpy.delete(rango,maxid)
1760
1776
1761 1777 heiRang1 = heiRang*math.cos(phi[maxid])
1762 1778 heiRangAux = heiRang*math.cos(phi[minid])
1763 1779 indOut = (heiRang1 < heiRangAux[0]).nonzero()
1764 1780 heiRang1 = numpy.delete(heiRang1,indOut)
1765
1781
1766 1782 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
1767 1783 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
1768
1784
1769 1785 for i in rango:
1770 1786 x = heiRang*math.cos(phi[i])
1771 1787 y1 = velRadial[i,:]
1772 1788 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
1773
1789
1774 1790 x1 = heiRang1
1775 1791 y11 = f1(x1)
1776
1792
1777 1793 y2 = SNR[i,:]
1778 1794 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
1779 1795 y21 = f2(x1)
1780
1796
1781 1797 velRadial1[i,:] = y11
1782 1798 SNR1[i,:] = y21
1783
1799
1784 1800 return heiRang1, velRadial1, SNR1
1785 1801
1786 1802 def __calculateVelUVW(self, A, velRadial):
1787
1803
1788 1804 #Operacion Matricial
1789 1805 # velUVW = numpy.zeros((velRadial.shape[1],3))
1790 1806 # for ind in range(velRadial.shape[1]):
1791 1807 # velUVW[ind,:] = numpy.dot(A,velRadial[:,ind])
1792 1808 # velUVW = velUVW.transpose()
1793 1809 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
1794 1810 velUVW[:,:] = numpy.dot(A,velRadial)
1795
1796
1811
1812
1797 1813 return velUVW
1798
1814
1799 1815 # def techniqueDBS(self, velRadial0, dirCosx, disrCosy, azimuth, correct, horizontalOnly, heiRang, SNR0):
1800
1816
1801 1817 def techniqueDBS(self, kwargs):
1802 1818 """
1803 1819 Function that implements Doppler Beam Swinging (DBS) technique.
1804
1820
1805 1821 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1806 1822 Direction correction (if necessary), Ranges and SNR
1807
1823
1808 1824 Output: Winds estimation (Zonal, Meridional and Vertical)
1809
1825
1810 1826 Parameters affected: Winds, height range, SNR
1811 1827 """
1812 1828 velRadial0 = kwargs['velRadial']
1813 1829 heiRang = kwargs['heightList']
1814 1830 SNR0 = kwargs['SNR']
1815
1831
1816 1832 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
1817 1833 theta_x = numpy.array(kwargs['dirCosx'])
1818 1834 theta_y = numpy.array(kwargs['dirCosy'])
1819 1835 else:
1820 1836 elev = numpy.array(kwargs['elevation'])
1821 1837 azim = numpy.array(kwargs['azimuth'])
1822 1838 theta_x, theta_y = self.__calculateCosDir(elev, azim)
1823 azimuth = kwargs['correctAzimuth']
1839 azimuth = kwargs['correctAzimuth']
1824 1840 if 'horizontalOnly' in kwargs:
1825 1841 horizontalOnly = kwargs['horizontalOnly']
1826 1842 else: horizontalOnly = False
1827 1843 if 'correctFactor' in kwargs:
1828 1844 correctFactor = kwargs['correctFactor']
1829 1845 else: correctFactor = 1
1830 1846 if 'channelList' in kwargs:
1831 1847 channelList = kwargs['channelList']
1832 1848 if len(channelList) == 2:
1833 1849 horizontalOnly = True
1834 1850 arrayChannel = numpy.array(channelList)
1835 1851 param = param[arrayChannel,:,:]
1836 1852 theta_x = theta_x[arrayChannel]
1837 1853 theta_y = theta_y[arrayChannel]
1838
1839 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
1840 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
1854
1855 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
1856 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
1841 1857 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
1842
1858
1843 1859 #Calculo de Componentes de la velocidad con DBS
1844 1860 winds = self.__calculateVelUVW(A,velRadial1)
1845
1861
1846 1862 return winds, heiRang1, SNR1
1847
1863
1848 1864 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
1849
1865
1850 1866 nPairs = len(pairs_ccf)
1851 1867 posx = numpy.asarray(posx)
1852 1868 posy = numpy.asarray(posy)
1853
1869
1854 1870 #Rotacion Inversa para alinear con el azimuth
1855 1871 if azimuth!= None:
1856 1872 azimuth = azimuth*math.pi/180
1857 1873 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
1858 1874 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
1859 1875 else:
1860 1876 posx1 = posx
1861 1877 posy1 = posy
1862
1878
1863 1879 #Calculo de Distancias
1864 1880 distx = numpy.zeros(nPairs)
1865 1881 disty = numpy.zeros(nPairs)
1866 1882 dist = numpy.zeros(nPairs)
1867 1883 ang = numpy.zeros(nPairs)
1868
1884
1869 1885 for i in range(nPairs):
1870 1886 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
1871 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
1887 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
1872 1888 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
1873 1889 ang[i] = numpy.arctan2(disty[i],distx[i])
1874
1890
1875 1891 return distx, disty, dist, ang
1876 #Calculo de Matrices
1892 #Calculo de Matrices
1877 1893 # nPairs = len(pairs)
1878 1894 # ang1 = numpy.zeros((nPairs, 2, 1))
1879 1895 # dist1 = numpy.zeros((nPairs, 2, 1))
1880 #
1896 #
1881 1897 # for j in range(nPairs):
1882 1898 # dist1[j,0,0] = dist[pairs[j][0]]
1883 1899 # dist1[j,1,0] = dist[pairs[j][1]]
1884 1900 # ang1[j,0,0] = ang[pairs[j][0]]
1885 1901 # ang1[j,1,0] = ang[pairs[j][1]]
1886 #
1902 #
1887 1903 # return distx,disty, dist1,ang1
1888 1904
1889
1905
1890 1906 def __calculateVelVer(self, phase, lagTRange, _lambda):
1891 1907
1892 1908 Ts = lagTRange[1] - lagTRange[0]
1893 1909 velW = -_lambda*phase/(4*math.pi*Ts)
1894
1910
1895 1911 return velW
1896
1912
1897 1913 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
1898 1914 nPairs = tau1.shape[0]
1899 1915 nHeights = tau1.shape[1]
1900 vel = numpy.zeros((nPairs,3,nHeights))
1916 vel = numpy.zeros((nPairs,3,nHeights))
1901 1917 dist1 = numpy.reshape(dist, (dist.size,1))
1902
1918
1903 1919 angCos = numpy.cos(ang)
1904 1920 angSin = numpy.sin(ang)
1905
1906 vel0 = dist1*tau1/(2*tau2**2)
1921
1922 vel0 = dist1*tau1/(2*tau2**2)
1907 1923 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
1908 1924 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
1909
1925
1910 1926 ind = numpy.where(numpy.isinf(vel))
1911 1927 vel[ind] = numpy.nan
1912
1928
1913 1929 return vel
1914
1930
1915 1931 # def __getPairsAutoCorr(self, pairsList, nChannels):
1916 #
1932 #
1917 1933 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1918 #
1919 # for l in range(len(pairsList)):
1934 #
1935 # for l in range(len(pairsList)):
1920 1936 # firstChannel = pairsList[l][0]
1921 1937 # secondChannel = pairsList[l][1]
1922 #
1923 # #Obteniendo pares de Autocorrelacion
1938 #
1939 # #Obteniendo pares de Autocorrelacion
1924 1940 # if firstChannel == secondChannel:
1925 1941 # pairsAutoCorr[firstChannel] = int(l)
1926 #
1942 #
1927 1943 # pairsAutoCorr = pairsAutoCorr.astype(int)
1928 #
1944 #
1929 1945 # pairsCrossCorr = range(len(pairsList))
1930 1946 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1931 #
1947 #
1932 1948 # return pairsAutoCorr, pairsCrossCorr
1933
1949
1934 1950 # def techniqueSA(self, pairsSelected, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, lagTRange, correctFactor):
1935 1951 def techniqueSA(self, kwargs):
1936
1937 """
1952
1953 """
1938 1954 Function that implements Spaced Antenna (SA) technique.
1939
1955
1940 1956 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1941 1957 Direction correction (if necessary), Ranges and SNR
1942
1958
1943 1959 Output: Winds estimation (Zonal, Meridional and Vertical)
1944
1960
1945 1961 Parameters affected: Winds
1946 1962 """
1947 1963 position_x = kwargs['positionX']
1948 1964 position_y = kwargs['positionY']
1949 1965 azimuth = kwargs['azimuth']
1950
1966
1951 1967 if 'correctFactor' in kwargs:
1952 1968 correctFactor = kwargs['correctFactor']
1953 1969 else:
1954 1970 correctFactor = 1
1955
1971
1956 1972 groupList = kwargs['groupList']
1957 1973 pairs_ccf = groupList[1]
1958 1974 tau = kwargs['tau']
1959 1975 _lambda = kwargs['_lambda']
1960
1976
1961 1977 #Cross Correlation pairs obtained
1962 1978 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairssList, nChannels)
1963 1979 # pairsArray = numpy.array(pairsList)[pairsCrossCorr]
1964 1980 # pairsSelArray = numpy.array(pairsSelected)
1965 1981 # pairs = []
1966 #
1982 #
1967 1983 # #Wind estimation pairs obtained
1968 1984 # for i in range(pairsSelArray.shape[0]/2):
1969 1985 # ind1 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i], axis = 1))[0][0]
1970 1986 # ind2 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i + 1], axis = 1))[0][0]
1971 1987 # pairs.append((ind1,ind2))
1972
1988
1973 1989 indtau = tau.shape[0]/2
1974 1990 tau1 = tau[:indtau,:]
1975 1991 tau2 = tau[indtau:-1,:]
1976 1992 # tau1 = tau1[pairs,:]
1977 1993 # tau2 = tau2[pairs,:]
1978 1994 phase1 = tau[-1,:]
1979
1995
1980 1996 #---------------------------------------------------------------------
1981 #Metodo Directo
1997 #Metodo Directo
1982 1998 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
1983 1999 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
1984 2000 winds = stats.nanmean(winds, axis=0)
1985 2001 #---------------------------------------------------------------------
1986 2002 #Metodo General
1987 2003 # distx, disty, dist = self.calculateDistance(position_x,position_y,pairsCrossCorr, pairsList, azimuth)
1988 2004 # #Calculo Coeficientes de Funcion de Correlacion
1989 2005 # F,G,A,B,H = self.calculateCoef(tau1,tau2,distx,disty,n)
1990 2006 # #Calculo de Velocidades
1991 2007 # winds = self.calculateVelUV(F,G,A,B,H)
1992 2008
1993 2009 #---------------------------------------------------------------------
1994 2010 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
1995 2011 winds = correctFactor*winds
1996 2012 return winds
1997
2013
1998 2014 def __checkTime(self, currentTime, paramInterval, outputInterval):
1999
2015
2000 2016 dataTime = currentTime + paramInterval
2001 2017 deltaTime = dataTime - self.__initime
2002
2018
2003 2019 if deltaTime >= outputInterval or deltaTime < 0:
2004 2020 self.__dataReady = True
2005 return
2006
2021 return
2022
2007 2023 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
2008 2024 '''
2009 2025 Function that implements winds estimation technique with detected meteors.
2010
2026
2011 2027 Input: Detected meteors, Minimum meteor quantity to wind estimation
2012
2028
2013 2029 Output: Winds estimation (Zonal and Meridional)
2014
2030
2015 2031 Parameters affected: Winds
2016 '''
2032 '''
2017 2033 #Settings
2018 2034 nInt = (heightMax - heightMin)/2
2019 2035 nInt = int(nInt)
2020 winds = numpy.zeros((2,nInt))*numpy.nan
2021
2036 winds = numpy.zeros((2,nInt))*numpy.nan
2037
2022 2038 #Filter errors
2023 2039 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
2024 2040 finalMeteor = arrayMeteor[error,:]
2025
2041
2026 2042 #Meteor Histogram
2027 2043 finalHeights = finalMeteor[:,2]
2028 2044 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
2029 2045 nMeteorsPerI = hist[0]
2030 2046 heightPerI = hist[1]
2031
2047
2032 2048 #Sort of meteors
2033 2049 indSort = finalHeights.argsort()
2034 2050 finalMeteor2 = finalMeteor[indSort,:]
2035
2051
2036 2052 # Calculating winds
2037 2053 ind1 = 0
2038 ind2 = 0
2039
2054 ind2 = 0
2055
2040 2056 for i in range(nInt):
2041 2057 nMet = nMeteorsPerI[i]
2042 2058 ind1 = ind2
2043 2059 ind2 = ind1 + nMet
2044
2060
2045 2061 meteorAux = finalMeteor2[ind1:ind2,:]
2046
2062
2047 2063 if meteorAux.shape[0] >= meteorThresh:
2048 2064 vel = meteorAux[:, 6]
2049 2065 zen = meteorAux[:, 4]*numpy.pi/180
2050 2066 azim = meteorAux[:, 3]*numpy.pi/180
2051
2067
2052 2068 n = numpy.cos(zen)
2053 2069 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
2054 2070 # l = m*numpy.tan(azim)
2055 2071 l = numpy.sin(zen)*numpy.sin(azim)
2056 2072 m = numpy.sin(zen)*numpy.cos(azim)
2057
2073
2058 2074 A = numpy.vstack((l, m)).transpose()
2059 2075 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
2060 2076 windsAux = numpy.dot(A1, vel)
2061
2077
2062 2078 winds[0,i] = windsAux[0]
2063 2079 winds[1,i] = windsAux[1]
2064
2080
2065 2081 return winds, heightPerI[:-1]
2066
2082
2067 2083 def techniqueNSM_SA(self, **kwargs):
2068 2084 metArray = kwargs['metArray']
2069 2085 heightList = kwargs['heightList']
2070 2086 timeList = kwargs['timeList']
2071
2087
2072 2088 rx_location = kwargs['rx_location']
2073 2089 groupList = kwargs['groupList']
2074 2090 azimuth = kwargs['azimuth']
2075 2091 dfactor = kwargs['dfactor']
2076 2092 k = kwargs['k']
2077
2093
2078 2094 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
2079 2095 d = dist*dfactor
2080 2096 #Phase calculation
2081 2097 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
2082
2098
2083 2099 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
2084
2100
2085 2101 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2086 2102 azimuth1 = azimuth1*numpy.pi/180
2087
2103
2088 2104 for i in range(heightList.size):
2089 2105 h = heightList[i]
2090 2106 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
2091 2107 metHeight = metArray1[indH,:]
2092 2108 if metHeight.shape[0] >= 2:
2093 2109 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
2094 2110 iazim = metHeight[:,1].astype(int)
2095 2111 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
2096 2112 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
2097 2113 A = numpy.asmatrix(A)
2098 2114 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
2099 2115 velHor = numpy.dot(A1,velAux)
2100
2116
2101 2117 velEst[i,:] = numpy.squeeze(velHor)
2102 2118 return velEst
2103
2119
2104 2120 def __getPhaseSlope(self, metArray, heightList, timeList):
2105 2121 meteorList = []
2106 2122 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
2107 2123 #Putting back together the meteor matrix
2108 2124 utctime = metArray[:,0]
2109 2125 uniqueTime = numpy.unique(utctime)
2110
2126
2111 2127 phaseDerThresh = 0.5
2112 2128 ippSeconds = timeList[1] - timeList[0]
2113 2129 sec = numpy.where(timeList>1)[0][0]
2114 2130 nPairs = metArray.shape[1] - 6
2115 2131 nHeights = len(heightList)
2116
2132
2117 2133 for t in uniqueTime:
2118 2134 metArray1 = metArray[utctime==t,:]
2119 2135 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
2120 2136 tmet = metArray1[:,1].astype(int)
2121 2137 hmet = metArray1[:,2].astype(int)
2122
2138
2123 2139 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
2124 2140 metPhase[:,:] = numpy.nan
2125 2141 metPhase[:,hmet,tmet] = metArray1[:,6:].T
2126
2142
2127 2143 #Delete short trails
2128 2144 metBool = ~numpy.isnan(metPhase[0,:,:])
2129 2145 heightVect = numpy.sum(metBool, axis = 1)
2130 2146 metBool[heightVect<sec,:] = False
2131 2147 metPhase[:,heightVect<sec,:] = numpy.nan
2132
2148
2133 2149 #Derivative
2134 2150 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
2135 2151 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
2136 2152 metPhase[phDerAux] = numpy.nan
2137
2153
2138 2154 #--------------------------METEOR DETECTION -----------------------------------------
2139 2155 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
2140
2156
2141 2157 for p in numpy.arange(nPairs):
2142 2158 phase = metPhase[p,:,:]
2143 2159 phDer = metDer[p,:,:]
2144
2160
2145 2161 for h in indMet:
2146 2162 height = heightList[h]
2147 2163 phase1 = phase[h,:] #82
2148 2164 phDer1 = phDer[h,:]
2149
2165
2150 2166 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
2151
2167
2152 2168 indValid = numpy.where(~numpy.isnan(phase1))[0]
2153 2169 initMet = indValid[0]
2154 2170 endMet = 0
2155
2171
2156 2172 for i in range(len(indValid)-1):
2157
2173
2158 2174 #Time difference
2159 2175 inow = indValid[i]
2160 2176 inext = indValid[i+1]
2161 2177 idiff = inext - inow
2162 2178 #Phase difference
2163 phDiff = numpy.abs(phase1[inext] - phase1[inow])
2164
2179 phDiff = numpy.abs(phase1[inext] - phase1[inow])
2180
2165 2181 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
2166 2182 sizeTrail = inow - initMet + 1
2167 2183 if sizeTrail>3*sec: #Too short meteors
2168 2184 x = numpy.arange(initMet,inow+1)*ippSeconds
2169 2185 y = phase1[initMet:inow+1]
2170 2186 ynnan = ~numpy.isnan(y)
2171 2187 x = x[ynnan]
2172 2188 y = y[ynnan]
2173 2189 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
2174 2190 ylin = x*slope + intercept
2175 2191 rsq = r_value**2
2176 2192 if rsq > 0.5:
2177 2193 vel = slope#*height*1000/(k*d)
2178 2194 estAux = numpy.array([utctime,p,height, vel, rsq])
2179 2195 meteorList.append(estAux)
2180 initMet = inext
2196 initMet = inext
2181 2197 metArray2 = numpy.array(meteorList)
2182
2198
2183 2199 return metArray2
2184
2200
2185 2201 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
2186
2202
2187 2203 azimuth1 = numpy.zeros(len(pairslist))
2188 2204 dist = numpy.zeros(len(pairslist))
2189
2205
2190 2206 for i in range(len(rx_location)):
2191 2207 ch0 = pairslist[i][0]
2192 2208 ch1 = pairslist[i][1]
2193
2209
2194 2210 diffX = rx_location[ch0][0] - rx_location[ch1][0]
2195 2211 diffY = rx_location[ch0][1] - rx_location[ch1][1]
2196 2212 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
2197 2213 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
2198
2214
2199 2215 azimuth1 -= azimuth0
2200 2216 return azimuth1, dist
2201
2217
2202 2218 def techniqueNSM_DBS(self, **kwargs):
2203 2219 metArray = kwargs['metArray']
2204 2220 heightList = kwargs['heightList']
2205 timeList = kwargs['timeList']
2221 timeList = kwargs['timeList']
2206 2222 azimuth = kwargs['azimuth']
2207 2223 theta_x = numpy.array(kwargs['theta_x'])
2208 2224 theta_y = numpy.array(kwargs['theta_y'])
2209
2225
2210 2226 utctime = metArray[:,0]
2211 2227 cmet = metArray[:,1].astype(int)
2212 2228 hmet = metArray[:,3].astype(int)
2213 2229 SNRmet = metArray[:,4]
2214 2230 vmet = metArray[:,5]
2215 2231 spcmet = metArray[:,6]
2216
2232
2217 2233 nChan = numpy.max(cmet) + 1
2218 2234 nHeights = len(heightList)
2219 2235
2220 2236 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
2221 2237 hmet = heightList[hmet]
2222 2238 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
2223 2239
2224 2240 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2225 2241
2226 2242 for i in range(nHeights - 1):
2227 2243 hmin = heightList[i]
2228 2244 hmax = heightList[i + 1]
2229 2245
2230 2246 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
2231 2247 indthisH = numpy.where(thisH)
2232
2248
2233 2249 if numpy.size(indthisH) > 3:
2234
2250
2235 2251 vel_aux = vmet[thisH]
2236 2252 chan_aux = cmet[thisH]
2237 2253 cosu_aux = dir_cosu[chan_aux]
2238 2254 cosv_aux = dir_cosv[chan_aux]
2239 2255 cosw_aux = dir_cosw[chan_aux]
2240
2241 nch = numpy.size(numpy.unique(chan_aux))
2256
2257 nch = numpy.size(numpy.unique(chan_aux))
2242 2258 if nch > 1:
2243 2259 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
2244 2260 velEst[i,:] = numpy.dot(A,vel_aux)
2245
2261
2246 2262 return velEst
2247 2263
2248 2264 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
2249 2265
2250 2266 param = dataOut.data_param
2251 2267 if dataOut.abscissaList != None:
2252 2268 absc = dataOut.abscissaList[:-1]
2253 2269 # noise = dataOut.noise
2254 2270 heightList = dataOut.heightList
2255 2271 SNR = dataOut.data_SNR
2256
2272
2257 2273 if technique == 'DBS':
2258
2259 kwargs['velRadial'] = param[:,1,:] #Radial velocity
2274
2275 kwargs['velRadial'] = param[:,1,:] #Radial velocity
2260 2276 kwargs['heightList'] = heightList
2261 2277 kwargs['SNR'] = SNR
2262
2278
2263 2279 dataOut.data_output, dataOut.heightList, dataOut.data_SNR = self.techniqueDBS(kwargs) #DBS Function
2264 2280 dataOut.utctimeInit = dataOut.utctime
2265 2281 dataOut.outputInterval = dataOut.paramInterval
2266
2282
2267 2283 elif technique == 'SA':
2268
2284
2269 2285 #Parameters
2270 2286 # position_x = kwargs['positionX']
2271 2287 # position_y = kwargs['positionY']
2272 2288 # azimuth = kwargs['azimuth']
2273 #
2289 #
2274 2290 # if kwargs.has_key('crosspairsList'):
2275 2291 # pairs = kwargs['crosspairsList']
2276 2292 # else:
2277 # pairs = None
2278 #
2293 # pairs = None
2294 #
2279 2295 # if kwargs.has_key('correctFactor'):
2280 2296 # correctFactor = kwargs['correctFactor']
2281 2297 # else:
2282 2298 # correctFactor = 1
2283
2299
2284 2300 # tau = dataOut.data_param
2285 2301 # _lambda = dataOut.C/dataOut.frequency
2286 2302 # pairsList = dataOut.groupList
2287 2303 # nChannels = dataOut.nChannels
2288
2304
2289 2305 kwargs['groupList'] = dataOut.groupList
2290 2306 kwargs['tau'] = dataOut.data_param
2291 2307 kwargs['_lambda'] = dataOut.C/dataOut.frequency
2292 2308 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
2293 2309 dataOut.data_output = self.techniqueSA(kwargs)
2294 2310 dataOut.utctimeInit = dataOut.utctime
2295 2311 dataOut.outputInterval = dataOut.timeInterval
2296
2297 elif technique == 'Meteors':
2312
2313 elif technique == 'Meteors':
2298 2314 dataOut.flagNoData = True
2299 2315 self.__dataReady = False
2300
2316
2301 2317 if 'nHours' in kwargs:
2302 2318 nHours = kwargs['nHours']
2303 else:
2319 else:
2304 2320 nHours = 1
2305
2321
2306 2322 if 'meteorsPerBin' in kwargs:
2307 2323 meteorThresh = kwargs['meteorsPerBin']
2308 2324 else:
2309 2325 meteorThresh = 6
2310
2326
2311 2327 if 'hmin' in kwargs:
2312 2328 hmin = kwargs['hmin']
2313 2329 else: hmin = 70
2314 2330 if 'hmax' in kwargs:
2315 2331 hmax = kwargs['hmax']
2316 2332 else: hmax = 110
2317
2333
2318 2334 dataOut.outputInterval = nHours*3600
2319
2335
2320 2336 if self.__isConfig == False:
2321 2337 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2322 2338 #Get Initial LTC time
2323 2339 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2324 2340 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2325 2341
2326 2342 self.__isConfig = True
2327
2343
2328 2344 if self.__buffer is None:
2329 2345 self.__buffer = dataOut.data_param
2330 2346 self.__firstdata = copy.copy(dataOut)
2331 2347
2332 2348 else:
2333 2349 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2334
2350
2335 2351 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2336
2352
2337 2353 if self.__dataReady:
2338 2354 dataOut.utctimeInit = self.__initime
2339
2355
2340 2356 self.__initime += dataOut.outputInterval #to erase time offset
2341
2357
2342 2358 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
2343 2359 dataOut.flagNoData = False
2344 2360 self.__buffer = None
2345
2361
2346 2362 elif technique == 'Meteors1':
2347 2363 dataOut.flagNoData = True
2348 2364 self.__dataReady = False
2349
2365
2350 2366 if 'nMins' in kwargs:
2351 2367 nMins = kwargs['nMins']
2352 2368 else: nMins = 20
2353 2369 if 'rx_location' in kwargs:
2354 2370 rx_location = kwargs['rx_location']
2355 2371 else: rx_location = [(0,1),(1,1),(1,0)]
2356 2372 if 'azimuth' in kwargs:
2357 2373 azimuth = kwargs['azimuth']
2358 2374 else: azimuth = 51.06
2359 2375 if 'dfactor' in kwargs:
2360 2376 dfactor = kwargs['dfactor']
2361 2377 if 'mode' in kwargs:
2362 2378 mode = kwargs['mode']
2363 2379 if 'theta_x' in kwargs:
2364 theta_x = kwargs['theta_x']
2380 theta_x = kwargs['theta_x']
2365 2381 if 'theta_y' in kwargs:
2366 2382 theta_y = kwargs['theta_y']
2367 2383 else: mode = 'SA'
2368 2384
2369 2385 #Borrar luego esto
2370 2386 if dataOut.groupList is None:
2371 2387 dataOut.groupList = [(0,1),(0,2),(1,2)]
2372 2388 groupList = dataOut.groupList
2373 2389 C = 3e8
2374 2390 freq = 50e6
2375 2391 lamb = C/freq
2376 2392 k = 2*numpy.pi/lamb
2377
2393
2378 2394 timeList = dataOut.abscissaList
2379 2395 heightList = dataOut.heightList
2380
2396
2381 2397 if self.__isConfig == False:
2382 2398 dataOut.outputInterval = nMins*60
2383 2399 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2384 2400 #Get Initial LTC time
2385 2401 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2386 2402 minuteAux = initime.minute
2387 2403 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
2388 2404 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2389 2405
2390 2406 self.__isConfig = True
2391
2407
2392 2408 if self.__buffer is None:
2393 2409 self.__buffer = dataOut.data_param
2394 2410 self.__firstdata = copy.copy(dataOut)
2395 2411
2396 2412 else:
2397 2413 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2398
2414
2399 2415 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2400
2416
2401 2417 if self.__dataReady:
2402 2418 dataOut.utctimeInit = self.__initime
2403 2419 self.__initime += dataOut.outputInterval #to erase time offset
2404
2420
2405 2421 metArray = self.__buffer
2406 2422 if mode == 'SA':
2407 2423 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
2408 2424 elif mode == 'DBS':
2409 2425 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
2410 2426 dataOut.data_output = dataOut.data_output.T
2411 2427 dataOut.flagNoData = False
2412 2428 self.__buffer = None
2413 2429
2414 2430 return
2415
2431
2416 2432 class EWDriftsEstimation(Operation):
2417
2418 def __init__(self):
2419 Operation.__init__(self)
2420
2433
2434 def __init__(self):
2435 Operation.__init__(self)
2436
2421 2437 def __correctValues(self, heiRang, phi, velRadial, SNR):
2422 2438 listPhi = phi.tolist()
2423 2439 maxid = listPhi.index(max(listPhi))
2424 2440 minid = listPhi.index(min(listPhi))
2425
2426 rango = list(range(len(phi)))
2441
2442 rango = list(range(len(phi)))
2427 2443 # rango = numpy.delete(rango,maxid)
2428
2444
2429 2445 heiRang1 = heiRang*math.cos(phi[maxid])
2430 2446 heiRangAux = heiRang*math.cos(phi[minid])
2431 2447 indOut = (heiRang1 < heiRangAux[0]).nonzero()
2432 2448 heiRang1 = numpy.delete(heiRang1,indOut)
2433
2449
2434 2450 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
2435 2451 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
2436
2452
2437 2453 for i in rango:
2438 2454 x = heiRang*math.cos(phi[i])
2439 2455 y1 = velRadial[i,:]
2440 2456 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
2441
2457
2442 2458 x1 = heiRang1
2443 2459 y11 = f1(x1)
2444
2460
2445 2461 y2 = SNR[i,:]
2446 2462 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
2447 2463 y21 = f2(x1)
2448
2464
2449 2465 velRadial1[i,:] = y11
2450 2466 SNR1[i,:] = y21
2451
2467
2452 2468 return heiRang1, velRadial1, SNR1
2453 2469
2454 2470 def run(self, dataOut, zenith, zenithCorrection):
2455 2471 heiRang = dataOut.heightList
2456 2472 velRadial = dataOut.data_param[:,3,:]
2457 2473 SNR = dataOut.data_SNR
2458
2474
2459 2475 zenith = numpy.array(zenith)
2460 zenith -= zenithCorrection
2476 zenith -= zenithCorrection
2461 2477 zenith *= numpy.pi/180
2462
2478
2463 2479 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
2464
2480
2465 2481 alp = zenith[0]
2466 2482 bet = zenith[1]
2467
2483
2468 2484 w_w = velRadial1[0,:]
2469 2485 w_e = velRadial1[1,:]
2470
2471 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
2472 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
2473
2486
2487 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
2488 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
2489
2474 2490 winds = numpy.vstack((u,w))
2475
2491
2476 2492 dataOut.heightList = heiRang1
2477 2493 dataOut.data_output = winds
2478 2494 dataOut.data_SNR = SNR1
2479
2495
2480 2496 dataOut.utctimeInit = dataOut.utctime
2481 2497 dataOut.outputInterval = dataOut.timeInterval
2482 2498 return
2483 2499
2484 2500 #--------------- Non Specular Meteor ----------------
2485 2501
2486 2502 class NonSpecularMeteorDetection(Operation):
2487 2503
2488 2504 def run(self, dataOut, mode, SNRthresh=8, phaseDerThresh=0.5, cohThresh=0.8, allData = False):
2489 2505 data_acf = dataOut.data_pre[0]
2490 2506 data_ccf = dataOut.data_pre[1]
2491 2507 pairsList = dataOut.groupList[1]
2492
2508
2493 2509 lamb = dataOut.C/dataOut.frequency
2494 2510 tSamp = dataOut.ippSeconds*dataOut.nCohInt
2495 2511 paramInterval = dataOut.paramInterval
2496
2512
2497 2513 nChannels = data_acf.shape[0]
2498 2514 nLags = data_acf.shape[1]
2499 2515 nProfiles = data_acf.shape[2]
2500 2516 nHeights = dataOut.nHeights
2501 2517 nCohInt = dataOut.nCohInt
2502 2518 sec = numpy.round(nProfiles/dataOut.paramInterval)
2503 2519 heightList = dataOut.heightList
2504 2520 ippSeconds = dataOut.ippSeconds*dataOut.nCohInt*dataOut.nAvg
2505 2521 utctime = dataOut.utctime
2506
2522
2507 2523 dataOut.abscissaList = numpy.arange(0,paramInterval+ippSeconds,ippSeconds)
2508 2524
2509 2525 #------------------------ SNR --------------------------------------
2510 2526 power = data_acf[:,0,:,:].real
2511 2527 noise = numpy.zeros(nChannels)
2512 2528 SNR = numpy.zeros(power.shape)
2513 2529 for i in range(nChannels):
2514 2530 noise[i] = hildebrand_sekhon(power[i,:], nCohInt)
2515 2531 SNR[i] = (power[i]-noise[i])/noise[i]
2516 2532 SNRm = numpy.nanmean(SNR, axis = 0)
2517 2533 SNRdB = 10*numpy.log10(SNR)
2518
2534
2519 2535 if mode == 'SA':
2520 2536 dataOut.groupList = dataOut.groupList[1]
2521 2537 nPairs = data_ccf.shape[0]
2522 2538 #---------------------- Coherence and Phase --------------------------
2523 2539 phase = numpy.zeros(data_ccf[:,0,:,:].shape)
2524 2540 # phase1 = numpy.copy(phase)
2525 2541 coh1 = numpy.zeros(data_ccf[:,0,:,:].shape)
2526
2542
2527 2543 for p in range(nPairs):
2528 2544 ch0 = pairsList[p][0]
2529 2545 ch1 = pairsList[p][1]
2530 2546 ccf = data_ccf[p,0,:,:]/numpy.sqrt(data_acf[ch0,0,:,:]*data_acf[ch1,0,:,:])
2531 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
2532 # phase1[p,:,:] = numpy.angle(ccf) #median filter
2533 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
2534 # coh1[p,:,:] = numpy.abs(ccf) #median filter
2547 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
2548 # phase1[p,:,:] = numpy.angle(ccf) #median filter
2549 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
2550 # coh1[p,:,:] = numpy.abs(ccf) #median filter
2535 2551 coh = numpy.nanmax(coh1, axis = 0)
2536 2552 # struc = numpy.ones((5,1))
2537 2553 # coh = ndimage.morphology.grey_dilation(coh, size=(10,1))
2538 2554 #---------------------- Radial Velocity ----------------------------
2539 2555 phaseAux = numpy.mean(numpy.angle(data_acf[:,1,:,:]), axis = 0)
2540 2556 velRad = phaseAux*lamb/(4*numpy.pi*tSamp)
2541
2557
2542 2558 if allData:
2543 2559 boolMetFin = ~numpy.isnan(SNRm)
2544 2560 # coh[:-1,:] = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2545 2561 else:
2546 2562 #------------------------ Meteor mask ---------------------------------
2547 2563 # #SNR mask
2548 2564 # boolMet = (SNRdB>SNRthresh)#|(~numpy.isnan(SNRdB))
2549 #
2565 #
2550 2566 # #Erase small objects
2551 # boolMet1 = self.__erase_small(boolMet, 2*sec, 5)
2552 #
2567 # boolMet1 = self.__erase_small(boolMet, 2*sec, 5)
2568 #
2553 2569 # auxEEJ = numpy.sum(boolMet1,axis=0)
2554 2570 # indOver = auxEEJ>nProfiles*0.8 #Use this later
2555 2571 # indEEJ = numpy.where(indOver)[0]
2556 2572 # indNEEJ = numpy.where(~indOver)[0]
2557 #
2573 #
2558 2574 # boolMetFin = boolMet1
2559 #
2575 #
2560 2576 # if indEEJ.size > 0:
2561 # boolMet1[:,indEEJ] = False #Erase heights with EEJ
2562 #
2577 # boolMet1[:,indEEJ] = False #Erase heights with EEJ
2578 #
2563 2579 # boolMet2 = coh > cohThresh
2564 2580 # boolMet2 = self.__erase_small(boolMet2, 2*sec,5)
2565 #
2581 #
2566 2582 # #Final Meteor mask
2567 2583 # boolMetFin = boolMet1|boolMet2
2568
2584
2569 2585 #Coherence mask
2570 2586 boolMet1 = coh > 0.75
2571 2587 struc = numpy.ones((30,1))
2572 2588 boolMet1 = ndimage.morphology.binary_dilation(boolMet1, structure=struc)
2573
2589
2574 2590 #Derivative mask
2575 2591 derPhase = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2576 2592 boolMet2 = derPhase < 0.2
2577 2593 # boolMet2 = ndimage.morphology.binary_opening(boolMet2)
2578 2594 # boolMet2 = ndimage.morphology.binary_closing(boolMet2, structure = numpy.ones((10,1)))
2579 2595 boolMet2 = ndimage.median_filter(boolMet2,size=5)
2580 2596 boolMet2 = numpy.vstack((boolMet2,numpy.full((1,nHeights), True, dtype=bool)))
2581 2597 # #Final mask
2582 2598 # boolMetFin = boolMet2
2583 2599 boolMetFin = boolMet1&boolMet2
2584 2600 # boolMetFin = ndimage.morphology.binary_dilation(boolMetFin)
2585 2601 #Creating data_param
2586 2602 coordMet = numpy.where(boolMetFin)
2587 2603
2588 2604 tmet = coordMet[0]
2589 2605 hmet = coordMet[1]
2590
2606
2591 2607 data_param = numpy.zeros((tmet.size, 6 + nPairs))
2592 2608 data_param[:,0] = utctime
2593 2609 data_param[:,1] = tmet
2594 2610 data_param[:,2] = hmet
2595 2611 data_param[:,3] = SNRm[tmet,hmet]
2596 2612 data_param[:,4] = velRad[tmet,hmet]
2597 2613 data_param[:,5] = coh[tmet,hmet]
2598 2614 data_param[:,6:] = phase[:,tmet,hmet].T
2599
2615
2600 2616 elif mode == 'DBS':
2601 2617 dataOut.groupList = numpy.arange(nChannels)
2602 2618
2603 2619 #Radial Velocities
2604 2620 phase = numpy.angle(data_acf[:,1,:,:])
2605 2621 # phase = ndimage.median_filter(numpy.angle(data_acf[:,1,:,:]), size = (1,5,1))
2606 2622 velRad = phase*lamb/(4*numpy.pi*tSamp)
2607
2623
2608 2624 #Spectral width
2609 2625 # acf1 = ndimage.median_filter(numpy.abs(data_acf[:,1,:,:]), size = (1,5,1))
2610 2626 # acf2 = ndimage.median_filter(numpy.abs(data_acf[:,2,:,:]), size = (1,5,1))
2611 2627 acf1 = data_acf[:,1,:,:]
2612 2628 acf2 = data_acf[:,2,:,:]
2613 2629
2614 2630 spcWidth = (lamb/(2*numpy.sqrt(6)*numpy.pi*tSamp))*numpy.sqrt(numpy.log(acf1/acf2))
2615 2631 # velRad = ndimage.median_filter(velRad, size = (1,5,1))
2616 2632 if allData:
2617 2633 boolMetFin = ~numpy.isnan(SNRdB)
2618 2634 else:
2619 2635 #SNR
2620 2636 boolMet1 = (SNRdB>SNRthresh) #SNR mask
2621 2637 boolMet1 = ndimage.median_filter(boolMet1, size=(1,5,5))
2622
2638
2623 2639 #Radial velocity
2624 2640 boolMet2 = numpy.abs(velRad) < 20
2625 2641 boolMet2 = ndimage.median_filter(boolMet2, (1,5,5))
2626
2642
2627 2643 #Spectral Width
2628 2644 boolMet3 = spcWidth < 30
2629 2645 boolMet3 = ndimage.median_filter(boolMet3, (1,5,5))
2630 2646 # boolMetFin = self.__erase_small(boolMet1, 10,5)
2631 2647 boolMetFin = boolMet1&boolMet2&boolMet3
2632
2648
2633 2649 #Creating data_param
2634 2650 coordMet = numpy.where(boolMetFin)
2635 2651
2636 2652 cmet = coordMet[0]
2637 2653 tmet = coordMet[1]
2638 2654 hmet = coordMet[2]
2639
2655
2640 2656 data_param = numpy.zeros((tmet.size, 7))
2641 2657 data_param[:,0] = utctime
2642 2658 data_param[:,1] = cmet
2643 2659 data_param[:,2] = tmet
2644 2660 data_param[:,3] = hmet
2645 2661 data_param[:,4] = SNR[cmet,tmet,hmet].T
2646 2662 data_param[:,5] = velRad[cmet,tmet,hmet].T
2647 2663 data_param[:,6] = spcWidth[cmet,tmet,hmet].T
2648
2664
2649 2665 # self.dataOut.data_param = data_int
2650 2666 if len(data_param) == 0:
2651 2667 dataOut.flagNoData = True
2652 2668 else:
2653 2669 dataOut.data_param = data_param
2654 2670
2655 2671 def __erase_small(self, binArray, threshX, threshY):
2656 2672 labarray, numfeat = ndimage.measurements.label(binArray)
2657 2673 binArray1 = numpy.copy(binArray)
2658
2674
2659 2675 for i in range(1,numfeat + 1):
2660 2676 auxBin = (labarray==i)
2661 2677 auxSize = auxBin.sum()
2662
2678
2663 2679 x,y = numpy.where(auxBin)
2664 2680 widthX = x.max() - x.min()
2665 2681 widthY = y.max() - y.min()
2666
2682
2667 2683 #width X: 3 seg -> 12.5*3
2668 #width Y:
2669
2684 #width Y:
2685
2670 2686 if (auxSize < 50) or (widthX < threshX) or (widthY < threshY):
2671 2687 binArray1[auxBin] = False
2672
2688
2673 2689 return binArray1
2674 2690
2675 2691 #--------------- Specular Meteor ----------------
2676 2692
2677 2693 class SMDetection(Operation):
2678 2694 '''
2679 2695 Function DetectMeteors()
2680 2696 Project developed with paper:
2681 2697 HOLDSWORTH ET AL. 2004
2682
2698
2683 2699 Input:
2684 2700 self.dataOut.data_pre
2685
2701
2686 2702 centerReceiverIndex: From the channels, which is the center receiver
2687
2703
2688 2704 hei_ref: Height reference for the Beacon signal extraction
2689 2705 tauindex:
2690 2706 predefinedPhaseShifts: Predefined phase offset for the voltge signals
2691
2707
2692 2708 cohDetection: Whether to user Coherent detection or not
2693 2709 cohDet_timeStep: Coherent Detection calculation time step
2694 2710 cohDet_thresh: Coherent Detection phase threshold to correct phases
2695
2711
2696 2712 noise_timeStep: Noise calculation time step
2697 2713 noise_multiple: Noise multiple to define signal threshold
2698
2714
2699 2715 multDet_timeLimit: Multiple Detection Removal time limit in seconds
2700 2716 multDet_rangeLimit: Multiple Detection Removal range limit in km
2701
2717
2702 2718 phaseThresh: Maximum phase difference between receiver to be consider a meteor
2703 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
2704
2719 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
2720
2705 2721 hmin: Minimum Height of the meteor to use it in the further wind estimations
2706 2722 hmax: Maximum Height of the meteor to use it in the further wind estimations
2707 2723 azimuth: Azimuth angle correction
2708
2724
2709 2725 Affected:
2710 2726 self.dataOut.data_param
2711
2727
2712 2728 Rejection Criteria (Errors):
2713 2729 0: No error; analysis OK
2714 2730 1: SNR < SNR threshold
2715 2731 2: angle of arrival (AOA) ambiguously determined
2716 2732 3: AOA estimate not feasible
2717 2733 4: Large difference in AOAs obtained from different antenna baselines
2718 2734 5: echo at start or end of time series
2719 2735 6: echo less than 5 examples long; too short for analysis
2720 2736 7: echo rise exceeds 0.3s
2721 2737 8: echo decay time less than twice rise time
2722 2738 9: large power level before echo
2723 2739 10: large power level after echo
2724 2740 11: poor fit to amplitude for estimation of decay time
2725 2741 12: poor fit to CCF phase variation for estimation of radial drift velocity
2726 2742 13: height unresolvable echo: not valid height within 70 to 110 km
2727 2743 14: height ambiguous echo: more then one possible height within 70 to 110 km
2728 2744 15: radial drift velocity or projected horizontal velocity exceeds 200 m/s
2729 2745 16: oscilatory echo, indicating event most likely not an underdense echo
2730
2746
2731 2747 17: phase difference in meteor Reestimation
2732
2748
2733 2749 Data Storage:
2734 2750 Meteors for Wind Estimation (8):
2735 2751 Utc Time | Range Height
2736 2752 Azimuth Zenith errorCosDir
2737 2753 VelRad errorVelRad
2738 2754 Phase0 Phase1 Phase2 Phase3
2739 2755 TypeError
2740
2741 '''
2742
2756
2757 '''
2758
2743 2759 def run(self, dataOut, hei_ref = None, tauindex = 0,
2744 2760 phaseOffsets = None,
2745 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
2761 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
2746 2762 noise_timeStep = 4, noise_multiple = 4,
2747 2763 multDet_timeLimit = 1, multDet_rangeLimit = 3,
2748 2764 phaseThresh = 20, SNRThresh = 5,
2749 2765 hmin = 50, hmax=150, azimuth = 0,
2750 2766 channelPositions = None) :
2751
2752
2767
2768
2753 2769 #Getting Pairslist
2754 2770 if channelPositions is None:
2755 2771 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
2756 2772 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
2757 2773 meteorOps = SMOperations()
2758 2774 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
2759 2775 heiRang = dataOut.getHeiRange()
2760 2776 #Get Beacon signal - No Beacon signal anymore
2761 2777 # newheis = numpy.where(self.dataOut.heightList>self.dataOut.radarControllerHeaderObj.Taus[tauindex])
2762 #
2778 #
2763 2779 # if hei_ref != None:
2764 2780 # newheis = numpy.where(self.dataOut.heightList>hei_ref)
2765 #
2766
2767
2781 #
2782
2783
2768 2784 #****************REMOVING HARDWARE PHASE DIFFERENCES***************
2769 2785 # see if the user put in pre defined phase shifts
2770 2786 voltsPShift = dataOut.data_pre.copy()
2771
2787
2772 2788 # if predefinedPhaseShifts != None:
2773 2789 # hardwarePhaseShifts = numpy.array(predefinedPhaseShifts)*numpy.pi/180
2774 #
2790 #
2775 2791 # # elif beaconPhaseShifts:
2776 2792 # # #get hardware phase shifts using beacon signal
2777 2793 # # hardwarePhaseShifts = self.__getHardwarePhaseDiff(self.dataOut.data_pre, pairslist, newheis, 10)
2778 2794 # # hardwarePhaseShifts = numpy.insert(hardwarePhaseShifts,centerReceiverIndex,0)
2779 #
2795 #
2780 2796 # else:
2781 # hardwarePhaseShifts = numpy.zeros(5)
2782 #
2797 # hardwarePhaseShifts = numpy.zeros(5)
2798 #
2783 2799 # voltsPShift = numpy.zeros((self.dataOut.data_pre.shape[0],self.dataOut.data_pre.shape[1],self.dataOut.data_pre.shape[2]), dtype = 'complex')
2784 2800 # for i in range(self.dataOut.data_pre.shape[0]):
2785 2801 # voltsPShift[i,:,:] = self.__shiftPhase(self.dataOut.data_pre[i,:,:], hardwarePhaseShifts[i])
2786 2802
2787 2803 #******************END OF REMOVING HARDWARE PHASE DIFFERENCES*********
2788
2804
2789 2805 #Remove DC
2790 2806 voltsDC = numpy.mean(voltsPShift,1)
2791 2807 voltsDC = numpy.mean(voltsDC,1)
2792 2808 for i in range(voltsDC.shape[0]):
2793 2809 voltsPShift[i] = voltsPShift[i] - voltsDC[i]
2794
2795 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
2810
2811 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
2796 2812 # voltsPShift = voltsPShift[:,:,:newheis[0][0]]
2797
2813
2798 2814 #************ FIND POWER OF DATA W/COH OR NON COH DETECTION (3.4) **********
2799 2815 #Coherent Detection
2800 2816 if cohDetection:
2801 2817 #use coherent detection to get the net power
2802 2818 cohDet_thresh = cohDet_thresh*numpy.pi/180
2803 2819 voltsPShift = self.__coherentDetection(voltsPShift, cohDet_timeStep, dataOut.timeInterval, pairslist0, cohDet_thresh)
2804
2820
2805 2821 #Non-coherent detection!
2806 2822 powerNet = numpy.nansum(numpy.abs(voltsPShift[:,:,:])**2,0)
2807 2823 #********** END OF COH/NON-COH POWER CALCULATION**********************
2808
2824
2809 2825 #********** FIND THE NOISE LEVEL AND POSSIBLE METEORS ****************
2810 2826 #Get noise
2811 2827 noise, noise1 = self.__getNoise(powerNet, noise_timeStep, dataOut.timeInterval)
2812 2828 # noise = self.getNoise1(powerNet, noise_timeStep, self.dataOut.timeInterval)
2813 2829 #Get signal threshold
2814 2830 signalThresh = noise_multiple*noise
2815 2831 #Meteor echoes detection
2816 2832 listMeteors = self.__findMeteors(powerNet, signalThresh)
2817 2833 #******* END OF NOISE LEVEL AND POSSIBLE METEORS CACULATION **********
2818
2834
2819 2835 #************** REMOVE MULTIPLE DETECTIONS (3.5) ***************************
2820 2836 #Parameters
2821 2837 heiRange = dataOut.getHeiRange()
2822 2838 rangeInterval = heiRange[1] - heiRange[0]
2823 2839 rangeLimit = multDet_rangeLimit/rangeInterval
2824 2840 timeLimit = multDet_timeLimit/dataOut.timeInterval
2825 2841 #Multiple detection removals
2826 2842 listMeteors1 = self.__removeMultipleDetections(listMeteors, rangeLimit, timeLimit)
2827 2843 #************ END OF REMOVE MULTIPLE DETECTIONS **********************
2828
2844
2829 2845 #********************* METEOR REESTIMATION (3.7, 3.8, 3.9, 3.10) ********************
2830 2846 #Parameters
2831 2847 phaseThresh = phaseThresh*numpy.pi/180
2832 2848 thresh = [phaseThresh, noise_multiple, SNRThresh]
2833 2849 #Meteor reestimation (Errors N 1, 6, 12, 17)
2834 2850 listMeteors2, listMeteorsPower, listMeteorsVolts = self.__meteorReestimation(listMeteors1, voltsPShift, pairslist0, thresh, noise, dataOut.timeInterval, dataOut.frequency)
2835 2851 # listMeteors2, listMeteorsPower, listMeteorsVolts = self.meteorReestimation3(listMeteors2, listMeteorsPower, listMeteorsVolts, voltsPShift, pairslist, thresh, noise)
2836 2852 #Estimation of decay times (Errors N 7, 8, 11)
2837 2853 listMeteors3 = self.__estimateDecayTime(listMeteors2, listMeteorsPower, dataOut.timeInterval, dataOut.frequency)
2838 2854 #******************* END OF METEOR REESTIMATION *******************
2839
2855
2840 2856 #********************* METEOR PARAMETERS CALCULATION (3.11, 3.12, 3.13) **************************
2841 2857 #Calculating Radial Velocity (Error N 15)
2842 2858 radialStdThresh = 10
2843 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
2859 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
2844 2860
2845 2861 if len(listMeteors4) > 0:
2846 2862 #Setting New Array
2847 2863 date = dataOut.utctime
2848 2864 arrayParameters = self.__setNewArrays(listMeteors4, date, heiRang)
2849
2865
2850 2866 #Correcting phase offset
2851 2867 if phaseOffsets != None:
2852 2868 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
2853 2869 arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
2854
2870
2855 2871 #Second Pairslist
2856 2872 pairsList = []
2857 2873 pairx = (0,1)
2858 2874 pairy = (2,3)
2859 2875 pairsList.append(pairx)
2860 2876 pairsList.append(pairy)
2861
2877
2862 2878 jph = numpy.array([0,0,0,0])
2863 2879 h = (hmin,hmax)
2864 2880 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
2865
2881
2866 2882 # #Calculate AOA (Error N 3, 4)
2867 2883 # #JONES ET AL. 1998
2868 2884 # error = arrayParameters[:,-1]
2869 2885 # AOAthresh = numpy.pi/8
2870 2886 # phases = -arrayParameters[:,9:13]
2871 2887 # arrayParameters[:,4:7], arrayParameters[:,-1] = meteorOps.getAOA(phases, pairsList, error, AOAthresh, azimuth)
2872 #
2888 #
2873 2889 # #Calculate Heights (Error N 13 and 14)
2874 2890 # error = arrayParameters[:,-1]
2875 2891 # Ranges = arrayParameters[:,2]
2876 2892 # zenith = arrayParameters[:,5]
2877 2893 # arrayParameters[:,3], arrayParameters[:,-1] = meteorOps.getHeights(Ranges, zenith, error, hmin, hmax)
2878 2894 # error = arrayParameters[:,-1]
2879 2895 #********************* END OF PARAMETERS CALCULATION **************************
2880
2881 #***************************+ PASS DATA TO NEXT STEP **********************
2896
2897 #***************************+ PASS DATA TO NEXT STEP **********************
2882 2898 # arrayFinal = arrayParameters.reshape((1,arrayParameters.shape[0],arrayParameters.shape[1]))
2883 2899 dataOut.data_param = arrayParameters
2884
2900
2885 2901 if arrayParameters is None:
2886 2902 dataOut.flagNoData = True
2887 2903 else:
2888 2904 dataOut.flagNoData = True
2889
2905
2890 2906 return
2891
2907
2892 2908 def __getHardwarePhaseDiff(self, voltage0, pairslist, newheis, n):
2893
2909
2894 2910 minIndex = min(newheis[0])
2895 2911 maxIndex = max(newheis[0])
2896
2912
2897 2913 voltage = voltage0[:,:,minIndex:maxIndex+1]
2898 2914 nLength = voltage.shape[1]/n
2899 2915 nMin = 0
2900 2916 nMax = 0
2901 2917 phaseOffset = numpy.zeros((len(pairslist),n))
2902
2918
2903 2919 for i in range(n):
2904 2920 nMax += nLength
2905 2921 phaseCCF = -numpy.angle(self.__calculateCCF(voltage[:,nMin:nMax,:], pairslist, [0]))
2906 2922 phaseCCF = numpy.mean(phaseCCF, axis = 2)
2907 phaseOffset[:,i] = phaseCCF.transpose()
2923 phaseOffset[:,i] = phaseCCF.transpose()
2908 2924 nMin = nMax
2909 2925 # phaseDiff, phaseArrival = self.estimatePhaseDifference(voltage, pairslist)
2910
2926
2911 2927 #Remove Outliers
2912 2928 factor = 2
2913 2929 wt = phaseOffset - signal.medfilt(phaseOffset,(1,5))
2914 2930 dw = numpy.std(wt,axis = 1)
2915 2931 dw = dw.reshape((dw.size,1))
2916 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
2932 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
2917 2933 phaseOffset[ind] = numpy.nan
2918 phaseOffset = stats.nanmean(phaseOffset, axis=1)
2919
2934 phaseOffset = stats.nanmean(phaseOffset, axis=1)
2935
2920 2936 return phaseOffset
2921
2937
2922 2938 def __shiftPhase(self, data, phaseShift):
2923 2939 #this will shift the phase of a complex number
2924 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
2940 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
2925 2941 return dataShifted
2926
2942
2927 2943 def __estimatePhaseDifference(self, array, pairslist):
2928 2944 nChannel = array.shape[0]
2929 2945 nHeights = array.shape[2]
2930 2946 numPairs = len(pairslist)
2931 2947 # phaseCCF = numpy.zeros((nChannel, 5, nHeights))
2932 2948 phaseCCF = numpy.angle(self.__calculateCCF(array, pairslist, [-2,-1,0,1,2]))
2933
2949
2934 2950 #Correct phases
2935 2951 derPhaseCCF = phaseCCF[:,1:,:] - phaseCCF[:,0:-1,:]
2936 2952 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
2937
2938 if indDer[0].shape[0] > 0:
2953
2954 if indDer[0].shape[0] > 0:
2939 2955 for i in range(indDer[0].shape[0]):
2940 2956 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i],indDer[2][i]])
2941 2957 phaseCCF[indDer[0][i],indDer[1][i]+1:,:] += signo*2*numpy.pi
2942
2958
2943 2959 # for j in range(numSides):
2944 2960 # phaseCCFAux = self.calculateCCF(arrayCenter, arraySides[j,:,:], [-2,1,0,1,2])
2945 2961 # phaseCCF[j,:,:] = numpy.angle(phaseCCFAux)
2946 #
2962 #
2947 2963 #Linear
2948 2964 phaseInt = numpy.zeros((numPairs,1))
2949 2965 angAllCCF = phaseCCF[:,[0,1,3,4],0]
2950 2966 for j in range(numPairs):
2951 2967 fit = stats.linregress([-2,-1,1,2],angAllCCF[j,:])
2952 2968 phaseInt[j] = fit[1]
2953 2969 #Phase Differences
2954 2970 phaseDiff = phaseInt - phaseCCF[:,2,:]
2955 2971 phaseArrival = phaseInt.reshape(phaseInt.size)
2956
2972
2957 2973 #Dealias
2958 2974 phaseArrival = numpy.angle(numpy.exp(1j*phaseArrival))
2959 2975 # indAlias = numpy.where(phaseArrival > numpy.pi)
2960 2976 # phaseArrival[indAlias] -= 2*numpy.pi
2961 2977 # indAlias = numpy.where(phaseArrival < -numpy.pi)
2962 2978 # phaseArrival[indAlias] += 2*numpy.pi
2963
2979
2964 2980 return phaseDiff, phaseArrival
2965
2981
2966 2982 def __coherentDetection(self, volts, timeSegment, timeInterval, pairslist, thresh):
2967 2983 #this function will run the coherent detection used in Holdworth et al. 2004 and return the net power
2968 2984 #find the phase shifts of each channel over 1 second intervals
2969 2985 #only look at ranges below the beacon signal
2970 2986 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
2971 2987 numBlocks = int(volts.shape[1]/numProfPerBlock)
2972 2988 numHeights = volts.shape[2]
2973 2989 nChannel = volts.shape[0]
2974 2990 voltsCohDet = volts.copy()
2975
2991
2976 2992 pairsarray = numpy.array(pairslist)
2977 2993 indSides = pairsarray[:,1]
2978 2994 # indSides = numpy.array(range(nChannel))
2979 2995 # indSides = numpy.delete(indSides, indCenter)
2980 #
2996 #
2981 2997 # listCenter = numpy.array_split(volts[indCenter,:,:], numBlocks, 0)
2982 2998 listBlocks = numpy.array_split(volts, numBlocks, 1)
2983
2999
2984 3000 startInd = 0
2985 3001 endInd = 0
2986
3002
2987 3003 for i in range(numBlocks):
2988 3004 startInd = endInd
2989 endInd = endInd + listBlocks[i].shape[1]
2990
3005 endInd = endInd + listBlocks[i].shape[1]
3006
2991 3007 arrayBlock = listBlocks[i]
2992 3008 # arrayBlockCenter = listCenter[i]
2993
3009
2994 3010 #Estimate the Phase Difference
2995 3011 phaseDiff, aux = self.__estimatePhaseDifference(arrayBlock, pairslist)
2996 3012 #Phase Difference RMS
2997 3013 arrayPhaseRMS = numpy.abs(phaseDiff)
2998 3014 phaseRMSaux = numpy.sum(arrayPhaseRMS < thresh,0)
2999 3015 indPhase = numpy.where(phaseRMSaux==4)
3000 3016 #Shifting
3001 3017 if indPhase[0].shape[0] > 0:
3002 3018 for j in range(indSides.size):
3003 3019 arrayBlock[indSides[j],:,indPhase] = self.__shiftPhase(arrayBlock[indSides[j],:,indPhase], phaseDiff[j,indPhase].transpose())
3004 3020 voltsCohDet[:,startInd:endInd,:] = arrayBlock
3005
3021
3006 3022 return voltsCohDet
3007
3023
3008 3024 def __calculateCCF(self, volts, pairslist ,laglist):
3009
3025
3010 3026 nHeights = volts.shape[2]
3011 nPoints = volts.shape[1]
3027 nPoints = volts.shape[1]
3012 3028 voltsCCF = numpy.zeros((len(pairslist), len(laglist), nHeights),dtype = 'complex')
3013
3029
3014 3030 for i in range(len(pairslist)):
3015 3031 volts1 = volts[pairslist[i][0]]
3016 volts2 = volts[pairslist[i][1]]
3017
3032 volts2 = volts[pairslist[i][1]]
3033
3018 3034 for t in range(len(laglist)):
3019 idxT = laglist[t]
3035 idxT = laglist[t]
3020 3036 if idxT >= 0:
3021 3037 vStacked = numpy.vstack((volts2[idxT:,:],
3022 3038 numpy.zeros((idxT, nHeights),dtype='complex')))
3023 3039 else:
3024 3040 vStacked = numpy.vstack((numpy.zeros((-idxT, nHeights),dtype='complex'),
3025 3041 volts2[:(nPoints + idxT),:]))
3026 3042 voltsCCF[i,t,:] = numpy.sum((numpy.conjugate(volts1)*vStacked),axis=0)
3027
3043
3028 3044 vStacked = None
3029 3045 return voltsCCF
3030
3046
3031 3047 def __getNoise(self, power, timeSegment, timeInterval):
3032 3048 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
3033 3049 numBlocks = int(power.shape[0]/numProfPerBlock)
3034 3050 numHeights = power.shape[1]
3035 3051
3036 3052 listPower = numpy.array_split(power, numBlocks, 0)
3037 3053 noise = numpy.zeros((power.shape[0], power.shape[1]))
3038 3054 noise1 = numpy.zeros((power.shape[0], power.shape[1]))
3039
3055
3040 3056 startInd = 0
3041 3057 endInd = 0
3042
3058
3043 3059 for i in range(numBlocks): #split por canal
3044 3060 startInd = endInd
3045 endInd = endInd + listPower[i].shape[0]
3046
3061 endInd = endInd + listPower[i].shape[0]
3062
3047 3063 arrayBlock = listPower[i]
3048 3064 noiseAux = numpy.mean(arrayBlock, 0)
3049 3065 # noiseAux = numpy.median(noiseAux)
3050 3066 # noiseAux = numpy.mean(arrayBlock)
3051 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
3052
3067 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
3068
3053 3069 noiseAux1 = numpy.mean(arrayBlock)
3054 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
3055
3070 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
3071
3056 3072 return noise, noise1
3057
3073
3058 3074 def __findMeteors(self, power, thresh):
3059 3075 nProf = power.shape[0]
3060 3076 nHeights = power.shape[1]
3061 3077 listMeteors = []
3062
3078
3063 3079 for i in range(nHeights):
3064 3080 powerAux = power[:,i]
3065 3081 threshAux = thresh[:,i]
3066
3082
3067 3083 indUPthresh = numpy.where(powerAux > threshAux)[0]
3068 3084 indDNthresh = numpy.where(powerAux <= threshAux)[0]
3069
3085
3070 3086 j = 0
3071
3087
3072 3088 while (j < indUPthresh.size - 2):
3073 3089 if (indUPthresh[j + 2] == indUPthresh[j] + 2):
3074 3090 indDNAux = numpy.where(indDNthresh > indUPthresh[j])
3075 3091 indDNthresh = indDNthresh[indDNAux]
3076
3092
3077 3093 if (indDNthresh.size > 0):
3078 3094 indEnd = indDNthresh[0] - 1
3079 3095 indInit = indUPthresh[j]
3080
3096
3081 3097 meteor = powerAux[indInit:indEnd + 1]
3082 3098 indPeak = meteor.argmax() + indInit
3083 3099 FLA = sum(numpy.conj(meteor)*numpy.hstack((meteor[1:],0)))
3084
3100
3085 3101 listMeteors.append(numpy.array([i,indInit,indPeak,indEnd,FLA])) #CHEQUEAR!!!!!
3086 3102 j = numpy.where(indUPthresh == indEnd)[0] + 1
3087 3103 else: j+=1
3088 3104 else: j+=1
3089
3105
3090 3106 return listMeteors
3091
3107
3092 3108 def __removeMultipleDetections(self,listMeteors, rangeLimit, timeLimit):
3093
3094 arrayMeteors = numpy.asarray(listMeteors)
3109
3110 arrayMeteors = numpy.asarray(listMeteors)
3095 3111 listMeteors1 = []
3096
3112
3097 3113 while arrayMeteors.shape[0] > 0:
3098 3114 FLAs = arrayMeteors[:,4]
3099 3115 maxFLA = FLAs.argmax()
3100 3116 listMeteors1.append(arrayMeteors[maxFLA,:])
3101
3117
3102 3118 MeteorInitTime = arrayMeteors[maxFLA,1]
3103 3119 MeteorEndTime = arrayMeteors[maxFLA,3]
3104 3120 MeteorHeight = arrayMeteors[maxFLA,0]
3105
3121
3106 3122 #Check neighborhood
3107 3123 maxHeightIndex = MeteorHeight + rangeLimit
3108 3124 minHeightIndex = MeteorHeight - rangeLimit
3109 3125 minTimeIndex = MeteorInitTime - timeLimit
3110 3126 maxTimeIndex = MeteorEndTime + timeLimit
3111
3127
3112 3128 #Check Heights
3113 3129 indHeight = numpy.logical_and(arrayMeteors[:,0] >= minHeightIndex, arrayMeteors[:,0] <= maxHeightIndex)
3114 3130 indTime = numpy.logical_and(arrayMeteors[:,3] >= minTimeIndex, arrayMeteors[:,1] <= maxTimeIndex)
3115 3131 indBoth = numpy.where(numpy.logical_and(indTime,indHeight))
3116
3132
3117 3133 arrayMeteors = numpy.delete(arrayMeteors, indBoth, axis = 0)
3118
3134
3119 3135 return listMeteors1
3120
3136
3121 3137 def __meteorReestimation(self, listMeteors, volts, pairslist, thresh, noise, timeInterval,frequency):
3122 3138 numHeights = volts.shape[2]
3123 3139 nChannel = volts.shape[0]
3124
3140
3125 3141 thresholdPhase = thresh[0]
3126 3142 thresholdNoise = thresh[1]
3127 3143 thresholdDB = float(thresh[2])
3128
3144
3129 3145 thresholdDB1 = 10**(thresholdDB/10)
3130 3146 pairsarray = numpy.array(pairslist)
3131 3147 indSides = pairsarray[:,1]
3132
3148
3133 3149 pairslist1 = list(pairslist)
3134 3150 pairslist1.append((0,1))
3135 3151 pairslist1.append((3,4))
3136 3152
3137 3153 listMeteors1 = []
3138 3154 listPowerSeries = []
3139 3155 listVoltageSeries = []
3140 3156 #volts has the war data
3141
3157
3142 3158 if frequency == 30e6:
3143 3159 timeLag = 45*10**-3
3144 3160 else:
3145 3161 timeLag = 15*10**-3
3146 3162 lag = numpy.ceil(timeLag/timeInterval)
3147
3163
3148 3164 for i in range(len(listMeteors)):
3149
3165
3150 3166 ###################### 3.6 - 3.7 PARAMETERS REESTIMATION #########################
3151 3167 meteorAux = numpy.zeros(16)
3152
3168
3153 3169 #Loading meteor Data (mHeight, mStart, mPeak, mEnd)
3154 3170 mHeight = listMeteors[i][0]
3155 3171 mStart = listMeteors[i][1]
3156 3172 mPeak = listMeteors[i][2]
3157 3173 mEnd = listMeteors[i][3]
3158
3174
3159 3175 #get the volt data between the start and end times of the meteor
3160 3176 meteorVolts = volts[:,mStart:mEnd+1,mHeight]
3161 3177 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3162
3178
3163 3179 #3.6. Phase Difference estimation
3164 3180 phaseDiff, aux = self.__estimatePhaseDifference(meteorVolts, pairslist)
3165
3181
3166 3182 #3.7. Phase difference removal & meteor start, peak and end times reestimated
3167 3183 #meteorVolts0.- all Channels, all Profiles
3168 3184 meteorVolts0 = volts[:,:,mHeight]
3169 3185 meteorThresh = noise[:,mHeight]*thresholdNoise
3170 3186 meteorNoise = noise[:,mHeight]
3171 3187 meteorVolts0[indSides,:] = self.__shiftPhase(meteorVolts0[indSides,:], phaseDiff) #Phase Shifting
3172 3188 powerNet0 = numpy.nansum(numpy.abs(meteorVolts0)**2, axis = 0) #Power
3173
3189
3174 3190 #Times reestimation
3175 3191 mStart1 = numpy.where(powerNet0[:mPeak] < meteorThresh[:mPeak])[0]
3176 3192 if mStart1.size > 0:
3177 3193 mStart1 = mStart1[-1] + 1
3178
3179 else:
3194
3195 else:
3180 3196 mStart1 = mPeak
3181
3197
3182 3198 mEnd1 = numpy.where(powerNet0[mPeak:] < meteorThresh[mPeak:])[0][0] + mPeak - 1
3183 3199 mEndDecayTime1 = numpy.where(powerNet0[mPeak:] < meteorNoise[mPeak:])[0]
3184 3200 if mEndDecayTime1.size == 0:
3185 3201 mEndDecayTime1 = powerNet0.size
3186 3202 else:
3187 3203 mEndDecayTime1 = mEndDecayTime1[0] + mPeak - 1
3188 3204 # mPeak1 = meteorVolts0[mStart1:mEnd1 + 1].argmax()
3189
3205
3190 3206 #meteorVolts1.- all Channels, from start to end
3191 3207 meteorVolts1 = meteorVolts0[:,mStart1:mEnd1 + 1]
3192 3208 meteorVolts2 = meteorVolts0[:,mPeak + lag:mEnd1 + 1]
3193 3209 if meteorVolts2.shape[1] == 0:
3194 3210 meteorVolts2 = meteorVolts0[:,mPeak:mEnd1 + 1]
3195 3211 meteorVolts1 = meteorVolts1.reshape(meteorVolts1.shape[0], meteorVolts1.shape[1], 1)
3196 3212 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1], 1)
3197 3213 ##################### END PARAMETERS REESTIMATION #########################
3198
3214
3199 3215 ##################### 3.8 PHASE DIFFERENCE REESTIMATION ########################
3200 3216 # if mEnd1 - mStart1 > 4: #Error Number 6: echo less than 5 samples long; too short for analysis
3201 if meteorVolts2.shape[1] > 0:
3217 if meteorVolts2.shape[1] > 0:
3202 3218 #Phase Difference re-estimation
3203 3219 phaseDiff1, phaseDiffint = self.__estimatePhaseDifference(meteorVolts2, pairslist1) #Phase Difference Estimation
3204 3220 # phaseDiff1, phaseDiffint = self.estimatePhaseDifference(meteorVolts2, pairslist)
3205 3221 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1])
3206 3222 phaseDiff11 = numpy.reshape(phaseDiff1, (phaseDiff1.shape[0],1))
3207 3223 meteorVolts2[indSides,:] = self.__shiftPhase(meteorVolts2[indSides,:], phaseDiff11[0:4]) #Phase Shifting
3208
3224
3209 3225 #Phase Difference RMS
3210 3226 phaseRMS1 = numpy.sqrt(numpy.mean(numpy.square(phaseDiff1)))
3211 3227 powerNet1 = numpy.nansum(numpy.abs(meteorVolts1[:,:])**2,0)
3212 3228 #Data from Meteor
3213 3229 mPeak1 = powerNet1.argmax() + mStart1
3214 3230 mPeakPower1 = powerNet1.max()
3215 3231 noiseAux = sum(noise[mStart1:mEnd1 + 1,mHeight])
3216 3232 mSNR1 = (sum(powerNet1)-noiseAux)/noiseAux
3217 3233 Meteor1 = numpy.array([mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1])
3218 3234 Meteor1 = numpy.hstack((Meteor1,phaseDiffint))
3219 3235 PowerSeries = powerNet0[mStart1:mEndDecayTime1 + 1]
3220 3236 #Vectorize
3221 3237 meteorAux[0:7] = [mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1]
3222 3238 meteorAux[7:11] = phaseDiffint[0:4]
3223
3239
3224 3240 #Rejection Criterions
3225 3241 if phaseRMS1 > thresholdPhase: #Error Number 17: Phase variation
3226 3242 meteorAux[-1] = 17
3227 3243 elif mSNR1 < thresholdDB1: #Error Number 1: SNR < threshold dB
3228 3244 meteorAux[-1] = 1
3229
3230
3231 else:
3245
3246
3247 else:
3232 3248 meteorAux[0:4] = [mHeight, mStart, mPeak, mEnd]
3233 3249 meteorAux[-1] = 6 #Error Number 6: echo less than 5 samples long; too short for analysis
3234 3250 PowerSeries = 0
3235
3251
3236 3252 listMeteors1.append(meteorAux)
3237 3253 listPowerSeries.append(PowerSeries)
3238 3254 listVoltageSeries.append(meteorVolts1)
3239
3240 return listMeteors1, listPowerSeries, listVoltageSeries
3241
3255
3256 return listMeteors1, listPowerSeries, listVoltageSeries
3257
3242 3258 def __estimateDecayTime(self, listMeteors, listPower, timeInterval, frequency):
3243
3259
3244 3260 threshError = 10
3245 3261 #Depending if it is 30 or 50 MHz
3246 3262 if frequency == 30e6:
3247 3263 timeLag = 45*10**-3
3248 3264 else:
3249 3265 timeLag = 15*10**-3
3250 3266 lag = numpy.ceil(timeLag/timeInterval)
3251
3267
3252 3268 listMeteors1 = []
3253
3269
3254 3270 for i in range(len(listMeteors)):
3255 3271 meteorPower = listPower[i]
3256 3272 meteorAux = listMeteors[i]
3257
3273
3258 3274 if meteorAux[-1] == 0:
3259 3275
3260 try:
3276 try:
3261 3277 indmax = meteorPower.argmax()
3262 3278 indlag = indmax + lag
3263
3279
3264 3280 y = meteorPower[indlag:]
3265 3281 x = numpy.arange(0, y.size)*timeLag
3266
3282
3267 3283 #first guess
3268 3284 a = y[0]
3269 3285 tau = timeLag
3270 3286 #exponential fit
3271 3287 popt, pcov = optimize.curve_fit(self.__exponential_function, x, y, p0 = [a, tau])
3272 3288 y1 = self.__exponential_function(x, *popt)
3273 3289 #error estimation
3274 3290 error = sum((y - y1)**2)/(numpy.var(y)*(y.size - popt.size))
3275
3291
3276 3292 decayTime = popt[1]
3277 3293 riseTime = indmax*timeInterval
3278 3294 meteorAux[11:13] = [decayTime, error]
3279
3295
3280 3296 #Table items 7, 8 and 11
3281 3297 if (riseTime > 0.3): #Number 7: Echo rise exceeds 0.3s
3282 meteorAux[-1] = 7
3298 meteorAux[-1] = 7
3283 3299 elif (decayTime < 2*riseTime) : #Number 8: Echo decay time less than than twice rise time
3284 3300 meteorAux[-1] = 8
3285 3301 if (error > threshError): #Number 11: Poor fit to amplitude for estimation of decay time
3286 meteorAux[-1] = 11
3287
3288
3302 meteorAux[-1] = 11
3303
3304
3289 3305 except:
3290 meteorAux[-1] = 11
3291
3292
3306 meteorAux[-1] = 11
3307
3308
3293 3309 listMeteors1.append(meteorAux)
3294
3310
3295 3311 return listMeteors1
3296 3312
3297 3313 #Exponential Function
3298 3314
3299 3315 def __exponential_function(self, x, a, tau):
3300 3316 y = a*numpy.exp(-x/tau)
3301 3317 return y
3302
3318
3303 3319 def __getRadialVelocity(self, listMeteors, listVolts, radialStdThresh, pairslist, timeInterval):
3304
3320
3305 3321 pairslist1 = list(pairslist)
3306 3322 pairslist1.append((0,1))
3307 3323 pairslist1.append((3,4))
3308 3324 numPairs = len(pairslist1)
3309 3325 #Time Lag
3310 3326 timeLag = 45*10**-3
3311 3327 c = 3e8
3312 3328 lag = numpy.ceil(timeLag/timeInterval)
3313 3329 freq = 30e6
3314
3330
3315 3331 listMeteors1 = []
3316
3332
3317 3333 for i in range(len(listMeteors)):
3318 3334 meteorAux = listMeteors[i]
3319 3335 if meteorAux[-1] == 0:
3320 3336 mStart = listMeteors[i][1]
3321 mPeak = listMeteors[i][2]
3337 mPeak = listMeteors[i][2]
3322 3338 mLag = mPeak - mStart + lag
3323
3339
3324 3340 #get the volt data between the start and end times of the meteor
3325 3341 meteorVolts = listVolts[i]
3326 3342 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3327 3343
3328 3344 #Get CCF
3329 3345 allCCFs = self.__calculateCCF(meteorVolts, pairslist1, [-2,-1,0,1,2])
3330
3346
3331 3347 #Method 2
3332 3348 slopes = numpy.zeros(numPairs)
3333 3349 time = numpy.array([-2,-1,1,2])*timeInterval
3334 3350 angAllCCF = numpy.angle(allCCFs[:,[0,1,3,4],0])
3335
3351
3336 3352 #Correct phases
3337 3353 derPhaseCCF = angAllCCF[:,1:] - angAllCCF[:,0:-1]
3338 3354 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
3339
3340 if indDer[0].shape[0] > 0:
3355
3356 if indDer[0].shape[0] > 0:
3341 3357 for i in range(indDer[0].shape[0]):
3342 3358 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i]])
3343 3359 angAllCCF[indDer[0][i],indDer[1][i]+1:] += signo*2*numpy.pi
3344 3360
3345 3361 # fit = scipy.stats.linregress(numpy.array([-2,-1,1,2])*timeInterval, numpy.array([phaseLagN2s[i],phaseLagN1s[i],phaseLag1s[i],phaseLag2s[i]]))
3346 3362 for j in range(numPairs):
3347 3363 fit = stats.linregress(time, angAllCCF[j,:])
3348 3364 slopes[j] = fit[0]
3349
3365
3350 3366 #Remove Outlier
3351 3367 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3352 3368 # slopes = numpy.delete(slopes,indOut)
3353 3369 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3354 3370 # slopes = numpy.delete(slopes,indOut)
3355
3371
3356 3372 radialVelocity = -numpy.mean(slopes)*(0.25/numpy.pi)*(c/freq)
3357 3373 radialError = numpy.std(slopes)*(0.25/numpy.pi)*(c/freq)
3358 3374 meteorAux[-2] = radialError
3359 3375 meteorAux[-3] = radialVelocity
3360
3376
3361 3377 #Setting Error
3362 3378 #Number 15: Radial Drift velocity or projected horizontal velocity exceeds 200 m/s
3363 if numpy.abs(radialVelocity) > 200:
3379 if numpy.abs(radialVelocity) > 200:
3364 3380 meteorAux[-1] = 15
3365 3381 #Number 12: Poor fit to CCF variation for estimation of radial drift velocity
3366 3382 elif radialError > radialStdThresh:
3367 3383 meteorAux[-1] = 12
3368
3384
3369 3385 listMeteors1.append(meteorAux)
3370 3386 return listMeteors1
3371
3387
3372 3388 def __setNewArrays(self, listMeteors, date, heiRang):
3373
3389
3374 3390 #New arrays
3375 3391 arrayMeteors = numpy.array(listMeteors)
3376 3392 arrayParameters = numpy.zeros((len(listMeteors), 13))
3377
3393
3378 3394 #Date inclusion
3379 3395 # date = re.findall(r'\((.*?)\)', date)
3380 3396 # date = date[0].split(',')
3381 3397 # date = map(int, date)
3382 #
3398 #
3383 3399 # if len(date)<6:
3384 3400 # date.append(0)
3385 #
3401 #
3386 3402 # date = [date[0]*10000 + date[1]*100 + date[2], date[3]*10000 + date[4]*100 + date[5]]
3387 3403 # arrayDate = numpy.tile(date, (len(listMeteors), 1))
3388 3404 arrayDate = numpy.tile(date, (len(listMeteors)))
3389
3405
3390 3406 #Meteor array
3391 3407 # arrayMeteors[:,0] = heiRang[arrayMeteors[:,0].astype(int)]
3392 3408 # arrayMeteors = numpy.hstack((arrayDate, arrayMeteors))
3393
3409
3394 3410 #Parameters Array
3395 3411 arrayParameters[:,0] = arrayDate #Date
3396 3412 arrayParameters[:,1] = heiRang[arrayMeteors[:,0].astype(int)] #Range
3397 3413 arrayParameters[:,6:8] = arrayMeteors[:,-3:-1] #Radial velocity and its error
3398 3414 arrayParameters[:,8:12] = arrayMeteors[:,7:11] #Phases
3399 3415 arrayParameters[:,-1] = arrayMeteors[:,-1] #Error
3400 3416
3401
3417
3402 3418 return arrayParameters
3403
3419
3404 3420 class CorrectSMPhases(Operation):
3405
3421
3406 3422 def run(self, dataOut, phaseOffsets, hmin = 50, hmax = 150, azimuth = 45, channelPositions = None):
3407
3423
3408 3424 arrayParameters = dataOut.data_param
3409 3425 pairsList = []
3410 3426 pairx = (0,1)
3411 3427 pairy = (2,3)
3412 3428 pairsList.append(pairx)
3413 3429 pairsList.append(pairy)
3414 3430 jph = numpy.zeros(4)
3415
3431
3416 3432 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
3417 3433 # arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
3418 3434 arrayParameters[:,8:12] = numpy.angle(numpy.exp(1j*(arrayParameters[:,8:12] + phaseOffsets)))
3419
3435
3420 3436 meteorOps = SMOperations()
3421 3437 if channelPositions is None:
3422 3438 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3423 3439 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3424
3440
3425 3441 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3426 3442 h = (hmin,hmax)
3427
3443
3428 3444 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
3429
3445
3430 3446 dataOut.data_param = arrayParameters
3431 3447 return
3432 3448
3433 3449 class SMPhaseCalibration(Operation):
3434
3450
3435 3451 __buffer = None
3436 3452
3437 3453 __initime = None
3438 3454
3439 3455 __dataReady = False
3440
3456
3441 3457 __isConfig = False
3442
3458
3443 3459 def __checkTime(self, currentTime, initTime, paramInterval, outputInterval):
3444
3460
3445 3461 dataTime = currentTime + paramInterval
3446 3462 deltaTime = dataTime - initTime
3447
3463
3448 3464 if deltaTime >= outputInterval or deltaTime < 0:
3449 3465 return True
3450
3466
3451 3467 return False
3452
3468
3453 3469 def __getGammas(self, pairs, d, phases):
3454 3470 gammas = numpy.zeros(2)
3455
3471
3456 3472 for i in range(len(pairs)):
3457
3473
3458 3474 pairi = pairs[i]
3459 3475
3460 3476 phip3 = phases[:,pairi[0]]
3461 3477 d3 = d[pairi[0]]
3462 3478 phip2 = phases[:,pairi[1]]
3463 3479 d2 = d[pairi[1]]
3464 3480 #Calculating gamma
3465 3481 # jdcos = alp1/(k*d1)
3466 3482 # jgamma = numpy.angle(numpy.exp(1j*(d0*alp1/d1 - alp0)))
3467 3483 jgamma = -phip2*d3/d2 - phip3
3468 3484 jgamma = numpy.angle(numpy.exp(1j*jgamma))
3469 3485 # jgamma[jgamma>numpy.pi] -= 2*numpy.pi
3470 3486 # jgamma[jgamma<-numpy.pi] += 2*numpy.pi
3471
3487
3472 3488 #Revised distribution
3473 3489 jgammaArray = numpy.hstack((jgamma,jgamma+0.5*numpy.pi,jgamma-0.5*numpy.pi))
3474 3490
3475 3491 #Histogram
3476 3492 nBins = 64
3477 3493 rmin = -0.5*numpy.pi
3478 3494 rmax = 0.5*numpy.pi
3479 3495 phaseHisto = numpy.histogram(jgammaArray, bins=nBins, range=(rmin,rmax))
3480
3496
3481 3497 meteorsY = phaseHisto[0]
3482 3498 phasesX = phaseHisto[1][:-1]
3483 3499 width = phasesX[1] - phasesX[0]
3484 3500 phasesX += width/2
3485
3501
3486 3502 #Gaussian aproximation
3487 3503 bpeak = meteorsY.argmax()
3488 3504 peak = meteorsY.max()
3489 3505 jmin = bpeak - 5
3490 3506 jmax = bpeak + 5 + 1
3491
3507
3492 3508 if jmin<0:
3493 3509 jmin = 0
3494 3510 jmax = 6
3495 3511 elif jmax > meteorsY.size:
3496 3512 jmin = meteorsY.size - 6
3497 3513 jmax = meteorsY.size
3498
3514
3499 3515 x0 = numpy.array([peak,bpeak,50])
3500 3516 coeff = optimize.leastsq(self.__residualFunction, x0, args=(meteorsY[jmin:jmax], phasesX[jmin:jmax]))
3501
3517
3502 3518 #Gammas
3503 3519 gammas[i] = coeff[0][1]
3504
3520
3505 3521 return gammas
3506
3522
3507 3523 def __residualFunction(self, coeffs, y, t):
3508
3524
3509 3525 return y - self.__gauss_function(t, coeffs)
3510 3526
3511 3527 def __gauss_function(self, t, coeffs):
3512
3528
3513 3529 return coeffs[0]*numpy.exp(-0.5*((t - coeffs[1]) / coeffs[2])**2)
3514 3530
3515 3531 def __getPhases(self, azimuth, h, pairsList, d, gammas, meteorsArray):
3516 3532 meteorOps = SMOperations()
3517 3533 nchan = 4
3518 3534 pairx = pairsList[0] #x es 0
3519 3535 pairy = pairsList[1] #y es 1
3520 3536 center_xangle = 0
3521 3537 center_yangle = 0
3522 3538 range_angle = numpy.array([10*numpy.pi,numpy.pi,numpy.pi/2,numpy.pi/4])
3523 3539 ntimes = len(range_angle)
3524 3540
3525 3541 nstepsx = 20
3526 3542 nstepsy = 20
3527 3543
3528 3544 for iz in range(ntimes):
3529 3545 min_xangle = -range_angle[iz]/2 + center_xangle
3530 3546 max_xangle = range_angle[iz]/2 + center_xangle
3531 3547 min_yangle = -range_angle[iz]/2 + center_yangle
3532 3548 max_yangle = range_angle[iz]/2 + center_yangle
3533
3549
3534 3550 inc_x = (max_xangle-min_xangle)/nstepsx
3535 3551 inc_y = (max_yangle-min_yangle)/nstepsy
3536
3552
3537 3553 alpha_y = numpy.arange(nstepsy)*inc_y + min_yangle
3538 3554 alpha_x = numpy.arange(nstepsx)*inc_x + min_xangle
3539 3555 penalty = numpy.zeros((nstepsx,nstepsy))
3540 3556 jph_array = numpy.zeros((nchan,nstepsx,nstepsy))
3541 3557 jph = numpy.zeros(nchan)
3542
3558
3543 3559 # Iterations looking for the offset
3544 3560 for iy in range(int(nstepsy)):
3545 3561 for ix in range(int(nstepsx)):
3546 3562 d3 = d[pairsList[1][0]]
3547 3563 d2 = d[pairsList[1][1]]
3548 3564 d5 = d[pairsList[0][0]]
3549 3565 d4 = d[pairsList[0][1]]
3550
3566
3551 3567 alp2 = alpha_y[iy] #gamma 1
3552 alp4 = alpha_x[ix] #gamma 0
3553
3568 alp4 = alpha_x[ix] #gamma 0
3569
3554 3570 alp3 = -alp2*d3/d2 - gammas[1]
3555 3571 alp5 = -alp4*d5/d4 - gammas[0]
3556 3572 # jph[pairy[1]] = alpha_y[iy]
3557 # jph[pairy[0]] = -gammas[1] - alpha_y[iy]*d[pairy[1]]/d[pairy[0]]
3558
3573 # jph[pairy[0]] = -gammas[1] - alpha_y[iy]*d[pairy[1]]/d[pairy[0]]
3574
3559 3575 # jph[pairx[1]] = alpha_x[ix]
3560 3576 # jph[pairx[0]] = -gammas[0] - alpha_x[ix]*d[pairx[1]]/d[pairx[0]]
3561 3577 jph[pairsList[0][1]] = alp4
3562 3578 jph[pairsList[0][0]] = alp5
3563 3579 jph[pairsList[1][0]] = alp3
3564 jph[pairsList[1][1]] = alp2
3580 jph[pairsList[1][1]] = alp2
3565 3581 jph_array[:,ix,iy] = jph
3566 3582 # d = [2.0,2.5,2.5,2.0]
3567 #falta chequear si va a leer bien los meteoros
3583 #falta chequear si va a leer bien los meteoros
3568 3584 meteorsArray1 = meteorOps.getMeteorParams(meteorsArray, azimuth, h, pairsList, d, jph)
3569 3585 error = meteorsArray1[:,-1]
3570 3586 ind1 = numpy.where(error==0)[0]
3571 3587 penalty[ix,iy] = ind1.size
3572
3588
3573 3589 i,j = numpy.unravel_index(penalty.argmax(), penalty.shape)
3574 3590 phOffset = jph_array[:,i,j]
3575
3591
3576 3592 center_xangle = phOffset[pairx[1]]
3577 3593 center_yangle = phOffset[pairy[1]]
3578
3594
3579 3595 phOffset = numpy.angle(numpy.exp(1j*jph_array[:,i,j]))
3580 phOffset = phOffset*180/numpy.pi
3596 phOffset = phOffset*180/numpy.pi
3581 3597 return phOffset
3582
3583
3598
3599
3584 3600 def run(self, dataOut, hmin, hmax, channelPositions=None, nHours = 1):
3585
3601
3586 3602 dataOut.flagNoData = True
3587 self.__dataReady = False
3603 self.__dataReady = False
3588 3604 dataOut.outputInterval = nHours*3600
3589
3605
3590 3606 if self.__isConfig == False:
3591 3607 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
3592 3608 #Get Initial LTC time
3593 3609 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
3594 3610 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
3595 3611
3596 3612 self.__isConfig = True
3597
3613
3598 3614 if self.__buffer is None:
3599 3615 self.__buffer = dataOut.data_param.copy()
3600 3616
3601 3617 else:
3602 3618 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
3603
3619
3604 3620 self.__dataReady = self.__checkTime(dataOut.utctime, self.__initime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
3605
3621
3606 3622 if self.__dataReady:
3607 3623 dataOut.utctimeInit = self.__initime
3608 3624 self.__initime += dataOut.outputInterval #to erase time offset
3609
3625
3610 3626 freq = dataOut.frequency
3611 3627 c = dataOut.C #m/s
3612 3628 lamb = c/freq
3613 3629 k = 2*numpy.pi/lamb
3614 3630 azimuth = 0
3615 3631 h = (hmin, hmax)
3616 3632 # pairs = ((0,1),(2,3)) #Estrella
3617 3633 # pairs = ((1,0),(2,3)) #T
3618 3634
3619 3635 if channelPositions is None:
3620 3636 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3621 3637 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3622 3638 meteorOps = SMOperations()
3623 3639 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3624 3640
3625 3641 #Checking correct order of pairs
3626 3642 pairs = []
3627 3643 if distances[1] > distances[0]:
3628 3644 pairs.append((1,0))
3629 3645 else:
3630 3646 pairs.append((0,1))
3631
3647
3632 3648 if distances[3] > distances[2]:
3633 3649 pairs.append((3,2))
3634 3650 else:
3635 3651 pairs.append((2,3))
3636 3652 # distances1 = [-distances[0]*lamb, distances[1]*lamb, -distances[2]*lamb, distances[3]*lamb]
3637
3653
3638 3654 meteorsArray = self.__buffer
3639 3655 error = meteorsArray[:,-1]
3640 3656 boolError = (error==0)|(error==3)|(error==4)|(error==13)|(error==14)
3641 3657 ind1 = numpy.where(boolError)[0]
3642 3658 meteorsArray = meteorsArray[ind1,:]
3643 3659 meteorsArray[:,-1] = 0
3644 3660 phases = meteorsArray[:,8:12]
3645
3661
3646 3662 #Calculate Gammas
3647 3663 gammas = self.__getGammas(pairs, distances, phases)
3648 3664 # gammas = numpy.array([-21.70409463,45.76935864])*numpy.pi/180
3649 3665 #Calculate Phases
3650 3666 phasesOff = self.__getPhases(azimuth, h, pairs, distances, gammas, meteorsArray)
3651 3667 phasesOff = phasesOff.reshape((1,phasesOff.size))
3652 3668 dataOut.data_output = -phasesOff
3653 3669 dataOut.flagNoData = False
3654 3670 self.__buffer = None
3655
3656
3671
3672
3657 3673 return
3658
3674
3659 3675 class SMOperations():
3660
3676
3661 3677 def __init__(self):
3662
3678
3663 3679 return
3664
3680
3665 3681 def getMeteorParams(self, arrayParameters0, azimuth, h, pairsList, distances, jph):
3666
3682
3667 3683 arrayParameters = arrayParameters0.copy()
3668 3684 hmin = h[0]
3669 3685 hmax = h[1]
3670
3686
3671 3687 #Calculate AOA (Error N 3, 4)
3672 3688 #JONES ET AL. 1998
3673 3689 AOAthresh = numpy.pi/8
3674 3690 error = arrayParameters[:,-1]
3675 3691 phases = -arrayParameters[:,8:12] + jph
3676 3692 # phases = numpy.unwrap(phases)
3677 3693 arrayParameters[:,3:6], arrayParameters[:,-1] = self.__getAOA(phases, pairsList, distances, error, AOAthresh, azimuth)
3678
3694
3679 3695 #Calculate Heights (Error N 13 and 14)
3680 3696 error = arrayParameters[:,-1]
3681 3697 Ranges = arrayParameters[:,1]
3682 3698 zenith = arrayParameters[:,4]
3683 3699 arrayParameters[:,2], arrayParameters[:,-1] = self.__getHeights(Ranges, zenith, error, hmin, hmax)
3684
3700
3685 3701 #----------------------- Get Final data ------------------------------------
3686 3702 # error = arrayParameters[:,-1]
3687 3703 # ind1 = numpy.where(error==0)[0]
3688 3704 # arrayParameters = arrayParameters[ind1,:]
3689
3705
3690 3706 return arrayParameters
3691
3707
3692 3708 def __getAOA(self, phases, pairsList, directions, error, AOAthresh, azimuth):
3693
3709
3694 3710 arrayAOA = numpy.zeros((phases.shape[0],3))
3695 3711 cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList,directions)
3696
3712
3697 3713 arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3698 3714 cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3699 3715 arrayAOA[:,2] = cosDirError
3700
3716
3701 3717 azimuthAngle = arrayAOA[:,0]
3702 3718 zenithAngle = arrayAOA[:,1]
3703
3719
3704 3720 #Setting Error
3705 3721 indError = numpy.where(numpy.logical_or(error == 3, error == 4))[0]
3706 3722 error[indError] = 0
3707 3723 #Number 3: AOA not fesible
3708 3724 indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3709 error[indInvalid] = 3
3725 error[indInvalid] = 3
3710 3726 #Number 4: Large difference in AOAs obtained from different antenna baselines
3711 3727 indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3712 error[indInvalid] = 4
3728 error[indInvalid] = 4
3713 3729 return arrayAOA, error
3714
3730
3715 3731 def __getDirectionCosines(self, arrayPhase, pairsList, distances):
3716
3732
3717 3733 #Initializing some variables
3718 3734 ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3719 3735 ang_aux = ang_aux.reshape(1,ang_aux.size)
3720
3736
3721 3737 cosdir = numpy.zeros((arrayPhase.shape[0],2))
3722 3738 cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3723
3724
3739
3740
3725 3741 for i in range(2):
3726 3742 ph0 = arrayPhase[:,pairsList[i][0]]
3727 3743 ph1 = arrayPhase[:,pairsList[i][1]]
3728 3744 d0 = distances[pairsList[i][0]]
3729 3745 d1 = distances[pairsList[i][1]]
3730
3731 ph0_aux = ph0 + ph1
3746
3747 ph0_aux = ph0 + ph1
3732 3748 ph0_aux = numpy.angle(numpy.exp(1j*ph0_aux))
3733 3749 # ph0_aux[ph0_aux > numpy.pi] -= 2*numpy.pi
3734 # ph0_aux[ph0_aux < -numpy.pi] += 2*numpy.pi
3750 # ph0_aux[ph0_aux < -numpy.pi] += 2*numpy.pi
3735 3751 #First Estimation
3736 3752 cosdir0[:,i] = (ph0_aux)/(2*numpy.pi*(d0 - d1))
3737
3753
3738 3754 #Most-Accurate Second Estimation
3739 3755 phi1_aux = ph0 - ph1
3740 3756 phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3741 3757 #Direction Cosine 1
3742 3758 cosdir1 = (phi1_aux + ang_aux)/(2*numpy.pi*(d0 + d1))
3743
3759
3744 3760 #Searching the correct Direction Cosine
3745 3761 cosdir0_aux = cosdir0[:,i]
3746 3762 cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3747 3763 #Minimum Distance
3748 3764 cosDiff = (cosdir1 - cosdir0_aux)**2
3749 3765 indcos = cosDiff.argmin(axis = 1)
3750 3766 #Saving Value obtained
3751 3767 cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3752
3768
3753 3769 return cosdir0, cosdir
3754
3770
3755 3771 def __calculateAOA(self, cosdir, azimuth):
3756 3772 cosdirX = cosdir[:,0]
3757 3773 cosdirY = cosdir[:,1]
3758
3774
3759 3775 zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3760 3776 azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth#0 deg north, 90 deg east
3761 3777 angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3762
3778
3763 3779 return angles
3764
3780
3765 3781 def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3766
3782
3767 3783 Ramb = 375 #Ramb = c/(2*PRF)
3768 3784 Re = 6371 #Earth Radius
3769 3785 heights = numpy.zeros(Ranges.shape)
3770
3786
3771 3787 R_aux = numpy.array([0,1,2])*Ramb
3772 3788 R_aux = R_aux.reshape(1,R_aux.size)
3773 3789
3774 3790 Ranges = Ranges.reshape(Ranges.size,1)
3775
3791
3776 3792 Ri = Ranges + R_aux
3777 3793 hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3778
3794
3779 3795 #Check if there is a height between 70 and 110 km
3780 3796 h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3781 3797 ind_h = numpy.where(h_bool == 1)[0]
3782
3798
3783 3799 hCorr = hi[ind_h, :]
3784 3800 ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3785
3801
3786 3802 hCorr = hi[ind_hCorr][:len(ind_h)]
3787 3803 heights[ind_h] = hCorr
3788
3804
3789 3805 #Setting Error
3790 3806 #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3791 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3807 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3792 3808 indError = numpy.where(numpy.logical_or(error == 13, error == 14))[0]
3793 3809 error[indError] = 0
3794 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3810 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3795 3811 error[indInvalid2] = 14
3796 3812 indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3797 error[indInvalid1] = 13
3798
3813 error[indInvalid1] = 13
3814
3799 3815 return heights, error
3800
3816
3801 3817 def getPhasePairs(self, channelPositions):
3802 3818 chanPos = numpy.array(channelPositions)
3803 3819 listOper = list(itertools.combinations(list(range(5)),2))
3804
3820
3805 3821 distances = numpy.zeros(4)
3806 3822 axisX = []
3807 3823 axisY = []
3808 3824 distX = numpy.zeros(3)
3809 3825 distY = numpy.zeros(3)
3810 3826 ix = 0
3811 3827 iy = 0
3812
3828
3813 3829 pairX = numpy.zeros((2,2))
3814 3830 pairY = numpy.zeros((2,2))
3815
3831
3816 3832 for i in range(len(listOper)):
3817 3833 pairi = listOper[i]
3818
3834
3819 3835 posDif = numpy.abs(chanPos[pairi[0],:] - chanPos[pairi[1],:])
3820
3836
3821 3837 if posDif[0] == 0:
3822 3838 axisY.append(pairi)
3823 3839 distY[iy] = posDif[1]
3824 3840 iy += 1
3825 3841 elif posDif[1] == 0:
3826 3842 axisX.append(pairi)
3827 3843 distX[ix] = posDif[0]
3828 3844 ix += 1
3829
3845
3830 3846 for i in range(2):
3831 3847 if i==0:
3832 3848 dist0 = distX
3833 3849 axis0 = axisX
3834 3850 else:
3835 3851 dist0 = distY
3836 3852 axis0 = axisY
3837
3853
3838 3854 side = numpy.argsort(dist0)[:-1]
3839 3855 axis0 = numpy.array(axis0)[side,:]
3840 3856 chanC = int(numpy.intersect1d(axis0[0,:], axis0[1,:])[0])
3841 3857 axis1 = numpy.unique(numpy.reshape(axis0,4))
3842 3858 side = axis1[axis1 != chanC]
3843 3859 diff1 = chanPos[chanC,i] - chanPos[side[0],i]
3844 3860 diff2 = chanPos[chanC,i] - chanPos[side[1],i]
3845 if diff1<0:
3861 if diff1<0:
3846 3862 chan2 = side[0]
3847 3863 d2 = numpy.abs(diff1)
3848 3864 chan1 = side[1]
3849 3865 d1 = numpy.abs(diff2)
3850 3866 else:
3851 3867 chan2 = side[1]
3852 3868 d2 = numpy.abs(diff2)
3853 3869 chan1 = side[0]
3854 3870 d1 = numpy.abs(diff1)
3855
3871
3856 3872 if i==0:
3857 3873 chanCX = chanC
3858 3874 chan1X = chan1
3859 3875 chan2X = chan2
3860 3876 distances[0:2] = numpy.array([d1,d2])
3861 3877 else:
3862 3878 chanCY = chanC
3863 3879 chan1Y = chan1
3864 3880 chan2Y = chan2
3865 3881 distances[2:4] = numpy.array([d1,d2])
3866 3882 # axisXsides = numpy.reshape(axisX[ix,:],4)
3867 #
3883 #
3868 3884 # channelCentX = int(numpy.intersect1d(pairX[0,:], pairX[1,:])[0])
3869 3885 # channelCentY = int(numpy.intersect1d(pairY[0,:], pairY[1,:])[0])
3870 #
3886 #
3871 3887 # ind25X = numpy.where(pairX[0,:] != channelCentX)[0][0]
3872 3888 # ind20X = numpy.where(pairX[1,:] != channelCentX)[0][0]
3873 3889 # channel25X = int(pairX[0,ind25X])
3874 3890 # channel20X = int(pairX[1,ind20X])
3875 3891 # ind25Y = numpy.where(pairY[0,:] != channelCentY)[0][0]
3876 3892 # ind20Y = numpy.where(pairY[1,:] != channelCentY)[0][0]
3877 3893 # channel25Y = int(pairY[0,ind25Y])
3878 3894 # channel20Y = int(pairY[1,ind20Y])
3879
3895
3880 3896 # pairslist = [(channelCentX, channel25X),(channelCentX, channel20X),(channelCentY,channel25Y),(channelCentY, channel20Y)]
3881 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
3882
3897 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
3898
3883 3899 return pairslist, distances
3884 3900 # def __getAOA(self, phases, pairsList, error, AOAthresh, azimuth):
3885 #
3901 #
3886 3902 # arrayAOA = numpy.zeros((phases.shape[0],3))
3887 3903 # cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList)
3888 #
3904 #
3889 3905 # arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3890 3906 # cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3891 3907 # arrayAOA[:,2] = cosDirError
3892 #
3908 #
3893 3909 # azimuthAngle = arrayAOA[:,0]
3894 3910 # zenithAngle = arrayAOA[:,1]
3895 #
3911 #
3896 3912 # #Setting Error
3897 3913 # #Number 3: AOA not fesible
3898 3914 # indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3899 # error[indInvalid] = 3
3915 # error[indInvalid] = 3
3900 3916 # #Number 4: Large difference in AOAs obtained from different antenna baselines
3901 3917 # indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3902 # error[indInvalid] = 4
3918 # error[indInvalid] = 4
3903 3919 # return arrayAOA, error
3904 #
3920 #
3905 3921 # def __getDirectionCosines(self, arrayPhase, pairsList):
3906 #
3922 #
3907 3923 # #Initializing some variables
3908 3924 # ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3909 3925 # ang_aux = ang_aux.reshape(1,ang_aux.size)
3910 #
3926 #
3911 3927 # cosdir = numpy.zeros((arrayPhase.shape[0],2))
3912 3928 # cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3913 #
3914 #
3929 #
3930 #
3915 3931 # for i in range(2):
3916 3932 # #First Estimation
3917 3933 # phi0_aux = arrayPhase[:,pairsList[i][0]] + arrayPhase[:,pairsList[i][1]]
3918 3934 # #Dealias
3919 3935 # indcsi = numpy.where(phi0_aux > numpy.pi)
3920 # phi0_aux[indcsi] -= 2*numpy.pi
3936 # phi0_aux[indcsi] -= 2*numpy.pi
3921 3937 # indcsi = numpy.where(phi0_aux < -numpy.pi)
3922 # phi0_aux[indcsi] += 2*numpy.pi
3938 # phi0_aux[indcsi] += 2*numpy.pi
3923 3939 # #Direction Cosine 0
3924 3940 # cosdir0[:,i] = -(phi0_aux)/(2*numpy.pi*0.5)
3925 #
3941 #
3926 3942 # #Most-Accurate Second Estimation
3927 3943 # phi1_aux = arrayPhase[:,pairsList[i][0]] - arrayPhase[:,pairsList[i][1]]
3928 3944 # phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3929 3945 # #Direction Cosine 1
3930 3946 # cosdir1 = -(phi1_aux + ang_aux)/(2*numpy.pi*4.5)
3931 #
3947 #
3932 3948 # #Searching the correct Direction Cosine
3933 3949 # cosdir0_aux = cosdir0[:,i]
3934 3950 # cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3935 3951 # #Minimum Distance
3936 3952 # cosDiff = (cosdir1 - cosdir0_aux)**2
3937 3953 # indcos = cosDiff.argmin(axis = 1)
3938 3954 # #Saving Value obtained
3939 3955 # cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3940 #
3956 #
3941 3957 # return cosdir0, cosdir
3942 #
3958 #
3943 3959 # def __calculateAOA(self, cosdir, azimuth):
3944 3960 # cosdirX = cosdir[:,0]
3945 3961 # cosdirY = cosdir[:,1]
3946 #
3962 #
3947 3963 # zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3948 3964 # azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth #0 deg north, 90 deg east
3949 3965 # angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3950 #
3966 #
3951 3967 # return angles
3952 #
3968 #
3953 3969 # def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3954 #
3970 #
3955 3971 # Ramb = 375 #Ramb = c/(2*PRF)
3956 3972 # Re = 6371 #Earth Radius
3957 3973 # heights = numpy.zeros(Ranges.shape)
3958 #
3974 #
3959 3975 # R_aux = numpy.array([0,1,2])*Ramb
3960 3976 # R_aux = R_aux.reshape(1,R_aux.size)
3961 #
3977 #
3962 3978 # Ranges = Ranges.reshape(Ranges.size,1)
3963 #
3979 #
3964 3980 # Ri = Ranges + R_aux
3965 3981 # hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3966 #
3982 #
3967 3983 # #Check if there is a height between 70 and 110 km
3968 3984 # h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3969 3985 # ind_h = numpy.where(h_bool == 1)[0]
3970 #
3986 #
3971 3987 # hCorr = hi[ind_h, :]
3972 3988 # ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3973 #
3974 # hCorr = hi[ind_hCorr]
3989 #
3990 # hCorr = hi[ind_hCorr]
3975 3991 # heights[ind_h] = hCorr
3976 #
3992 #
3977 3993 # #Setting Error
3978 3994 # #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3979 # #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3980 #
3981 # indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3995 # #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3996 #
3997 # indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3982 3998 # error[indInvalid2] = 14
3983 3999 # indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3984 # error[indInvalid1] = 13
3985 #
3986 # return heights, error
3987 No newline at end of file
4000 # error[indInvalid1] = 13
4001 #
4002 # return heights, error
@@ -1,1587 +1,1608
1 1 import sys
2 2 import numpy,math
3 3 from scipy import interpolate
4 4 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
5 from schainpy.model.data.jrodata import Voltage
5 from schainpy.model.data.jrodata import Voltage,hildebrand_sekhon
6 from schainpy.model.data import _noise
6 7 from schainpy.utils import log
7 8 from time import time
8 9
9 10
10 11
11 12 class VoltageProc(ProcessingUnit):
12 13
13 14 def __init__(self):
14 15
15 16 ProcessingUnit.__init__(self)
16 17
17 18 self.dataOut = Voltage()
18 19 self.flip = 1
19 20 self.setupReq = False
20 21
21 22 def run(self):
22 23
23 24 if self.dataIn.type == 'AMISR':
24 25 self.__updateObjFromAmisrInput()
25 26
26 27 if self.dataIn.type == 'Voltage':
27 28 self.dataOut.copy(self.dataIn)
28 29
29 30 def __updateObjFromAmisrInput(self):
30 31
31 32 self.dataOut.timeZone = self.dataIn.timeZone
32 33 self.dataOut.dstFlag = self.dataIn.dstFlag
33 34 self.dataOut.errorCount = self.dataIn.errorCount
34 35 self.dataOut.useLocalTime = self.dataIn.useLocalTime
35 36
36 37 self.dataOut.flagNoData = self.dataIn.flagNoData
37 38 self.dataOut.data = self.dataIn.data
38 39 self.dataOut.utctime = self.dataIn.utctime
39 40 self.dataOut.channelList = self.dataIn.channelList
40 41 #self.dataOut.timeInterval = self.dataIn.timeInterval
41 42 self.dataOut.heightList = self.dataIn.heightList
42 43 self.dataOut.nProfiles = self.dataIn.nProfiles
43 44
44 45 self.dataOut.nCohInt = self.dataIn.nCohInt
45 46 self.dataOut.ippSeconds = self.dataIn.ippSeconds
46 47 self.dataOut.frequency = self.dataIn.frequency
47 48
48 49 self.dataOut.azimuth = self.dataIn.azimuth
49 50 self.dataOut.zenith = self.dataIn.zenith
50 51
51 52 self.dataOut.beam.codeList = self.dataIn.beam.codeList
52 53 self.dataOut.beam.azimuthList = self.dataIn.beam.azimuthList
53 54 self.dataOut.beam.zenithList = self.dataIn.beam.zenithList
54 55
55 56
56 57 class selectChannels(Operation):
57 58
58 59 def run(self, dataOut, channelList):
59 60
60 61 channelIndexList = []
61 62 self.dataOut = dataOut
62 63 for channel in channelList:
63 64 if channel not in self.dataOut.channelList:
64 65 raise ValueError("Channel %d is not in %s" %(channel, str(self.dataOut.channelList)))
65 66
66 67 index = self.dataOut.channelList.index(channel)
67 68 channelIndexList.append(index)
68 69 self.selectChannelsByIndex(channelIndexList)
69 70 return self.dataOut
70 71
71 72 def selectChannelsByIndex(self, channelIndexList):
72 73 """
73 74 Selecciona un bloque de datos en base a canales segun el channelIndexList
74 75
75 76 Input:
76 77 channelIndexList : lista sencilla de canales a seleccionar por ej. [2,3,7]
77 78
78 79 Affected:
79 80 self.dataOut.data
80 81 self.dataOut.channelIndexList
81 82 self.dataOut.nChannels
82 83 self.dataOut.m_ProcessingHeader.totalSpectra
83 84 self.dataOut.systemHeaderObj.numChannels
84 85 self.dataOut.m_ProcessingHeader.blockSize
85 86
86 87 Return:
87 88 None
88 89 """
89 90
90 91 for channelIndex in channelIndexList:
91 92 if channelIndex not in self.dataOut.channelIndexList:
92 93 raise ValueError("The value %d in channelIndexList is not valid" %channelIndex)
93 94
94 95 if self.dataOut.type == 'Voltage':
95 96 if self.dataOut.flagDataAsBlock:
96 97 """
97 98 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
98 99 """
99 100 data = self.dataOut.data[channelIndexList,:,:]
100 101 else:
101 102 data = self.dataOut.data[channelIndexList,:]
102 103
103 104 self.dataOut.data = data
104 105 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
105 106 self.dataOut.channelList = range(len(channelIndexList))
106 107
107 108 elif self.dataOut.type == 'Spectra':
108 109 data_spc = self.dataOut.data_spc[channelIndexList, :]
109 110 data_dc = self.dataOut.data_dc[channelIndexList, :]
110 111
111 112 self.dataOut.data_spc = data_spc
112 113 self.dataOut.data_dc = data_dc
113 114
114 115 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
115 116 self.dataOut.channelList = range(len(channelIndexList))
116 117 self.__selectPairsByChannel(channelIndexList)
117 118
118 119 return 1
119 120
120 121 def __selectPairsByChannel(self, channelList=None):
121 122
122 123 if channelList == None:
123 124 return
124 125
125 126 pairsIndexListSelected = []
126 127 for pairIndex in self.dataOut.pairsIndexList:
127 128 # First pair
128 129 if self.dataOut.pairsList[pairIndex][0] not in channelList:
129 130 continue
130 131 # Second pair
131 132 if self.dataOut.pairsList[pairIndex][1] not in channelList:
132 133 continue
133 134
134 135 pairsIndexListSelected.append(pairIndex)
135 136
136 137 if not pairsIndexListSelected:
137 138 self.dataOut.data_cspc = None
138 139 self.dataOut.pairsList = []
139 140 return
140 141
141 142 self.dataOut.data_cspc = self.dataOut.data_cspc[pairsIndexListSelected]
142 143 self.dataOut.pairsList = [self.dataOut.pairsList[i]
143 144 for i in pairsIndexListSelected]
144 145
145 146 return
146 147
147 148 class selectHeights(Operation):
148 149
149 150 def run(self, dataOut, minHei=None, maxHei=None):
150 151 """
151 152 Selecciona un bloque de datos en base a un grupo de valores de alturas segun el rango
152 153 minHei <= height <= maxHei
153 154
154 155 Input:
155 156 minHei : valor minimo de altura a considerar
156 157 maxHei : valor maximo de altura a considerar
157 158
158 159 Affected:
159 160 Indirectamente son cambiados varios valores a travez del metodo selectHeightsByIndex
160 161
161 162 Return:
162 163 1 si el metodo se ejecuto con exito caso contrario devuelve 0
163 164 """
164 165
165 166 self.dataOut = dataOut
166 167
167 168 if minHei == None:
168 169 minHei = self.dataOut.heightList[0]
169 170
170 171 if maxHei == None:
171 172 maxHei = self.dataOut.heightList[-1]
172 173
173 174 if (minHei < self.dataOut.heightList[0]):
174 175 minHei = self.dataOut.heightList[0]
175 176
176 177 if (maxHei > self.dataOut.heightList[-1]):
177 178 maxHei = self.dataOut.heightList[-1]
178 179
179 180 minIndex = 0
180 181 maxIndex = 0
181 182 heights = self.dataOut.heightList
182 183
183 184 inda = numpy.where(heights >= minHei)
184 185 indb = numpy.where(heights <= maxHei)
185 186
186 187 try:
187 188 minIndex = inda[0][0]
188 189 except:
189 190 minIndex = 0
190 191
191 192 try:
192 193 maxIndex = indb[0][-1]
193 194 except:
194 195 maxIndex = len(heights)
195 196
196 197 self.selectHeightsByIndex(minIndex, maxIndex)
197 198
198 199 return self.dataOut
199 200
200 201 def selectHeightsByIndex(self, minIndex, maxIndex):
201 202 """
202 203 Selecciona un bloque de datos en base a un grupo indices de alturas segun el rango
203 204 minIndex <= index <= maxIndex
204 205
205 206 Input:
206 207 minIndex : valor de indice minimo de altura a considerar
207 208 maxIndex : valor de indice maximo de altura a considerar
208 209
209 210 Affected:
210 211 self.dataOut.data
211 212 self.dataOut.heightList
212 213
213 214 Return:
214 215 1 si el metodo se ejecuto con exito caso contrario devuelve 0
215 216 """
216 217
217 218 if self.dataOut.type == 'Voltage':
218 219 if (minIndex < 0) or (minIndex > maxIndex):
219 220 raise ValueError("Height index range (%d,%d) is not valid" % (minIndex, maxIndex))
220 221
221 222 if (maxIndex >= self.dataOut.nHeights):
222 223 maxIndex = self.dataOut.nHeights
223 224
224 225 #voltage
225 226 if self.dataOut.flagDataAsBlock:
226 227 """
227 228 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
228 229 """
229 230 data = self.dataOut.data[:,:, minIndex:maxIndex]
230 231 else:
231 232 data = self.dataOut.data[:, minIndex:maxIndex]
232 233
233 234 # firstHeight = self.dataOut.heightList[minIndex]
234 235
235 236 self.dataOut.data = data
236 237 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex]
237 238
238 239 if self.dataOut.nHeights <= 1:
239 240 raise ValueError("selectHeights: Too few heights. Current number of heights is %d" %(self.dataOut.nHeights))
240 241 elif self.dataOut.type == 'Spectra':
241 242 if (minIndex < 0) or (minIndex > maxIndex):
242 243 raise ValueError("Error selecting heights: Index range (%d,%d) is not valid" % (
243 244 minIndex, maxIndex))
244 245
245 246 if (maxIndex >= self.dataOut.nHeights):
246 247 maxIndex = self.dataOut.nHeights - 1
247 248
248 249 # Spectra
249 250 data_spc = self.dataOut.data_spc[:, :, minIndex:maxIndex + 1]
250 251
251 252 data_cspc = None
252 253 if self.dataOut.data_cspc is not None:
253 254 data_cspc = self.dataOut.data_cspc[:, :, minIndex:maxIndex + 1]
254 255
255 256 data_dc = None
256 257 if self.dataOut.data_dc is not None:
257 258 data_dc = self.dataOut.data_dc[:, minIndex:maxIndex + 1]
258 259
259 260 self.dataOut.data_spc = data_spc
260 261 self.dataOut.data_cspc = data_cspc
261 262 self.dataOut.data_dc = data_dc
262 263
263 264 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex + 1]
264 265
265 266 return 1
266 267
267 268
268 269 class filterByHeights(Operation):
269 270
270 271 def run(self, dataOut, window):
271 272
272 273 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
273 274
274 275 if window == None:
275 276 window = (dataOut.radarControllerHeaderObj.txA/dataOut.radarControllerHeaderObj.nBaud) / deltaHeight
276 277
277 278 newdelta = deltaHeight * window
278 279 r = dataOut.nHeights % window
279 280 newheights = (dataOut.nHeights-r)/window
280 281
281 282 if newheights <= 1:
282 283 raise ValueError("filterByHeights: Too few heights. Current number of heights is %d and window is %d" %(dataOut.nHeights, window))
283 284
284 285 if dataOut.flagDataAsBlock:
285 286 """
286 287 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
287 288 """
288 289 buffer = dataOut.data[:, :, 0:int(dataOut.nHeights-r)]
289 290 buffer = buffer.reshape(dataOut.nChannels, dataOut.nProfiles, int(dataOut.nHeights/window), window)
290 291 buffer = numpy.sum(buffer,3)
291 292
292 293 else:
293 294 buffer = dataOut.data[:,0:int(dataOut.nHeights-r)]
294 295 buffer = buffer.reshape(dataOut.nChannels,int(dataOut.nHeights/window),int(window))
295 296 buffer = numpy.sum(buffer,2)
296 297
297 298 dataOut.data = buffer
298 299 dataOut.heightList = dataOut.heightList[0] + numpy.arange( newheights )*newdelta
299 300 dataOut.windowOfFilter = window
300 301
301 302 return dataOut
302 303
303 304
304 305 class setH0(Operation):
305 306
306 307 def run(self, dataOut, h0, deltaHeight = None):
307 308
308 309 if not deltaHeight:
309 310 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
310 311
311 312 nHeights = dataOut.nHeights
312 313
313 314 newHeiRange = h0 + numpy.arange(nHeights)*deltaHeight
314 315
315 316 dataOut.heightList = newHeiRange
316 317
317 318 return dataOut
318 319
319 320
320 321 class deFlip(Operation):
321 322
322 323 def run(self, dataOut, channelList = []):
323 324
324 325 data = dataOut.data.copy()
325 326
326 327 if dataOut.flagDataAsBlock:
327 328 flip = self.flip
328 329 profileList = list(range(dataOut.nProfiles))
329 330
330 331 if not channelList:
331 332 for thisProfile in profileList:
332 333 data[:,thisProfile,:] = data[:,thisProfile,:]*flip
333 334 flip *= -1.0
334 335 else:
335 336 for thisChannel in channelList:
336 337 if thisChannel not in dataOut.channelList:
337 338 continue
338 339
339 340 for thisProfile in profileList:
340 341 data[thisChannel,thisProfile,:] = data[thisChannel,thisProfile,:]*flip
341 342 flip *= -1.0
342 343
343 344 self.flip = flip
344 345
345 346 else:
346 347 if not channelList:
347 348 data[:,:] = data[:,:]*self.flip
348 349 else:
349 350 for thisChannel in channelList:
350 351 if thisChannel not in dataOut.channelList:
351 352 continue
352 353
353 354 data[thisChannel,:] = data[thisChannel,:]*self.flip
354 355
355 356 self.flip *= -1.
356 357
357 358 dataOut.data = data
358 359
359 360 return dataOut
360 361
361 362
362 363 class setAttribute(Operation):
363 364 '''
364 365 Set an arbitrary attribute(s) to dataOut
365 366 '''
366 367
367 368 def __init__(self):
368 369
369 370 Operation.__init__(self)
370 371 self._ready = False
371 372
372 373 def run(self, dataOut, **kwargs):
373 374
374 375 for key, value in kwargs.items():
375 376 setattr(dataOut, key, value)
376 377
377 378 return dataOut
378 379
379 380
380 381 class interpolateHeights(Operation):
381 382
382 383 def run(self, dataOut, topLim, botLim):
383 384 #69 al 72 para julia
384 385 #82-84 para meteoros
385 386 if len(numpy.shape(dataOut.data))==2:
386 387 sampInterp = (dataOut.data[:,botLim-1] + dataOut.data[:,topLim+1])/2
387 388 sampInterp = numpy.transpose(numpy.tile(sampInterp,(topLim-botLim + 1,1)))
388 389 #dataOut.data[:,botLim:limSup+1] = sampInterp
389 390 dataOut.data[:,botLim:topLim+1] = sampInterp
390 391 else:
391 392 nHeights = dataOut.data.shape[2]
392 393 x = numpy.hstack((numpy.arange(botLim),numpy.arange(topLim+1,nHeights)))
393 394 y = dataOut.data[:,:,list(range(botLim))+list(range(topLim+1,nHeights))]
394 395 f = interpolate.interp1d(x, y, axis = 2)
395 396 xnew = numpy.arange(botLim,topLim+1)
396 397 ynew = f(xnew)
397 398 dataOut.data[:,:,botLim:topLim+1] = ynew
398 399
399 400 return dataOut
400 401
401 402
402 403 class CohInt(Operation):
403 404
404 405 isConfig = False
405 406 __profIndex = 0
406 407 __byTime = False
407 408 __initime = None
408 409 __lastdatatime = None
409 410 __integrationtime = None
410 411 __buffer = None
411 412 __bufferStride = []
412 413 __dataReady = False
413 414 __profIndexStride = 0
414 415 __dataToPutStride = False
415 416 n = None
416 417
417 418 def __init__(self, **kwargs):
418 419
419 420 Operation.__init__(self, **kwargs)
420 421
421 422 # self.isConfig = False
422 423
423 424 def setup(self, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False):
424 425 """
425 426 Set the parameters of the integration class.
426 427
427 428 Inputs:
428 429
429 430 n : Number of coherent integrations
430 431 timeInterval : Time of integration. If the parameter "n" is selected this one does not work
431 432 overlapping :
432 433 """
433 434
434 435 self.__initime = None
435 436 self.__lastdatatime = 0
436 437 self.__buffer = None
437 438 self.__dataReady = False
438 439 self.byblock = byblock
439 440 self.stride = stride
440 441
441 442 if n == None and timeInterval == None:
442 443 raise ValueError("n or timeInterval should be specified ...")
443 444
444 445 if n != None:
445 446 self.n = n
446 447 self.__byTime = False
447 448 else:
448 449 self.__integrationtime = timeInterval #* 60. #if (type(timeInterval)!=integer) -> change this line
449 450 self.n = 9999
450 451 self.__byTime = True
451 452
452 453 if overlapping:
453 454 self.__withOverlapping = True
454 455 self.__buffer = None
455 456 else:
456 457 self.__withOverlapping = False
457 458 self.__buffer = 0
458 459
459 460 self.__profIndex = 0
460 461
461 462 def putData(self, data):
462 463
463 464 """
464 465 Add a profile to the __buffer and increase in one the __profileIndex
465 466
466 467 """
467 468
468 469 if not self.__withOverlapping:
469 470 self.__buffer += data.copy()
470 471 self.__profIndex += 1
471 472 return
472 473
473 474 #Overlapping data
474 475 nChannels, nHeis = data.shape
475 476 data = numpy.reshape(data, (1, nChannels, nHeis))
476 477
477 478 #If the buffer is empty then it takes the data value
478 479 if self.__buffer is None:
479 480 self.__buffer = data
480 481 self.__profIndex += 1
481 482 return
482 483
483 484 #If the buffer length is lower than n then stakcing the data value
484 485 if self.__profIndex < self.n:
485 486 self.__buffer = numpy.vstack((self.__buffer, data))
486 487 self.__profIndex += 1
487 488 return
488 489
489 490 #If the buffer length is equal to n then replacing the last buffer value with the data value
490 491 self.__buffer = numpy.roll(self.__buffer, -1, axis=0)
491 492 self.__buffer[self.n-1] = data
492 493 self.__profIndex = self.n
493 494 return
494 495
495 496
496 497 def pushData(self):
497 498 """
498 499 Return the sum of the last profiles and the profiles used in the sum.
499 500
500 501 Affected:
501 502
502 503 self.__profileIndex
503 504
504 505 """
505 506
506 507 if not self.__withOverlapping:
507 508 data = self.__buffer
508 509 n = self.__profIndex
509 510
510 511 self.__buffer = 0
511 512 self.__profIndex = 0
512 513
513 514 return data, n
514 515
515 516 #Integration with Overlapping
516 517 data = numpy.sum(self.__buffer, axis=0)
517 518 # print data
518 519 # raise
519 520 n = self.__profIndex
520 521
521 522 return data, n
522 523
523 524 def byProfiles(self, data):
524 525
525 526 self.__dataReady = False
526 527 avgdata = None
527 528 # n = None
528 529 # print data
529 530 # raise
530 531 self.putData(data)
531 532
532 533 if self.__profIndex == self.n:
533 534 avgdata, n = self.pushData()
534 535 self.__dataReady = True
535 536
536 537 return avgdata
537 538
538 539 def byTime(self, data, datatime):
539 540
540 541 self.__dataReady = False
541 542 avgdata = None
542 543 n = None
543 544
544 545 self.putData(data)
545 546
546 547 if (datatime - self.__initime) >= self.__integrationtime:
547 548 avgdata, n = self.pushData()
548 549 self.n = n
549 550 self.__dataReady = True
550 551
551 552 return avgdata
552 553
553 554 def integrateByStride(self, data, datatime):
554 555 # print data
555 556 if self.__profIndex == 0:
556 557 self.__buffer = [[data.copy(), datatime]]
557 558 else:
558 559 self.__buffer.append([data.copy(),datatime])
559 560 self.__profIndex += 1
560 561 self.__dataReady = False
561 562
562 563 if self.__profIndex == self.n * self.stride :
563 564 self.__dataToPutStride = True
564 565 self.__profIndexStride = 0
565 566 self.__profIndex = 0
566 567 self.__bufferStride = []
567 568 for i in range(self.stride):
568 569 current = self.__buffer[i::self.stride]
569 570 data = numpy.sum([t[0] for t in current], axis=0)
570 571 avgdatatime = numpy.average([t[1] for t in current])
571 572 # print data
572 573 self.__bufferStride.append((data, avgdatatime))
573 574
574 575 if self.__dataToPutStride:
575 576 self.__dataReady = True
576 577 self.__profIndexStride += 1
577 578 if self.__profIndexStride == self.stride:
578 579 self.__dataToPutStride = False
579 580 # print self.__bufferStride[self.__profIndexStride - 1]
580 581 # raise
581 582 return self.__bufferStride[self.__profIndexStride - 1]
582 583
583 584
584 585 return None, None
585 586
586 587 def integrate(self, data, datatime=None):
587 588
588 589 if self.__initime == None:
589 590 self.__initime = datatime
590 591
591 592 if self.__byTime:
592 593 avgdata = self.byTime(data, datatime)
593 594 else:
594 595 avgdata = self.byProfiles(data)
595 596
596 597
597 598 self.__lastdatatime = datatime
598 599
599 600 if avgdata is None:
600 601 return None, None
601 602
602 603 avgdatatime = self.__initime
603 604
604 605 deltatime = datatime - self.__lastdatatime
605 606
606 607 if not self.__withOverlapping:
607 608 self.__initime = datatime
608 609 else:
609 610 self.__initime += deltatime
610 611
611 612 return avgdata, avgdatatime
612 613
613 614 def integrateByBlock(self, dataOut):
614 615
615 616 times = int(dataOut.data.shape[1]/self.n)
616 617 avgdata = numpy.zeros((dataOut.nChannels, times, dataOut.nHeights), dtype=numpy.complex)
617 618
618 619 id_min = 0
619 620 id_max = self.n
620 621
621 622 for i in range(times):
622 623 junk = dataOut.data[:,id_min:id_max,:]
623 624 avgdata[:,i,:] = junk.sum(axis=1)
624 625 id_min += self.n
625 626 id_max += self.n
626 627
627 628 timeInterval = dataOut.ippSeconds*self.n
628 629 avgdatatime = (times - 1) * timeInterval + dataOut.utctime
629 630 self.__dataReady = True
630 631 return avgdata, avgdatatime
631 632
632 633 def run(self, dataOut, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False, **kwargs):
633 634
634 635 if not self.isConfig:
635 636 self.setup(n=n, stride=stride, timeInterval=timeInterval, overlapping=overlapping, byblock=byblock, **kwargs)
636 637 self.isConfig = True
637 638
638 639 if dataOut.flagDataAsBlock:
639 640 """
640 641 Si la data es leida por bloques, dimension = [nChannels, nProfiles, nHeis]
641 642 """
642 643 avgdata, avgdatatime = self.integrateByBlock(dataOut)
643 644 dataOut.nProfiles /= self.n
644 645 else:
645 646 if stride is None:
646 647 avgdata, avgdatatime = self.integrate(dataOut.data, dataOut.utctime)
647 648 else:
648 649 avgdata, avgdatatime = self.integrateByStride(dataOut.data, dataOut.utctime)
649 650
650 651
651 652 # dataOut.timeInterval *= n
652 653 dataOut.flagNoData = True
653 654
654 655 if self.__dataReady:
655 656 dataOut.data = avgdata
656 657 dataOut.nCohInt *= self.n
657 658 dataOut.utctime = avgdatatime
658 659 # print avgdata, avgdatatime
659 660 # raise
660 661 # dataOut.timeInterval = dataOut.ippSeconds * dataOut.nCohInt
661 662 dataOut.flagNoData = False
662 663 return dataOut
663 664
664 665 class Decoder(Operation):
665 666
666 667 isConfig = False
667 668 __profIndex = 0
668 669
669 670 code = None
670 671
671 672 nCode = None
672 673 nBaud = None
673 674
674 675 def __init__(self, **kwargs):
675 676
676 677 Operation.__init__(self, **kwargs)
677 678
678 679 self.times = None
679 680 self.osamp = None
680 681 # self.__setValues = False
681 682 self.isConfig = False
682 683 self.setupReq = False
683 684 def setup(self, code, osamp, dataOut):
684 685
685 686 self.__profIndex = 0
686 687
687 688 self.code = code
688 689
689 690 self.nCode = len(code)
690 691 self.nBaud = len(code[0])
691 692
692 693 if (osamp != None) and (osamp >1):
693 694 self.osamp = osamp
694 695 self.code = numpy.repeat(code, repeats=self.osamp, axis=1)
695 696 self.nBaud = self.nBaud*self.osamp
696 697
697 698 self.__nChannels = dataOut.nChannels
698 699 self.__nProfiles = dataOut.nProfiles
699 700 self.__nHeis = dataOut.nHeights
700 701
701 702 if self.__nHeis < self.nBaud:
702 703 raise ValueError('Number of heights (%d) should be greater than number of bauds (%d)' %(self.__nHeis, self.nBaud))
703 704
704 705 #Frequency
705 706 __codeBuffer = numpy.zeros((self.nCode, self.__nHeis), dtype=numpy.complex)
706 707
707 708 __codeBuffer[:,0:self.nBaud] = self.code
708 709
709 710 self.fft_code = numpy.conj(numpy.fft.fft(__codeBuffer, axis=1))
710 711
711 712 if dataOut.flagDataAsBlock:
712 713
713 714 self.ndatadec = self.__nHeis #- self.nBaud + 1
714 715
715 716 self.datadecTime = numpy.zeros((self.__nChannels, self.__nProfiles, self.ndatadec), dtype=numpy.complex)
716 717
717 718 else:
718 719
719 720 #Time
720 721 self.ndatadec = self.__nHeis #- self.nBaud + 1
721 722
722 723 self.datadecTime = numpy.zeros((self.__nChannels, self.ndatadec), dtype=numpy.complex)
723 724
724 725 def __convolutionInFreq(self, data):
725 726
726 727 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
727 728
728 729 fft_data = numpy.fft.fft(data, axis=1)
729 730
730 731 conv = fft_data*fft_code
731 732
732 733 data = numpy.fft.ifft(conv,axis=1)
733 734
734 735 return data
735 736
736 737 def __convolutionInFreqOpt(self, data):
737 738
738 739 raise NotImplementedError
739 740
740 741 def __convolutionInTime(self, data):
741 742
742 743 code = self.code[self.__profIndex]
743 744 for i in range(self.__nChannels):
744 745 self.datadecTime[i,:] = numpy.correlate(data[i,:], code, mode='full')[self.nBaud-1:]
745 746
746 747 return self.datadecTime
747 748
748 749 def __convolutionByBlockInTime(self, data):
749 750
750 751 repetitions = int(self.__nProfiles / self.nCode)
751 752 junk = numpy.lib.stride_tricks.as_strided(self.code, (repetitions, self.code.size), (0, self.code.itemsize))
752 753 junk = junk.flatten()
753 754 code_block = numpy.reshape(junk, (self.nCode*repetitions, self.nBaud))
754 755 profilesList = range(self.__nProfiles)
755 756
756 757 for i in range(self.__nChannels):
757 758 for j in profilesList:
758 759 self.datadecTime[i,j,:] = numpy.correlate(data[i,j,:], code_block[j,:], mode='full')[self.nBaud-1:]
759 760 return self.datadecTime
760 761
761 762 def __convolutionByBlockInFreq(self, data):
762 763
763 764 raise NotImplementedError("Decoder by frequency fro Blocks not implemented")
764 765
765 766
766 767 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
767 768
768 769 fft_data = numpy.fft.fft(data, axis=2)
769 770
770 771 conv = fft_data*fft_code
771 772
772 773 data = numpy.fft.ifft(conv,axis=2)
773 774
774 775 return data
775 776
776 777
777 778 def run(self, dataOut, code=None, nCode=None, nBaud=None, mode = 0, osamp=None, times=None):
778 779
779 780 if dataOut.flagDecodeData:
780 781 print("This data is already decoded, recoding again ...")
781 782
782 783 if not self.isConfig:
783 784
784 785 if code is None:
785 786 if dataOut.code is None:
786 787 raise ValueError("Code could not be read from %s instance. Enter a value in Code parameter" %dataOut.type)
787 788
788 789 code = dataOut.code
789 790 else:
790 791 code = numpy.array(code).reshape(nCode,nBaud)
791 792 self.setup(code, osamp, dataOut)
792 793
793 794 self.isConfig = True
794 795
795 796 if mode == 3:
796 797 sys.stderr.write("Decoder Warning: mode=%d is not valid, using mode=0\n" %mode)
797 798
798 799 if times != None:
799 800 sys.stderr.write("Decoder Warning: Argument 'times' in not used anymore\n")
800 801
801 802 if self.code is None:
802 803 print("Fail decoding: Code is not defined.")
803 804 return
804 805
805 806 self.__nProfiles = dataOut.nProfiles
806 807 datadec = None
807 808
808 809 if mode == 3:
809 810 mode = 0
810 811
811 812 if dataOut.flagDataAsBlock:
812 813 """
813 814 Decoding when data have been read as block,
814 815 """
815 816
816 817 if mode == 0:
817 818 datadec = self.__convolutionByBlockInTime(dataOut.data)
818 819 if mode == 1:
819 820 datadec = self.__convolutionByBlockInFreq(dataOut.data)
820 821 else:
821 822 """
822 823 Decoding when data have been read profile by profile
823 824 """
824 825 if mode == 0:
825 826 datadec = self.__convolutionInTime(dataOut.data)
826 827
827 828 if mode == 1:
828 829 datadec = self.__convolutionInFreq(dataOut.data)
829 830
830 831 if mode == 2:
831 832 datadec = self.__convolutionInFreqOpt(dataOut.data)
832 833
833 834 if datadec is None:
834 835 raise ValueError("Codification mode selected is not valid: mode=%d. Try selecting 0 or 1" %mode)
835 836
836 837 dataOut.code = self.code
837 838 dataOut.nCode = self.nCode
838 839 dataOut.nBaud = self.nBaud
839 840
840 841 dataOut.data = datadec
841 842
842 843 dataOut.heightList = dataOut.heightList[0:datadec.shape[-1]]
843 844
844 845 dataOut.flagDecodeData = True #asumo q la data esta decodificada
845 846
846 847 if self.__profIndex == self.nCode-1:
847 848 self.__profIndex = 0
848 849 return dataOut
849 850
850 851 self.__profIndex += 1
851 852
852 853 return dataOut
853 854 # dataOut.flagDeflipData = True #asumo q la data no esta sin flip
854 855
855 856
856 857 class ProfileConcat(Operation):
857 858
858 859 isConfig = False
859 860 buffer = None
860 861
861 862 def __init__(self, **kwargs):
862 863
863 864 Operation.__init__(self, **kwargs)
864 865 self.profileIndex = 0
865 866
866 867 def reset(self):
867 868 self.buffer = numpy.zeros_like(self.buffer)
868 869 self.start_index = 0
869 870 self.times = 1
870 871
871 872 def setup(self, data, m, n=1):
872 873 self.buffer = numpy.zeros((data.shape[0],data.shape[1]*m),dtype=type(data[0,0]))
873 874 self.nHeights = data.shape[1]#.nHeights
874 875 self.start_index = 0
875 876 self.times = 1
876 877
877 878 def concat(self, data):
878 879
879 880 self.buffer[:,self.start_index:self.nHeights*self.times] = data.copy()
880 881 self.start_index = self.start_index + self.nHeights
881 882
882 883 def run(self, dataOut, m):
883 884 dataOut.flagNoData = True
884 885
885 886 if not self.isConfig:
886 887 self.setup(dataOut.data, m, 1)
887 888 self.isConfig = True
888 889
889 890 if dataOut.flagDataAsBlock:
890 891 raise ValueError("ProfileConcat can only be used when voltage have been read profile by profile, getBlock = False")
891 892
892 893 else:
893 894 self.concat(dataOut.data)
894 895 self.times += 1
895 896 if self.times > m:
896 897 dataOut.data = self.buffer
897 898 self.reset()
898 899 dataOut.flagNoData = False
899 900 # se deben actualizar mas propiedades del header y del objeto dataOut, por ejemplo, las alturas
900 901 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
901 902 xf = dataOut.heightList[0] + dataOut.nHeights * deltaHeight * m
902 903 dataOut.heightList = numpy.arange(dataOut.heightList[0], xf, deltaHeight)
903 904 dataOut.ippSeconds *= m
904 905 return dataOut
905 906
906 907 class ProfileSelector(Operation):
907 908
908 909 profileIndex = None
909 910 # Tamanho total de los perfiles
910 911 nProfiles = None
911 912
912 913 def __init__(self, **kwargs):
913 914
914 915 Operation.__init__(self, **kwargs)
915 916 self.profileIndex = 0
916 917
917 918 def incProfileIndex(self):
918 919
919 920 self.profileIndex += 1
920 921
921 922 if self.profileIndex >= self.nProfiles:
922 923 self.profileIndex = 0
923 924
924 925 def isThisProfileInRange(self, profileIndex, minIndex, maxIndex):
925 926
926 927 if profileIndex < minIndex:
927 928 return False
928 929
929 930 if profileIndex > maxIndex:
930 931 return False
931 932
932 933 return True
933 934
934 935 def isThisProfileInList(self, profileIndex, profileList):
935 936
936 937 if profileIndex not in profileList:
937 938 return False
938 939
939 940 return True
940 941
941 942 def run(self, dataOut, profileList=None, profileRangeList=None, beam=None, byblock=False, rangeList = None, nProfiles=None):
942 943
943 944 """
944 945 ProfileSelector:
945 946
946 947 Inputs:
947 948 profileList : Index of profiles selected. Example: profileList = (0,1,2,7,8)
948 949
949 950 profileRangeList : Minimum and maximum profile indexes. Example: profileRangeList = (4, 30)
950 951
951 952 rangeList : List of profile ranges. Example: rangeList = ((4, 30), (32, 64), (128, 256))
952 953
953 954 """
954 955
955 956 if rangeList is not None:
956 957 if type(rangeList[0]) not in (tuple, list):
957 958 rangeList = [rangeList]
958 959
959 960 dataOut.flagNoData = True
960 961
961 962 if dataOut.flagDataAsBlock:
962 963 """
963 964 data dimension = [nChannels, nProfiles, nHeis]
964 965 """
965 966 if profileList != None:
966 967 dataOut.data = dataOut.data[:,profileList,:]
967 968
968 969 if profileRangeList != None:
969 970 minIndex = profileRangeList[0]
970 971 maxIndex = profileRangeList[1]
971 972 profileList = list(range(minIndex, maxIndex+1))
972 973
973 974 dataOut.data = dataOut.data[:,minIndex:maxIndex+1,:]
974 975
975 976 if rangeList != None:
976 977
977 978 profileList = []
978 979
979 980 for thisRange in rangeList:
980 981 minIndex = thisRange[0]
981 982 maxIndex = thisRange[1]
982 983
983 984 profileList.extend(list(range(minIndex, maxIndex+1)))
984 985
985 986 dataOut.data = dataOut.data[:,profileList,:]
986 987
987 988 dataOut.nProfiles = len(profileList)
988 989 dataOut.profileIndex = dataOut.nProfiles - 1
989 990 dataOut.flagNoData = False
990 991
991 992 return dataOut
992 993
993 994 """
994 995 data dimension = [nChannels, nHeis]
995 996 """
996 997
997 998 if profileList != None:
998 999
999 1000 if self.isThisProfileInList(dataOut.profileIndex, profileList):
1000 1001
1001 1002 self.nProfiles = len(profileList)
1002 1003 dataOut.nProfiles = self.nProfiles
1003 1004 dataOut.profileIndex = self.profileIndex
1004 1005 dataOut.flagNoData = False
1005 1006
1006 1007 self.incProfileIndex()
1007 1008 return dataOut
1008 1009
1009 1010 if profileRangeList != None:
1010 1011
1011 1012 minIndex = profileRangeList[0]
1012 1013 maxIndex = profileRangeList[1]
1013 1014
1014 1015 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1015 1016
1016 1017 self.nProfiles = maxIndex - minIndex + 1
1017 1018 dataOut.nProfiles = self.nProfiles
1018 1019 dataOut.profileIndex = self.profileIndex
1019 1020 dataOut.flagNoData = False
1020 1021
1021 1022 self.incProfileIndex()
1022 1023 return dataOut
1023 1024
1024 1025 if rangeList != None:
1025 1026
1026 1027 nProfiles = 0
1027 1028
1028 1029 for thisRange in rangeList:
1029 1030 minIndex = thisRange[0]
1030 1031 maxIndex = thisRange[1]
1031 1032
1032 1033 nProfiles += maxIndex - minIndex + 1
1033 1034
1034 1035 for thisRange in rangeList:
1035 1036
1036 1037 minIndex = thisRange[0]
1037 1038 maxIndex = thisRange[1]
1038 1039
1039 1040 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1040 1041
1041 1042 self.nProfiles = nProfiles
1042 1043 dataOut.nProfiles = self.nProfiles
1043 1044 dataOut.profileIndex = self.profileIndex
1044 1045 dataOut.flagNoData = False
1045 1046
1046 1047 self.incProfileIndex()
1047 1048
1048 1049 break
1049 1050
1050 1051 return dataOut
1051 1052
1052 1053
1053 1054 if beam != None: #beam is only for AMISR data
1054 1055 if self.isThisProfileInList(dataOut.profileIndex, dataOut.beamRangeDict[beam]):
1055 1056 dataOut.flagNoData = False
1056 1057 dataOut.profileIndex = self.profileIndex
1057 1058
1058 1059 self.incProfileIndex()
1059 1060
1060 1061 return dataOut
1061 1062
1062 1063 raise ValueError("ProfileSelector needs profileList, profileRangeList or rangeList parameter")
1063 1064
1064 1065
1065 1066 class Reshaper(Operation):
1066 1067
1067 1068 def __init__(self, **kwargs):
1068 1069
1069 1070 Operation.__init__(self, **kwargs)
1070 1071
1071 1072 self.__buffer = None
1072 1073 self.__nitems = 0
1073 1074
1074 1075 def __appendProfile(self, dataOut, nTxs):
1075 1076
1076 1077 if self.__buffer is None:
1077 1078 shape = (dataOut.nChannels, int(dataOut.nHeights/nTxs) )
1078 1079 self.__buffer = numpy.empty(shape, dtype = dataOut.data.dtype)
1079 1080
1080 1081 ini = dataOut.nHeights * self.__nitems
1081 1082 end = ini + dataOut.nHeights
1082 1083
1083 1084 self.__buffer[:, ini:end] = dataOut.data
1084 1085
1085 1086 self.__nitems += 1
1086 1087
1087 1088 return int(self.__nitems*nTxs)
1088 1089
1089 1090 def __getBuffer(self):
1090 1091
1091 1092 if self.__nitems == int(1./self.__nTxs):
1092 1093
1093 1094 self.__nitems = 0
1094 1095
1095 1096 return self.__buffer.copy()
1096 1097
1097 1098 return None
1098 1099
1099 1100 def __checkInputs(self, dataOut, shape, nTxs):
1100 1101
1101 1102 if shape is None and nTxs is None:
1102 1103 raise ValueError("Reshaper: shape of factor should be defined")
1103 1104
1104 1105 if nTxs:
1105 1106 if nTxs < 0:
1106 1107 raise ValueError("nTxs should be greater than 0")
1107 1108
1108 1109 if nTxs < 1 and dataOut.nProfiles % (1./nTxs) != 0:
1109 1110 raise ValueError("nProfiles= %d is not divisibled by (1./nTxs) = %f" %(dataOut.nProfiles, (1./nTxs)))
1110 1111
1111 1112 shape = [dataOut.nChannels, dataOut.nProfiles*nTxs, dataOut.nHeights/nTxs]
1112 1113
1113 1114 return shape, nTxs
1114 1115
1115 1116 if len(shape) != 2 and len(shape) != 3:
1116 1117 raise ValueError("shape dimension should be equal to 2 or 3. shape = (nProfiles, nHeis) or (nChannels, nProfiles, nHeis). Actually shape = (%d, %d, %d)" %(dataOut.nChannels, dataOut.nProfiles, dataOut.nHeights))
1117 1118
1118 1119 if len(shape) == 2:
1119 1120 shape_tuple = [dataOut.nChannels]
1120 1121 shape_tuple.extend(shape)
1121 1122 else:
1122 1123 shape_tuple = list(shape)
1123 1124
1124 1125 nTxs = 1.0*shape_tuple[1]/dataOut.nProfiles
1125 1126
1126 1127 return shape_tuple, nTxs
1127 1128
1128 1129 def run(self, dataOut, shape=None, nTxs=None):
1129 1130
1130 1131 shape_tuple, self.__nTxs = self.__checkInputs(dataOut, shape, nTxs)
1131 1132
1132 1133 dataOut.flagNoData = True
1133 1134 profileIndex = None
1134 1135
1135 1136 if dataOut.flagDataAsBlock:
1136 1137
1137 1138 dataOut.data = numpy.reshape(dataOut.data, shape_tuple)
1138 1139 dataOut.flagNoData = False
1139 1140
1140 1141 profileIndex = int(dataOut.nProfiles*self.__nTxs) - 1
1141 1142
1142 1143 else:
1143 1144
1144 1145 if self.__nTxs < 1:
1145 1146
1146 1147 self.__appendProfile(dataOut, self.__nTxs)
1147 1148 new_data = self.__getBuffer()
1148 1149
1149 1150 if new_data is not None:
1150 1151 dataOut.data = new_data
1151 1152 dataOut.flagNoData = False
1152 1153
1153 1154 profileIndex = dataOut.profileIndex*nTxs
1154 1155
1155 1156 else:
1156 1157 raise ValueError("nTxs should be greater than 0 and lower than 1, or use VoltageReader(..., getblock=True)")
1157 1158
1158 1159 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1159 1160
1160 1161 dataOut.heightList = numpy.arange(dataOut.nHeights/self.__nTxs) * deltaHeight + dataOut.heightList[0]
1161 1162
1162 1163 dataOut.nProfiles = int(dataOut.nProfiles*self.__nTxs)
1163 1164
1164 1165 dataOut.profileIndex = profileIndex
1165 1166
1166 1167 dataOut.ippSeconds /= self.__nTxs
1167 1168
1168 1169 return dataOut
1169 1170
1170 1171 class SplitProfiles(Operation):
1171 1172
1172 1173 def __init__(self, **kwargs):
1173 1174
1174 1175 Operation.__init__(self, **kwargs)
1175 1176
1176 1177 def run(self, dataOut, n):
1177 1178
1178 1179 dataOut.flagNoData = True
1179 1180 profileIndex = None
1180 1181
1181 1182 if dataOut.flagDataAsBlock:
1182 1183
1183 1184 #nchannels, nprofiles, nsamples
1184 1185 shape = dataOut.data.shape
1185 1186
1186 1187 if shape[2] % n != 0:
1187 1188 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[2]))
1188 1189
1189 1190 new_shape = shape[0], shape[1]*n, int(shape[2]/n)
1190 1191
1191 1192 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1192 1193 dataOut.flagNoData = False
1193 1194
1194 1195 profileIndex = int(dataOut.nProfiles/n) - 1
1195 1196
1196 1197 else:
1197 1198
1198 1199 raise ValueError("Could not split the data when is read Profile by Profile. Use VoltageReader(..., getblock=True)")
1199 1200
1200 1201 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1201 1202
1202 1203 dataOut.heightList = numpy.arange(dataOut.nHeights/n) * deltaHeight + dataOut.heightList[0]
1203 1204
1204 1205 dataOut.nProfiles = int(dataOut.nProfiles*n)
1205 1206
1206 1207 dataOut.profileIndex = profileIndex
1207 1208
1208 1209 dataOut.ippSeconds /= n
1209 1210
1210 1211 return dataOut
1211 1212
1212 1213 class CombineProfiles(Operation):
1213 1214 def __init__(self, **kwargs):
1214 1215
1215 1216 Operation.__init__(self, **kwargs)
1216 1217
1217 1218 self.__remData = None
1218 1219 self.__profileIndex = 0
1219 1220
1220 1221 def run(self, dataOut, n):
1221 1222
1222 1223 dataOut.flagNoData = True
1223 1224 profileIndex = None
1224 1225
1225 1226 if dataOut.flagDataAsBlock:
1226 1227
1227 1228 #nchannels, nprofiles, nsamples
1228 1229 shape = dataOut.data.shape
1229 1230 new_shape = shape[0], shape[1]/n, shape[2]*n
1230 1231
1231 1232 if shape[1] % n != 0:
1232 1233 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[1]))
1233 1234
1234 1235 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1235 1236 dataOut.flagNoData = False
1236 1237
1237 1238 profileIndex = int(dataOut.nProfiles*n) - 1
1238 1239
1239 1240 else:
1240 1241
1241 1242 #nchannels, nsamples
1242 1243 if self.__remData is None:
1243 1244 newData = dataOut.data
1244 1245 else:
1245 1246 newData = numpy.concatenate((self.__remData, dataOut.data), axis=1)
1246 1247
1247 1248 self.__profileIndex += 1
1248 1249
1249 1250 if self.__profileIndex < n:
1250 1251 self.__remData = newData
1251 1252 #continue
1252 1253 return
1253 1254
1254 1255 self.__profileIndex = 0
1255 1256 self.__remData = None
1256 1257
1257 1258 dataOut.data = newData
1258 1259 dataOut.flagNoData = False
1259 1260
1260 1261 profileIndex = dataOut.profileIndex/n
1261 1262
1262 1263
1263 1264 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1264 1265
1265 1266 dataOut.heightList = numpy.arange(dataOut.nHeights*n) * deltaHeight + dataOut.heightList[0]
1266 1267
1267 1268 dataOut.nProfiles = int(dataOut.nProfiles/n)
1268 1269
1269 1270 dataOut.profileIndex = profileIndex
1270 1271
1271 1272 dataOut.ippSeconds *= n
1272 1273
1273 1274 return dataOut
1274 1275
1275 1276 class PulsePairVoltage(Operation):
1276 1277 '''
1277 1278 Function PulsePair(Signal Power, Velocity)
1278 1279 The real component of Lag[0] provides Intensity Information
1279 1280 The imag component of Lag[1] Phase provides Velocity Information
1280 1281
1281 1282 Configuration Parameters:
1282 1283 nPRF = Number of Several PRF
1283 1284 theta = Degree Azimuth angel Boundaries
1284 1285
1285 1286 Input:
1286 1287 self.dataOut
1287 1288 lag[N]
1288 1289 Affected:
1289 1290 self.dataOut.spc
1290 1291 '''
1291 1292 isConfig = False
1292 1293 __profIndex = 0
1293 1294 __initime = None
1294 1295 __lastdatatime = None
1295 1296 __buffer = None
1296 1297 noise = None
1297 1298 __dataReady = False
1298 1299 n = None
1299 1300 __nch = 0
1300 1301 __nHeis = 0
1301 1302 removeDC = False
1302 1303 ipp = None
1303 1304 lambda_ = 0
1304 1305
1305 1306 def __init__(self,**kwargs):
1306 1307 Operation.__init__(self,**kwargs)
1307 1308
1308 1309 def setup(self, dataOut, n = None, removeDC=False):
1309 1310 '''
1310 1311 n= Numero de PRF's de entrada
1311 1312 '''
1312 1313 self.__initime = None
1313 1314 self.__lastdatatime = 0
1314 1315 self.__dataReady = False
1315 1316 self.__buffer = 0
1316 1317 self.__profIndex = 0
1317 1318 self.noise = None
1318 1319 self.__nch = dataOut.nChannels
1319 1320 self.__nHeis = dataOut.nHeights
1320 1321 self.removeDC = removeDC
1321 1322 self.lambda_ = 3.0e8/(9345.0e6)
1322 1323 self.ippSec = dataOut.ippSeconds
1323 1324 self.nCohInt = dataOut.nCohInt
1324 1325 print("IPPseconds",dataOut.ippSeconds)
1325 1326
1326 1327 print("ELVALOR DE n es:", n)
1327 1328 if n == None:
1328 1329 raise ValueError("n should be specified.")
1329 1330
1330 1331 if n != None:
1331 1332 if n<2:
1332 1333 raise ValueError("n should be greater than 2")
1333 1334
1334 1335 self.n = n
1335 1336 self.__nProf = n
1336 1337
1337 1338 self.__buffer = numpy.zeros((dataOut.nChannels,
1338 1339 n,
1339 1340 dataOut.nHeights),
1340 1341 dtype='complex')
1341 #self.noise = numpy.zeros([self.__nch,self.__nHeis])
1342 #for i in range(self.__nch):
1343 # self.noise[i]=dataOut.getNoise(channel=i)
1344 1342
1345 1343 def putData(self,data):
1346 1344 '''
1347 1345 Add a profile to he __buffer and increase in one the __profiel Index
1348 1346 '''
1349 1347 self.__buffer[:,self.__profIndex,:]= data
1350 1348 self.__profIndex += 1
1351 1349 return
1352 1350
1353 1351 def pushData(self,dataOut):
1354 1352 '''
1355 1353 Return the PULSEPAIR and the profiles used in the operation
1356 1354 Affected : self.__profileIndex
1357 1355 '''
1356 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Remove DCΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1358 1357 if self.removeDC==True:
1359 1358 mean = numpy.mean(self.__buffer,1)
1360 1359 tmp = mean.reshape(self.__nch,1,self.__nHeis)
1361 1360 dc= numpy.tile(tmp,[1,self.__nProf,1])
1362 1361 self.__buffer = self.__buffer - dc
1362 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Calculo de Potencia Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1363 pair0 = self.__buffer*numpy.conj(self.__buffer)
1364 pair0 = pair0.real
1365 lag_0 = numpy.sum(pair0,1)
1366 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Calculo de Ruido x canalΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1367 self.noise = numpy.zeros(self.__nch)
1368 for i in range(self.__nch):
1369 daux = numpy.sort(pair0[i,:,:],axis= None)
1370 self.noise[i]=hildebrand_sekhon( daux ,self.nCohInt)
1371
1372 self.noise = self.noise.reshape(self.__nch,1)
1373 self.noise = numpy.tile(self.noise,[1,self.__nHeis])
1374 noise_buffer = self.noise.reshape(self.__nch,1,self.__nHeis)
1375 noise_buffer = numpy.tile(noise_buffer,[1,self.__nProf,1])
1376 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Potencia recibida= P , Potencia senal = S , Ruido= NΒ·Β·
1377 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· P= S+N ,P=lag_0/N Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1378 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Power Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1379 data_power = lag_0/(self.n*self.nCohInt)
1380 #------------------ Senal Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1381 data_intensity = pair0 - noise_buffer
1382 data_intensity = numpy.sum(data_intensity,axis=1)*(self.n*self.nCohInt)#*self.nCohInt)
1383 #data_intensity = (lag_0-self.noise*self.n)*(self.n*self.nCohInt)
1384 for i in range(self.__nch):
1385 for j in range(self.__nHeis):
1386 if data_intensity[i][j] < 0:
1387 data_intensity[i][j] = numpy.min(numpy.absolute(data_intensity[i][j]))
1363 1388
1364 lag_0 = numpy.sum(self.__buffer*numpy.conj(self.__buffer),1)
1365 data_intensity = lag_0/(self.n*self.nCohInt)#*self.nCohInt)
1366
1389 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Calculo de Frecuencia y Velocidad dopplerΒ·Β·Β·Β·Β·Β·Β·Β·
1367 1390 pair1 = self.__buffer[:,:-1,:]*numpy.conjugate(self.__buffer[:,1:,:])
1368 1391 lag_1 = numpy.sum(pair1,1)
1369 #angle = numpy.angle(numpy.sum(pair1,1))*180/(math.pi)
1370 data_velocity = (-1.0*self.lambda_/(4*math.pi*self.ippSec))*numpy.angle(lag_1)#self.ippSec*self.nCohInt
1392 data_freq = (-1/(2.0*math.pi*self.ippSec*self.nCohInt))*numpy.angle(lag_1)
1393 data_velocity = (self.lambda_/2.0)*data_freq
1371 1394
1372 self.noise = numpy.zeros([self.__nch,self.__nHeis])
1373 for i in range(self.__nch):
1374 self.noise[i]=dataOut.getNoise(channel=i)
1395 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Potencia promedio estimada de la SenalΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1396 lag_0 = lag_0/self.n
1397 S = lag_0-self.noise
1375 1398
1376 lag_0 = lag_0.real/(self.n)
1399 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Frecuencia Doppler promedio Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1377 1400 lag_1 = lag_1/(self.n-1)
1378 1401 R1 = numpy.abs(lag_1)
1379 S = (lag_0-self.noise)
1380 1402
1403 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Calculo del SNRΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1381 1404 data_snrPP = S/self.noise
1382 data_snrPP = numpy.where(data_snrPP<0,1,data_snrPP)
1405 for i in range(self.__nch):
1406 for j in range(self.__nHeis):
1407 if data_snrPP[i][j] < 1.e-20:
1408 data_snrPP[i][j] = 1.e-20
1383 1409
1410 #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Calculo del ancho espectral Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
1384 1411 L = S/R1
1385 1412 L = numpy.where(L<0,1,L)
1386 1413 L = numpy.log(L)
1387
1388 1414 tmp = numpy.sqrt(numpy.absolute(L))
1389
1390 data_specwidth = (self.lambda_/(2*math.sqrt(2)*math.pi*self.ippSec))*tmp*numpy.sign(L)
1391 #data_specwidth = (self.lambda_/(2*math.sqrt(2)*math.pi*self.ippSec))*k
1415 data_specwidth = (self.lambda_/(2*math.sqrt(2)*math.pi*self.ippSec*self.nCohInt))*tmp*numpy.sign(L)
1392 1416 n = self.__profIndex
1393 1417
1394 1418 self.__buffer = numpy.zeros((self.__nch, self.__nProf,self.__nHeis), dtype='complex')
1395 1419 self.__profIndex = 0
1396 return data_intensity,data_velocity,data_snrPP,data_specwidth,n
1420 return data_power,data_intensity,data_velocity,data_snrPP,data_specwidth,n
1397 1421
1398 1422 def pulsePairbyProfiles(self,dataOut):
1399 1423
1400 1424 self.__dataReady = False
1425 data_power = None
1401 1426 data_intensity = None
1402 1427 data_velocity = None
1403 1428 data_specwidth = None
1404 1429 data_snrPP = None
1405 1430 self.putData(data=dataOut.data)
1406 1431 if self.__profIndex == self.n:
1407 #self.noise = numpy.zeros([self.__nch,self.__nHeis])
1408 #for i in range(self.__nch):
1409 # self.noise[i]=data.getNoise(channel=i)
1410 #print(self.noise.shape)
1411 data_intensity, data_velocity,data_snrPP,data_specwidth, n = self.pushData(dataOut=dataOut)
1432 data_power,data_intensity, data_velocity,data_snrPP,data_specwidth, n = self.pushData(dataOut=dataOut)
1412 1433 self.__dataReady = True
1413 1434
1414 return data_intensity, data_velocity,data_snrPP,data_specwidth
1435 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth
1415 1436
1416 1437 def pulsePairOp(self, dataOut, datatime= None):
1417 1438
1418 1439 if self.__initime == None:
1419 1440 self.__initime = datatime
1420 #print("hola")
1421 data_intensity, data_velocity,data_snrPP,data_specwidth = self.pulsePairbyProfiles(dataOut)
1441 data_power, data_intensity, data_velocity, data_snrPP, data_specwidth = self.pulsePairbyProfiles(dataOut)
1422 1442 self.__lastdatatime = datatime
1423 1443
1424 if data_intensity is None:
1425 return None, None,None,None,None
1444 if data_power is None:
1445 return None, None, None,None,None,None
1426 1446
1427 1447 avgdatatime = self.__initime
1428 1448 deltatime = datatime - self.__lastdatatime
1429 1449 self.__initime = datatime
1430 1450
1431 return data_intensity, data_velocity,data_snrPP,data_specwidth,avgdatatime
1451 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth, avgdatatime
1432 1452
1433 1453 def run(self, dataOut,n = None,removeDC= False, overlapping= False,**kwargs):
1434 1454
1435 1455 if not self.isConfig:
1436 1456 self.setup(dataOut = dataOut, n = n , removeDC=removeDC , **kwargs)
1437 1457 self.isConfig = True
1438 data_intensity, data_velocity,data_snrPP,data_specwidth, avgdatatime = self.pulsePairOp(dataOut, dataOut.utctime)
1458 data_power, data_intensity, data_velocity,data_snrPP,data_specwidth, avgdatatime = self.pulsePairOp(dataOut, dataOut.utctime)
1439 1459 dataOut.flagNoData = True
1440 1460
1441 1461 if self.__dataReady:
1442 1462 dataOut.nCohInt *= self.n
1443 dataOut.data_intensity = data_intensity #valor para intensidad
1444 dataOut.data_velocity = data_velocity #valor para velocidad
1445 dataOut.data_snrPP = data_snrPP # valor para snr
1446 dataOut.data_specwidth = data_specwidth
1463 dataOut.dataPP_POW = data_intensity # S
1464 dataOut.dataPP_POWER = data_power # P
1465 dataOut.dataPP_DOP = data_velocity
1466 dataOut.dataPP_SNR = data_snrPP
1467 dataOut.dataPP_WIDTH = data_specwidth
1447 1468 dataOut.PRFbyAngle = self.n #numero de PRF*cada angulo rotado que equivale a un tiempo.
1448 1469 dataOut.utctime = avgdatatime
1449 1470 dataOut.flagNoData = False
1450 1471 return dataOut
1451 1472
1452 1473
1453 1474 # import collections
1454 1475 # from scipy.stats import mode
1455 1476 #
1456 1477 # class Synchronize(Operation):
1457 1478 #
1458 1479 # isConfig = False
1459 1480 # __profIndex = 0
1460 1481 #
1461 1482 # def __init__(self, **kwargs):
1462 1483 #
1463 1484 # Operation.__init__(self, **kwargs)
1464 1485 # # self.isConfig = False
1465 1486 # self.__powBuffer = None
1466 1487 # self.__startIndex = 0
1467 1488 # self.__pulseFound = False
1468 1489 #
1469 1490 # def __findTxPulse(self, dataOut, channel=0, pulse_with = None):
1470 1491 #
1471 1492 # #Read data
1472 1493 #
1473 1494 # powerdB = dataOut.getPower(channel = channel)
1474 1495 # noisedB = dataOut.getNoise(channel = channel)[0]
1475 1496 #
1476 1497 # self.__powBuffer.extend(powerdB.flatten())
1477 1498 #
1478 1499 # dataArray = numpy.array(self.__powBuffer)
1479 1500 #
1480 1501 # filteredPower = numpy.correlate(dataArray, dataArray[0:self.__nSamples], "same")
1481 1502 #
1482 1503 # maxValue = numpy.nanmax(filteredPower)
1483 1504 #
1484 1505 # if maxValue < noisedB + 10:
1485 1506 # #No se encuentra ningun pulso de transmision
1486 1507 # return None
1487 1508 #
1488 1509 # maxValuesIndex = numpy.where(filteredPower > maxValue - 0.1*abs(maxValue))[0]
1489 1510 #
1490 1511 # if len(maxValuesIndex) < 2:
1491 1512 # #Solo se encontro un solo pulso de transmision de un baudio, esperando por el siguiente TX
1492 1513 # return None
1493 1514 #
1494 1515 # phasedMaxValuesIndex = maxValuesIndex - self.__nSamples
1495 1516 #
1496 1517 # #Seleccionar solo valores con un espaciamiento de nSamples
1497 1518 # pulseIndex = numpy.intersect1d(maxValuesIndex, phasedMaxValuesIndex)
1498 1519 #
1499 1520 # if len(pulseIndex) < 2:
1500 1521 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1501 1522 # return None
1502 1523 #
1503 1524 # spacing = pulseIndex[1:] - pulseIndex[:-1]
1504 1525 #
1505 1526 # #remover senales que se distancien menos de 10 unidades o muestras
1506 1527 # #(No deberian existir IPP menor a 10 unidades)
1507 1528 #
1508 1529 # realIndex = numpy.where(spacing > 10 )[0]
1509 1530 #
1510 1531 # if len(realIndex) < 2:
1511 1532 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1512 1533 # return None
1513 1534 #
1514 1535 # #Eliminar pulsos anchos (deja solo la diferencia entre IPPs)
1515 1536 # realPulseIndex = pulseIndex[realIndex]
1516 1537 #
1517 1538 # period = mode(realPulseIndex[1:] - realPulseIndex[:-1])[0][0]
1518 1539 #
1519 1540 # print "IPP = %d samples" %period
1520 1541 #
1521 1542 # self.__newNSamples = dataOut.nHeights #int(period)
1522 1543 # self.__startIndex = int(realPulseIndex[0])
1523 1544 #
1524 1545 # return 1
1525 1546 #
1526 1547 #
1527 1548 # def setup(self, nSamples, nChannels, buffer_size = 4):
1528 1549 #
1529 1550 # self.__powBuffer = collections.deque(numpy.zeros( buffer_size*nSamples,dtype=numpy.float),
1530 1551 # maxlen = buffer_size*nSamples)
1531 1552 #
1532 1553 # bufferList = []
1533 1554 #
1534 1555 # for i in range(nChannels):
1535 1556 # bufferByChannel = collections.deque(numpy.zeros( buffer_size*nSamples, dtype=numpy.complex) + numpy.NAN,
1536 1557 # maxlen = buffer_size*nSamples)
1537 1558 #
1538 1559 # bufferList.append(bufferByChannel)
1539 1560 #
1540 1561 # self.__nSamples = nSamples
1541 1562 # self.__nChannels = nChannels
1542 1563 # self.__bufferList = bufferList
1543 1564 #
1544 1565 # def run(self, dataOut, channel = 0):
1545 1566 #
1546 1567 # if not self.isConfig:
1547 1568 # nSamples = dataOut.nHeights
1548 1569 # nChannels = dataOut.nChannels
1549 1570 # self.setup(nSamples, nChannels)
1550 1571 # self.isConfig = True
1551 1572 #
1552 1573 # #Append new data to internal buffer
1553 1574 # for thisChannel in range(self.__nChannels):
1554 1575 # bufferByChannel = self.__bufferList[thisChannel]
1555 1576 # bufferByChannel.extend(dataOut.data[thisChannel])
1556 1577 #
1557 1578 # if self.__pulseFound:
1558 1579 # self.__startIndex -= self.__nSamples
1559 1580 #
1560 1581 # #Finding Tx Pulse
1561 1582 # if not self.__pulseFound:
1562 1583 # indexFound = self.__findTxPulse(dataOut, channel)
1563 1584 #
1564 1585 # if indexFound == None:
1565 1586 # dataOut.flagNoData = True
1566 1587 # return
1567 1588 #
1568 1589 # self.__arrayBuffer = numpy.zeros((self.__nChannels, self.__newNSamples), dtype = numpy.complex)
1569 1590 # self.__pulseFound = True
1570 1591 # self.__startIndex = indexFound
1571 1592 #
1572 1593 # #If pulse was found ...
1573 1594 # for thisChannel in range(self.__nChannels):
1574 1595 # bufferByChannel = self.__bufferList[thisChannel]
1575 1596 # #print self.__startIndex
1576 1597 # x = numpy.array(bufferByChannel)
1577 1598 # self.__arrayBuffer[thisChannel] = x[self.__startIndex:self.__startIndex+self.__newNSamples]
1578 1599 #
1579 1600 # deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1580 1601 # dataOut.heightList = numpy.arange(self.__newNSamples)*deltaHeight
1581 1602 # # dataOut.ippSeconds = (self.__newNSamples / deltaHeight)/1e6
1582 1603 #
1583 1604 # dataOut.data = self.__arrayBuffer
1584 1605 #
1585 1606 # self.__startIndex += self.__newNSamples
1586 1607 #
1587 1608 # return
@@ -1,49 +1,76
1 1 import os,sys
2 2 import datetime
3 3 import time
4 4 from schainpy.controller import Project
5 path = '/home/alex/Downloads/NEW_WR2/spc16removeDC'
6 figpath = path
5 #path = '/home/alex/Downloads/NEW_WR2/spc16removeDC'
6 #figpath = path
7
8 path = '/home/alex/Downloads/test_rawdata'
9 figpath = '/home/alex/Downloads/hdf5_testPP'
7 10 desc = "Simulator Test"
8 11
9 12 controllerObj = Project()
10 13
11 14 controllerObj.setup(id='10',name='Test Simulator',description=desc)
12 15
13 16 readUnitConfObj = controllerObj.addReadUnit(datatype='SimulatorReader',
14 17 frequency=9.345e9,
15 18 FixRCP_IPP= 60,
16 19 Tau_0 = 30,
17 20 AcqH0_0=0,
18 21 samples=330,
19 22 AcqDH_0=0.15,
20 23 FixRCP_TXA=0.15,
21 24 FixRCP_TXB=0.15,
22 25 Fdoppler=600.0,
23 26 Hdoppler=36,
24 27 Adoppler=300,#300
25 28 delay=0,
26 29 online=0,
27 30 walk=0,
28 nTotalReadFiles=3)
29
30 opObj11 = readUnitConfObj.addOperation(name='printInfo')
31 profilesPerBlock=625,
32 dataBlocksPerFile=100)#,#nTotalReadFiles=2)
31 33
34 '''
35 readUnitConfObj = controllerObj.addReadUnit(datatype='VoltageReader',
36 path=path,
37 startDate="2020/01/01", #"2020/01/01",#today,
38 endDate= "2020/12/01", #"2020/12/30",#today,
39 startTime='00:00:00',
40 endTime='23:59:59',
41 delay=0,
42 #set=0,
43 online=0,
44 walk=1)
45 '''
46 #opObj11 = readUnitConfObj.addOperation(name='printInfo')
32 47 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
33 48 #opObj11 = procUnitConfObjA.addOperation(name='CohInt', optype='other')
34 #opObj11.addParameter(name='n', value='10', format='int')
49 #opObj11.addParameter(name='n', value='4', format='int')
35 50
36 51 #opObj10 = procUnitConfObjA.addOperation(name='selectChannels')
37 52 #opObj10.addParameter(name='channelList', value=[0])
38 53 opObj11 = procUnitConfObjA.addOperation(name='PulsePairVoltage', optype='other')
39 opObj11.addParameter(name='n', value='300', format='int')#10
54 opObj11.addParameter(name='n', value='625', format='int')#10
40 55 opObj11.addParameter(name='removeDC', value=1, format='int')
41 56
42 57 #opObj11 = procUnitConfObjA.addOperation(name='PulsepairPowerPlot', optype='other')
58 #opObj11 = procUnitConfObjA.addOperation(name='PulsepairSignalPlot', optype='other')
43 59
44 opObj11 = procUnitConfObjA.addOperation(name='PulsepairVelocityPlot', optype='other')
60
61 #opObj11 = procUnitConfObjA.addOperation(name='PulsepairVelocityPlot', optype='other')
45 62 #opObj11.addParameter(name='xmax', value=8)
46 63
47 opObj11 = procUnitConfObjA.addOperation(name='PulsepairSpecwidthPlot', optype='other')
64 #opObj11 = procUnitConfObjA.addOperation(name='PulsepairSpecwidthPlot', optype='other')
65
66 procUnitConfObjB= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjA.getId())
67
68
69 opObj10 = procUnitConfObjB.addOperation(name='ParameterWriter')
70 opObj10.addParameter(name='path',value=figpath)
71 #opObj10.addParameter(name='mode',value=0)
72 opObj10.addParameter(name='blocksPerFile',value='100',format='int')
73 opObj10.addParameter(name='metadataList',value='utctimeInit,timeInterval',format='list')
74 opObj10.addParameter(name='dataList',value='dataPP_POW,dataPP_DOP,dataPP_SNR,dataPP_WIDTH')#,format='list'
48 75
49 76 controllerObj.start()
General Comments 0
You need to be logged in to leave comments. Login now