##// END OF EJS Templates
Correct localtime in plots, handle exception in send_to_server
Juan C. Espinoza -
r1327:e2336f44bb45
parent child
Show More
@@ -1,1402 +1,1400
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 363 dataPP_POW = None
364 364 dataPP_DOP = None
365 365 dataPP_WIDTH = None
366 366 dataPP_SNR = None
367 367
368 368 def __init__(self):
369 369 '''
370 370 Constructor
371 371 '''
372 372
373 373 self.useLocalTime = True
374 374 self.radarControllerHeaderObj = RadarControllerHeader()
375 375 self.systemHeaderObj = SystemHeader()
376 376 self.type = "Voltage"
377 377 self.data = None
378 378 # self.dtype = None
379 379 # self.nChannels = 0
380 380 # self.nHeights = 0
381 381 self.nProfiles = None
382 382 self.heightList = None
383 383 self.channelList = None
384 384 # self.channelIndexList = None
385 385 self.flagNoData = True
386 386 self.flagDiscontinuousBlock = False
387 387 self.utctime = None
388 388 self.timeZone = 0
389 389 self.dstFlag = None
390 390 self.errorCount = None
391 391 self.nCohInt = None
392 392 self.blocksize = None
393 393 self.flagCohInt = False
394 394 self.flagDecodeData = False # asumo q la data no esta decodificada
395 395 self.flagDeflipData = False # asumo q la data no esta sin flip
396 396 self.flagShiftFFT = False
397 397 self.flagDataAsBlock = False # Asumo que la data es leida perfil a perfil
398 398 self.profileIndex = 0
399 399
400 400 def getNoisebyHildebrand(self, channel=None):
401 401 """
402 402 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
403 403
404 404 Return:
405 405 noiselevel
406 406 """
407 407
408 408 if channel != None:
409 409 data = self.data[channel]
410 410 nChannels = 1
411 411 else:
412 412 data = self.data
413 413 nChannels = self.nChannels
414 414
415 415 noise = numpy.zeros(nChannels)
416 416 power = data * numpy.conjugate(data)
417 417
418 418 for thisChannel in range(nChannels):
419 419 if nChannels == 1:
420 420 daux = power[:].real
421 421 else:
422 422 daux = power[thisChannel, :].real
423 423 noise[thisChannel] = hildebrand_sekhon(daux, self.nCohInt)
424 424
425 425 return noise
426 426
427 427 def getNoise(self, type=1, channel=None):
428 428
429 429 if type == 1:
430 430 noise = self.getNoisebyHildebrand(channel)
431 431
432 432 return noise
433 433
434 434 def getPower(self, channel=None):
435 435
436 436 if channel != None:
437 437 data = self.data[channel]
438 438 else:
439 439 data = self.data
440 440
441 441 power = data * numpy.conjugate(data)
442 442 powerdB = 10 * numpy.log10(power.real)
443 443 powerdB = numpy.squeeze(powerdB)
444 444
445 445 return powerdB
446 446
447 447 def getTimeInterval(self):
448 448
449 449 timeInterval = self.ippSeconds * self.nCohInt
450 450
451 451 return timeInterval
452 452
453 453 noise = property(getNoise, "I'm the 'nHeights' property.")
454 454 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
455 455
456 456
457 457 class Spectra(JROData):
458 458
459 459 # data spc es un numpy array de 2 dmensiones (canales, perfiles, alturas)
460 460 data_spc = None
461 461 # data cspc es un numpy array de 2 dmensiones (canales, pares, alturas)
462 462 data_cspc = None
463 463 # data dc es un numpy array de 2 dmensiones (canales, alturas)
464 464 data_dc = None
465 465 # data power
466 466 data_pwr = None
467 467 nFFTPoints = None
468 468 # nPairs = None
469 469 pairsList = None
470 470 nIncohInt = None
471 471 wavelength = None # Necesario para cacular el rango de velocidad desde la frecuencia
472 472 nCohInt = None # se requiere para determinar el valor de timeInterval
473 473 ippFactor = None
474 474 profileIndex = 0
475 475 plotting = "spectra"
476 476
477 477 def __init__(self):
478 478 '''
479 479 Constructor
480 480 '''
481 481
482 482 self.useLocalTime = True
483 483 self.radarControllerHeaderObj = RadarControllerHeader()
484 484 self.systemHeaderObj = SystemHeader()
485 485 self.type = "Spectra"
486 486 self.timeZone = 0
487 487 # self.data = None
488 488 # self.dtype = None
489 489 # self.nChannels = 0
490 490 # self.nHeights = 0
491 491 self.nProfiles = None
492 492 self.heightList = None
493 493 self.channelList = None
494 494 # self.channelIndexList = None
495 495 self.pairsList = None
496 496 self.flagNoData = True
497 497 self.flagDiscontinuousBlock = False
498 498 self.utctime = None
499 499 self.nCohInt = None
500 500 self.nIncohInt = None
501 501 self.blocksize = None
502 502 self.nFFTPoints = None
503 503 self.wavelength = None
504 504 self.flagDecodeData = False # asumo q la data no esta decodificada
505 505 self.flagDeflipData = False # asumo q la data no esta sin flip
506 506 self.flagShiftFFT = False
507 507 self.ippFactor = 1
508 508 #self.noise = None
509 509 self.beacon_heiIndexList = []
510 510 self.noise_estimation = None
511 511
512 512 def getNoisebyHildebrand(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
513 513 """
514 514 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
515 515
516 516 Return:
517 517 noiselevel
518 518 """
519 519
520 520 noise = numpy.zeros(self.nChannels)
521 521
522 522 for channel in range(self.nChannels):
523 523 daux = self.data_spc[channel,
524 524 xmin_index:xmax_index, ymin_index:ymax_index]
525 525 noise[channel] = hildebrand_sekhon(daux, self.nIncohInt)
526 526
527 527 return noise
528 528
529 529 def getNoise(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
530 530
531 531 if self.noise_estimation is not None:
532 532 # this was estimated by getNoise Operation defined in jroproc_spectra.py
533 533 return self.noise_estimation
534 534 else:
535 535 noise = self.getNoisebyHildebrand(
536 536 xmin_index, xmax_index, ymin_index, ymax_index)
537 537 return noise
538 538
539 539 def getFreqRangeTimeResponse(self, extrapoints=0):
540 540
541 541 deltafreq = self.getFmaxTimeResponse() / (self.nFFTPoints * self.ippFactor)
542 542 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.) - deltafreq / 2
543 543
544 544 return freqrange
545 545
546 546 def getAcfRange(self, extrapoints=0):
547 547
548 548 deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor))
549 549 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
550 550
551 551 return freqrange
552 552
553 553 def getFreqRange(self, extrapoints=0):
554 554
555 555 deltafreq = self.getFmax() / (self.nFFTPoints * self.ippFactor)
556 556 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
557 557
558 558 return freqrange
559 559
560 560 def getVelRange(self, extrapoints=0):
561 561
562 562 deltav = self.getVmax() / (self.nFFTPoints * self.ippFactor)
563 563 velrange = deltav * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.)
564 564
565 565 if self.nmodes:
566 566 return velrange/self.nmodes
567 567 else:
568 568 return velrange
569 569
570 570 def getNPairs(self):
571 571
572 572 return len(self.pairsList)
573 573
574 574 def getPairsIndexList(self):
575 575
576 576 return list(range(self.nPairs))
577 577
578 578 def getNormFactor(self):
579 579
580 580 pwcode = 1
581 581
582 582 if self.flagDecodeData:
583 583 pwcode = numpy.sum(self.code[0]**2)
584 584 #normFactor = min(self.nFFTPoints,self.nProfiles)*self.nIncohInt*self.nCohInt*pwcode*self.windowOfFilter
585 585 normFactor = self.nProfiles * self.nIncohInt * self.nCohInt * pwcode * self.windowOfFilter
586 586
587 587 return normFactor
588 588
589 589 def getFlagCspc(self):
590 590
591 591 if self.data_cspc is None:
592 592 return True
593 593
594 594 return False
595 595
596 596 def getFlagDc(self):
597 597
598 598 if self.data_dc is None:
599 599 return True
600 600
601 601 return False
602 602
603 603 def getTimeInterval(self):
604 604
605 605 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt * self.nProfiles * self.ippFactor
606 606 if self.nmodes:
607 607 return self.nmodes*timeInterval
608 608 else:
609 609 return timeInterval
610 610
611 611 def getPower(self):
612 612
613 613 factor = self.normFactor
614 614 z = self.data_spc / factor
615 615 z = numpy.where(numpy.isfinite(z), z, numpy.NAN)
616 616 avg = numpy.average(z, axis=1)
617 617
618 618 return 10 * numpy.log10(avg)
619 619
620 620 def getCoherence(self, pairsList=None, phase=False):
621 621
622 622 z = []
623 623 if pairsList is None:
624 624 pairsIndexList = self.pairsIndexList
625 625 else:
626 626 pairsIndexList = []
627 627 for pair in pairsList:
628 628 if pair not in self.pairsList:
629 629 raise ValueError("Pair %s is not in dataOut.pairsList" % (
630 630 pair))
631 631 pairsIndexList.append(self.pairsList.index(pair))
632 632 for i in range(len(pairsIndexList)):
633 633 pair = self.pairsList[pairsIndexList[i]]
634 634 ccf = numpy.average(self.data_cspc[pairsIndexList[i], :, :], axis=0)
635 635 powa = numpy.average(self.data_spc[pair[0], :, :], axis=0)
636 636 powb = numpy.average(self.data_spc[pair[1], :, :], axis=0)
637 637 avgcoherenceComplex = ccf / numpy.sqrt(powa * powb)
638 638 if phase:
639 639 data = numpy.arctan2(avgcoherenceComplex.imag,
640 640 avgcoherenceComplex.real) * 180 / numpy.pi
641 641 else:
642 642 data = numpy.abs(avgcoherenceComplex)
643 643
644 644 z.append(data)
645 645
646 646 return numpy.array(z)
647 647
648 648 def setValue(self, value):
649 649
650 650 print("This property should not be initialized")
651 651
652 652 return
653 653
654 654 nPairs = property(getNPairs, setValue, "I'm the 'nPairs' property.")
655 655 pairsIndexList = property(
656 656 getPairsIndexList, setValue, "I'm the 'pairsIndexList' property.")
657 657 normFactor = property(getNormFactor, setValue,
658 658 "I'm the 'getNormFactor' property.")
659 659 flag_cspc = property(getFlagCspc, setValue)
660 660 flag_dc = property(getFlagDc, setValue)
661 661 noise = property(getNoise, setValue, "I'm the 'nHeights' property.")
662 662 timeInterval = property(getTimeInterval, setValue,
663 663 "I'm the 'timeInterval' property")
664 664
665 665
666 666 class SpectraHeis(Spectra):
667 667
668 668 data_spc = None
669 669 data_cspc = None
670 670 data_dc = None
671 671 nFFTPoints = None
672 672 # nPairs = None
673 673 pairsList = None
674 674 nCohInt = None
675 675 nIncohInt = None
676 676
677 677 def __init__(self):
678 678
679 679 self.radarControllerHeaderObj = RadarControllerHeader()
680 680
681 681 self.systemHeaderObj = SystemHeader()
682 682
683 683 self.type = "SpectraHeis"
684 684
685 685 # self.dtype = None
686 686
687 687 # self.nChannels = 0
688 688
689 689 # self.nHeights = 0
690 690
691 691 self.nProfiles = None
692 692
693 693 self.heightList = None
694 694
695 695 self.channelList = None
696 696
697 697 # self.channelIndexList = None
698 698
699 699 self.flagNoData = True
700 700
701 701 self.flagDiscontinuousBlock = False
702 702
703 703 # self.nPairs = 0
704 704
705 705 self.utctime = None
706 706
707 707 self.blocksize = None
708 708
709 709 self.profileIndex = 0
710 710
711 711 self.nCohInt = 1
712 712
713 713 self.nIncohInt = 1
714 714
715 715 def getNormFactor(self):
716 716 pwcode = 1
717 717 if self.flagDecodeData:
718 718 pwcode = numpy.sum(self.code[0]**2)
719 719
720 720 normFactor = self.nIncohInt * self.nCohInt * pwcode
721 721
722 722 return normFactor
723 723
724 724 def getTimeInterval(self):
725 725
726 726 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
727 727
728 728 return timeInterval
729 729
730 730 normFactor = property(getNormFactor, "I'm the 'getNormFactor' property.")
731 731 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
732 732
733 733
734 734 class Fits(JROData):
735 735
736 736 heightList = None
737 737 channelList = None
738 738 flagNoData = True
739 739 flagDiscontinuousBlock = False
740 740 useLocalTime = False
741 741 utctime = None
742 742 # ippSeconds = None
743 743 # timeInterval = None
744 744 nCohInt = None
745 745 nIncohInt = None
746 746 noise = None
747 747 windowOfFilter = 1
748 748 # Speed of ligth
749 749 C = 3e8
750 750 frequency = 49.92e6
751 751 realtime = False
752 752
753 753 def __init__(self):
754 754
755 755 self.type = "Fits"
756 756
757 757 self.nProfiles = None
758 758
759 759 self.heightList = None
760 760
761 761 self.channelList = None
762 762
763 763 # self.channelIndexList = None
764 764
765 765 self.flagNoData = True
766 766
767 767 self.utctime = None
768 768
769 769 self.nCohInt = 1
770 770
771 771 self.nIncohInt = 1
772 772
773 773 self.useLocalTime = True
774 774
775 775 self.profileIndex = 0
776 776
777 777 # self.utctime = None
778 778 self.timeZone = 0
779 779 # self.ltctime = None
780 780 # self.timeInterval = None
781 781 # self.header = None
782 782 # self.data_header = None
783 783 # self.data = None
784 784 # self.datatime = None
785 785 # self.flagNoData = False
786 786 # self.expName = ''
787 787 # self.nChannels = None
788 788 # self.nSamples = None
789 789 # self.dataBlocksPerFile = None
790 790 # self.comments = ''
791 791 #
792 792
793 793 def getltctime(self):
794 794
795 795 if self.useLocalTime:
796 796 return self.utctime - self.timeZone * 60
797 797
798 798 return self.utctime
799 799
800 800 def getDatatime(self):
801 801
802 802 datatime = datetime.datetime.utcfromtimestamp(self.ltctime)
803 803 return datatime
804 804
805 805 def getTimeRange(self):
806 806
807 807 datatime = []
808 808
809 809 datatime.append(self.ltctime)
810 810 datatime.append(self.ltctime + self.timeInterval)
811 811
812 812 datatime = numpy.array(datatime)
813 813
814 814 return datatime
815 815
816 816 def getHeiRange(self):
817 817
818 818 heis = self.heightList
819 819
820 820 return heis
821 821
822 822 def getNHeights(self):
823 823
824 824 return len(self.heightList)
825 825
826 826 def getNChannels(self):
827 827
828 828 return len(self.channelList)
829 829
830 830 def getChannelIndexList(self):
831 831
832 832 return list(range(self.nChannels))
833 833
834 834 def getNoise(self, type=1):
835 835
836 836 #noise = numpy.zeros(self.nChannels)
837 837
838 838 if type == 1:
839 839 noise = self.getNoisebyHildebrand()
840 840
841 841 if type == 2:
842 842 noise = self.getNoisebySort()
843 843
844 844 if type == 3:
845 845 noise = self.getNoisebyWindow()
846 846
847 847 return noise
848 848
849 849 def getTimeInterval(self):
850 850
851 851 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
852 852
853 853 return timeInterval
854 854
855 855 def get_ippSeconds(self):
856 856 '''
857 857 '''
858 858 return self.ipp_sec
859 859
860 860
861 861 datatime = property(getDatatime, "I'm the 'datatime' property")
862 862 nHeights = property(getNHeights, "I'm the 'nHeights' property.")
863 863 nChannels = property(getNChannels, "I'm the 'nChannel' property.")
864 864 channelIndexList = property(
865 865 getChannelIndexList, "I'm the 'channelIndexList' property.")
866 866 noise = property(getNoise, "I'm the 'nHeights' property.")
867 867
868 868 ltctime = property(getltctime, "I'm the 'ltctime' property")
869 869 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
870 870 ippSeconds = property(get_ippSeconds, '')
871 871
872 872 class Correlation(JROData):
873 873
874 874 noise = None
875 875 SNR = None
876 876 #--------------------------------------------------
877 877 mode = None
878 878 split = False
879 879 data_cf = None
880 880 lags = None
881 881 lagRange = None
882 882 pairsList = None
883 883 normFactor = None
884 884 #--------------------------------------------------
885 885 # calculateVelocity = None
886 886 nLags = None
887 887 nPairs = None
888 888 nAvg = None
889 889
890 890 def __init__(self):
891 891 '''
892 892 Constructor
893 893 '''
894 894 self.radarControllerHeaderObj = RadarControllerHeader()
895 895
896 896 self.systemHeaderObj = SystemHeader()
897 897
898 898 self.type = "Correlation"
899 899
900 900 self.data = None
901 901
902 902 self.dtype = None
903 903
904 904 self.nProfiles = None
905 905
906 906 self.heightList = None
907 907
908 908 self.channelList = None
909 909
910 910 self.flagNoData = True
911 911
912 912 self.flagDiscontinuousBlock = False
913 913
914 914 self.utctime = None
915 915
916 916 self.timeZone = 0
917 917
918 918 self.dstFlag = None
919 919
920 920 self.errorCount = None
921 921
922 922 self.blocksize = None
923 923
924 924 self.flagDecodeData = False # asumo q la data no esta decodificada
925 925
926 926 self.flagDeflipData = False # asumo q la data no esta sin flip
927 927
928 928 self.pairsList = None
929 929
930 930 self.nPoints = None
931 931
932 932 def getPairsList(self):
933 933
934 934 return self.pairsList
935 935
936 936 def getNoise(self, mode=2):
937 937
938 938 indR = numpy.where(self.lagR == 0)[0][0]
939 939 indT = numpy.where(self.lagT == 0)[0][0]
940 940
941 941 jspectra0 = self.data_corr[:, :, indR, :]
942 942 jspectra = copy.copy(jspectra0)
943 943
944 944 num_chan = jspectra.shape[0]
945 945 num_hei = jspectra.shape[2]
946 946
947 947 freq_dc = jspectra.shape[1] / 2
948 948 ind_vel = numpy.array([-2, -1, 1, 2]) + freq_dc
949 949
950 950 if ind_vel[0] < 0:
951 951 ind_vel[list(range(0, 1))] = ind_vel[list(
952 952 range(0, 1))] + self.num_prof
953 953
954 954 if mode == 1:
955 955 jspectra[:, freq_dc, :] = (
956 956 jspectra[:, ind_vel[1], :] + jspectra[:, ind_vel[2], :]) / 2 # CORRECCION
957 957
958 958 if mode == 2:
959 959
960 960 vel = numpy.array([-2, -1, 1, 2])
961 961 xx = numpy.zeros([4, 4])
962 962
963 963 for fil in range(4):
964 964 xx[fil, :] = vel[fil]**numpy.asarray(list(range(4)))
965 965
966 966 xx_inv = numpy.linalg.inv(xx)
967 967 xx_aux = xx_inv[0, :]
968 968
969 969 for ich in range(num_chan):
970 970 yy = jspectra[ich, ind_vel, :]
971 971 jspectra[ich, freq_dc, :] = numpy.dot(xx_aux, yy)
972 972
973 973 junkid = jspectra[ich, freq_dc, :] <= 0
974 974 cjunkid = sum(junkid)
975 975
976 976 if cjunkid.any():
977 977 jspectra[ich, freq_dc, junkid.nonzero()] = (
978 978 jspectra[ich, ind_vel[1], junkid] + jspectra[ich, ind_vel[2], junkid]) / 2
979 979
980 980 noise = jspectra0[:, freq_dc, :] - jspectra[:, freq_dc, :]
981 981
982 982 return noise
983 983
984 984 def getTimeInterval(self):
985 985
986 986 timeInterval = self.ippSeconds * self.nCohInt * self.nProfiles
987 987
988 988 return timeInterval
989 989
990 990 def splitFunctions(self):
991 991
992 992 pairsList = self.pairsList
993 993 ccf_pairs = []
994 994 acf_pairs = []
995 995 ccf_ind = []
996 996 acf_ind = []
997 997 for l in range(len(pairsList)):
998 998 chan0 = pairsList[l][0]
999 999 chan1 = pairsList[l][1]
1000 1000
1001 1001 # Obteniendo pares de Autocorrelacion
1002 1002 if chan0 == chan1:
1003 1003 acf_pairs.append(chan0)
1004 1004 acf_ind.append(l)
1005 1005 else:
1006 1006 ccf_pairs.append(pairsList[l])
1007 1007 ccf_ind.append(l)
1008 1008
1009 1009 data_acf = self.data_cf[acf_ind]
1010 1010 data_ccf = self.data_cf[ccf_ind]
1011 1011
1012 1012 return acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf
1013 1013
1014 1014 def getNormFactor(self):
1015 1015 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.splitFunctions()
1016 1016 acf_pairs = numpy.array(acf_pairs)
1017 1017 normFactor = numpy.zeros((self.nPairs, self.nHeights))
1018 1018
1019 1019 for p in range(self.nPairs):
1020 1020 pair = self.pairsList[p]
1021 1021
1022 1022 ch0 = pair[0]
1023 1023 ch1 = pair[1]
1024 1024
1025 1025 ch0_max = numpy.max(data_acf[acf_pairs == ch0, :, :], axis=1)
1026 1026 ch1_max = numpy.max(data_acf[acf_pairs == ch1, :, :], axis=1)
1027 1027 normFactor[p, :] = numpy.sqrt(ch0_max * ch1_max)
1028 1028
1029 1029 return normFactor
1030 1030
1031 1031 timeInterval = property(getTimeInterval, "I'm the 'timeInterval' property")
1032 1032 normFactor = property(getNormFactor, "I'm the 'normFactor property'")
1033 1033
1034 1034
1035 1035 class Parameters(Spectra):
1036 1036
1037 1037 experimentInfo = None # Information about the experiment
1038 1038 # Information from previous data
1039 1039 inputUnit = None # Type of data to be processed
1040 1040 operation = None # Type of operation to parametrize
1041 1041 # normFactor = None #Normalization Factor
1042 1042 groupList = None # List of Pairs, Groups, etc
1043 1043 # Parameters
1044 1044 data_param = None # Parameters obtained
1045 1045 data_pre = None # Data Pre Parametrization
1046 1046 data_SNR = None # Signal to Noise Ratio
1047 1047 # heightRange = None #Heights
1048 1048 abscissaList = None # Abscissa, can be velocities, lags or time
1049 1049 # noise = None #Noise Potency
1050 1050 utctimeInit = None # Initial UTC time
1051 1051 paramInterval = None # Time interval to calculate Parameters in seconds
1052 1052 useLocalTime = True
1053 1053 # Fitting
1054 1054 data_error = None # Error of the estimation
1055 1055 constants = None
1056 1056 library = None
1057 1057 # Output signal
1058 1058 outputInterval = None # Time interval to calculate output signal in seconds
1059 1059 data_output = None # Out signal
1060 1060 nAvg = None
1061 1061 noise_estimation = None
1062 1062 GauSPC = None # Fit gaussian SPC
1063 1063
1064 1064 def __init__(self):
1065 1065 '''
1066 1066 Constructor
1067 1067 '''
1068 1068 self.radarControllerHeaderObj = RadarControllerHeader()
1069 1069 self.systemHeaderObj = SystemHeader()
1070 1070 self.type = "Parameters"
1071 1071 self.timeZone = 0
1072 1072
1073 1073 def getTimeRange1(self, interval):
1074 1074
1075 1075 datatime = []
1076 1076
1077 1077 if self.useLocalTime:
1078 1078 time1 = self.utctimeInit - self.timeZone * 60
1079 1079 else:
1080 1080 time1 = self.utctimeInit
1081 1081
1082 1082 datatime.append(time1)
1083 1083 datatime.append(time1 + interval)
1084 1084 datatime = numpy.array(datatime)
1085 1085
1086 1086 return datatime
1087 1087
1088 1088 def getTimeInterval(self):
1089 1089
1090 1090 if hasattr(self, 'timeInterval1'):
1091 1091 return self.timeInterval1
1092 1092 else:
1093 1093 return self.paramInterval
1094 1094
1095 1095 def setValue(self, value):
1096 1096
1097 1097 print("This property should not be initialized")
1098 1098
1099 1099 return
1100 1100
1101 1101 def getNoise(self):
1102 1102
1103 1103 return self.spc_noise
1104 1104
1105 1105 timeInterval = property(getTimeInterval)
1106 1106 noise = property(getNoise, setValue, "I'm the 'Noise' property.")
1107 1107
1108 1108
1109 1109 class PlotterData(object):
1110 1110 '''
1111 1111 Object to hold data to be plotted
1112 1112 '''
1113 1113
1114 1114 MAXNUMX = 200
1115 1115 MAXNUMY = 200
1116 1116
1117 def __init__(self, code, throttle_value, exp_code, buffering=True, snr=False):
1117 def __init__(self, code, throttle_value, exp_code, localtime=True, buffering=True, snr=False):
1118 1118
1119 1119 self.key = code
1120 1120 self.throttle = throttle_value
1121 1121 self.exp_code = exp_code
1122 1122 self.buffering = buffering
1123 1123 self.ready = False
1124 1124 self.flagNoData = False
1125 self.localtime = False
1125 self.localtime = localtime
1126 1126 self.data = {}
1127 1127 self.meta = {}
1128 1128 self.__heights = []
1129 1129
1130 1130 if 'snr' in code:
1131 1131 self.plottypes = ['snr']
1132 1132 elif code == 'spc':
1133 1133 self.plottypes = ['spc', 'noise', 'rti']
1134 1134 elif code == 'cspc':
1135 1135 self.plottypes = ['cspc', 'spc', 'noise', 'rti']
1136 1136 elif code == 'rti':
1137 1137 self.plottypes = ['noise', 'rti']
1138 1138 else:
1139 1139 self.plottypes = [code]
1140 1140
1141 1141 if 'snr' not in self.plottypes and snr:
1142 1142 self.plottypes.append('snr')
1143 1143
1144 1144 for plot in self.plottypes:
1145 1145 self.data[plot] = {}
1146 1146
1147
1148 1147 def __str__(self):
1149 1148 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
1150 1149 return 'Data[{}][{}]'.format(';'.join(dum), len(self.times))
1151 1150
1152 1151 def __len__(self):
1153 1152 return len(self.data[self.key])
1154 1153
1155 1154 def __getitem__(self, key):
1156 1155
1157 1156 if key not in self.data:
1158 1157 raise KeyError(log.error('Missing key: {}'.format(key)))
1159 1158 if 'spc' in key or not self.buffering:
1160 1159 ret = self.data[key][self.tm]
1161 1160 elif 'scope' in key:
1162 1161 ret = numpy.array(self.data[key][float(self.tm)])
1163 1162 else:
1164 1163 ret = numpy.array([self.data[key][x] for x in self.times])
1165 1164 if ret.ndim > 1:
1166 1165 ret = numpy.swapaxes(ret, 0, 1)
1167 1166 return ret
1168 1167
1169 1168 def __contains__(self, key):
1170 1169 return key in self.data
1171 1170
1172 1171 def setup(self):
1173 1172 '''
1174 1173 Configure object
1175 1174 '''
1176 1175 self.type = ''
1177 1176 self.ready = False
1178 1177 del self.data
1179 1178 self.data = {}
1180 1179 self.__heights = []
1181 1180 self.__all_heights = set()
1182 1181 for plot in self.plottypes:
1183 1182 if 'snr' in plot:
1184 1183 plot = 'snr'
1185 1184 elif 'spc_moments' == plot:
1186 1185 plot = 'moments'
1187 1186 self.data[plot] = {}
1188 1187
1189 1188 if 'spc' in self.data or 'rti' in self.data or 'cspc' in self.data or 'moments' in self.data:
1190 1189 self.data['noise'] = {}
1191 1190 self.data['rti'] = {}
1192 1191 if 'noise' not in self.plottypes:
1193 1192 self.plottypes.append('noise')
1194 1193 if 'rti' not in self.plottypes:
1195 1194 self.plottypes.append('rti')
1196 1195
1197 1196 def shape(self, key):
1198 1197 '''
1199 1198 Get the shape of the one-element data for the given key
1200 1199 '''
1201 1200
1202 1201 if len(self.data[key]):
1203 1202 if 'spc' in key or not self.buffering:
1204 1203 return self.data[key].shape
1205 1204 return self.data[key][self.times[0]].shape
1206 1205 return (0,)
1207 1206
1208 1207 def update(self, dataOut, tm):
1209 1208 '''
1210 1209 Update data object with new dataOut
1211 1210 '''
1212 1211
1213 1212 self.profileIndex = dataOut.profileIndex
1214 1213 self.tm = tm
1215 1214 self.type = dataOut.type
1216 1215 self.parameters = getattr(dataOut, 'parameters', [])
1217 1216
1218 1217 if hasattr(dataOut, 'meta'):
1219 1218 self.meta.update(dataOut.meta)
1220 1219
1221 1220 if hasattr(dataOut, 'pairsList'):
1222 1221 self.pairs = dataOut.pairsList
1223 1222
1224 1223 self.interval = dataOut.getTimeInterval()
1225 self.localtime = dataOut.useLocalTime
1226 1224 if True in ['spc' in ptype for ptype in self.plottypes]:
1227 1225 self.xrange = (dataOut.getFreqRange(1)/1000.,
1228 1226 dataOut.getAcfRange(1), dataOut.getVelRange(1))
1229 1227 self.__heights.append(dataOut.heightList)
1230 1228 self.__all_heights.update(dataOut.heightList)
1231 1229
1232 1230 for plot in self.plottypes:
1233 1231 if plot in ('spc', 'spc_moments', 'spc_cut'):
1234 1232 z = dataOut.data_spc/dataOut.normFactor
1235 1233 buffer = 10*numpy.log10(z)
1236 1234 if plot == 'cspc':
1237 1235 buffer = (dataOut.data_spc, dataOut.data_cspc)
1238 1236 if plot == 'noise':
1239 1237 buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
1240 1238 if plot in ('rti', 'spcprofile'):
1241 1239 buffer = dataOut.getPower()
1242 1240 if plot == 'snr_db':
1243 1241 buffer = dataOut.data_SNR
1244 1242 if plot == 'snr':
1245 1243 buffer = 10*numpy.log10(dataOut.data_SNR)
1246 1244 if plot == 'dop':
1247 1245 buffer = dataOut.data_DOP
1248 1246 if plot == 'pow':
1249 1247 buffer = 10*numpy.log10(dataOut.data_POW)
1250 1248 if plot == 'width':
1251 1249 buffer = dataOut.data_WIDTH
1252 1250 if plot == 'coh':
1253 1251 buffer = dataOut.getCoherence()
1254 1252 if plot == 'phase':
1255 1253 buffer = dataOut.getCoherence(phase=True)
1256 1254 if plot == 'output':
1257 1255 buffer = dataOut.data_output
1258 1256 if plot == 'param':
1259 1257 buffer = dataOut.data_param
1260 1258 if plot == 'scope':
1261 1259 buffer = dataOut.data
1262 1260 self.flagDataAsBlock = dataOut.flagDataAsBlock
1263 1261 self.nProfiles = dataOut.nProfiles
1264 1262 if plot == 'pp_power':
1265 1263 buffer = dataOut.dataPP_POWER
1266 1264 self.flagDataAsBlock = dataOut.flagDataAsBlock
1267 1265 self.nProfiles = dataOut.nProfiles
1268 1266 if plot == 'pp_signal':
1269 1267 buffer = dataOut.dataPP_POW
1270 1268 self.flagDataAsBlock = dataOut.flagDataAsBlock
1271 1269 self.nProfiles = dataOut.nProfiles
1272 1270 if plot == 'pp_velocity':
1273 1271 buffer = dataOut.dataPP_DOP
1274 1272 self.flagDataAsBlock = dataOut.flagDataAsBlock
1275 1273 self.nProfiles = dataOut.nProfiles
1276 1274 if plot == 'pp_specwidth':
1277 1275 buffer = dataOut.dataPP_WIDTH
1278 1276 self.flagDataAsBlock = dataOut.flagDataAsBlock
1279 1277 self.nProfiles = dataOut.nProfiles
1280 1278
1281 1279 if plot == 'spc':
1282 1280 self.data['spc'][tm] = buffer
1283 1281 elif plot == 'cspc':
1284 1282 self.data['cspc'][tm] = buffer
1285 1283 elif plot == 'spc_moments':
1286 1284 self.data['spc'][tm] = buffer
1287 1285 self.data['moments'][tm] = dataOut.moments
1288 1286 else:
1289 1287 if self.buffering:
1290 1288 self.data[plot][tm] = buffer
1291 1289 else:
1292 1290 self.data[plot][tm] = buffer
1293 1291
1294 1292 if dataOut.channelList is None:
1295 1293 self.channels = range(buffer.shape[0])
1296 1294 else:
1297 1295 self.channels = dataOut.channelList
1298 1296
1299 1297 if buffer is None:
1300 1298 self.flagNoData = True
1301 1299 raise schainpy.admin.SchainWarning('Attribute data_{} is empty'.format(self.key))
1302 1300
1303 1301 def normalize_heights(self):
1304 1302 '''
1305 1303 Ensure same-dimension of the data for different heighList
1306 1304 '''
1307 1305
1308 1306 H = numpy.array(list(self.__all_heights))
1309 1307 H.sort()
1310 1308 for key in self.data:
1311 1309 shape = self.shape(key)[:-1] + H.shape
1312 1310 for tm, obj in list(self.data[key].items()):
1313 1311 h = self.__heights[self.times.tolist().index(tm)]
1314 1312 if H.size == h.size:
1315 1313 continue
1316 1314 index = numpy.where(numpy.in1d(H, h))[0]
1317 1315 dummy = numpy.zeros(shape) + numpy.nan
1318 1316 if len(shape) == 2:
1319 1317 dummy[:, index] = obj
1320 1318 else:
1321 1319 dummy[index] = obj
1322 1320 self.data[key][tm] = dummy
1323 1321
1324 1322 self.__heights = [H for tm in self.times]
1325 1323
1326 1324 def jsonify(self, tm, plot_name, plot_type, decimate=False):
1327 1325 '''
1328 1326 Convert data to json
1329 1327 '''
1330 1328
1331 1329 dy = int(self.heights.size/self.MAXNUMY) + 1
1332 1330 if self.key in ('spc', 'cspc'):
1333 1331 dx = int(self.data[self.key][tm].shape[1]/self.MAXNUMX) + 1
1334 1332 data = self.roundFloats(
1335 1333 self.data[self.key][tm][::, ::dx, ::dy].tolist())
1336 1334 else:
1337 1335 if self.key is 'noise':
1338 1336 data = [[x] for x in self.roundFloats(self.data[self.key][tm].tolist())]
1339 1337 else:
1340 1338 data = self.roundFloats(self.data[self.key][tm][::, ::dy].tolist())
1341 1339
1342 1340 meta = {}
1343 1341 ret = {
1344 1342 'plot': plot_name,
1345 1343 'code': self.exp_code,
1346 1344 'time': float(tm),
1347 1345 'data': data,
1348 1346 }
1349 1347 meta['type'] = plot_type
1350 1348 meta['interval'] = float(self.interval)
1351 1349 meta['localtime'] = self.localtime
1352 1350 meta['yrange'] = self.roundFloats(self.heights[::dy].tolist())
1353 1351 if 'spc' in self.data or 'cspc' in self.data:
1354 1352 meta['xrange'] = self.roundFloats(self.xrange[2][::dx].tolist())
1355 1353 else:
1356 1354 meta['xrange'] = []
1357 1355
1358 1356 meta.update(self.meta)
1359 1357 ret['metadata'] = meta
1360 1358 return json.dumps(ret)
1361 1359
1362 1360 @property
1363 1361 def times(self):
1364 1362 '''
1365 1363 Return the list of times of the current data
1366 1364 '''
1367 1365
1368 1366 ret = numpy.array([*self.data[self.key]])
1369 1367 if self:
1370 1368 ret.sort()
1371 1369 return ret
1372 1370
1373 1371 @property
1374 1372 def min_time(self):
1375 1373 '''
1376 1374 Return the minimun time value
1377 1375 '''
1378 1376
1379 1377 return self.times[0]
1380 1378
1381 1379 @property
1382 1380 def max_time(self):
1383 1381 '''
1384 1382 Return the maximun time value
1385 1383 '''
1386 1384
1387 1385 return self.times[-1]
1388 1386
1389 1387 @property
1390 1388 def heights(self):
1391 1389 '''
1392 1390 Return the list of heights of the current data
1393 1391 '''
1394 1392
1395 1393 return numpy.array(self.__heights[-1])
1396 1394
1397 1395 @staticmethod
1398 1396 def roundFloats(obj):
1399 1397 if isinstance(obj, list):
1400 1398 return list(map(PlotterData.roundFloats, obj))
1401 1399 elif isinstance(obj, float):
1402 1400 return round(obj, 2)
@@ -1,717 +1,713
1 1
2 2 import os
3 3 import sys
4 4 import zmq
5 5 import time
6 6 import numpy
7 7 import datetime
8 8 from queue import Queue
9 9 from functools import wraps
10 10 from threading import Thread
11 11 import matplotlib
12 12
13 13 if 'BACKEND' in os.environ:
14 14 matplotlib.use(os.environ['BACKEND'])
15 15 elif 'linux' in sys.platform:
16 16 matplotlib.use("TkAgg")
17 17 elif 'darwin' in sys.platform:
18 18 matplotlib.use('WxAgg')
19 19 else:
20 20 from schainpy.utils import log
21 21 log.warning('Using default Backend="Agg"', 'INFO')
22 22 matplotlib.use('Agg')
23 23
24 24 import matplotlib.pyplot as plt
25 25 from matplotlib.patches import Polygon
26 26 from mpl_toolkits.axes_grid1 import make_axes_locatable
27 27 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
28 28
29 29 from schainpy.model.data.jrodata import PlotterData
30 30 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
31 31 from schainpy.utils import log
32 32
33 33 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
34 34 blu_values = matplotlib.pyplot.get_cmap(
35 35 'seismic_r', 20)(numpy.arange(20))[10:15]
36 36 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
37 37 'jro', numpy.vstack((blu_values, jet_values)))
38 38 matplotlib.pyplot.register_cmap(cmap=ncmap)
39 39
40 40 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
41 41 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
42 42
43 43 EARTH_RADIUS = 6.3710e3
44 44
45 45 def ll2xy(lat1, lon1, lat2, lon2):
46 46
47 47 p = 0.017453292519943295
48 48 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
49 49 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
50 50 r = 12742 * numpy.arcsin(numpy.sqrt(a))
51 51 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
52 52 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
53 53 theta = -theta + numpy.pi/2
54 54 return r*numpy.cos(theta), r*numpy.sin(theta)
55 55
56 56
57 57 def km2deg(km):
58 58 '''
59 59 Convert distance in km to degrees
60 60 '''
61 61
62 62 return numpy.rad2deg(km/EARTH_RADIUS)
63 63
64 64
65 65 def figpause(interval):
66 66 backend = plt.rcParams['backend']
67 67 if backend in matplotlib.rcsetup.interactive_bk:
68 68 figManager = matplotlib._pylab_helpers.Gcf.get_active()
69 69 if figManager is not None:
70 70 canvas = figManager.canvas
71 71 if canvas.figure.stale:
72 72 canvas.draw()
73 73 try:
74 74 canvas.start_event_loop(interval)
75 75 except:
76 76 pass
77 77 return
78 78
79 79
80 80 def popup(message):
81 81 '''
82 82 '''
83 83
84 84 fig = plt.figure(figsize=(12, 8), facecolor='r')
85 85 text = '\n'.join([s.strip() for s in message.split(':')])
86 86 fig.text(0.01, 0.5, text, ha='left', va='center',
87 87 size='20', weight='heavy', color='w')
88 88 fig.show()
89 89 figpause(1000)
90 90
91 91
92 92 class Throttle(object):
93 93 '''
94 94 Decorator that prevents a function from being called more than once every
95 95 time period.
96 96 To create a function that cannot be called more than once a minute, but
97 97 will sleep until it can be called:
98 98 @Throttle(minutes=1)
99 99 def foo():
100 100 pass
101 101
102 102 for i in range(10):
103 103 foo()
104 104 print "This function has run %s times." % i
105 105 '''
106 106
107 107 def __init__(self, seconds=0, minutes=0, hours=0):
108 108 self.throttle_period = datetime.timedelta(
109 109 seconds=seconds, minutes=minutes, hours=hours
110 110 )
111 111
112 112 self.time_of_last_call = datetime.datetime.min
113 113
114 114 def __call__(self, fn):
115 115 @wraps(fn)
116 116 def wrapper(*args, **kwargs):
117 117 coerce = kwargs.pop('coerce', None)
118 118 if coerce:
119 119 self.time_of_last_call = datetime.datetime.now()
120 120 return fn(*args, **kwargs)
121 121 else:
122 122 now = datetime.datetime.now()
123 123 time_since_last_call = now - self.time_of_last_call
124 124 time_left = self.throttle_period - time_since_last_call
125 125
126 126 if time_left > datetime.timedelta(seconds=0):
127 127 return
128 128
129 129 self.time_of_last_call = datetime.datetime.now()
130 130 return fn(*args, **kwargs)
131 131
132 132 return wrapper
133 133
134 134 def apply_throttle(value):
135 135
136 136 @Throttle(seconds=value)
137 137 def fnThrottled(fn):
138 138 fn()
139 139
140 140 return fnThrottled
141 141
142 142
143 143 @MPDecorator
144 144 class Plot(Operation):
145 145 '''
146 146 Base class for Schain plotting operations
147 147 '''
148 148
149 149 CODE = 'Figure'
150 150 colormap = 'jet'
151 151 bgcolor = 'white'
152 152 buffering = True
153 153 __missing = 1E30
154 154
155 155 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
156 156 'showprofile']
157 157
158 158 def __init__(self):
159 159
160 160 Operation.__init__(self)
161 161 self.isConfig = False
162 162 self.isPlotConfig = False
163 163 self.save_counter = 1
164 164 self.sender_time = 0
165 165 self.data = None
166 166 self.firsttime = True
167 self.sender_queue = Queue(maxsize=10)
167 self.sender_queue = Queue(maxsize=60)
168 168 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
169 169
170 170 def __fmtTime(self, x, pos):
171 171 '''
172 172 '''
173 173
174 174 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
175 175
176 176 def __setup(self, **kwargs):
177 177 '''
178 178 Initialize variables
179 179 '''
180 180
181 181 self.figures = []
182 182 self.axes = []
183 183 self.cb_axes = []
184 184 self.localtime = kwargs.pop('localtime', True)
185 185 self.show = kwargs.get('show', True)
186 186 self.save = kwargs.get('save', False)
187 187 self.save_period = kwargs.get('save_period', 1)
188 self.ftp = kwargs.get('ftp', False)
189 188 self.colormap = kwargs.get('colormap', self.colormap)
190 189 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
191 190 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
192 191 self.colormaps = kwargs.get('colormaps', None)
193 192 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
194 193 self.showprofile = kwargs.get('showprofile', False)
195 194 self.title = kwargs.get('wintitle', self.CODE.upper())
196 195 self.cb_label = kwargs.get('cb_label', None)
197 196 self.cb_labels = kwargs.get('cb_labels', None)
198 197 self.labels = kwargs.get('labels', None)
199 198 self.xaxis = kwargs.get('xaxis', 'frequency')
200 199 self.zmin = kwargs.get('zmin', None)
201 200 self.zmax = kwargs.get('zmax', None)
202 201 self.zlimits = kwargs.get('zlimits', None)
203 202 self.xmin = kwargs.get('xmin', None)
204 203 self.xmax = kwargs.get('xmax', None)
205 204 self.xrange = kwargs.get('xrange', 12)
206 205 self.xscale = kwargs.get('xscale', None)
207 206 self.ymin = kwargs.get('ymin', None)
208 207 self.ymax = kwargs.get('ymax', None)
209 208 self.yscale = kwargs.get('yscale', None)
210 209 self.xlabel = kwargs.get('xlabel', None)
211 210 self.attr_time = kwargs.get('attr_time', 'utctime')
212 211 self.decimation = kwargs.get('decimation', None)
213 212 self.showSNR = kwargs.get('showSNR', False)
214 213 self.oneFigure = kwargs.get('oneFigure', True)
215 214 self.width = kwargs.get('width', None)
216 215 self.height = kwargs.get('height', None)
217 216 self.colorbar = kwargs.get('colorbar', True)
218 217 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
219 218 self.channels = kwargs.get('channels', None)
220 219 self.titles = kwargs.get('titles', [])
221 220 self.polar = False
222 221 self.type = kwargs.get('type', 'iq')
223 222 self.grid = kwargs.get('grid', False)
224 223 self.pause = kwargs.get('pause', False)
225 224 self.save_code = kwargs.get('save_code', None)
226 self.realtime = kwargs.get('realtime', True)
227 225 self.throttle = kwargs.get('throttle', 0)
228 226 self.exp_code = kwargs.get('exp_code', None)
229 227 self.plot_server = kwargs.get('plot_server', False)
230 228 self.sender_period = kwargs.get('sender_period', 60)
231 229 self.tag = kwargs.get('tag', '')
232 230 self.height_index = kwargs.get('height_index', None)
233 231 self.__throttle_plot = apply_throttle(self.throttle)
234 232 self.data = PlotterData(
235 self.CODE, self.throttle, self.exp_code, self.buffering, snr=self.showSNR)
233 self.CODE, self.throttle, self.exp_code, self.localtime, self.buffering, snr=self.showSNR)
236 234
237 235 if self.plot_server:
238 236 if not self.plot_server.startswith('tcp://'):
239 237 self.plot_server = 'tcp://{}'.format(self.plot_server)
240 238 log.success(
241 239 'Sending to server: {}'.format(self.plot_server),
242 240 self.name
243 241 )
244 242 if 'plot_name' in kwargs:
245 243 self.plot_name = kwargs['plot_name']
246 244
247 245 def __setup_plot(self):
248 246 '''
249 247 Common setup for all figures, here figures and axes are created
250 248 '''
251 249
252 250 self.setup()
253 251
254 252 self.time_label = 'LT' if self.localtime else 'UTC'
255 253
256 254 if self.width is None:
257 255 self.width = 8
258 256
259 257 self.figures = []
260 258 self.axes = []
261 259 self.cb_axes = []
262 260 self.pf_axes = []
263 261 self.cmaps = []
264 262
265 263 size = '15%' if self.ncols == 1 else '30%'
266 264 pad = '4%' if self.ncols == 1 else '8%'
267 265
268 266 if self.oneFigure:
269 267 if self.height is None:
270 268 self.height = 1.4 * self.nrows + 1
271 269 fig = plt.figure(figsize=(self.width, self.height),
272 270 edgecolor='k',
273 271 facecolor='w')
274 272 self.figures.append(fig)
275 273 for n in range(self.nplots):
276 274 ax = fig.add_subplot(self.nrows, self.ncols,
277 275 n + 1, polar=self.polar)
278 276 ax.tick_params(labelsize=8)
279 277 ax.firsttime = True
280 278 ax.index = 0
281 279 ax.press = None
282 280 self.axes.append(ax)
283 281 if self.showprofile:
284 282 cax = self.__add_axes(ax, size=size, pad=pad)
285 283 cax.tick_params(labelsize=8)
286 284 self.pf_axes.append(cax)
287 285 else:
288 286 if self.height is None:
289 287 self.height = 3
290 288 for n in range(self.nplots):
291 289 fig = plt.figure(figsize=(self.width, self.height),
292 290 edgecolor='k',
293 291 facecolor='w')
294 292 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
295 293 ax.tick_params(labelsize=8)
296 294 ax.firsttime = True
297 295 ax.index = 0
298 296 ax.press = None
299 297 self.figures.append(fig)
300 298 self.axes.append(ax)
301 299 if self.showprofile:
302 300 cax = self.__add_axes(ax, size=size, pad=pad)
303 301 cax.tick_params(labelsize=8)
304 302 self.pf_axes.append(cax)
305 303
306 304 for n in range(self.nrows):
307 305 if self.colormaps is not None:
308 306 cmap = plt.get_cmap(self.colormaps[n])
309 307 else:
310 308 cmap = plt.get_cmap(self.colormap)
311 309 cmap.set_bad(self.bgcolor, 1.)
312 310 self.cmaps.append(cmap)
313 311
314 312 def __add_axes(self, ax, size='30%', pad='8%'):
315 313 '''
316 314 Add new axes to the given figure
317 315 '''
318 316 divider = make_axes_locatable(ax)
319 317 nax = divider.new_horizontal(size=size, pad=pad)
320 318 ax.figure.add_axes(nax)
321 319 return nax
322 320
323 321 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
324 322 '''
325 323 Create a masked array for missing data
326 324 '''
327 325 if x_buffer.shape[0] < 2:
328 326 return x_buffer, y_buffer, z_buffer
329 327
330 328 deltas = x_buffer[1:] - x_buffer[0:-1]
331 329 x_median = numpy.median(deltas)
332 330
333 331 index = numpy.where(deltas > 5 * x_median)
334 332
335 333 if len(index[0]) != 0:
336 334 z_buffer[::, index[0], ::] = self.__missing
337 335 z_buffer = numpy.ma.masked_inside(z_buffer,
338 336 0.99 * self.__missing,
339 337 1.01 * self.__missing)
340 338
341 339 return x_buffer, y_buffer, z_buffer
342 340
343 341 def decimate(self):
344 342
345 343 # dx = int(len(self.x)/self.__MAXNUMX) + 1
346 344 dy = int(len(self.y) / self.decimation) + 1
347 345
348 346 # x = self.x[::dx]
349 347 x = self.x
350 348 y = self.y[::dy]
351 349 z = self.z[::, ::, ::dy]
352 350
353 351 return x, y, z
354 352
355 353 def format(self):
356 354 '''
357 355 Set min and max values, labels, ticks and titles
358 356 '''
359 357
360 358 if self.xmin is None:
361 359 xmin = self.data.min_time
362 360 else:
363 361 if self.xaxis is 'time':
364 362 dt = self.getDateTime(self.data.min_time)
365 363 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
366 364 datetime.datetime(1970, 1, 1)).total_seconds()
367 365 if self.data.localtime:
368 366 xmin += time.timezone
369 367 else:
370 368 xmin = self.xmin
371 369
372 370 if self.xmax is None:
373 371 xmax = xmin + self.xrange * 60 * 60
374 372 else:
375 373 if self.xaxis is 'time':
376 374 dt = self.getDateTime(self.data.max_time)
377 375 xmax = self.xmax - 1
378 376 xmax = (dt.replace(hour=int(xmax), minute=59, second=59) -
379 377 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
380 378 if self.data.localtime:
381 379 xmax += time.timezone
382 380 else:
383 381 xmax = self.xmax
384 382
385 383 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
386 384 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
387 385
388 386 for n, ax in enumerate(self.axes):
389 387 if ax.firsttime:
390 388
391 389 dig = int(numpy.log10(ymax))
392 390 if dig == 0:
393 391 digD = len(str(ymax)) - 2
394 392 ydec = ymax*(10**digD)
395 393
396 394 dig = int(numpy.log10(ydec))
397 395 ystep = ((ydec + (10**(dig)))//10**(dig))*(10**(dig))
398 396 ystep = ystep/5
399 397 ystep = ystep/(10**digD)
400 398
401 399 else:
402 400 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
403 401 ystep = ystep/5
404 402
405 403 if self.xaxis is not 'time':
406 404
407 405 dig = int(numpy.log10(xmax))
408 406
409 407 if dig <= 0:
410 408 digD = len(str(xmax)) - 2
411 409 xdec = xmax*(10**digD)
412 410
413 411 dig = int(numpy.log10(xdec))
414 412 xstep = ((xdec + (10**(dig)))//10**(dig))*(10**(dig))
415 413 xstep = xstep*0.5
416 414 xstep = xstep/(10**digD)
417 415
418 416 else:
419 417 xstep = ((xmax + (10**(dig)))//10**(dig))*(10**(dig))
420 418 xstep = xstep/5
421 419
422 420 ax.set_facecolor(self.bgcolor)
423 421 ax.yaxis.set_major_locator(MultipleLocator(ystep))
424 422 if self.xscale:
425 423 ax.xaxis.set_major_formatter(FuncFormatter(
426 424 lambda x, pos: '{0:g}'.format(x*self.xscale)))
427 425 if self.xscale:
428 426 ax.yaxis.set_major_formatter(FuncFormatter(
429 427 lambda x, pos: '{0:g}'.format(x*self.yscale)))
430 428 if self.xaxis is 'time':
431 429 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
432 430 ax.xaxis.set_major_locator(LinearLocator(9))
433 431 else:
434 432 ax.xaxis.set_major_locator(MultipleLocator(xstep))
435 433 if self.xlabel is not None:
436 434 ax.set_xlabel(self.xlabel)
437 435 ax.set_ylabel(self.ylabel)
438 436 ax.firsttime = False
439 437 if self.showprofile:
440 438 self.pf_axes[n].set_ylim(ymin, ymax)
441 439 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
442 440 self.pf_axes[n].set_xlabel('dB')
443 441 self.pf_axes[n].grid(b=True, axis='x')
444 442 [tick.set_visible(False)
445 443 for tick in self.pf_axes[n].get_yticklabels()]
446 444 if self.colorbar:
447 445 ax.cbar = plt.colorbar(
448 446 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
449 447 ax.cbar.ax.tick_params(labelsize=8)
450 448 ax.cbar.ax.press = None
451 449 if self.cb_label:
452 450 ax.cbar.set_label(self.cb_label, size=8)
453 451 elif self.cb_labels:
454 452 ax.cbar.set_label(self.cb_labels[n], size=8)
455 453 else:
456 454 ax.cbar = None
457 455 if self.grid:
458 456 ax.grid(True)
459 457
460 458 if not self.polar:
461 459 ax.set_xlim(xmin, xmax)
462 460 ax.set_ylim(ymin, ymax)
463 461 ax.set_title('{} {} {}'.format(
464 462 self.titles[n],
465 463 self.getDateTime(self.data.max_time).strftime(
466 464 '%Y-%m-%d %H:%M:%S'),
467 465 self.time_label),
468 466 size=8)
469 467 else:
470 468 ax.set_title('{}'.format(self.titles[n]), size=8)
471 469 ax.set_ylim(0, 90)
472 470 ax.set_yticks(numpy.arange(0, 90, 20))
473 471 ax.yaxis.labelpad = 40
474 472
475 473 if self.firsttime:
476 474 for n, fig in enumerate(self.figures):
477 475 fig.subplots_adjust(**self.plots_adjust)
478 476 self.firsttime = False
479 477
480 478 def clear_figures(self):
481 479 '''
482 480 Reset axes for redraw plots
483 481 '''
484 482
485 483 for ax in self.axes+self.pf_axes+self.cb_axes:
486 484 ax.clear()
487 485 ax.firsttime = True
488 if ax.cbar:
486 if hasattr(ax, 'cbar') and ax.cbar:
489 487 ax.cbar.remove()
490 488
491 489 def __plot(self):
492 490 '''
493 491 Main function to plot, format and save figures
494 492 '''
495 493
496 494 self.plot()
497 495 self.format()
498 496
499 497 for n, fig in enumerate(self.figures):
500 498 if self.nrows == 0 or self.nplots == 0:
501 499 log.warning('No data', self.name)
502 500 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
503 501 fig.canvas.manager.set_window_title(self.CODE)
504 502 continue
505 503
506 504 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
507 505 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
508 506 fig.canvas.draw()
509 507 if self.show:
510 508 fig.show()
511 509 figpause(0.01)
512 510
513 511 if self.save:
514 512 self.save_figure(n)
515 513
516 514 if self.plot_server:
517 515 self.send_to_server()
518 516
519 517 def save_figure(self, n):
520 518 '''
521 519 '''
522 520
523 521 if self.save_counter < self.save_period:
524 522 self.save_counter += 1
525 523 return
526 524
527 525 self.save_counter = 1
528 526
529 527 fig = self.figures[n]
530 528
531 529 if self.save_code:
532 530 if isinstance(self.save_code, str):
533 531 labels = [self.save_code for x in self.figures]
534 532 else:
535 533 labels = self.save_code
536 534 else:
537 535 labels = [self.CODE for x in self.figures]
538 536
539 537 figname = os.path.join(
540 538 self.save,
541 539 labels[n],
542 540 '{}_{}.png'.format(
543 541 labels[n],
544 542 self.getDateTime(self.data.max_time).strftime(
545 543 '%Y%m%d_%H%M%S'
546 544 ),
547 545 )
548 546 )
549 547 log.log('Saving figure: {}'.format(figname), self.name)
550 548 if not os.path.isdir(os.path.dirname(figname)):
551 549 os.makedirs(os.path.dirname(figname))
552 550 fig.savefig(figname)
553 551
554 552 if self.throttle == 0:
555 553 figname = os.path.join(
556 554 self.save,
557 555 '{}_{}.png'.format(
558 556 labels[n],
559 557 self.getDateTime(self.data.min_time).strftime(
560 558 '%Y%m%d'
561 559 ),
562 560 )
563 561 )
564 562 fig.savefig(figname)
565 563
566 564 def send_to_server(self):
567 565 '''
568 566 '''
569 567
570 568 interval = self.data.tm - self.sender_time
571 569 if interval < self.sender_period:
572 570 return
573 571
574 572 self.sender_time = self.data.tm
575 573
576 574 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
577 575 for attr in attrs:
578 576 value = getattr(self, attr)
579 577 if value:
580 578 if isinstance(value, (numpy.float32, numpy.float64)):
581 579 value = round(float(value), 2)
582 580 self.data.meta[attr] = value
583 581 if self.colormap == 'jet':
584 582 self.data.meta['colormap'] = 'Jet'
585 583 elif 'RdBu' in self.colormap:
586 584 self.data.meta['colormap'] = 'RdBu'
587 585 else:
588 586 self.data.meta['colormap'] = 'Viridis'
589 587 self.data.meta['interval'] = int(interval)
590 588 # msg = self.data.jsonify(self.data.tm, self.plot_name, self.plot_type)
591 self.sender_queue.put(self.data.tm)
589 try:
590 self.sender_queue.put(self.data.tm, block=False)
591 except:
592 tm = self.sender_queue.get()
593 self.sender_queue.put(self.data.tm)
592 594
593 595 while True:
594 596 if self.sender_queue.empty():
595 597 break
596 598 tm = self.sender_queue.get()
597 msg = self.data.jsonify(tm, self.plot_name, self.plot_type)
599 try:
600 msg = self.data.jsonify(tm, self.plot_name, self.plot_type)
601 except:
602 continue
598 603 self.socket.send_string(msg)
599 604 socks = dict(self.poll.poll(5000))
600 605 if socks.get(self.socket) == zmq.POLLIN:
601 606 reply = self.socket.recv_string()
602 607 if reply == 'ok':
603 608 log.log("Response from server ok", self.name)
604 time.sleep(0.1)
609 time.sleep(0.2)
605 610 continue
606 611 else:
607 612 log.warning(
608 613 "Malformed reply from server: {}".format(reply), self.name)
609 614 else:
610 615 log.warning(
611 616 "No response from server, retrying...", self.name)
612 617 self.sender_queue.put(self.data.tm)
613 618 self.socket.setsockopt(zmq.LINGER, 0)
614 619 self.socket.close()
615 620 self.poll.unregister(self.socket)
616 621 time.sleep(0.1)
617 622 self.socket = self.context.socket(zmq.REQ)
618 623 self.socket.connect(self.plot_server)
619 624 self.poll.register(self.socket, zmq.POLLIN)
620 625 break
621 626
622 627 def setup(self):
623 628 '''
624 629 This method should be implemented in the child class, the following
625 630 attributes should be set:
626 631
627 632 self.nrows: number of rows
628 633 self.ncols: number of cols
629 634 self.nplots: number of plots (channels or pairs)
630 635 self.ylabel: label for Y axes
631 636 self.titles: list of axes title
632 637
633 638 '''
634 639 raise NotImplementedError
635 640
636 641 def plot(self):
637 642 '''
638 643 Must be defined in the child class
639 644 '''
640 645 raise NotImplementedError
641 646
642 647 def run(self, dataOut, **kwargs):
643 648 '''
644 649 Main plotting routine
645 650 '''
646 651
647 652 if self.isConfig is False:
648 653 self.__setup(**kwargs)
649 654
650 655 t = getattr(dataOut, self.attr_time)
651 656
652 if dataOut.useLocalTime:
657 if self.localtime:
653 658 self.getDateTime = datetime.datetime.fromtimestamp
654 if not self.localtime:
655 t += time.timezone
656 659 else:
657 660 self.getDateTime = datetime.datetime.utcfromtimestamp
658 if self.localtime:
659 t -= time.timezone
660 661
661 662 if self.xmin is None:
662 663 self.tmin = t
663 664 if 'buffer' in self.plot_type:
664 665 self.xmin = self.getDateTime(t).hour
665 666 else:
666 667 self.tmin = (
667 668 self.getDateTime(t).replace(
668 669 hour=int(self.xmin),
669 670 minute=0,
670 671 second=0) - self.getDateTime(0)).total_seconds()
671 672
672 673 self.data.setup()
673 674 self.isConfig = True
674 675 if self.plot_server:
675 676 self.context = zmq.Context()
676 677 self.socket = self.context.socket(zmq.REQ)
677 678 self.socket.connect(self.plot_server)
678 679 self.poll = zmq.Poller()
679 680 self.poll.register(self.socket, zmq.POLLIN)
680 681
681 682 tm = getattr(dataOut, self.attr_time)
682
683 if not dataOut.useLocalTime and self.localtime:
684 tm -= time.timezone
685 if dataOut.useLocalTime and not self.localtime:
686 tm += time.timezone
687 683
688 684 if self.data and (tm - self.tmin) >= self.xrange*60*60:
689 685 self.save_counter = self.save_period
690 686 self.__plot()
691 687 if 'time' in self.xaxis:
692 688 self.xmin += self.xrange
693 689 if self.xmin >= 24:
694 690 self.xmin -= 24
695 691 self.tmin += self.xrange*60*60
696 692 self.data.setup()
697 693 self.clear_figures()
698 694
699 695 self.data.update(dataOut, tm)
700 696
701 697 if self.isPlotConfig is False:
702 698 self.__setup_plot()
703 699 self.isPlotConfig = True
704 700
705 701 if self.throttle == 0:
706 702 self.__plot()
707 703 else:
708 704 self.__throttle_plot(self.__plot)#, coerce=coerce)
709 705
710 706 def close(self):
711 707
712 708 if self.data and not self.data.flagNoData:
713 709 self.save_counter = self.save_period
714 710 self.__plot()
715 711 if self.data and not self.data.flagNoData and self.pause:
716 712 figpause(10)
717 713
General Comments 0
You need to be logged in to leave comments. Login now