##// END OF EJS Templates
modificacion de atributos pulsepair y ploteo
avaldez -
r1315:a7b50d75d689
parent child
Show More
@@ -1,1397 +1,1403
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 362 data = None
363 data_intensity = None
364 data_velocity = None
365 data_specwidth = 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.flagCohInt = False
392 394 self.flagDecodeData = False # asumo q la data no esta decodificada
393 395 self.flagDeflipData = False # asumo q la data no esta sin flip
394 396 self.flagShiftFFT = False
395 397 self.flagDataAsBlock = False # Asumo que la data es leida perfil a perfil
396 398 self.profileIndex = 0
397 399
398 400 def getNoisebyHildebrand(self, channel=None):
399 401 """
400 402 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
401 403
402 404 Return:
403 405 noiselevel
404 406 """
405 407
406 408 if channel != None:
407 409 data = self.data[channel]
408 410 nChannels = 1
409 411 else:
410 412 data = self.data
411 413 nChannels = self.nChannels
412 414
413 415 noise = numpy.zeros(nChannels)
414 416 power = data * numpy.conjugate(data)
415 417
416 418 for thisChannel in range(nChannels):
417 419 if nChannels == 1:
418 420 daux = power[:].real
419 421 else:
420 422 daux = power[thisChannel, :].real
421 423 noise[thisChannel] = hildebrand_sekhon(daux, self.nCohInt)
422 424
423 425 return noise
424 426
425 427 def getNoise(self, type=1, channel=None):
426 428
427 429 if type == 1:
428 430 noise = self.getNoisebyHildebrand(channel)
429 431
430 432 return noise
431 433
432 434 def getPower(self, channel=None):
433 435
434 436 if channel != None:
435 437 data = self.data[channel]
436 438 else:
437 439 data = self.data
438 440
439 441 power = data * numpy.conjugate(data)
440 442 powerdB = 10 * numpy.log10(power.real)
441 443 powerdB = numpy.squeeze(powerdB)
442 444
443 445 return powerdB
444 446
445 447 def getTimeInterval(self):
446 448
447 449 timeInterval = self.ippSeconds * self.nCohInt
448 450
449 451 return timeInterval
450 452
451 453 noise = property(getNoise, "I'm the 'nHeights' property.")
452 454 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
453 455
454 456
455 457 class Spectra(JROData):
456 458
457 459 # data spc es un numpy array de 2 dmensiones (canales, perfiles, alturas)
458 460 data_spc = None
459 461 # data cspc es un numpy array de 2 dmensiones (canales, pares, alturas)
460 462 data_cspc = None
461 463 # data dc es un numpy array de 2 dmensiones (canales, alturas)
462 464 data_dc = None
463 465 # data power
464 466 data_pwr = None
465 467 nFFTPoints = None
466 468 # nPairs = None
467 469 pairsList = None
468 470 nIncohInt = None
469 471 wavelength = None # Necesario para cacular el rango de velocidad desde la frecuencia
470 472 nCohInt = None # se requiere para determinar el valor de timeInterval
471 473 ippFactor = None
472 474 profileIndex = 0
473 475 plotting = "spectra"
474 476
475 477 def __init__(self):
476 478 '''
477 479 Constructor
478 480 '''
479 481
480 482 self.useLocalTime = True
481 483 self.radarControllerHeaderObj = RadarControllerHeader()
482 484 self.systemHeaderObj = SystemHeader()
483 485 self.type = "Spectra"
484 486 # self.data = None
485 487 # self.dtype = None
486 488 # self.nChannels = 0
487 489 # self.nHeights = 0
488 490 self.nProfiles = None
489 491 self.heightList = None
490 492 self.channelList = None
491 493 # self.channelIndexList = None
492 494 self.pairsList = None
493 495 self.flagNoData = True
494 496 self.flagDiscontinuousBlock = False
495 497 self.utctime = None
496 498 self.nCohInt = None
497 499 self.nIncohInt = None
498 500 self.blocksize = None
499 501 self.nFFTPoints = None
500 502 self.wavelength = None
501 503 self.flagDecodeData = False # asumo q la data no esta decodificada
502 504 self.flagDeflipData = False # asumo q la data no esta sin flip
503 505 self.flagShiftFFT = False
504 506 self.ippFactor = 1
505 507 #self.noise = None
506 508 self.beacon_heiIndexList = []
507 509 self.noise_estimation = None
508 510
509 511 def getNoisebyHildebrand(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
510 512 """
511 513 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
512 514
513 515 Return:
514 516 noiselevel
515 517 """
516 518
517 519 noise = numpy.zeros(self.nChannels)
518 520
519 521 for channel in range(self.nChannels):
520 522 daux = self.data_spc[channel,
521 523 xmin_index:xmax_index, ymin_index:ymax_index]
522 524 noise[channel] = hildebrand_sekhon(daux, self.nIncohInt)
523 525
524 526 return noise
525 527
526 528 def getNoise(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
527 529
528 530 if self.noise_estimation is not None:
529 531 # this was estimated by getNoise Operation defined in jroproc_spectra.py
530 532 return self.noise_estimation
531 533 else:
532 534 noise = self.getNoisebyHildebrand(
533 535 xmin_index, xmax_index, ymin_index, ymax_index)
534 536 return noise
535 537
536 538 def getFreqRangeTimeResponse(self, extrapoints=0):
537 539
538 540 deltafreq = self.getFmaxTimeResponse() / (self.nFFTPoints * self.ippFactor)
539 541 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.) - deltafreq / 2
540 542
541 543 return freqrange
542 544
543 545 def getAcfRange(self, extrapoints=0):
544 546
545 547 deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor))
546 548 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
547 549
548 550 return freqrange
549 551
550 552 def getFreqRange(self, extrapoints=0):
551 553
552 554 deltafreq = self.getFmax() / (self.nFFTPoints * self.ippFactor)
553 555 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
554 556
555 557 return freqrange
556 558
557 559 def getVelRange(self, extrapoints=0):
558 560
559 561 deltav = self.getVmax() / (self.nFFTPoints * self.ippFactor)
560 562 velrange = deltav * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.)
561 563
562 564 if self.nmodes:
563 565 return velrange/self.nmodes
564 566 else:
565 567 return velrange
566 568
567 569 def getNPairs(self):
568 570
569 571 return len(self.pairsList)
570 572
571 573 def getPairsIndexList(self):
572 574
573 575 return list(range(self.nPairs))
574 576
575 577 def getNormFactor(self):
576 578
577 579 pwcode = 1
578 580
579 581 if self.flagDecodeData:
580 582 pwcode = numpy.sum(self.code[0]**2)
581 583 #normFactor = min(self.nFFTPoints,self.nProfiles)*self.nIncohInt*self.nCohInt*pwcode*self.windowOfFilter
582 584 normFactor = self.nProfiles * self.nIncohInt * self.nCohInt * pwcode * self.windowOfFilter
583 585
584 586 return normFactor
585 587
586 588 def getFlagCspc(self):
587 589
588 590 if self.data_cspc is None:
589 591 return True
590 592
591 593 return False
592 594
593 595 def getFlagDc(self):
594 596
595 597 if self.data_dc is None:
596 598 return True
597 599
598 600 return False
599 601
600 602 def getTimeInterval(self):
601 603
602 604 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt * self.nProfiles * self.ippFactor
603 605 if self.nmodes:
604 606 return self.nmodes*timeInterval
605 607 else:
606 608 return timeInterval
607 609
608 610 def getPower(self):
609 611
610 612 factor = self.normFactor
611 613 z = self.data_spc / factor
612 614 z = numpy.where(numpy.isfinite(z), z, numpy.NAN)
613 615 avg = numpy.average(z, axis=1)
614 616
615 617 return 10 * numpy.log10(avg)
616 618
617 619 def getCoherence(self, pairsList=None, phase=False):
618 620
619 621 z = []
620 622 if pairsList is None:
621 623 pairsIndexList = self.pairsIndexList
622 624 else:
623 625 pairsIndexList = []
624 626 for pair in pairsList:
625 627 if pair not in self.pairsList:
626 628 raise ValueError("Pair %s is not in dataOut.pairsList" % (
627 629 pair))
628 630 pairsIndexList.append(self.pairsList.index(pair))
629 631 for i in range(len(pairsIndexList)):
630 632 pair = self.pairsList[pairsIndexList[i]]
631 633 ccf = numpy.average(self.data_cspc[pairsIndexList[i], :, :], axis=0)
632 634 powa = numpy.average(self.data_spc[pair[0], :, :], axis=0)
633 635 powb = numpy.average(self.data_spc[pair[1], :, :], axis=0)
634 636 avgcoherenceComplex = ccf / numpy.sqrt(powa * powb)
635 637 if phase:
636 638 data = numpy.arctan2(avgcoherenceComplex.imag,
637 639 avgcoherenceComplex.real) * 180 / numpy.pi
638 640 else:
639 641 data = numpy.abs(avgcoherenceComplex)
640 642
641 643 z.append(data)
642 644
643 645 return numpy.array(z)
644 646
645 647 def setValue(self, value):
646 648
647 649 print("This property should not be initialized")
648 650
649 651 return
650 652
651 653 nPairs = property(getNPairs, setValue, "I'm the 'nPairs' property.")
652 654 pairsIndexList = property(
653 655 getPairsIndexList, setValue, "I'm the 'pairsIndexList' property.")
654 656 normFactor = property(getNormFactor, setValue,
655 657 "I'm the 'getNormFactor' property.")
656 658 flag_cspc = property(getFlagCspc, setValue)
657 659 flag_dc = property(getFlagDc, setValue)
658 660 noise = property(getNoise, setValue, "I'm the 'nHeights' property.")
659 661 timeInterval = property(getTimeInterval, setValue,
660 662 "I'm the 'timeInterval' property")
661 663
662 664
663 665 class SpectraHeis(Spectra):
664 666
665 667 data_spc = None
666 668 data_cspc = None
667 669 data_dc = None
668 670 nFFTPoints = None
669 671 # nPairs = None
670 672 pairsList = None
671 673 nCohInt = None
672 674 nIncohInt = None
673 675
674 676 def __init__(self):
675 677
676 678 self.radarControllerHeaderObj = RadarControllerHeader()
677 679
678 680 self.systemHeaderObj = SystemHeader()
679 681
680 682 self.type = "SpectraHeis"
681 683
682 684 # self.dtype = None
683 685
684 686 # self.nChannels = 0
685 687
686 688 # self.nHeights = 0
687 689
688 690 self.nProfiles = None
689 691
690 692 self.heightList = None
691 693
692 694 self.channelList = None
693 695
694 696 # self.channelIndexList = None
695 697
696 698 self.flagNoData = True
697 699
698 700 self.flagDiscontinuousBlock = False
699 701
700 702 # self.nPairs = 0
701 703
702 704 self.utctime = None
703 705
704 706 self.blocksize = None
705 707
706 708 self.profileIndex = 0
707 709
708 710 self.nCohInt = 1
709 711
710 712 self.nIncohInt = 1
711 713
712 714 def getNormFactor(self):
713 715 pwcode = 1
714 716 if self.flagDecodeData:
715 717 pwcode = numpy.sum(self.code[0]**2)
716 718
717 719 normFactor = self.nIncohInt * self.nCohInt * pwcode
718 720
719 721 return normFactor
720 722
721 723 def getTimeInterval(self):
722 724
723 725 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
724 726
725 727 return timeInterval
726 728
727 729 normFactor = property(getNormFactor, "I'm the 'getNormFactor' property.")
728 730 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
729 731
730 732
731 733 class Fits(JROData):
732 734
733 735 heightList = None
734 736 channelList = None
735 737 flagNoData = True
736 738 flagDiscontinuousBlock = False
737 739 useLocalTime = False
738 740 utctime = None
739 741 timeZone = None
740 742 # ippSeconds = None
741 743 # timeInterval = None
742 744 nCohInt = None
743 745 nIncohInt = None
744 746 noise = None
745 747 windowOfFilter = 1
746 748 # Speed of ligth
747 749 C = 3e8
748 750 frequency = 49.92e6
749 751 realtime = False
750 752
751 753 def __init__(self):
752 754
753 755 self.type = "Fits"
754 756
755 757 self.nProfiles = None
756 758
757 759 self.heightList = None
758 760
759 761 self.channelList = None
760 762
761 763 # self.channelIndexList = None
762 764
763 765 self.flagNoData = True
764 766
765 767 self.utctime = None
766 768
767 769 self.nCohInt = 1
768 770
769 771 self.nIncohInt = 1
770 772
771 773 self.useLocalTime = True
772 774
773 775 self.profileIndex = 0
774 776
775 777 # self.utctime = None
776 778 # self.timeZone = None
777 779 # self.ltctime = None
778 780 # self.timeInterval = None
779 781 # self.header = None
780 782 # self.data_header = None
781 783 # self.data = None
782 784 # self.datatime = None
783 785 # self.flagNoData = False
784 786 # self.expName = ''
785 787 # self.nChannels = None
786 788 # self.nSamples = None
787 789 # self.dataBlocksPerFile = None
788 790 # self.comments = ''
789 791 #
790 792
791 793 def getltctime(self):
792 794
793 795 if self.useLocalTime:
794 796 return self.utctime - self.timeZone * 60
795 797
796 798 return self.utctime
797 799
798 800 def getDatatime(self):
799 801
800 802 datatime = datetime.datetime.utcfromtimestamp(self.ltctime)
801 803 return datatime
802 804
803 805 def getTimeRange(self):
804 806
805 807 datatime = []
806 808
807 809 datatime.append(self.ltctime)
808 810 datatime.append(self.ltctime + self.timeInterval)
809 811
810 812 datatime = numpy.array(datatime)
811 813
812 814 return datatime
813 815
814 816 def getHeiRange(self):
815 817
816 818 heis = self.heightList
817 819
818 820 return heis
819 821
820 822 def getNHeights(self):
821 823
822 824 return len(self.heightList)
823 825
824 826 def getNChannels(self):
825 827
826 828 return len(self.channelList)
827 829
828 830 def getChannelIndexList(self):
829 831
830 832 return list(range(self.nChannels))
831 833
832 834 def getNoise(self, type=1):
833 835
834 836 #noise = numpy.zeros(self.nChannels)
835 837
836 838 if type == 1:
837 839 noise = self.getNoisebyHildebrand()
838 840
839 841 if type == 2:
840 842 noise = self.getNoisebySort()
841 843
842 844 if type == 3:
843 845 noise = self.getNoisebyWindow()
844 846
845 847 return noise
846 848
847 849 def getTimeInterval(self):
848 850
849 851 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
850 852
851 853 return timeInterval
852 854
853 855 def get_ippSeconds(self):
854 856 '''
855 857 '''
856 858 return self.ipp_sec
857 859
858 860
859 861 datatime = property(getDatatime, "I'm the 'datatime' property")
860 862 nHeights = property(getNHeights, "I'm the 'nHeights' property.")
861 863 nChannels = property(getNChannels, "I'm the 'nChannel' property.")
862 864 channelIndexList = property(
863 865 getChannelIndexList, "I'm the 'channelIndexList' property.")
864 866 noise = property(getNoise, "I'm the 'nHeights' property.")
865 867
866 868 ltctime = property(getltctime, "I'm the 'ltctime' property")
867 869 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
868 870 ippSeconds = property(get_ippSeconds, '')
869 871
870 872 class Correlation(JROData):
871 873
872 874 noise = None
873 875 SNR = None
874 876 #--------------------------------------------------
875 877 mode = None
876 878 split = False
877 879 data_cf = None
878 880 lags = None
879 881 lagRange = None
880 882 pairsList = None
881 883 normFactor = None
882 884 #--------------------------------------------------
883 885 # calculateVelocity = None
884 886 nLags = None
885 887 nPairs = None
886 888 nAvg = None
887 889
888 890 def __init__(self):
889 891 '''
890 892 Constructor
891 893 '''
892 894 self.radarControllerHeaderObj = RadarControllerHeader()
893 895
894 896 self.systemHeaderObj = SystemHeader()
895 897
896 898 self.type = "Correlation"
897 899
898 900 self.data = None
899 901
900 902 self.dtype = None
901 903
902 904 self.nProfiles = None
903 905
904 906 self.heightList = None
905 907
906 908 self.channelList = None
907 909
908 910 self.flagNoData = True
909 911
910 912 self.flagDiscontinuousBlock = False
911 913
912 914 self.utctime = None
913 915
914 916 self.timeZone = None
915 917
916 918 self.dstFlag = None
917 919
918 920 self.errorCount = None
919 921
920 922 self.blocksize = None
921 923
922 924 self.flagDecodeData = False # asumo q la data no esta decodificada
923 925
924 926 self.flagDeflipData = False # asumo q la data no esta sin flip
925 927
926 928 self.pairsList = None
927 929
928 930 self.nPoints = None
929 931
930 932 def getPairsList(self):
931 933
932 934 return self.pairsList
933 935
934 936 def getNoise(self, mode=2):
935 937
936 938 indR = numpy.where(self.lagR == 0)[0][0]
937 939 indT = numpy.where(self.lagT == 0)[0][0]
938 940
939 941 jspectra0 = self.data_corr[:, :, indR, :]
940 942 jspectra = copy.copy(jspectra0)
941 943
942 944 num_chan = jspectra.shape[0]
943 945 num_hei = jspectra.shape[2]
944 946
945 947 freq_dc = jspectra.shape[1] / 2
946 948 ind_vel = numpy.array([-2, -1, 1, 2]) + freq_dc
947 949
948 950 if ind_vel[0] < 0:
949 951 ind_vel[list(range(0, 1))] = ind_vel[list(
950 952 range(0, 1))] + self.num_prof
951 953
952 954 if mode == 1:
953 955 jspectra[:, freq_dc, :] = (
954 956 jspectra[:, ind_vel[1], :] + jspectra[:, ind_vel[2], :]) / 2 # CORRECCION
955 957
956 958 if mode == 2:
957 959
958 960 vel = numpy.array([-2, -1, 1, 2])
959 961 xx = numpy.zeros([4, 4])
960 962
961 963 for fil in range(4):
962 964 xx[fil, :] = vel[fil]**numpy.asarray(list(range(4)))
963 965
964 966 xx_inv = numpy.linalg.inv(xx)
965 967 xx_aux = xx_inv[0, :]
966 968
967 969 for ich in range(num_chan):
968 970 yy = jspectra[ich, ind_vel, :]
969 971 jspectra[ich, freq_dc, :] = numpy.dot(xx_aux, yy)
970 972
971 973 junkid = jspectra[ich, freq_dc, :] <= 0
972 974 cjunkid = sum(junkid)
973 975
974 976 if cjunkid.any():
975 977 jspectra[ich, freq_dc, junkid.nonzero()] = (
976 978 jspectra[ich, ind_vel[1], junkid] + jspectra[ich, ind_vel[2], junkid]) / 2
977 979
978 980 noise = jspectra0[:, freq_dc, :] - jspectra[:, freq_dc, :]
979 981
980 982 return noise
981 983
982 984 def getTimeInterval(self):
983 985
984 986 timeInterval = self.ippSeconds * self.nCohInt * self.nProfiles
985 987
986 988 return timeInterval
987 989
988 990 def splitFunctions(self):
989 991
990 992 pairsList = self.pairsList
991 993 ccf_pairs = []
992 994 acf_pairs = []
993 995 ccf_ind = []
994 996 acf_ind = []
995 997 for l in range(len(pairsList)):
996 998 chan0 = pairsList[l][0]
997 999 chan1 = pairsList[l][1]
998 1000
999 1001 # Obteniendo pares de Autocorrelacion
1000 1002 if chan0 == chan1:
1001 1003 acf_pairs.append(chan0)
1002 1004 acf_ind.append(l)
1003 1005 else:
1004 1006 ccf_pairs.append(pairsList[l])
1005 1007 ccf_ind.append(l)
1006 1008
1007 1009 data_acf = self.data_cf[acf_ind]
1008 1010 data_ccf = self.data_cf[ccf_ind]
1009 1011
1010 1012 return acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf
1011 1013
1012 1014 def getNormFactor(self):
1013 1015 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.splitFunctions()
1014 1016 acf_pairs = numpy.array(acf_pairs)
1015 1017 normFactor = numpy.zeros((self.nPairs, self.nHeights))
1016 1018
1017 1019 for p in range(self.nPairs):
1018 1020 pair = self.pairsList[p]
1019 1021
1020 1022 ch0 = pair[0]
1021 1023 ch1 = pair[1]
1022 1024
1023 1025 ch0_max = numpy.max(data_acf[acf_pairs == ch0, :, :], axis=1)
1024 1026 ch1_max = numpy.max(data_acf[acf_pairs == ch1, :, :], axis=1)
1025 1027 normFactor[p, :] = numpy.sqrt(ch0_max * ch1_max)
1026 1028
1027 1029 return normFactor
1028 1030
1029 1031 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
1030 1032 normFactor = property(getNormFactor, "I'm the 'normFactor property'")
1031 1033
1032 1034
1033 1035 class Parameters(Spectra):
1034 1036
1035 1037 experimentInfo = None # Information about the experiment
1036 1038 # Information from previous data
1037 1039 inputUnit = None # Type of data to be processed
1038 1040 operation = None # Type of operation to parametrize
1039 1041 # normFactor = None #Normalization Factor
1040 1042 groupList = None # List of Pairs, Groups, etc
1041 1043 # Parameters
1042 1044 data_param = None # Parameters obtained
1043 1045 data_pre = None # Data Pre Parametrization
1044 1046 data_SNR = None # Signal to Noise Ratio
1045 1047 # heightRange = None #Heights
1046 1048 abscissaList = None # Abscissa, can be velocities, lags or time
1047 1049 # noise = None #Noise Potency
1048 1050 utctimeInit = None # Initial UTC time
1049 1051 paramInterval = None # Time interval to calculate Parameters in seconds
1050 1052 useLocalTime = True
1051 1053 # Fitting
1052 1054 data_error = None # Error of the estimation
1053 1055 constants = None
1054 1056 library = None
1055 1057 # Output signal
1056 1058 outputInterval = None # Time interval to calculate output signal in seconds
1057 1059 data_output = None # Out signal
1058 1060 nAvg = None
1059 1061 noise_estimation = None
1060 1062 GauSPC = None # Fit gaussian SPC
1061 1063
1062 1064 def __init__(self):
1063 1065 '''
1064 1066 Constructor
1065 1067 '''
1066 1068 self.radarControllerHeaderObj = RadarControllerHeader()
1067 1069
1068 1070 self.systemHeaderObj = SystemHeader()
1069 1071
1070 1072 self.type = "Parameters"
1071 1073
1072 1074 def getTimeRange1(self, interval):
1073 1075
1074 1076 datatime = []
1075 1077
1076 1078 if self.useLocalTime:
1077 1079 time1 = self.utctimeInit - self.timeZone * 60
1078 1080 else:
1079 1081 time1 = self.utctimeInit
1080 1082
1081 1083 datatime.append(time1)
1082 1084 datatime.append(time1 + interval)
1083 1085 datatime = numpy.array(datatime)
1084 1086
1085 1087 return datatime
1086 1088
1087 1089 def getTimeInterval(self):
1088 1090
1089 1091 if hasattr(self, 'timeInterval1'):
1090 1092 return self.timeInterval1
1091 1093 else:
1092 1094 return self.paramInterval
1093 1095
1094 1096 def setValue(self, value):
1095 1097
1096 1098 print("This property should not be initialized")
1097 1099
1098 1100 return
1099 1101
1100 1102 def getNoise(self):
1101 1103
1102 1104 return self.spc_noise
1103 1105
1104 1106 timeInterval = property(getTimeInterval)
1105 1107 noise = property(getNoise, setValue, "I'm the 'Noise' property.")
1106 1108
1107 1109
1108 1110 class PlotterData(object):
1109 1111 '''
1110 1112 Object to hold data to be plotted
1111 1113 '''
1112 1114
1113 1115 MAXNUMX = 200
1114 1116 MAXNUMY = 200
1115 1117
1116 1118 def __init__(self, code, throttle_value, exp_code, buffering=True, snr=False):
1117 1119
1118 1120 self.key = code
1119 1121 self.throttle = throttle_value
1120 1122 self.exp_code = exp_code
1121 1123 self.buffering = buffering
1122 1124 self.ready = False
1123 1125 self.flagNoData = False
1124 1126 self.localtime = False
1125 1127 self.data = {}
1126 1128 self.meta = {}
1127 1129 self.__heights = []
1128 1130
1129 1131 if 'snr' in code:
1130 1132 self.plottypes = ['snr']
1131 1133 elif code == 'spc':
1132 1134 self.plottypes = ['spc', 'noise', 'rti']
1133 1135 elif code == 'cspc':
1134 1136 self.plottypes = ['cspc', 'spc', 'noise', 'rti']
1135 1137 elif code == 'rti':
1136 1138 self.plottypes = ['noise', 'rti']
1137 1139 else:
1138 1140 self.plottypes = [code]
1139 1141
1140 1142 if 'snr' not in self.plottypes and snr:
1141 1143 self.plottypes.append('snr')
1142 1144
1143 1145 for plot in self.plottypes:
1144 1146 self.data[plot] = {}
1145 1147
1146 1148
1147 1149 def __str__(self):
1148 1150 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
1149 1151 return 'Data[{}][{}]'.format(';'.join(dum), len(self.times))
1150 1152
1151 1153 def __len__(self):
1152 1154 return len(self.data[self.key])
1153 1155
1154 1156 def __getitem__(self, key):
1155 1157
1156 1158 if key not in self.data:
1157 1159 raise KeyError(log.error('Missing key: {}'.format(key)))
1158 1160 if 'spc' in key or not self.buffering:
1159 1161 ret = self.data[key][self.tm]
1160 1162 elif 'scope' in key:
1161 1163 ret = numpy.array(self.data[key][float(self.tm)])
1162 1164 else:
1163 1165 ret = numpy.array([self.data[key][x] for x in self.times])
1164 1166 if ret.ndim > 1:
1165 1167 ret = numpy.swapaxes(ret, 0, 1)
1166 1168 return ret
1167 1169
1168 1170 def __contains__(self, key):
1169 1171 return key in self.data
1170 1172
1171 1173 def setup(self):
1172 1174 '''
1173 1175 Configure object
1174 1176 '''
1175 1177 self.type = ''
1176 1178 self.ready = False
1177 1179 del self.data
1178 1180 self.data = {}
1179 1181 self.__heights = []
1180 1182 self.__all_heights = set()
1181 1183 for plot in self.plottypes:
1182 1184 if 'snr' in plot:
1183 1185 plot = 'snr'
1184 1186 elif 'spc_moments' == plot:
1185 1187 plot = 'moments'
1186 1188 self.data[plot] = {}
1187 1189
1188 1190 if 'spc' in self.data or 'rti' in self.data or 'cspc' in self.data or 'moments' in self.data:
1189 1191 self.data['noise'] = {}
1190 1192 self.data['rti'] = {}
1191 1193 if 'noise' not in self.plottypes:
1192 1194 self.plottypes.append('noise')
1193 1195 if 'rti' not in self.plottypes:
1194 1196 self.plottypes.append('rti')
1195 1197
1196 1198 def shape(self, key):
1197 1199 '''
1198 1200 Get the shape of the one-element data for the given key
1199 1201 '''
1200 1202
1201 1203 if len(self.data[key]):
1202 1204 if 'spc' in key or not self.buffering:
1203 1205 return self.data[key].shape
1204 1206 return self.data[key][self.times[0]].shape
1205 1207 return (0,)
1206 1208
1207 1209 def update(self, dataOut, tm):
1208 1210 '''
1209 1211 Update data object with new dataOut
1210 1212 '''
1211
1213
1212 1214 self.profileIndex = dataOut.profileIndex
1213 1215 self.tm = tm
1214 1216 self.type = dataOut.type
1215 1217 self.parameters = getattr(dataOut, 'parameters', [])
1216 1218
1217 1219 if hasattr(dataOut, 'meta'):
1218 1220 self.meta.update(dataOut.meta)
1219 1221
1220 1222 if hasattr(dataOut, 'pairsList'):
1221 1223 self.pairs = dataOut.pairsList
1222 1224
1223 1225 self.interval = dataOut.getTimeInterval()
1224 1226 self.localtime = dataOut.useLocalTime
1225 1227 if True in ['spc' in ptype for ptype in self.plottypes]:
1226 1228 self.xrange = (dataOut.getFreqRange(1)/1000.,
1227 1229 dataOut.getAcfRange(1), dataOut.getVelRange(1))
1228 1230 self.__heights.append(dataOut.heightList)
1229 1231 self.__all_heights.update(dataOut.heightList)
1230 1232
1231 1233 for plot in self.plottypes:
1232 1234 if plot in ('spc', 'spc_moments', 'spc_cut'):
1233 1235 z = dataOut.data_spc/dataOut.normFactor
1234 1236 buffer = 10*numpy.log10(z)
1235 1237 if plot == 'cspc':
1236 1238 buffer = (dataOut.data_spc, dataOut.data_cspc)
1237 1239 if plot == 'noise':
1238 1240 buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
1239 1241 if plot in ('rti', 'spcprofile'):
1240 1242 buffer = dataOut.getPower()
1241 1243 if plot == 'snr_db':
1242 1244 buffer = dataOut.data_SNR
1243 1245 if plot == 'snr':
1244 1246 buffer = 10*numpy.log10(dataOut.data_SNR)
1245 1247 if plot == 'dop':
1246 1248 buffer = dataOut.data_DOP
1247 1249 if plot == 'pow':
1248 1250 buffer = 10*numpy.log10(dataOut.data_POW)
1249 1251 if plot == 'width':
1250 1252 buffer = dataOut.data_WIDTH
1251 1253 if plot == 'coh':
1252 1254 buffer = dataOut.getCoherence()
1253 1255 if plot == 'phase':
1254 1256 buffer = dataOut.getCoherence(phase=True)
1255 1257 if plot == 'output':
1256 1258 buffer = dataOut.data_output
1257 1259 if plot == 'param':
1258 1260 buffer = dataOut.data_param
1259 1261 if plot == 'scope':
1260 1262 buffer = dataOut.data
1261 1263 self.flagDataAsBlock = dataOut.flagDataAsBlock
1262 1264 self.nProfiles = dataOut.nProfiles
1263 1265 if plot == 'pp_power':
1264 buffer = dataOut.data_intensity
1266 buffer = dataOut.dataPP_POWER
1267 self.flagDataAsBlock = dataOut.flagDataAsBlock
1268 self.nProfiles = dataOut.nProfiles
1269 if plot == 'pp_signal':
1270 buffer = dataOut.dataPP_POW
1265 1271 self.flagDataAsBlock = dataOut.flagDataAsBlock
1266 1272 self.nProfiles = dataOut.nProfiles
1267 1273 if plot == 'pp_velocity':
1268 buffer = dataOut.data_velocity
1274 buffer = dataOut.dataPP_DOP
1269 1275 self.flagDataAsBlock = dataOut.flagDataAsBlock
1270 1276 self.nProfiles = dataOut.nProfiles
1271 1277 if plot == 'pp_specwidth':
1272 buffer = dataOut.data_specwidth
1278 buffer = dataOut.dataPP_WIDTH
1273 1279 self.flagDataAsBlock = dataOut.flagDataAsBlock
1274 1280 self.nProfiles = dataOut.nProfiles
1275 1281
1276 1282 if plot == 'spc':
1277 1283 self.data['spc'][tm] = buffer
1278 1284 elif plot == 'cspc':
1279 1285 self.data['cspc'][tm] = buffer
1280 1286 elif plot == 'spc_moments':
1281 1287 self.data['spc'][tm] = buffer
1282 1288 self.data['moments'][tm] = dataOut.moments
1283 1289 else:
1284 1290 if self.buffering:
1285 1291 self.data[plot][tm] = buffer
1286 1292 else:
1287 1293 self.data[plot][tm] = buffer
1288 1294
1289 1295 if dataOut.channelList is None:
1290 1296 self.channels = range(buffer.shape[0])
1291 1297 else:
1292 1298 self.channels = dataOut.channelList
1293 1299
1294 1300 if buffer is None:
1295 1301 self.flagNoData = True
1296 1302 raise schainpy.admin.SchainWarning('Attribute data_{} is empty'.format(self.key))
1297 1303
1298 1304 def normalize_heights(self):
1299 1305 '''
1300 1306 Ensure same-dimension of the data for different heighList
1301 1307 '''
1302 1308
1303 1309 H = numpy.array(list(self.__all_heights))
1304 1310 H.sort()
1305 1311 for key in self.data:
1306 1312 shape = self.shape(key)[:-1] + H.shape
1307 1313 for tm, obj in list(self.data[key].items()):
1308 1314 h = self.__heights[self.times.index(tm)]
1309 1315 if H.size == h.size:
1310 1316 continue
1311 1317 index = numpy.where(numpy.in1d(H, h))[0]
1312 1318 dummy = numpy.zeros(shape) + numpy.nan
1313 1319 if len(shape) == 2:
1314 1320 dummy[:, index] = obj
1315 1321 else:
1316 1322 dummy[index] = obj
1317 1323 self.data[key][tm] = dummy
1318 1324
1319 1325 self.__heights = [H for tm in self.times]
1320 1326
1321 1327 def jsonify(self, tm, plot_name, plot_type, decimate=False):
1322 1328 '''
1323 1329 Convert data to json
1324 1330 '''
1325 1331
1326 1332 dy = int(self.heights.size/self.MAXNUMY) + 1
1327 1333 if self.key in ('spc', 'cspc'):
1328 1334 dx = int(self.data[self.key][tm].shape[1]/self.MAXNUMX) + 1
1329 1335 data = self.roundFloats(
1330 1336 self.data[self.key][tm][::, ::dx, ::dy].tolist())
1331 1337 else:
1332 1338 if self.key is 'noise':
1333 1339 data = [[x] for x in self.roundFloats(self.data[self.key][tm].tolist())]
1334 1340 else:
1335 1341 data = self.roundFloats(self.data[self.key][tm][::, ::dy].tolist())
1336 1342
1337 1343 meta = {}
1338 1344 ret = {
1339 1345 'plot': plot_name,
1340 1346 'code': self.exp_code,
1341 1347 'time': float(tm),
1342 1348 'data': data,
1343 1349 }
1344 1350 meta['type'] = plot_type
1345 1351 meta['interval'] = float(self.interval)
1346 1352 meta['localtime'] = self.localtime
1347 1353 meta['yrange'] = self.roundFloats(self.heights[::dy].tolist())
1348 1354 if 'spc' in self.data or 'cspc' in self.data:
1349 1355 meta['xrange'] = self.roundFloats(self.xrange[2][::dx].tolist())
1350 1356 else:
1351 1357 meta['xrange'] = []
1352 1358
1353 1359 meta.update(self.meta)
1354 1360 ret['metadata'] = meta
1355 1361 return json.dumps(ret)
1356 1362
1357 1363 @property
1358 1364 def times(self):
1359 1365 '''
1360 1366 Return the list of times of the current data
1361 1367 '''
1362 1368
1363 1369 ret = numpy.array([*self.data[self.key]])
1364 1370 if self:
1365 1371 ret.sort()
1366 1372 return ret
1367 1373
1368 1374 @property
1369 1375 def min_time(self):
1370 1376 '''
1371 1377 Return the minimun time value
1372 1378 '''
1373 1379
1374 1380 return self.times[0]
1375 1381
1376 1382 @property
1377 1383 def max_time(self):
1378 1384 '''
1379 1385 Return the maximun time value
1380 1386 '''
1381 1387
1382 1388 return self.times[-1]
1383 1389
1384 1390 @property
1385 1391 def heights(self):
1386 1392 '''
1387 1393 Return the list of heights of the current data
1388 1394 '''
1389 1395
1390 1396 return numpy.array(self.__heights[-1])
1391 1397
1392 1398 @staticmethod
1393 1399 def roundFloats(obj):
1394 1400 if isinstance(obj, list):
1395 1401 return list(map(PlotterData.roundFloats, obj))
1396 1402 elif isinstance(obj, float):
1397 1403 return round(obj, 2)
General Comments 0
You need to be logged in to leave comments. Login now