##// END OF EJS Templates
last debbug fix pulsepair and spectralmoment
avaldez -
r1395:e5714b82613d
parent child
Show More
@@ -1,517 +1,517
1 1 import os
2 2 import datetime
3 3 import numpy
4 4
5 5 from schainpy.model.graphics.jroplot_base import Plot, plt
6 6 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot
7 7 from schainpy.utils import log
8 8 # libreria wradlib
9 9 import wradlib as wrl
10 10
11 11 EARTH_RADIUS = 6.3710e3
12 12
13 13
14 14 def ll2xy(lat1, lon1, lat2, lon2):
15 15
16 16 p = 0.017453292519943295
17 17 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
18 18 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
19 19 r = 12742 * numpy.arcsin(numpy.sqrt(a))
20 20 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
21 21 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
22 22 theta = -theta + numpy.pi/2
23 23 return r*numpy.cos(theta), r*numpy.sin(theta)
24 24
25 25
26 26 def km2deg(km):
27 27 '''
28 28 Convert distance in km to degrees
29 29 '''
30 30
31 31 return numpy.rad2deg(km/EARTH_RADIUS)
32 32
33 33
34 34
35 35 class SpectralMomentsPlot(SpectraPlot):
36 36 '''
37 37 Plot for Spectral Moments
38 38 '''
39 39 CODE = 'spc_moments'
40 40 # colormap = 'jet'
41 41 # plot_type = 'pcolor'
42 42
43 43 class DobleGaussianPlot(SpectraPlot):
44 44 '''
45 45 Plot for Double Gaussian Plot
46 46 '''
47 47 CODE = 'gaussian_fit'
48 48 # colormap = 'jet'
49 49 # plot_type = 'pcolor'
50 50
51 51 class DoubleGaussianSpectraCutPlot(SpectraCutPlot):
52 52 '''
53 53 Plot SpectraCut with Double Gaussian Fit
54 54 '''
55 55 CODE = 'cut_gaussian_fit'
56 56
57 57 class SnrPlot(RTIPlot):
58 58 '''
59 59 Plot for SNR Data
60 60 '''
61 61
62 62 CODE = 'snr'
63 63 colormap = 'jet'
64 64
65 65 def update(self, dataOut):
66 66
67 67 data = {
68 68 'snr': 10*numpy.log10(dataOut.data_snr)
69 69 }
70 70
71 71 return data, {}
72 72
73 73 class DopplerPlot(RTIPlot):
74 74 '''
75 75 Plot for DOPPLER Data (1st moment)
76 76 '''
77 77
78 78 CODE = 'dop'
79 79 colormap = 'jet'
80 80
81 81 def update(self, dataOut):
82 82
83 83 data = {
84 84 'dop': 10*numpy.log10(dataOut.data_dop)
85 85 }
86 86
87 87 return data, {}
88 88
89 89 class PowerPlot(RTIPlot):
90 90 '''
91 91 Plot for Power Data (0 moment)
92 92 '''
93 93
94 94 CODE = 'pow'
95 95 colormap = 'jet'
96 96
97 97 def update(self, dataOut):
98 98 data = {
99 99 'pow': 10*numpy.log10(dataOut.data_pow/dataOut.normFactor)
100 100 }
101 101 return data, {}
102 102
103 103 class SpectralWidthPlot(RTIPlot):
104 104 '''
105 105 Plot for Spectral Width Data (2nd moment)
106 106 '''
107 107
108 108 CODE = 'width'
109 109 colormap = 'jet'
110 110
111 111 def update(self, dataOut):
112 112
113 113 data = {
114 114 'width': dataOut.data_width
115 115 }
116 116
117 117 return data, {}
118 118
119 119 class SkyMapPlot(Plot):
120 120 '''
121 121 Plot for meteors detection data
122 122 '''
123 123
124 124 CODE = 'param'
125 125
126 126 def setup(self):
127 127
128 128 self.ncols = 1
129 129 self.nrows = 1
130 130 self.width = 7.2
131 131 self.height = 7.2
132 132 self.nplots = 1
133 133 self.xlabel = 'Zonal Zenith Angle (deg)'
134 134 self.ylabel = 'Meridional Zenith Angle (deg)'
135 135 self.polar = True
136 136 self.ymin = -180
137 137 self.ymax = 180
138 138 self.colorbar = False
139 139
140 140 def plot(self):
141 141
142 142 arrayParameters = numpy.concatenate(self.data['param'])
143 143 error = arrayParameters[:, -1]
144 144 indValid = numpy.where(error == 0)[0]
145 145 finalMeteor = arrayParameters[indValid, :]
146 146 finalAzimuth = finalMeteor[:, 3]
147 147 finalZenith = finalMeteor[:, 4]
148 148
149 149 x = finalAzimuth * numpy.pi / 180
150 150 y = finalZenith
151 151
152 152 ax = self.axes[0]
153 153
154 154 if ax.firsttime:
155 155 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
156 156 else:
157 157 ax.plot.set_data(x, y)
158 158
159 159 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
160 160 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
161 161 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
162 162 dt2,
163 163 len(x))
164 164 self.titles[0] = title
165 165
166 166
167 167 class GenericRTIPlot(Plot):
168 168 '''
169 169 Plot for data_xxxx object
170 170 '''
171 171
172 172 CODE = 'param'
173 173 colormap = 'viridis'
174 174 plot_type = 'pcolorbuffer'
175 175
176 176 def setup(self):
177 177 self.xaxis = 'time'
178 178 self.ncols = 1
179 179 self.nrows = self.data.shape('param')[0]
180 180 self.nplots = self.nrows
181 181 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
182 182
183 183 if not self.xlabel:
184 184 self.xlabel = 'Time'
185 185
186 186 self.ylabel = 'Range [km]'
187 187 if not self.titles:
188 188 self.titles = ['Param {}'.format(x) for x in range(self.nrows)]
189 189
190 190 def update(self, dataOut):
191 191
192 192 data = {
193 193 'param' : numpy.concatenate([getattr(dataOut, attr) for attr in self.attr_data], axis=0)
194 194 }
195 195
196 196 meta = {}
197 197
198 198 return data, meta
199 199
200 200 def plot(self):
201 201 # self.data.normalize_heights()
202 202 self.x = self.data.times
203 203 self.y = self.data.yrange
204 204 self.z = self.data['param']
205 205 self.z = 10*numpy.log10(self.z)
206 206 self.z = numpy.ma.masked_invalid(self.z)
207 207
208 208 if self.decimation is None:
209 209 x, y, z = self.fill_gaps(self.x, self.y, self.z)
210 210 else:
211 211 x, y, z = self.fill_gaps(*self.decimate())
212 212
213 213 for n, ax in enumerate(self.axes):
214 214
215 215 self.zmax = self.zmax if self.zmax is not None else numpy.max(
216 216 self.z[n])
217 217 self.zmin = self.zmin if self.zmin is not None else numpy.min(
218 218 self.z[n])
219 219
220 220 if ax.firsttime:
221 221 if self.zlimits is not None:
222 222 self.zmin, self.zmax = self.zlimits[n]
223 223
224 224 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
225 225 vmin=self.zmin,
226 226 vmax=self.zmax,
227 227 cmap=self.cmaps[n]
228 228 )
229 229 else:
230 230 if self.zlimits is not None:
231 231 self.zmin, self.zmax = self.zlimits[n]
232 232 ax.collections.remove(ax.collections[0])
233 233 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
234 234 vmin=self.zmin,
235 235 vmax=self.zmax,
236 236 cmap=self.cmaps[n]
237 237 )
238 238
239 239
240 240 class PolarMapPlot(Plot):
241 241 '''
242 242 Plot for weather radar
243 243 '''
244 244
245 245 CODE = 'param'
246 246 colormap = 'seismic'
247 247
248 248 def setup(self):
249 249 self.ncols = 1
250 250 self.nrows = 1
251 251 self.width = 9
252 252 self.height = 8
253 253 self.mode = self.data.meta['mode']
254 254 if self.channels is not None:
255 255 self.nplots = len(self.channels)
256 256 self.nrows = len(self.channels)
257 257 else:
258 258 self.nplots = self.data.shape(self.CODE)[0]
259 259 self.nrows = self.nplots
260 260 self.channels = list(range(self.nplots))
261 261 if self.mode == 'E':
262 262 self.xlabel = 'Longitude'
263 263 self.ylabel = 'Latitude'
264 264 else:
265 265 self.xlabel = 'Range (km)'
266 266 self.ylabel = 'Height (km)'
267 267 self.bgcolor = 'white'
268 268 self.cb_labels = self.data.meta['units']
269 269 self.lat = self.data.meta['latitude']
270 270 self.lon = self.data.meta['longitude']
271 271 self.xmin, self.xmax = float(
272 272 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
273 273 self.ymin, self.ymax = float(
274 274 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
275 275 # self.polar = True
276 276
277 277 def plot(self):
278 278
279 279 for n, ax in enumerate(self.axes):
280 280 data = self.data['param'][self.channels[n]]
281 281
282 282 zeniths = numpy.linspace(
283 283 0, self.data.meta['max_range'], data.shape[1])
284 284 if self.mode == 'E':
285 285 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
286 286 r, theta = numpy.meshgrid(zeniths, azimuths)
287 287 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
288 288 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
289 289 x = km2deg(x) + self.lon
290 290 y = km2deg(y) + self.lat
291 291 else:
292 292 azimuths = numpy.radians(self.data.yrange)
293 293 r, theta = numpy.meshgrid(zeniths, azimuths)
294 294 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
295 295 self.y = zeniths
296 296
297 297 if ax.firsttime:
298 298 if self.zlimits is not None:
299 299 self.zmin, self.zmax = self.zlimits[n]
300 300 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
301 301 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
302 302 vmin=self.zmin,
303 303 vmax=self.zmax,
304 304 cmap=self.cmaps[n])
305 305 else:
306 306 if self.zlimits is not None:
307 307 self.zmin, self.zmax = self.zlimits[n]
308 308 ax.collections.remove(ax.collections[0])
309 309 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
310 310 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
311 311 vmin=self.zmin,
312 312 vmax=self.zmax,
313 313 cmap=self.cmaps[n])
314 314
315 315 if self.mode == 'A':
316 316 continue
317 317
318 318 # plot district names
319 319 f = open('/data/workspace/schain_scripts/distrito.csv')
320 320 for line in f:
321 321 label, lon, lat = [s.strip() for s in line.split(',') if s]
322 322 lat = float(lat)
323 323 lon = float(lon)
324 324 # ax.plot(lon, lat, '.b', ms=2)
325 325 ax.text(lon, lat, label.decode('utf8'), ha='center',
326 326 va='bottom', size='8', color='black')
327 327
328 328 # plot limites
329 329 limites = []
330 330 tmp = []
331 331 for line in open('/data/workspace/schain_scripts/lima.csv'):
332 332 if '#' in line:
333 333 if tmp:
334 334 limites.append(tmp)
335 335 tmp = []
336 336 continue
337 337 values = line.strip().split(',')
338 338 tmp.append((float(values[0]), float(values[1])))
339 339 for points in limites:
340 340 ax.add_patch(
341 341 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
342 342
343 343 # plot Cuencas
344 344 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
345 345 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
346 346 values = [line.strip().split(',') for line in f]
347 347 points = [(float(s[0]), float(s[1])) for s in values]
348 348 ax.add_patch(Polygon(points, ec='b', fc='none'))
349 349
350 350 # plot grid
351 351 for r in (15, 30, 45, 60):
352 352 ax.add_artist(plt.Circle((self.lon, self.lat),
353 353 km2deg(r), color='0.6', fill=False, lw=0.2))
354 354 ax.text(
355 355 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
356 356 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
357 357 '{}km'.format(r),
358 358 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
359 359
360 360 if self.mode == 'E':
361 361 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
362 362 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
363 363 else:
364 364 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
365 365 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
366 366
367 367 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
368 368 self.titles = ['{} {}'.format(
369 369 self.data.parameters[x], title) for x in self.channels]
370 370
371 371 class WeatherPlot(Plot):
372 372 CODE = 'weather'
373 373 plot_name = 'weather'
374 374 plot_type = 'ppistyle'
375 375 buffering = False
376 376
377 377 def setup(self):
378 378 self.ncols = 1
379 379 self.nrows = 1
380 380 self.nplots= 1
381 381 self.ylabel= 'Range [Km]'
382 382 self.titles= ['Weather']
383 383 self.colorbar=False
384 384 self.width =8
385 385 self.height =8
386 386 self.ini =0
387 387 self.len_azi =0
388 388 self.buffer_ini = None
389 389 self.buffer_azi = None
390 390 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
391 391 self.flag =0
392 392 self.indicador= 0
393 393
394 394 def update(self, dataOut):
395 395
396 396 data = {}
397 397 meta = {}
398 398 if hasattr(dataOut, 'dataPP_POWER'):
399 399 factor = 1
400 400
401 401 if hasattr(dataOut, 'nFFTPoints'):
402 402 factor = dataOut.normFactor
403 403
404 print("factor",factor)
404 ####print("factor",factor)
405 405 data['weather'] = 10*numpy.log10(dataOut.data_360[0]/(factor))
406 406 print("weather",data['weather'])
407 407 data['azi'] = dataOut.data_azi
408 408 return data, meta
409 409
410 410 def const_ploteo(self,data_weather,data_azi,step,res):
411 411 if self.ini==0:
412 412 #------- AZIMUTH
413 413 n = (360/res)-len(data_azi)
414 414 start = data_azi[-1] + res
415 415 end = data_azi[0] - res
416 416 if start>end:
417 417 end = end + 360
418 418 azi_vacia = numpy.linspace(start,end,int(n))
419 419 azi_vacia = numpy.where(azi_vacia>360,azi_vacia-360,azi_vacia)
420 420 data_azi = numpy.hstack((data_azi,azi_vacia))
421 421 # RADAR
422 422 val_mean = numpy.mean(data_weather[:,0])
423 423 data_weather_cmp = numpy.ones([(360-data_weather.shape[0]),data_weather.shape[1]])*val_mean
424 424 data_weather = numpy.vstack((data_weather,data_weather_cmp))
425 425 else:
426 426 # azimuth
427 427 flag=0
428 428 start_azi = self.res_azi[0]
429 429 start = data_azi[0]
430 430 end = data_azi[-1]
431 431 print("start",start)
432 432 print("end",end)
433 433 if start< start_azi:
434 434 start = start +360
435 435 if end <start_azi:
436 436 end = end +360
437 437
438 438 print("start",start)
439 439 print("end",end)
440 440 #### AQUI SERA LA MAGIA
441 441 pos_ini = int((start-start_azi)/res)
442 442 len_azi = len(data_azi)
443 443 if (360-pos_ini)<len_azi:
444 444 if pos_ini+1==360:
445 445 pos_ini=0
446 446 else:
447 447 flag=1
448 448 dif= 360-pos_ini
449 449 comp= len_azi-dif
450 450
451 451 print(pos_ini)
452 452 print(len_azi)
453 453 print("shape",self.res_azi.shape)
454 454 if flag==0:
455 455 # AZIMUTH
456 456 self.res_azi[pos_ini:pos_ini+len_azi] = data_azi
457 457 # RADAR
458 458 self.res_weather[pos_ini:pos_ini+len_azi,:] = data_weather
459 459 else:
460 460 # AZIMUTH
461 461 self.res_azi[pos_ini:pos_ini+dif] = data_azi[0:dif]
462 462 self.res_azi[0:comp] = data_azi[dif:]
463 463 # RADAR
464 464 self.res_weather[pos_ini:pos_ini+dif,:] = data_weather[0:dif,:]
465 465 self.res_weather[0:comp,:] = data_weather[dif:,:]
466 466 flag=0
467 467 data_azi = self.res_azi
468 468 data_weather = self.res_weather
469 469
470 470 return data_weather,data_azi
471 471
472 472 def plot(self):
473 473 print("--------------------------------------",self.ini,"-----------------------------------")
474 474 #numpy.set_printoptions(suppress=True)
475 475 #print(self.data.times)
476 476 thisDatetime = datetime.datetime.utcfromtimestamp(self.data.times[-1])
477 477 data = self.data[-1]
478 478 # ALTURA altura_tmp_h
479 479 altura_h = (data['weather'].shape[1])/10.0
480 480 stoprange = float(altura_h*1.5)#stoprange = float(33*1.5) por ahora 400
481 481 rangestep = float(0.15)
482 482 r = numpy.arange(0, stoprange, rangestep)
483 483 self.y = 2*r
484 484 # RADAR
485 485 #data_weather = data['weather']
486 486 # PEDESTAL
487 487 #data_azi = data['azi']
488 488 res = 1
489 489 # STEP
490 490 step = (360/(res*data['weather'].shape[0]))
491 491 #print("shape wr_data", wr_data.shape)
492 492 #print("shape wr_azi",wr_azi.shape)
493 493 #print("step",step)
494 494 print("Time---->",self.data.times[-1],thisDatetime)
495 495 #print("alturas", len(self.y))
496 496 self.res_weather, self.res_azi = self.const_ploteo(data_weather=data['weather'],data_azi=data['azi'],step=step,res=res)
497 497 #numpy.set_printoptions(suppress=True)
498 498 #print("resultado",self.res_azi)
499 499 ##########################################################
500 500 ################# PLOTEO ###################
501 501 ##########################################################
502 502
503 503 for i,ax in enumerate(self.axes):
504 504 if ax.firsttime:
505 505 plt.clf()
506 506 cgax, pm = wrl.vis.plot_ppi(self.res_weather,r=r,az=self.res_azi,fig=self.figures[0], proj='cg', vmin=1, vmax=60)
507 507 else:
508 508 plt.clf()
509 509 cgax, pm = wrl.vis.plot_ppi(self.res_weather,r=r,az=self.res_azi,fig=self.figures[0], proj='cg', vmin=1, vmax=60)
510 510 caax = cgax.parasites[0]
511 511 paax = cgax.parasites[1]
512 512 cbar = plt.gcf().colorbar(pm, pad=0.075)
513 513 caax.set_xlabel('x_range [km]')
514 514 caax.set_ylabel('y_range [km]')
515 515 plt.text(1.0, 1.05, 'azimuth '+str(thisDatetime)+"step"+str(self.ini), transform=caax.transAxes, va='bottom',ha='right')
516 516
517 517 self.ini= self.ini+1
@@ -1,4473 +1,4473
1 1 import numpy,os,h5py
2 2 import math
3 3 from scipy import optimize, interpolate, signal, stats, ndimage
4 4 import scipy
5 5 import re
6 6 import datetime
7 7 import copy
8 8 import sys
9 9 import importlib
10 10 import itertools
11 11 from multiprocessing import Pool, TimeoutError
12 12 from multiprocessing.pool import ThreadPool
13 13 import time
14 14
15 15 from scipy.optimize import fmin_l_bfgs_b #optimize with bounds on state papameters
16 16 from .jroproc_base import ProcessingUnit, Operation, MPDecorator
17 17 from schainpy.model.data.jrodata import Parameters, hildebrand_sekhon
18 18 from scipy import asarray as ar,exp
19 19 from scipy.optimize import curve_fit
20 20 from schainpy.utils import log
21 21 import warnings
22 22 from numpy import NaN
23 23 from scipy.optimize.optimize import OptimizeWarning
24 24 warnings.filterwarnings('ignore')
25 25
26 26 import matplotlib.pyplot as plt
27 27
28 28 SPEED_OF_LIGHT = 299792458
29 29
30 30 '''solving pickling issue'''
31 31
32 32 def _pickle_method(method):
33 33 func_name = method.__func__.__name__
34 34 obj = method.__self__
35 35 cls = method.__self__.__class__
36 36 return _unpickle_method, (func_name, obj, cls)
37 37
38 38 def _unpickle_method(func_name, obj, cls):
39 39 for cls in cls.mro():
40 40 try:
41 41 func = cls.__dict__[func_name]
42 42 except KeyError:
43 43 pass
44 44 else:
45 45 break
46 46 return func.__get__(obj, cls)
47 47
48 48 def isNumber(str):
49 49 try:
50 50 float(str)
51 51 return True
52 52 except:
53 53 return False
54 54
55 55 class ParametersProc(ProcessingUnit):
56 56
57 57 METHODS = {}
58 58 nSeconds = None
59 59
60 60 def __init__(self):
61 61 ProcessingUnit.__init__(self)
62 62
63 63 # self.objectDict = {}
64 64 self.buffer = None
65 65 self.firstdatatime = None
66 66 self.profIndex = 0
67 67 self.dataOut = Parameters()
68 68 self.setupReq = False #Agregar a todas las unidades de proc
69 69
70 70 def __updateObjFromInput(self):
71 71
72 72 self.dataOut.inputUnit = self.dataIn.type
73 73
74 74 self.dataOut.timeZone = self.dataIn.timeZone
75 75 self.dataOut.dstFlag = self.dataIn.dstFlag
76 76 self.dataOut.errorCount = self.dataIn.errorCount
77 77 self.dataOut.useLocalTime = self.dataIn.useLocalTime
78 78
79 79 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
80 80 self.dataOut.systemHeaderObj = self.dataIn.systemHeaderObj.copy()
81 81 self.dataOut.channelList = self.dataIn.channelList
82 82 self.dataOut.heightList = self.dataIn.heightList
83 83 self.dataOut.dtype = numpy.dtype([('real','<f4'),('imag','<f4')])
84 84 # self.dataOut.nHeights = self.dataIn.nHeights
85 85 # self.dataOut.nChannels = self.dataIn.nChannels
86 86 # self.dataOut.nBaud = self.dataIn.nBaud
87 87 # self.dataOut.nCode = self.dataIn.nCode
88 88 # self.dataOut.code = self.dataIn.code
89 89 # self.dataOut.nProfiles = self.dataOut.nFFTPoints
90 90 self.dataOut.flagDiscontinuousBlock = self.dataIn.flagDiscontinuousBlock
91 91 # self.dataOut.utctime = self.firstdatatime
92 92 self.dataOut.utctime = self.dataIn.utctime
93 93 self.dataOut.flagDecodeData = self.dataIn.flagDecodeData #asumo q la data esta decodificada
94 94 self.dataOut.flagDeflipData = self.dataIn.flagDeflipData #asumo q la data esta sin flip
95 95 self.dataOut.nCohInt = self.dataIn.nCohInt
96 96 # self.dataOut.nIncohInt = 1
97 97 # self.dataOut.ippSeconds = self.dataIn.ippSeconds
98 98 # self.dataOut.windowOfFilter = self.dataIn.windowOfFilter
99 99 self.dataOut.timeInterval1 = self.dataIn.timeInterval
100 100 self.dataOut.heightList = self.dataIn.heightList
101 101 self.dataOut.frequency = self.dataIn.frequency
102 102 # self.dataOut.noise = self.dataIn.noise
103 103
104 104 def run(self):
105 105
106 106
107 107 #print("HOLA MUNDO SOY YO")
108 108 #---------------------- Voltage Data ---------------------------
109 109
110 110 if self.dataIn.type == "Voltage":
111 111
112 112 self.__updateObjFromInput()
113 113 self.dataOut.data_pre = self.dataIn.data.copy()
114 114 self.dataOut.flagNoData = False
115 115 self.dataOut.utctimeInit = self.dataIn.utctime
116 116 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
117 117
118 118 if hasattr(self.dataIn, 'flagDataAsBlock'):
119 119 self.dataOut.flagDataAsBlock = self.dataIn.flagDataAsBlock
120 120
121 121 if hasattr(self.dataIn, 'profileIndex'):
122 122 self.dataOut.profileIndex = self.dataIn.profileIndex
123 123
124 124 if hasattr(self.dataIn, 'dataPP_POW'):
125 125 self.dataOut.dataPP_POW = self.dataIn.dataPP_POW
126 126
127 127 if hasattr(self.dataIn, 'dataPP_POWER'):
128 128 self.dataOut.dataPP_POWER = self.dataIn.dataPP_POWER
129 129
130 130 if hasattr(self.dataIn, 'dataPP_DOP'):
131 131 self.dataOut.dataPP_DOP = self.dataIn.dataPP_DOP
132 132
133 133 if hasattr(self.dataIn, 'dataPP_SNR'):
134 134 self.dataOut.dataPP_SNR = self.dataIn.dataPP_SNR
135 135
136 136 if hasattr(self.dataIn, 'dataPP_WIDTH'):
137 137 self.dataOut.dataPP_WIDTH = self.dataIn.dataPP_WIDTH
138 138 return
139 139
140 140 #---------------------- Spectra Data ---------------------------
141 141
142 142 if self.dataIn.type == "Spectra":
143 143 #print("que paso en spectra")
144 144 self.dataOut.data_pre = [self.dataIn.data_spc, self.dataIn.data_cspc]
145 145 self.dataOut.data_spc = self.dataIn.data_spc
146 146 self.dataOut.data_cspc = self.dataIn.data_cspc
147 147 self.dataOut.nProfiles = self.dataIn.nProfiles
148 148 self.dataOut.nIncohInt = self.dataIn.nIncohInt
149 149 self.dataOut.nFFTPoints = self.dataIn.nFFTPoints
150 150 self.dataOut.ippFactor = self.dataIn.ippFactor
151 151 self.dataOut.abscissaList = self.dataIn.getVelRange(1)
152 152 self.dataOut.spc_noise = self.dataIn.getNoise()
153 153 self.dataOut.spc_range = (self.dataIn.getFreqRange(1) , self.dataIn.getAcfRange(1) , self.dataIn.getVelRange(1))
154 154 # self.dataOut.normFactor = self.dataIn.normFactor
155 155 self.dataOut.pairsList = self.dataIn.pairsList
156 156 self.dataOut.groupList = self.dataIn.pairsList
157 157 self.dataOut.flagNoData = False
158 158
159 159 if hasattr(self.dataIn, 'flagDataAsBlock'):
160 160 self.dataOut.flagDataAsBlock = self.dataIn.flagDataAsBlock
161 161
162 162 if hasattr(self.dataIn, 'ChanDist'): #Distances of receiver channels
163 163 self.dataOut.ChanDist = self.dataIn.ChanDist
164 164 else: self.dataOut.ChanDist = None
165 165
166 166 #if hasattr(self.dataIn, 'VelRange'): #Velocities range
167 167 # self.dataOut.VelRange = self.dataIn.VelRange
168 168 #else: self.dataOut.VelRange = None
169 169
170 170 if hasattr(self.dataIn, 'RadarConst'): #Radar Constant
171 171 self.dataOut.RadarConst = self.dataIn.RadarConst
172 172
173 173 if hasattr(self.dataIn, 'NPW'): #NPW
174 174 self.dataOut.NPW = self.dataIn.NPW
175 175
176 176 if hasattr(self.dataIn, 'COFA'): #COFA
177 177 self.dataOut.COFA = self.dataIn.COFA
178 178
179 179
180 180
181 181 #---------------------- Correlation Data ---------------------------
182 182
183 183 if self.dataIn.type == "Correlation":
184 184 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.dataIn.splitFunctions()
185 185
186 186 self.dataOut.data_pre = (self.dataIn.data_cf[acf_ind,:], self.dataIn.data_cf[ccf_ind,:,:])
187 187 self.dataOut.normFactor = (self.dataIn.normFactor[acf_ind,:], self.dataIn.normFactor[ccf_ind,:])
188 188 self.dataOut.groupList = (acf_pairs, ccf_pairs)
189 189
190 190 self.dataOut.abscissaList = self.dataIn.lagRange
191 191 self.dataOut.noise = self.dataIn.noise
192 192 self.dataOut.data_snr = self.dataIn.SNR
193 193 self.dataOut.flagNoData = False
194 194 self.dataOut.nAvg = self.dataIn.nAvg
195 195
196 196 #---------------------- Parameters Data ---------------------------
197 197
198 198 if self.dataIn.type == "Parameters":
199 199 self.dataOut.copy(self.dataIn)
200 200 self.dataOut.flagNoData = False
201 201 #print("yo si entre")
202 202
203 203 return True
204 204
205 205 self.__updateObjFromInput()
206 206 #print("yo si entre2")
207 207
208 208 self.dataOut.utctimeInit = self.dataIn.utctime
209 209 self.dataOut.paramInterval = self.dataIn.timeInterval
210 210 #print("soy spectra ",self.dataOut.utctimeInit)
211 211 return
212 212
213 213
214 214 def target(tups):
215 215
216 216 obj, args = tups
217 217
218 218 return obj.FitGau(args)
219 219
220 220 class RemoveWideGC(Operation):
221 221 ''' This class remove the wide clutter and replace it with a simple interpolation points
222 222 This mainly applies to CLAIRE radar
223 223
224 224 ClutterWidth : Width to look for the clutter peak
225 225
226 226 Input:
227 227
228 228 self.dataOut.data_pre : SPC and CSPC
229 229 self.dataOut.spc_range : To select wind and rainfall velocities
230 230
231 231 Affected:
232 232
233 233 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
234 234
235 235 Written by D. ScipiΓ³n 25.02.2021
236 236 '''
237 237 def __init__(self):
238 238 Operation.__init__(self)
239 239 self.i = 0
240 240 self.ich = 0
241 241 self.ir = 0
242 242
243 243 def run(self, dataOut, ClutterWidth=2.5):
244 244 # print ('Entering RemoveWideGC ... ')
245 245
246 246 self.spc = dataOut.data_pre[0].copy()
247 247 self.spc_out = dataOut.data_pre[0].copy()
248 248 self.Num_Chn = self.spc.shape[0]
249 249 self.Num_Hei = self.spc.shape[2]
250 250 VelRange = dataOut.spc_range[2][:-1]
251 251 dv = VelRange[1]-VelRange[0]
252 252
253 253 # Find the velocities that corresponds to zero
254 254 gc_values = numpy.squeeze(numpy.where(numpy.abs(VelRange) <= ClutterWidth))
255 255
256 256 # Removing novalid data from the spectra
257 257 for ich in range(self.Num_Chn) :
258 258 for ir in range(self.Num_Hei) :
259 259 # Estimate the noise at each range
260 260 HSn = hildebrand_sekhon(self.spc[ich,:,ir],dataOut.nIncohInt)
261 261
262 262 # Removing the noise floor at each range
263 263 novalid = numpy.where(self.spc[ich,:,ir] < HSn)
264 264 self.spc[ich,novalid,ir] = HSn
265 265
266 266 junk = numpy.append(numpy.insert(numpy.squeeze(self.spc[ich,gc_values,ir]),0,HSn),HSn)
267 267 j1index = numpy.squeeze(numpy.where(numpy.diff(junk)>0))
268 268 j2index = numpy.squeeze(numpy.where(numpy.diff(junk)<0))
269 269 if ((numpy.size(j1index)<=1) | (numpy.size(j2index)<=1)) :
270 270 continue
271 271 junk3 = numpy.squeeze(numpy.diff(j1index))
272 272 junk4 = numpy.squeeze(numpy.diff(j2index))
273 273
274 274 valleyindex = j2index[numpy.where(junk4>1)]
275 275 peakindex = j1index[numpy.where(junk3>1)]
276 276
277 277 isvalid = numpy.squeeze(numpy.where(numpy.abs(VelRange[gc_values[peakindex]]) <= 2.5*dv))
278 278 if numpy.size(isvalid) == 0 :
279 279 continue
280 280 if numpy.size(isvalid) >1 :
281 281 vindex = numpy.argmax(self.spc[ich,gc_values[peakindex[isvalid]],ir])
282 282 isvalid = isvalid[vindex]
283 283
284 284 # clutter peak
285 285 gcpeak = peakindex[isvalid]
286 286 vl = numpy.where(valleyindex < gcpeak)
287 287 if numpy.size(vl) == 0:
288 288 continue
289 289 gcvl = valleyindex[vl[0][-1]]
290 290 vr = numpy.where(valleyindex > gcpeak)
291 291 if numpy.size(vr) == 0:
292 292 continue
293 293 gcvr = valleyindex[vr[0][0]]
294 294
295 295 # Removing the clutter
296 296 interpindex = numpy.array([gc_values[gcvl], gc_values[gcvr]])
297 297 gcindex = gc_values[gcvl+1:gcvr-1]
298 298 self.spc_out[ich,gcindex,ir] = numpy.interp(VelRange[gcindex],VelRange[interpindex],self.spc[ich,interpindex,ir])
299 299
300 300 dataOut.data_pre[0] = self.spc_out
301 301 #print ('Leaving RemoveWideGC ... ')
302 302 return dataOut
303 303
304 304 class SpectralFilters(Operation):
305 305 ''' This class allows to replace the novalid values with noise for each channel
306 306 This applies to CLAIRE RADAR
307 307
308 308 PositiveLimit : RightLimit of novalid data
309 309 NegativeLimit : LeftLimit of novalid data
310 310
311 311 Input:
312 312
313 313 self.dataOut.data_pre : SPC and CSPC
314 314 self.dataOut.spc_range : To select wind and rainfall velocities
315 315
316 316 Affected:
317 317
318 318 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
319 319
320 320 Written by D. ScipiΓ³n 29.01.2021
321 321 '''
322 322 def __init__(self):
323 323 Operation.__init__(self)
324 324 self.i = 0
325 325
326 326 def run(self, dataOut, ):
327 327
328 328 self.spc = dataOut.data_pre[0].copy()
329 329 self.Num_Chn = self.spc.shape[0]
330 330 VelRange = dataOut.spc_range[2]
331 331
332 332 # novalid corresponds to data within the Negative and PositiveLimit
333 333
334 334
335 335 # Removing novalid data from the spectra
336 336 for i in range(self.Num_Chn):
337 337 self.spc[i,novalid,:] = dataOut.noise[i]
338 338 dataOut.data_pre[0] = self.spc
339 339 return dataOut
340 340
341 341 class GaussianFit(Operation):
342 342
343 343 '''
344 344 Function that fit of one and two generalized gaussians (gg) based
345 345 on the PSD shape across an "power band" identified from a cumsum of
346 346 the measured spectrum - noise.
347 347
348 348 Input:
349 349 self.dataOut.data_pre : SelfSpectra
350 350
351 351 Output:
352 352 self.dataOut.SPCparam : SPC_ch1, SPC_ch2
353 353
354 354 '''
355 355 def __init__(self):
356 356 Operation.__init__(self)
357 357 self.i=0
358 358
359 359
360 360 # def run(self, dataOut, num_intg=7, pnoise=1., SNRlimit=-9): #num_intg: Incoherent integrations, pnoise: Noise, vel_arr: range of velocities, similar to the ftt points
361 361 def run(self, dataOut, SNRdBlimit=-9, method='generalized'):
362 362 """This routine will find a couple of generalized Gaussians to a power spectrum
363 363 methods: generalized, squared
364 364 input: spc
365 365 output:
366 366 noise, amplitude0,shift0,width0,p0,Amplitude1,shift1,width1,p1
367 367 """
368 368 print ('Entering ',method,' double Gaussian fit')
369 369 self.spc = dataOut.data_pre[0].copy()
370 370 self.Num_Hei = self.spc.shape[2]
371 371 self.Num_Bin = self.spc.shape[1]
372 372 self.Num_Chn = self.spc.shape[0]
373 373
374 374 start_time = time.time()
375 375
376 376 pool = Pool(processes=self.Num_Chn)
377 377 args = [(dataOut.spc_range[2], ich, dataOut.spc_noise[ich], dataOut.nIncohInt, SNRdBlimit) for ich in range(self.Num_Chn)]
378 378 objs = [self for __ in range(self.Num_Chn)]
379 379 attrs = list(zip(objs, args))
380 380 DGauFitParam = pool.map(target, attrs)
381 381 # Parameters:
382 382 # 0. Noise, 1. Amplitude, 2. Shift, 3. Width 4. Power
383 383 dataOut.DGauFitParams = numpy.asarray(DGauFitParam)
384 384
385 385 # Double Gaussian Curves
386 386 gau0 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
387 387 gau0[:] = numpy.NaN
388 388 gau1 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
389 389 gau1[:] = numpy.NaN
390 390 x_mtr = numpy.transpose(numpy.tile(dataOut.getVelRange(1)[:-1], (self.Num_Hei,1)))
391 391 for iCh in range(self.Num_Chn):
392 392 N0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,0]] * self.Num_Bin))
393 393 N1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,1]] * self.Num_Bin))
394 394 A0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,0]] * self.Num_Bin))
395 395 A1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,1]] * self.Num_Bin))
396 396 v0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,0]] * self.Num_Bin))
397 397 v1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,1]] * self.Num_Bin))
398 398 s0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,0]] * self.Num_Bin))
399 399 s1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,1]] * self.Num_Bin))
400 400 if method == 'genealized':
401 401 p0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,0]] * self.Num_Bin))
402 402 p1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,1]] * self.Num_Bin))
403 403 elif method == 'squared':
404 404 p0 = 2.
405 405 p1 = 2.
406 406 gau0[iCh] = A0*numpy.exp(-0.5*numpy.abs((x_mtr-v0)/s0)**p0)+N0
407 407 gau1[iCh] = A1*numpy.exp(-0.5*numpy.abs((x_mtr-v1)/s1)**p1)+N1
408 408 dataOut.GaussFit0 = gau0
409 409 dataOut.GaussFit1 = gau1
410 410
411 411 print('Leaving ',method ,' double Gaussian fit')
412 412 return dataOut
413 413
414 414 def FitGau(self, X):
415 415 # print('Entering FitGau')
416 416 # Assigning the variables
417 417 Vrange, ch, wnoise, num_intg, SNRlimit = X
418 418 # Noise Limits
419 419 noisebl = wnoise * 0.9
420 420 noisebh = wnoise * 1.1
421 421 # Radar Velocity
422 422 Va = max(Vrange)
423 423 deltav = Vrange[1] - Vrange[0]
424 424 x = numpy.arange(self.Num_Bin)
425 425
426 426 # print ('stop 0')
427 427
428 428 # 5 parameters, 2 Gaussians
429 429 DGauFitParam = numpy.zeros([5, self.Num_Hei,2])
430 430 DGauFitParam[:] = numpy.NaN
431 431
432 432 # SPCparam = []
433 433 # SPC_ch1 = numpy.zeros([self.Num_Bin,self.Num_Hei])
434 434 # SPC_ch2 = numpy.zeros([self.Num_Bin,self.Num_Hei])
435 435 # SPC_ch1[:] = 0 #numpy.NaN
436 436 # SPC_ch2[:] = 0 #numpy.NaN
437 437 # print ('stop 1')
438 438 for ht in range(self.Num_Hei):
439 439 # print (ht)
440 440 # print ('stop 2')
441 441 # Spectra at each range
442 442 spc = numpy.asarray(self.spc)[ch,:,ht]
443 443 snr = ( spc.mean() - wnoise ) / wnoise
444 444 snrdB = 10.*numpy.log10(snr)
445 445
446 446 #print ('stop 3')
447 447 if snrdB < SNRlimit :
448 448 # snr = numpy.NaN
449 449 # SPC_ch1[:,ht] = 0#numpy.NaN
450 450 # SPC_ch1[:,ht] = 0#numpy.NaN
451 451 # SPCparam = (SPC_ch1,SPC_ch2)
452 452 # print ('SNR less than SNRth')
453 453 continue
454 454 # wnoise = hildebrand_sekhon(spc,num_intg)
455 455 # print ('stop 2.01')
456 456 #############################################
457 457 # normalizing spc and noise
458 458 # This part differs from gg1
459 459 # spc_norm_max = max(spc) #commented by D. ScipiΓ³n 19.03.2021
460 460 #spc = spc / spc_norm_max
461 461 # pnoise = pnoise #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
462 462 #############################################
463 463
464 464 # print ('stop 2.1')
465 465 fatspectra=1.0
466 466 # noise per channel.... we might want to use the noise at each range
467 467
468 468 # wnoise = noise_ #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
469 469 #wnoise,stdv,i_max,index =enoise(spc,num_intg) #noise estimate using Hildebrand Sekhon, only wnoise is used
470 470 #if wnoise>1.1*pnoise: # to be tested later
471 471 # wnoise=pnoise
472 472 # noisebl = wnoise*0.9
473 473 # noisebh = wnoise*1.1
474 474 spc = spc - wnoise # signal
475 475
476 476 # print ('stop 2.2')
477 477 minx = numpy.argmin(spc)
478 478 #spcs=spc.copy()
479 479 spcs = numpy.roll(spc,-minx)
480 480 cum = numpy.cumsum(spcs)
481 481 # tot_noise = wnoise * self.Num_Bin #64;
482 482
483 483 # print ('stop 2.3')
484 484 # snr = sum(spcs) / tot_noise
485 485 # snrdB = 10.*numpy.log10(snr)
486 486 #print ('stop 3')
487 487 # if snrdB < SNRlimit :
488 488 # snr = numpy.NaN
489 489 # SPC_ch1[:,ht] = 0#numpy.NaN
490 490 # SPC_ch1[:,ht] = 0#numpy.NaN
491 491 # SPCparam = (SPC_ch1,SPC_ch2)
492 492 # print ('SNR less than SNRth')
493 493 # continue
494 494
495 495
496 496 #if snrdB<-18 or numpy.isnan(snrdB) or num_intg<4:
497 497 # return [None,]*4,[None,]*4,None,snrdB,None,None,[None,]*5,[None,]*9,None
498 498 # print ('stop 4')
499 499 cummax = max(cum)
500 500 epsi = 0.08 * fatspectra # cumsum to narrow down the energy region
501 501 cumlo = cummax * epsi
502 502 cumhi = cummax * (1-epsi)
503 503 powerindex = numpy.array(numpy.where(numpy.logical_and(cum>cumlo, cum<cumhi))[0])
504 504
505 505 # print ('stop 5')
506 506 if len(powerindex) < 1:# case for powerindex 0
507 507 # print ('powerindex < 1')
508 508 continue
509 509 powerlo = powerindex[0]
510 510 powerhi = powerindex[-1]
511 511 powerwidth = powerhi-powerlo
512 512 if powerwidth <= 1:
513 513 # print('powerwidth <= 1')
514 514 continue
515 515
516 516 # print ('stop 6')
517 517 firstpeak = powerlo + powerwidth/10.# first gaussian energy location
518 518 secondpeak = powerhi - powerwidth/10. #second gaussian energy location
519 519 midpeak = (firstpeak + secondpeak)/2.
520 520 firstamp = spcs[int(firstpeak)]
521 521 secondamp = spcs[int(secondpeak)]
522 522 midamp = spcs[int(midpeak)]
523 523
524 524 y_data = spc + wnoise
525 525
526 526 ''' single Gaussian '''
527 527 shift0 = numpy.mod(midpeak+minx, self.Num_Bin )
528 528 width0 = powerwidth/4.#Initialization entire power of spectrum divided by 4
529 529 power0 = 2.
530 530 amplitude0 = midamp
531 531 state0 = [shift0,width0,amplitude0,power0,wnoise]
532 532 bnds = ((0,self.Num_Bin-1),(1,powerwidth),(0,None),(0.5,3.),(noisebl,noisebh))
533 533 lsq1 = fmin_l_bfgs_b(self.misfit1, state0, args=(y_data,x,num_intg), bounds=bnds, approx_grad=True)
534 534 # print ('stop 7.1')
535 535 # print (bnds)
536 536
537 537 chiSq1=lsq1[1]
538 538
539 539 # print ('stop 8')
540 540 if fatspectra<1.0 and powerwidth<4:
541 541 choice=0
542 542 Amplitude0=lsq1[0][2]
543 543 shift0=lsq1[0][0]
544 544 width0=lsq1[0][1]
545 545 p0=lsq1[0][3]
546 546 Amplitude1=0.
547 547 shift1=0.
548 548 width1=0.
549 549 p1=0.
550 550 noise=lsq1[0][4]
551 551 #return (numpy.array([shift0,width0,Amplitude0,p0]),
552 552 # numpy.array([shift1,width1,Amplitude1,p1]),noise,snrdB,chiSq1,6.,sigmas1,[None,]*9,choice)
553 553
554 554 # print ('stop 9')
555 555 ''' two Gaussians '''
556 556 #shift0=numpy.mod(firstpeak+minx,64); shift1=numpy.mod(secondpeak+minx,64)
557 557 shift0 = numpy.mod(firstpeak+minx, self.Num_Bin )
558 558 shift1 = numpy.mod(secondpeak+minx, self.Num_Bin )
559 559 width0 = powerwidth/6.
560 560 width1 = width0
561 561 power0 = 2.
562 562 power1 = power0
563 563 amplitude0 = firstamp
564 564 amplitude1 = secondamp
565 565 state0 = [shift0,width0,amplitude0,power0,shift1,width1,amplitude1,power1,wnoise]
566 566 #bnds=((0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
567 567 bnds=((0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
568 568 #bnds=(( 0,(self.Num_Bin-1) ),(1,powerwidth/2.),(0,None),(0.5,3.),( 0,(self.Num_Bin-1)),(1,powerwidth/2.),(0,None),(0.5,3.),(0.1,0.5))
569 569
570 570 # print ('stop 10')
571 571 lsq2 = fmin_l_bfgs_b( self.misfit2 , state0 , args=(y_data,x,num_intg) , bounds=bnds , approx_grad=True )
572 572
573 573 # print ('stop 11')
574 574 chiSq2 = lsq2[1]
575 575
576 576 # print ('stop 12')
577 577
578 578 oneG = (chiSq1<5 and chiSq1/chiSq2<2.0) and (abs(lsq2[0][0]-lsq2[0][4])<(lsq2[0][1]+lsq2[0][5])/3. or abs(lsq2[0][0]-lsq2[0][4])<10)
579 579
580 580 # print ('stop 13')
581 581 if snrdB>-12: # when SNR is strong pick the peak with least shift (LOS velocity) error
582 582 if oneG:
583 583 choice = 0
584 584 else:
585 585 w1 = lsq2[0][1]; w2 = lsq2[0][5]
586 586 a1 = lsq2[0][2]; a2 = lsq2[0][6]
587 587 p1 = lsq2[0][3]; p2 = lsq2[0][7]
588 588 s1 = (2**(1+1./p1))*scipy.special.gamma(1./p1)/p1
589 589 s2 = (2**(1+1./p2))*scipy.special.gamma(1./p2)/p2
590 590 gp1 = a1*w1*s1; gp2 = a2*w2*s2 # power content of each ggaussian with proper p scaling
591 591
592 592 if gp1>gp2:
593 593 if a1>0.7*a2:
594 594 choice = 1
595 595 else:
596 596 choice = 2
597 597 elif gp2>gp1:
598 598 if a2>0.7*a1:
599 599 choice = 2
600 600 else:
601 601 choice = 1
602 602 else:
603 603 choice = numpy.argmax([a1,a2])+1
604 604 #else:
605 605 #choice=argmin([std2a,std2b])+1
606 606
607 607 else: # with low SNR go to the most energetic peak
608 608 choice = numpy.argmax([lsq1[0][2]*lsq1[0][1],lsq2[0][2]*lsq2[0][1],lsq2[0][6]*lsq2[0][5]])
609 609
610 610 # print ('stop 14')
611 611 shift0 = lsq2[0][0]
612 612 vel0 = Vrange[0] + shift0 * deltav
613 613 shift1 = lsq2[0][4]
614 614 # vel1=Vrange[0] + shift1 * deltav
615 615
616 616 # max_vel = 1.0
617 617 # Va = max(Vrange)
618 618 # deltav = Vrange[1]-Vrange[0]
619 619 # print ('stop 15')
620 620 #first peak will be 0, second peak will be 1
621 621 # if vel0 > -1.0 and vel0 < max_vel : #first peak is in the correct range # Commented by D.ScipiΓ³n 19.03.2021
622 622 if vel0 > -Va and vel0 < Va : #first peak is in the correct range
623 623 shift0 = lsq2[0][0]
624 624 width0 = lsq2[0][1]
625 625 Amplitude0 = lsq2[0][2]
626 626 p0 = lsq2[0][3]
627 627
628 628 shift1 = lsq2[0][4]
629 629 width1 = lsq2[0][5]
630 630 Amplitude1 = lsq2[0][6]
631 631 p1 = lsq2[0][7]
632 632 noise = lsq2[0][8]
633 633 else:
634 634 shift1 = lsq2[0][0]
635 635 width1 = lsq2[0][1]
636 636 Amplitude1 = lsq2[0][2]
637 637 p1 = lsq2[0][3]
638 638
639 639 shift0 = lsq2[0][4]
640 640 width0 = lsq2[0][5]
641 641 Amplitude0 = lsq2[0][6]
642 642 p0 = lsq2[0][7]
643 643 noise = lsq2[0][8]
644 644
645 645 if Amplitude0<0.05: # in case the peak is noise
646 646 shift0,width0,Amplitude0,p0 = 4*[numpy.NaN]
647 647 if Amplitude1<0.05:
648 648 shift1,width1,Amplitude1,p1 = 4*[numpy.NaN]
649 649
650 650 # print ('stop 16 ')
651 651 # SPC_ch1[:,ht] = noise + Amplitude0*numpy.exp(-0.5*(abs(x-shift0)/width0)**p0)
652 652 # SPC_ch2[:,ht] = noise + Amplitude1*numpy.exp(-0.5*(abs(x-shift1)/width1)**p1)
653 653 # SPCparam = (SPC_ch1,SPC_ch2)
654 654
655 655 DGauFitParam[0,ht,0] = noise
656 656 DGauFitParam[0,ht,1] = noise
657 657 DGauFitParam[1,ht,0] = Amplitude0
658 658 DGauFitParam[1,ht,1] = Amplitude1
659 659 DGauFitParam[2,ht,0] = Vrange[0] + shift0 * deltav
660 660 DGauFitParam[2,ht,1] = Vrange[0] + shift1 * deltav
661 661 DGauFitParam[3,ht,0] = width0 * deltav
662 662 DGauFitParam[3,ht,1] = width1 * deltav
663 663 DGauFitParam[4,ht,0] = p0
664 664 DGauFitParam[4,ht,1] = p1
665 665
666 666 # print (DGauFitParam.shape)
667 667 # print ('Leaving FitGau')
668 668 return DGauFitParam
669 669 # return SPCparam
670 670 # return GauSPC
671 671
672 672 def y_model1(self,x,state):
673 673 shift0, width0, amplitude0, power0, noise = state
674 674 model0 = amplitude0*numpy.exp(-0.5*abs((x - shift0)/width0)**power0)
675 675 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
676 676 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
677 677 return model0 + model0u + model0d + noise
678 678
679 679 def y_model2(self,x,state): #Equation for two generalized Gaussians with Nyquist
680 680 shift0, width0, amplitude0, power0, shift1, width1, amplitude1, power1, noise = state
681 681 model0 = amplitude0*numpy.exp(-0.5*abs((x-shift0)/width0)**power0)
682 682 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
683 683 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
684 684
685 685 model1 = amplitude1*numpy.exp(-0.5*abs((x - shift1)/width1)**power1)
686 686 model1u = amplitude1*numpy.exp(-0.5*abs((x - shift1 - self.Num_Bin)/width1)**power1)
687 687 model1d = amplitude1*numpy.exp(-0.5*abs((x - shift1 + self.Num_Bin)/width1)**power1)
688 688 return model0 + model0u + model0d + model1 + model1u + model1d + noise
689 689
690 690 def misfit1(self,state,y_data,x,num_intg): # This function compares how close real data is with the model data, the close it is, the better it is.
691 691
692 692 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model1(x,state)))**2)#/(64-5.) # /(64-5.) can be commented
693 693
694 694 def misfit2(self,state,y_data,x,num_intg):
695 695 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model2(x,state)))**2)#/(64-9.)
696 696
697 697
698 698
699 699 class PrecipitationProc(Operation):
700 700
701 701 '''
702 702 Operator that estimates Reflectivity factor (Z), and estimates rainfall Rate (R)
703 703
704 704 Input:
705 705 self.dataOut.data_pre : SelfSpectra
706 706
707 707 Output:
708 708
709 709 self.dataOut.data_output : Reflectivity factor, rainfall Rate
710 710
711 711
712 712 Parameters affected:
713 713 '''
714 714
715 715 def __init__(self):
716 716 Operation.__init__(self)
717 717 self.i=0
718 718
719 719 def run(self, dataOut, radar=None, Pt=5000, Gt=295.1209, Gr=70.7945, Lambda=0.6741, aL=2.5118,
720 720 tauW=4e-06, ThetaT=0.1656317, ThetaR=0.36774087, Km2 = 0.93, Altitude=3350,SNRdBlimit=-30):
721 721
722 722 # print ('Entering PrecepitationProc ... ')
723 723
724 724 if radar == "MIRA35C" :
725 725
726 726 self.spc = dataOut.data_pre[0].copy()
727 727 self.Num_Hei = self.spc.shape[2]
728 728 self.Num_Bin = self.spc.shape[1]
729 729 self.Num_Chn = self.spc.shape[0]
730 730 Ze = self.dBZeMODE2(dataOut)
731 731
732 732 else:
733 733
734 734 self.spc = dataOut.data_pre[0].copy()
735 735
736 736 #NOTA SE DEBE REMOVER EL RANGO DEL PULSO TX
737 737 self.spc[:,:,0:7]= numpy.NaN
738 738
739 739 self.Num_Hei = self.spc.shape[2]
740 740 self.Num_Bin = self.spc.shape[1]
741 741 self.Num_Chn = self.spc.shape[0]
742 742
743 743 VelRange = dataOut.spc_range[2]
744 744
745 745 ''' Se obtiene la constante del RADAR '''
746 746
747 747 self.Pt = Pt
748 748 self.Gt = Gt
749 749 self.Gr = Gr
750 750 self.Lambda = Lambda
751 751 self.aL = aL
752 752 self.tauW = tauW
753 753 self.ThetaT = ThetaT
754 754 self.ThetaR = ThetaR
755 755 self.GSys = 10**(36.63/10) # Ganancia de los LNA 36.63 dB
756 756 self.lt = 10**(1.67/10) # Perdida en cables Tx 1.67 dB
757 757 self.lr = 10**(5.73/10) # Perdida en cables Rx 5.73 dB
758 758
759 759 Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
760 760 Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * tauW * numpy.pi * ThetaT * ThetaR)
761 761 RadarConstant = 10e-26 * Numerator / Denominator #
762 762 ExpConstant = 10**(40/10) #Constante Experimental
763 763
764 764 SignalPower = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
765 765 for i in range(self.Num_Chn):
766 766 SignalPower[i,:,:] = self.spc[i,:,:] - dataOut.noise[i]
767 767 SignalPower[numpy.where(SignalPower < 0)] = 1e-20
768 768
769 769 SPCmean = numpy.mean(SignalPower, 0)
770 770 Pr = SPCmean[:,:]/dataOut.normFactor
771 771
772 772 # Declaring auxiliary variables
773 773 Range = dataOut.heightList*1000. #Range in m
774 774 # replicate the heightlist to obtain a matrix [Num_Bin,Num_Hei]
775 775 rMtrx = numpy.transpose(numpy.transpose([dataOut.heightList*1000.] * self.Num_Bin))
776 776 zMtrx = rMtrx+Altitude
777 777 # replicate the VelRange to obtain a matrix [Num_Bin,Num_Hei]
778 778 VelMtrx = numpy.transpose(numpy.tile(VelRange[:-1], (self.Num_Hei,1)))
779 779
780 780 # height dependence to air density Foote and Du Toit (1969)
781 781 delv_z = 1 + 3.68e-5 * zMtrx + 1.71e-9 * zMtrx**2
782 782 VMtrx = VelMtrx / delv_z #Normalized velocity
783 783 VMtrx[numpy.where(VMtrx> 9.6)] = numpy.NaN
784 784 # Diameter is related to the fall speed of falling drops
785 785 D_Vz = -1.667 * numpy.log( 0.9369 - 0.097087 * VMtrx ) # D in [mm]
786 786 # Only valid for D>= 0.16 mm
787 787 D_Vz[numpy.where(D_Vz < 0.16)] = numpy.NaN
788 788
789 789 #Calculate Radar Reflectivity ETAn
790 790 ETAn = (RadarConstant *ExpConstant) * Pr * rMtrx**2 #Reflectivity (ETA)
791 791 ETAd = ETAn * 6.18 * exp( -0.6 * D_Vz ) * delv_z
792 792 # Radar Cross Section
793 793 sigmaD = Km2 * (D_Vz * 1e-3 )**6 * numpy.pi**5 / Lambda**4
794 794 # Drop Size Distribution
795 795 DSD = ETAn / sigmaD
796 796 # Equivalente Reflectivy
797 797 Ze_eqn = numpy.nansum( DSD * D_Vz**6 ,axis=0)
798 798 Ze_org = numpy.nansum(ETAn * Lambda**4, axis=0) / (1e-18*numpy.pi**5 * Km2) # [mm^6 /m^3]
799 799 # RainFall Rate
800 800 RR = 0.0006*numpy.pi * numpy.nansum( D_Vz**3 * DSD * VelMtrx ,0) #mm/hr
801 801
802 802 # Censoring the data
803 803 # Removing data with SNRth < 0dB se debe considerar el SNR por canal
804 804 SNRth = 10**(SNRdBlimit/10) #-30dB
805 805 novalid = numpy.where((dataOut.data_snr[0,:] <SNRth) | (dataOut.data_snr[1,:] <SNRth) | (dataOut.data_snr[2,:] <SNRth)) # AND condition. Maybe OR condition better
806 806 W = numpy.nanmean(dataOut.data_dop,0)
807 807 W[novalid] = numpy.NaN
808 808 Ze_org[novalid] = numpy.NaN
809 809 RR[novalid] = numpy.NaN
810 810
811 811 dataOut.data_output = RR[8]
812 812 dataOut.data_param = numpy.ones([3,self.Num_Hei])
813 813 dataOut.channelList = [0,1,2]
814 814
815 815 dataOut.data_param[0]=10*numpy.log10(Ze_org)
816 816 dataOut.data_param[1]=-W
817 817 dataOut.data_param[2]=RR
818 818
819 819 # print ('Leaving PrecepitationProc ... ')
820 820 return dataOut
821 821
822 822 def dBZeMODE2(self, dataOut): # Processing for MIRA35C
823 823
824 824 NPW = dataOut.NPW
825 825 COFA = dataOut.COFA
826 826
827 827 SNR = numpy.array([self.spc[0,:,:] / NPW[0]]) #, self.spc[1,:,:] / NPW[1]])
828 828 RadarConst = dataOut.RadarConst
829 829 #frequency = 34.85*10**9
830 830
831 831 ETA = numpy.zeros(([self.Num_Chn ,self.Num_Hei]))
832 832 data_output = numpy.ones([self.Num_Chn , self.Num_Hei])*numpy.NaN
833 833
834 834 ETA = numpy.sum(SNR,1)
835 835
836 836 ETA = numpy.where(ETA != 0. , ETA, numpy.NaN)
837 837
838 838 Ze = numpy.ones([self.Num_Chn, self.Num_Hei] )
839 839
840 840 for r in range(self.Num_Hei):
841 841
842 842 Ze[0,r] = ( ETA[0,r] ) * COFA[0,r][0] * RadarConst * ((r/5000.)**2)
843 843 #Ze[1,r] = ( ETA[1,r] ) * COFA[1,r][0] * RadarConst * ((r/5000.)**2)
844 844
845 845 return Ze
846 846
847 847 # def GetRadarConstant(self):
848 848 #
849 849 # """
850 850 # Constants:
851 851 #
852 852 # Pt: Transmission Power dB 5kW 5000
853 853 # Gt: Transmission Gain dB 24.7 dB 295.1209
854 854 # Gr: Reception Gain dB 18.5 dB 70.7945
855 855 # Lambda: Wavelenght m 0.6741 m 0.6741
856 856 # aL: Attenuation loses dB 4dB 2.5118
857 857 # tauW: Width of transmission pulse s 4us 4e-6
858 858 # ThetaT: Transmission antenna bean angle rad 0.1656317 rad 0.1656317
859 859 # ThetaR: Reception antenna beam angle rad 0.36774087 rad 0.36774087
860 860 #
861 861 # """
862 862 #
863 863 # Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
864 864 # Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * TauW * numpy.pi * ThetaT * TheraR)
865 865 # RadarConstant = Numerator / Denominator
866 866 #
867 867 # return RadarConstant
868 868
869 869
870 870
871 871 class FullSpectralAnalysis(Operation):
872 872
873 873 """
874 874 Function that implements Full Spectral Analysis technique.
875 875
876 876 Input:
877 877 self.dataOut.data_pre : SelfSpectra and CrossSpectra data
878 878 self.dataOut.groupList : Pairlist of channels
879 879 self.dataOut.ChanDist : Physical distance between receivers
880 880
881 881
882 882 Output:
883 883
884 884 self.dataOut.data_output : Zonal wind, Meridional wind, and Vertical wind
885 885
886 886
887 887 Parameters affected: Winds, height range, SNR
888 888
889 889 """
890 890 def run(self, dataOut, Xi01=None, Xi02=None, Xi12=None, Eta01=None, Eta02=None, Eta12=None, SNRdBlimit=-30,
891 891 minheight=None, maxheight=None, NegativeLimit=None, PositiveLimit=None):
892 892
893 893 spc = dataOut.data_pre[0].copy()
894 894 cspc = dataOut.data_pre[1]
895 895 nHeights = spc.shape[2]
896 896
897 897 # first_height = 0.75 #km (ref: data header 20170822)
898 898 # resolution_height = 0.075 #km
899 899 '''
900 900 finding height range. check this when radar parameters are changed!
901 901 '''
902 902 if maxheight is not None:
903 903 # range_max = math.ceil((maxheight - first_height) / resolution_height) # theoretical
904 904 range_max = math.ceil(13.26 * maxheight - 3) # empirical, works better
905 905 else:
906 906 range_max = nHeights
907 907 if minheight is not None:
908 908 # range_min = int((minheight - first_height) / resolution_height) # theoretical
909 909 range_min = int(13.26 * minheight - 5) # empirical, works better
910 910 if range_min < 0:
911 911 range_min = 0
912 912 else:
913 913 range_min = 0
914 914
915 915 pairsList = dataOut.groupList
916 916 if dataOut.ChanDist is not None :
917 917 ChanDist = dataOut.ChanDist
918 918 else:
919 919 ChanDist = numpy.array([[Xi01, Eta01],[Xi02,Eta02],[Xi12,Eta12]])
920 920
921 921 # 4 variables: zonal, meridional, vertical, and average SNR
922 922 data_param = numpy.zeros([4,nHeights]) * numpy.NaN
923 923 velocityX = numpy.zeros([nHeights]) * numpy.NaN
924 924 velocityY = numpy.zeros([nHeights]) * numpy.NaN
925 925 velocityZ = numpy.zeros([nHeights]) * numpy.NaN
926 926
927 927 dbSNR = 10*numpy.log10(numpy.average(dataOut.data_snr,0))
928 928
929 929 '''***********************************************WIND ESTIMATION**************************************'''
930 930 for Height in range(nHeights):
931 931
932 932 if Height >= range_min and Height < range_max:
933 933 # error_code will be useful in future analysis
934 934 [Vzon,Vmer,Vver, error_code] = self.WindEstimation(spc[:,:,Height], cspc[:,:,Height], pairsList,
935 935 ChanDist, Height, dataOut.noise, dataOut.spc_range, dbSNR[Height], SNRdBlimit, NegativeLimit, PositiveLimit,dataOut.frequency)
936 936
937 937 if abs(Vzon) < 100. and abs(Vmer) < 100.:
938 938 velocityX[Height] = Vzon
939 939 velocityY[Height] = -Vmer
940 940 velocityZ[Height] = Vver
941 941
942 942 # Censoring data with SNR threshold
943 943 dbSNR [dbSNR < SNRdBlimit] = numpy.NaN
944 944
945 945 data_param[0] = velocityX
946 946 data_param[1] = velocityY
947 947 data_param[2] = velocityZ
948 948 data_param[3] = dbSNR
949 949 dataOut.data_param = data_param
950 950 return dataOut
951 951
952 952 def moving_average(self,x, N=2):
953 953 """ convolution for smoothenig data. note that last N-1 values are convolution with zeroes """
954 954 return numpy.convolve(x, numpy.ones((N,))/N)[(N-1):]
955 955
956 956 def gaus(self,xSamples,Amp,Mu,Sigma):
957 957 return Amp * numpy.exp(-0.5*((xSamples - Mu)/Sigma)**2)
958 958
959 959 def Moments(self, ySamples, xSamples):
960 960 Power = numpy.nanmean(ySamples) # Power, 0th Moment
961 961 yNorm = ySamples / numpy.nansum(ySamples)
962 962 RadVel = numpy.nansum(xSamples * yNorm) # Radial Velocity, 1st Moment
963 963 Sigma2 = numpy.nansum(yNorm * (xSamples - RadVel)**2) # Spectral Width, 2nd Moment
964 964 StdDev = numpy.sqrt(numpy.abs(Sigma2)) # Desv. Estandar, Ancho espectral
965 965 return numpy.array([Power,RadVel,StdDev])
966 966
967 967 def StopWindEstimation(self, error_code):
968 968 Vzon = numpy.NaN
969 969 Vmer = numpy.NaN
970 970 Vver = numpy.NaN
971 971 return Vzon, Vmer, Vver, error_code
972 972
973 973 def AntiAliasing(self, interval, maxstep):
974 974 """
975 975 function to prevent errors from aliased values when computing phaseslope
976 976 """
977 977 antialiased = numpy.zeros(len(interval))
978 978 copyinterval = interval.copy()
979 979
980 980 antialiased[0] = copyinterval[0]
981 981
982 982 for i in range(1,len(antialiased)):
983 983 step = interval[i] - interval[i-1]
984 984 if step > maxstep:
985 985 copyinterval -= 2*numpy.pi
986 986 antialiased[i] = copyinterval[i]
987 987 elif step < maxstep*(-1):
988 988 copyinterval += 2*numpy.pi
989 989 antialiased[i] = copyinterval[i]
990 990 else:
991 991 antialiased[i] = copyinterval[i].copy()
992 992
993 993 return antialiased
994 994
995 995 def WindEstimation(self, spc, cspc, pairsList, ChanDist, Height, noise, AbbsisaRange, dbSNR, SNRlimit, NegativeLimit, PositiveLimit, radfreq):
996 996 """
997 997 Function that Calculates Zonal, Meridional and Vertical wind velocities.
998 998 Initial Version by E. Bocanegra updated by J. Zibell until Nov. 2019.
999 999
1000 1000 Input:
1001 1001 spc, cspc : self spectra and cross spectra data. In Briggs notation something like S_i*(S_i)_conj, (S_j)_conj respectively.
1002 1002 pairsList : Pairlist of channels
1003 1003 ChanDist : array of xi_ij and eta_ij
1004 1004 Height : height at which data is processed
1005 1005 noise : noise in [channels] format for specific height
1006 1006 Abbsisarange : range of the frequencies or velocities
1007 1007 dbSNR, SNRlimit : signal to noise ratio in db, lower limit
1008 1008
1009 1009 Output:
1010 1010 Vzon, Vmer, Vver : wind velocities
1011 1011 error_code : int that states where code is terminated
1012 1012
1013 1013 0 : no error detected
1014 1014 1 : Gaussian of mean spc exceeds widthlimit
1015 1015 2 : no Gaussian of mean spc found
1016 1016 3 : SNR to low or velocity to high -> prec. e.g.
1017 1017 4 : at least one Gaussian of cspc exceeds widthlimit
1018 1018 5 : zero out of three cspc Gaussian fits converged
1019 1019 6 : phase slope fit could not be found
1020 1020 7 : arrays used to fit phase have different length
1021 1021 8 : frequency range is either too short (len <= 5) or very long (> 30% of cspc)
1022 1022
1023 1023 """
1024 1024
1025 1025 error_code = 0
1026 1026
1027 1027 nChan = spc.shape[0]
1028 1028 nProf = spc.shape[1]
1029 1029 nPair = cspc.shape[0]
1030 1030
1031 1031 SPC_Samples = numpy.zeros([nChan, nProf]) # for normalized spc values for one height
1032 1032 CSPC_Samples = numpy.zeros([nPair, nProf], dtype=numpy.complex_) # for normalized cspc values
1033 1033 phase = numpy.zeros([nPair, nProf]) # phase between channels
1034 1034 PhaseSlope = numpy.zeros(nPair) # slope of the phases, channelwise
1035 1035 PhaseInter = numpy.zeros(nPair) # intercept to the slope of the phases, channelwise
1036 1036 xFrec = AbbsisaRange[0][:-1] # frequency range
1037 1037 xVel = AbbsisaRange[2][:-1] # velocity range
1038 1038 xSamples = xFrec # the frequency range is taken
1039 1039 delta_x = xSamples[1] - xSamples[0] # delta_f or delta_x
1040 1040
1041 1041 # only consider velocities with in NegativeLimit and PositiveLimit
1042 1042 if (NegativeLimit is None):
1043 1043 NegativeLimit = numpy.min(xVel)
1044 1044 if (PositiveLimit is None):
1045 1045 PositiveLimit = numpy.max(xVel)
1046 1046 xvalid = numpy.where((xVel > NegativeLimit) & (xVel < PositiveLimit))
1047 1047 xSamples_zoom = xSamples[xvalid]
1048 1048
1049 1049 '''Getting Eij and Nij'''
1050 1050 Xi01, Xi02, Xi12 = ChanDist[:,0]
1051 1051 Eta01, Eta02, Eta12 = ChanDist[:,1]
1052 1052
1053 1053 # spwd limit - updated by D. ScipiΓ³n 30.03.2021
1054 1054 widthlimit = 10
1055 1055 '''************************* SPC is normalized ********************************'''
1056 1056 spc_norm = spc.copy()
1057 1057 # For each channel
1058 1058 for i in range(nChan):
1059 1059 spc_sub = spc_norm[i,:] - noise[i] # only the signal power
1060 1060 SPC_Samples[i] = spc_sub / (numpy.nansum(spc_sub) * delta_x)
1061 1061
1062 1062 '''********************** FITTING MEAN SPC GAUSSIAN **********************'''
1063 1063
1064 1064 """ the gaussian of the mean: first subtract noise, then normalize. this is legal because
1065 1065 you only fit the curve and don't need the absolute value of height for calculation,
1066 1066 only for estimation of width. for normalization of cross spectra, you need initial,
1067 1067 unnormalized self-spectra With noise.
1068 1068
1069 1069 Technically, you don't even need to normalize the self-spectra, as you only need the
1070 1070 width of the peak. However, it was left this way. Note that the normalization has a flaw:
1071 1071 due to subtraction of the noise, some values are below zero. Raw "spc" values should be
1072 1072 >= 0, as it is the modulus squared of the signals (complex * it's conjugate)
1073 1073 """
1074 1074 # initial conditions
1075 1075 popt = [1e-10,0,1e-10]
1076 1076 # Spectra average
1077 1077 SPCMean = numpy.average(SPC_Samples,0)
1078 1078 # Moments in frequency
1079 1079 SPCMoments = self.Moments(SPCMean[xvalid], xSamples_zoom)
1080 1080
1081 1081 # Gauss Fit SPC in frequency domain
1082 1082 if dbSNR > SNRlimit: # only if SNR > SNRth
1083 1083 try:
1084 1084 popt,pcov = curve_fit(self.gaus,xSamples_zoom,SPCMean[xvalid],p0=SPCMoments)
1085 1085 if popt[2] <= 0 or popt[2] > widthlimit: # CONDITION
1086 1086 return self.StopWindEstimation(error_code = 1)
1087 1087 FitGauss = self.gaus(xSamples_zoom,*popt)
1088 1088 except :#RuntimeError:
1089 1089 return self.StopWindEstimation(error_code = 2)
1090 1090 else:
1091 1091 return self.StopWindEstimation(error_code = 3)
1092 1092
1093 1093 '''***************************** CSPC Normalization *************************
1094 1094 The Spc spectra are used to normalize the crossspectra. Peaks from precipitation
1095 1095 influence the norm which is not desired. First, a range is identified where the
1096 1096 wind peak is estimated -> sum_wind is sum of those frequencies. Next, the area
1097 1097 around it gets cut off and values replaced by mean determined by the boundary
1098 1098 data -> sum_noise (spc is not normalized here, thats why the noise is important)
1099 1099
1100 1100 The sums are then added and multiplied by range/datapoints, because you need
1101 1101 an integral and not a sum for normalization.
1102 1102
1103 1103 A norm is found according to Briggs 92.
1104 1104 '''
1105 1105 # for each pair
1106 1106 for i in range(nPair):
1107 1107 cspc_norm = cspc[i,:].copy()
1108 1108 chan_index0 = pairsList[i][0]
1109 1109 chan_index1 = pairsList[i][1]
1110 1110 CSPC_Samples[i] = cspc_norm / (numpy.sqrt(numpy.nansum(spc_norm[chan_index0])*numpy.nansum(spc_norm[chan_index1])) * delta_x)
1111 1111 phase[i] = numpy.arctan2(CSPC_Samples[i].imag, CSPC_Samples[i].real)
1112 1112
1113 1113 CSPCmoments = numpy.vstack([self.Moments(numpy.abs(CSPC_Samples[0,xvalid]), xSamples_zoom),
1114 1114 self.Moments(numpy.abs(CSPC_Samples[1,xvalid]), xSamples_zoom),
1115 1115 self.Moments(numpy.abs(CSPC_Samples[2,xvalid]), xSamples_zoom)])
1116 1116
1117 1117 popt01, popt02, popt12 = [1e-10,0,1e-10], [1e-10,0,1e-10] ,[1e-10,0,1e-10]
1118 1118 FitGauss01, FitGauss02, FitGauss12 = numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples))
1119 1119
1120 1120 '''*******************************FIT GAUSS CSPC************************************'''
1121 1121 try:
1122 1122 popt01,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[0][xvalid]),p0=CSPCmoments[0])
1123 1123 if popt01[2] > widthlimit: # CONDITION
1124 1124 return self.StopWindEstimation(error_code = 4)
1125 1125 popt02,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[1][xvalid]),p0=CSPCmoments[1])
1126 1126 if popt02[2] > widthlimit: # CONDITION
1127 1127 return self.StopWindEstimation(error_code = 4)
1128 1128 popt12,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[2][xvalid]),p0=CSPCmoments[2])
1129 1129 if popt12[2] > widthlimit: # CONDITION
1130 1130 return self.StopWindEstimation(error_code = 4)
1131 1131
1132 1132 FitGauss01 = self.gaus(xSamples_zoom, *popt01)
1133 1133 FitGauss02 = self.gaus(xSamples_zoom, *popt02)
1134 1134 FitGauss12 = self.gaus(xSamples_zoom, *popt12)
1135 1135 except:
1136 1136 return self.StopWindEstimation(error_code = 5)
1137 1137
1138 1138
1139 1139 '''************* Getting Fij ***************'''
1140 1140 # x-axis point of the gaussian where the center is located from GaussFit of spectra
1141 1141 GaussCenter = popt[1]
1142 1142 ClosestCenter = xSamples_zoom[numpy.abs(xSamples_zoom-GaussCenter).argmin()]
1143 1143 PointGauCenter = numpy.where(xSamples_zoom==ClosestCenter)[0][0]
1144 1144
1145 1145 # Point where e^-1 is located in the gaussian
1146 1146 PeMinus1 = numpy.max(FitGauss) * numpy.exp(-1)
1147 1147 FijClosest = FitGauss[numpy.abs(FitGauss-PeMinus1).argmin()] # The closest point to"Peminus1" in "FitGauss"
1148 1148 PointFij = numpy.where(FitGauss==FijClosest)[0][0]
1149 1149 Fij = numpy.abs(xSamples_zoom[PointFij] - xSamples_zoom[PointGauCenter])
1150 1150
1151 1151 '''********** Taking frequency ranges from mean SPCs **********'''
1152 1152 GauWidth = popt[2] * 3/2 # Bandwidth of Gau01
1153 1153 Range = numpy.empty(2)
1154 1154 Range[0] = GaussCenter - GauWidth
1155 1155 Range[1] = GaussCenter + GauWidth
1156 1156 # Point in x-axis where the bandwidth is located (min:max)
1157 1157 ClosRangeMin = xSamples_zoom[numpy.abs(xSamples_zoom-Range[0]).argmin()]
1158 1158 ClosRangeMax = xSamples_zoom[numpy.abs(xSamples_zoom-Range[1]).argmin()]
1159 1159 PointRangeMin = numpy.where(xSamples_zoom==ClosRangeMin)[0][0]
1160 1160 PointRangeMax = numpy.where(xSamples_zoom==ClosRangeMax)[0][0]
1161 1161 Range = numpy.array([ PointRangeMin, PointRangeMax ])
1162 1162 FrecRange = xSamples_zoom[ Range[0] : Range[1] ]
1163 1163
1164 1164 '''************************** Getting Phase Slope ***************************'''
1165 1165 for i in range(nPair):
1166 1166 if len(FrecRange) > 5:
1167 1167 PhaseRange = phase[i, xvalid[0][Range[0]:Range[1]]].copy()
1168 1168 mask = ~numpy.isnan(FrecRange) & ~numpy.isnan(PhaseRange)
1169 1169 if len(FrecRange) == len(PhaseRange):
1170 1170 try:
1171 1171 slope, intercept, _, _, _ = stats.linregress(FrecRange[mask], self.AntiAliasing(PhaseRange[mask], 4.5))
1172 1172 PhaseSlope[i] = slope
1173 1173 PhaseInter[i] = intercept
1174 1174 except:
1175 1175 return self.StopWindEstimation(error_code = 6)
1176 1176 else:
1177 1177 return self.StopWindEstimation(error_code = 7)
1178 1178 else:
1179 1179 return self.StopWindEstimation(error_code = 8)
1180 1180
1181 1181 '''*** Constants A-H correspond to the convention as in Briggs and Vincent 1992 ***'''
1182 1182
1183 1183 '''Getting constant C'''
1184 1184 cC=(Fij*numpy.pi)**2
1185 1185
1186 1186 '''****** Getting constants F and G ******'''
1187 1187 MijEijNij = numpy.array([[Xi02,Eta02], [Xi12,Eta12]])
1188 1188 # MijEijNij = numpy.array([[Xi01,Eta01], [Xi02,Eta02], [Xi12,Eta12]])
1189 1189 # MijResult0 = (-PhaseSlope[0] * cC) / (2*numpy.pi)
1190 1190 MijResult1 = (-PhaseSlope[1] * cC) / (2*numpy.pi)
1191 1191 MijResult2 = (-PhaseSlope[2] * cC) / (2*numpy.pi)
1192 1192 # MijResults = numpy.array([MijResult0, MijResult1, MijResult2])
1193 1193 MijResults = numpy.array([MijResult1, MijResult2])
1194 1194 (cF,cG) = numpy.linalg.solve(MijEijNij, MijResults)
1195 1195
1196 1196 '''****** Getting constants A, B and H ******'''
1197 1197 W01 = numpy.nanmax( FitGauss01 )
1198 1198 W02 = numpy.nanmax( FitGauss02 )
1199 1199 W12 = numpy.nanmax( FitGauss12 )
1200 1200
1201 1201 WijResult01 = ((cF * Xi01 + cG * Eta01)**2)/cC - numpy.log(W01 / numpy.sqrt(numpy.pi / cC))
1202 1202 WijResult02 = ((cF * Xi02 + cG * Eta02)**2)/cC - numpy.log(W02 / numpy.sqrt(numpy.pi / cC))
1203 1203 WijResult12 = ((cF * Xi12 + cG * Eta12)**2)/cC - numpy.log(W12 / numpy.sqrt(numpy.pi / cC))
1204 1204 WijResults = numpy.array([WijResult01, WijResult02, WijResult12])
1205 1205
1206 1206 WijEijNij = numpy.array([ [Xi01**2, Eta01**2, 2*Xi01*Eta01] , [Xi02**2, Eta02**2, 2*Xi02*Eta02] , [Xi12**2, Eta12**2, 2*Xi12*Eta12] ])
1207 1207 (cA,cB,cH) = numpy.linalg.solve(WijEijNij, WijResults)
1208 1208
1209 1209 VxVy = numpy.array([[cA,cH],[cH,cB]])
1210 1210 VxVyResults = numpy.array([-cF,-cG])
1211 1211 (Vmer,Vzon) = numpy.linalg.solve(VxVy, VxVyResults)
1212 1212 Vver = -SPCMoments[1]*SPEED_OF_LIGHT/(2*radfreq)
1213 1213 error_code = 0
1214 1214
1215 1215 return Vzon, Vmer, Vver, error_code
1216 1216
1217 1217 class SpectralMoments(Operation):
1218 1218
1219 1219 '''
1220 1220 Function SpectralMoments()
1221 1221
1222 1222 Calculates moments (power, mean, standard deviation) and SNR of the signal
1223 1223
1224 1224 Type of dataIn: Spectra
1225 1225
1226 1226 Configuration Parameters:
1227 1227
1228 1228 dirCosx : Cosine director in X axis
1229 1229 dirCosy : Cosine director in Y axis
1230 1230
1231 1231 elevation :
1232 1232 azimuth :
1233 1233
1234 1234 Input:
1235 1235 channelList : simple channel list to select e.g. [2,3,7]
1236 1236 self.dataOut.data_pre : Spectral data
1237 1237 self.dataOut.abscissaList : List of frequencies
1238 1238 self.dataOut.noise : Noise level per channel
1239 1239
1240 1240 Affected:
1241 1241 self.dataOut.moments : Parameters per channel
1242 1242 self.dataOut.data_snr : SNR per channel
1243 1243
1244 1244 '''
1245 1245
1246 1246 def run(self, dataOut):
1247 1247
1248 1248 data = dataOut.data_pre[0]
1249 1249 absc = dataOut.abscissaList[:-1]
1250 1250 noise = dataOut.noise
1251 1251 nChannel = data.shape[0]
1252 1252 data_param = numpy.zeros((nChannel, 4, data.shape[2]))
1253 1253
1254 1254 for ind in range(nChannel):
1255 1255 data_param[ind,:,:] = self.__calculateMoments( data[ind,:,:] , absc , noise[ind] )
1256 1256
1257 1257 dataOut.moments = data_param[:,1:,:]
1258 1258 dataOut.data_snr = data_param[:,0]
1259 1259 dataOut.data_pow = data_param[:,1]
1260 1260 dataOut.data_dop = data_param[:,2]
1261 1261 dataOut.data_width = data_param[:,3]
1262 1262 return dataOut
1263 1263
1264 1264 def __calculateMoments(self, oldspec, oldfreq, n0,
1265 1265 nicoh = None, graph = None, smooth = None, type1 = None, fwindow = None, snrth = None, dc = None, aliasing = None, oldfd = None, wwauto = None):
1266 1266
1267 1267 if (nicoh is None): nicoh = 1
1268 1268 if (graph is None): graph = 0
1269 1269 if (smooth is None): smooth = 0
1270 1270 elif (self.smooth < 3): smooth = 0
1271 1271
1272 1272 if (type1 is None): type1 = 0
1273 1273 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
1274 1274 if (snrth is None): snrth = -3
1275 1275 if (dc is None): dc = 0
1276 1276 if (aliasing is None): aliasing = 0
1277 1277 if (oldfd is None): oldfd = 0
1278 1278 if (wwauto is None): wwauto = 0
1279 1279
1280 1280 if (n0 < 1.e-20): n0 = 1.e-20
1281 1281
1282 1282 freq = oldfreq
1283 1283 vec_power = numpy.zeros(oldspec.shape[1])
1284 1284 vec_fd = numpy.zeros(oldspec.shape[1])
1285 1285 vec_w = numpy.zeros(oldspec.shape[1])
1286 1286 vec_snr = numpy.zeros(oldspec.shape[1])
1287 1287
1288 1288 # oldspec = numpy.ma.masked_invalid(oldspec)
1289 1289 for ind in range(oldspec.shape[1]):
1290 1290
1291 1291 spec = oldspec[:,ind]
1292 1292 aux = spec*fwindow
1293 1293 max_spec = aux.max()
1294 1294 m = aux.tolist().index(max_spec)
1295 1295
1296 1296 # Smooth
1297 1297 if (smooth == 0):
1298 1298 spec2 = spec
1299 1299 else:
1300 1300 spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
1301 1301
1302 1302 # Moments Estimation
1303 1303 bb = spec2[numpy.arange(m,spec2.size)]
1304 1304 bb = (bb<n0).nonzero()
1305 1305 bb = bb[0]
1306 1306
1307 1307 ss = spec2[numpy.arange(0,m + 1)]
1308 1308 ss = (ss<n0).nonzero()
1309 1309 ss = ss[0]
1310 1310
1311 1311 if (bb.size == 0):
1312 1312 bb0 = spec.size - 1 - m
1313 1313 else:
1314 1314 bb0 = bb[0] - 1
1315 1315 if (bb0 < 0):
1316 1316 bb0 = 0
1317 1317
1318 1318 if (ss.size == 0):
1319 1319 ss1 = 1
1320 1320 else:
1321 1321 ss1 = max(ss) + 1
1322 1322
1323 1323 if (ss1 > m):
1324 1324 ss1 = m
1325 1325
1326 1326 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
1327 1327 #valid = numpy.arange(1,oldspec.shape[0])# valid perfil completo igual pulsepair
1328 1328 signal_power = ((spec2[valid] - n0) * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
1329 1329 total_power = (spec2[valid] * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
1330 1330 power = ((spec2[valid] - n0) * fwindow[valid]).sum()
1331 1331 fd = ((spec2[valid]- n0)*freq[valid] * fwindow[valid]).sum() / power
1332 1332 w = numpy.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum() / power)
1333 1333 snr = (spec2.mean()-n0)/n0
1334 1334 if (snr < 1.e-20) :
1335 1335 snr = 1.e-20
1336 1336
1337 1337 # vec_power[ind] = power #D. ScipiΓ³n replaced with the line below
1338 1338 vec_power[ind] = total_power
1339 1339 vec_fd[ind] = fd
1340 1340 vec_w[ind] = w
1341 1341 vec_snr[ind] = snr
1342 1342
1343 1343 return numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
1344 1344
1345 1345 #------------------ Get SA Parameters --------------------------
1346 1346
1347 1347 def GetSAParameters(self):
1348 1348 #SA en frecuencia
1349 1349 pairslist = self.dataOut.groupList
1350 1350 num_pairs = len(pairslist)
1351 1351
1352 1352 vel = self.dataOut.abscissaList
1353 1353 spectra = self.dataOut.data_pre
1354 1354 cspectra = self.dataIn.data_cspc
1355 1355 delta_v = vel[1] - vel[0]
1356 1356
1357 1357 #Calculating the power spectrum
1358 1358 spc_pow = numpy.sum(spectra, 3)*delta_v
1359 1359 #Normalizing Spectra
1360 1360 norm_spectra = spectra/spc_pow
1361 1361 #Calculating the norm_spectra at peak
1362 1362 max_spectra = numpy.max(norm_spectra, 3)
1363 1363
1364 1364 #Normalizing Cross Spectra
1365 1365 norm_cspectra = numpy.zeros(cspectra.shape)
1366 1366
1367 1367 for i in range(num_chan):
1368 1368 norm_cspectra[i,:,:] = cspectra[i,:,:]/numpy.sqrt(spc_pow[pairslist[i][0],:]*spc_pow[pairslist[i][1],:])
1369 1369
1370 1370 max_cspectra = numpy.max(norm_cspectra,2)
1371 1371 max_cspectra_index = numpy.argmax(norm_cspectra, 2)
1372 1372
1373 1373 for i in range(num_pairs):
1374 1374 cspc_par[i,:,:] = __calculateMoments(norm_cspectra)
1375 1375 #------------------- Get Lags ----------------------------------
1376 1376
1377 1377 class SALags(Operation):
1378 1378 '''
1379 1379 Function GetMoments()
1380 1380
1381 1381 Input:
1382 1382 self.dataOut.data_pre
1383 1383 self.dataOut.abscissaList
1384 1384 self.dataOut.noise
1385 1385 self.dataOut.normFactor
1386 1386 self.dataOut.data_snr
1387 1387 self.dataOut.groupList
1388 1388 self.dataOut.nChannels
1389 1389
1390 1390 Affected:
1391 1391 self.dataOut.data_param
1392 1392
1393 1393 '''
1394 1394 def run(self, dataOut):
1395 1395 data_acf = dataOut.data_pre[0]
1396 1396 data_ccf = dataOut.data_pre[1]
1397 1397 normFactor_acf = dataOut.normFactor[0]
1398 1398 normFactor_ccf = dataOut.normFactor[1]
1399 1399 pairs_acf = dataOut.groupList[0]
1400 1400 pairs_ccf = dataOut.groupList[1]
1401 1401
1402 1402 nHeights = dataOut.nHeights
1403 1403 absc = dataOut.abscissaList
1404 1404 noise = dataOut.noise
1405 1405 SNR = dataOut.data_snr
1406 1406 nChannels = dataOut.nChannels
1407 1407 # pairsList = dataOut.groupList
1408 1408 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairsList, nChannels)
1409 1409
1410 1410 for l in range(len(pairs_acf)):
1411 1411 data_acf[l,:,:] = data_acf[l,:,:]/normFactor_acf[l,:]
1412 1412
1413 1413 for l in range(len(pairs_ccf)):
1414 1414 data_ccf[l,:,:] = data_ccf[l,:,:]/normFactor_ccf[l,:]
1415 1415
1416 1416 dataOut.data_param = numpy.zeros((len(pairs_ccf)*2 + 1, nHeights))
1417 1417 dataOut.data_param[:-1,:] = self.__calculateTaus(data_acf, data_ccf, absc)
1418 1418 dataOut.data_param[-1,:] = self.__calculateLag1Phase(data_acf, absc)
1419 1419 return
1420 1420
1421 1421 # def __getPairsAutoCorr(self, pairsList, nChannels):
1422 1422 #
1423 1423 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1424 1424 #
1425 1425 # for l in range(len(pairsList)):
1426 1426 # firstChannel = pairsList[l][0]
1427 1427 # secondChannel = pairsList[l][1]
1428 1428 #
1429 1429 # #Obteniendo pares de Autocorrelacion
1430 1430 # if firstChannel == secondChannel:
1431 1431 # pairsAutoCorr[firstChannel] = int(l)
1432 1432 #
1433 1433 # pairsAutoCorr = pairsAutoCorr.astype(int)
1434 1434 #
1435 1435 # pairsCrossCorr = range(len(pairsList))
1436 1436 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1437 1437 #
1438 1438 # return pairsAutoCorr, pairsCrossCorr
1439 1439
1440 1440 def __calculateTaus(self, data_acf, data_ccf, lagRange):
1441 1441
1442 1442 lag0 = data_acf.shape[1]/2
1443 1443 #Funcion de Autocorrelacion
1444 1444 mean_acf = stats.nanmean(data_acf, axis = 0)
1445 1445
1446 1446 #Obtencion Indice de TauCross
1447 1447 ind_ccf = data_ccf.argmax(axis = 1)
1448 1448 #Obtencion Indice de TauAuto
1449 1449 ind_acf = numpy.zeros(ind_ccf.shape,dtype = 'int')
1450 1450 ccf_lag0 = data_ccf[:,lag0,:]
1451 1451
1452 1452 for i in range(ccf_lag0.shape[0]):
1453 1453 ind_acf[i,:] = numpy.abs(mean_acf - ccf_lag0[i,:]).argmin(axis = 0)
1454 1454
1455 1455 #Obtencion de TauCross y TauAuto
1456 1456 tau_ccf = lagRange[ind_ccf]
1457 1457 tau_acf = lagRange[ind_acf]
1458 1458
1459 1459 Nan1, Nan2 = numpy.where(tau_ccf == lagRange[0])
1460 1460
1461 1461 tau_ccf[Nan1,Nan2] = numpy.nan
1462 1462 tau_acf[Nan1,Nan2] = numpy.nan
1463 1463 tau = numpy.vstack((tau_ccf,tau_acf))
1464 1464
1465 1465 return tau
1466 1466
1467 1467 def __calculateLag1Phase(self, data, lagTRange):
1468 1468 data1 = stats.nanmean(data, axis = 0)
1469 1469 lag1 = numpy.where(lagTRange == 0)[0][0] + 1
1470 1470
1471 1471 phase = numpy.angle(data1[lag1,:])
1472 1472
1473 1473 return phase
1474 1474
1475 1475 class SpectralFitting(Operation):
1476 1476 '''
1477 1477 Function GetMoments()
1478 1478
1479 1479 Input:
1480 1480 Output:
1481 1481 Variables modified:
1482 1482 '''
1483 1483
1484 1484 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None):
1485 1485
1486 1486
1487 1487 if path != None:
1488 1488 sys.path.append(path)
1489 1489 self.dataOut.library = importlib.import_module(file)
1490 1490
1491 1491 #To be inserted as a parameter
1492 1492 groupArray = numpy.array(groupList)
1493 1493 # groupArray = numpy.array([[0,1],[2,3]])
1494 1494 self.dataOut.groupList = groupArray
1495 1495
1496 1496 nGroups = groupArray.shape[0]
1497 1497 nChannels = self.dataIn.nChannels
1498 1498 nHeights=self.dataIn.heightList.size
1499 1499
1500 1500 #Parameters Array
1501 1501 self.dataOut.data_param = None
1502 1502
1503 1503 #Set constants
1504 1504 constants = self.dataOut.library.setConstants(self.dataIn)
1505 1505 self.dataOut.constants = constants
1506 1506 M = self.dataIn.normFactor
1507 1507 N = self.dataIn.nFFTPoints
1508 1508 ippSeconds = self.dataIn.ippSeconds
1509 1509 K = self.dataIn.nIncohInt
1510 1510 pairsArray = numpy.array(self.dataIn.pairsList)
1511 1511
1512 1512 #List of possible combinations
1513 1513 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
1514 1514 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
1515 1515
1516 1516 if getSNR:
1517 1517 listChannels = groupArray.reshape((groupArray.size))
1518 1518 listChannels.sort()
1519 1519 noise = self.dataIn.getNoise()
1520 1520 self.dataOut.data_snr = self.__getSNR(self.dataIn.data_spc[listChannels,:,:], noise[listChannels])
1521 1521
1522 1522 for i in range(nGroups):
1523 1523 coord = groupArray[i,:]
1524 1524
1525 1525 #Input data array
1526 1526 data = self.dataIn.data_spc[coord,:,:]/(M*N)
1527 1527 data = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
1528 1528
1529 1529 #Cross Spectra data array for Covariance Matrixes
1530 1530 ind = 0
1531 1531 for pairs in listComb:
1532 1532 pairsSel = numpy.array([coord[x],coord[y]])
1533 1533 indCross[ind] = int(numpy.where(numpy.all(pairsArray == pairsSel, axis = 1))[0][0])
1534 1534 ind += 1
1535 1535 dataCross = self.dataIn.data_cspc[indCross,:,:]/(M*N)
1536 1536 dataCross = dataCross**2/K
1537 1537
1538 1538 for h in range(nHeights):
1539 1539
1540 1540 #Input
1541 1541 d = data[:,h]
1542 1542
1543 1543 #Covariance Matrix
1544 1544 D = numpy.diag(d**2/K)
1545 1545 ind = 0
1546 1546 for pairs in listComb:
1547 1547 #Coordinates in Covariance Matrix
1548 1548 x = pairs[0]
1549 1549 y = pairs[1]
1550 1550 #Channel Index
1551 1551 S12 = dataCross[ind,:,h]
1552 1552 D12 = numpy.diag(S12)
1553 1553 #Completing Covariance Matrix with Cross Spectras
1554 1554 D[x*N:(x+1)*N,y*N:(y+1)*N] = D12
1555 1555 D[y*N:(y+1)*N,x*N:(x+1)*N] = D12
1556 1556 ind += 1
1557 1557 Dinv=numpy.linalg.inv(D)
1558 1558 L=numpy.linalg.cholesky(Dinv)
1559 1559 LT=L.T
1560 1560
1561 1561 dp = numpy.dot(LT,d)
1562 1562
1563 1563 #Initial values
1564 1564 data_spc = self.dataIn.data_spc[coord,:,h]
1565 1565
1566 1566 if (h>0)and(error1[3]<5):
1567 1567 p0 = self.dataOut.data_param[i,:,h-1]
1568 1568 else:
1569 1569 p0 = numpy.array(self.dataOut.library.initialValuesFunction(data_spc, constants, i))
1570 1570
1571 1571 try:
1572 1572 #Least Squares
1573 1573 minp,covp,infodict,mesg,ier = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants),full_output=True)
1574 1574 # minp,covp = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants))
1575 1575 #Chi square error
1576 1576 error0 = numpy.sum(infodict['fvec']**2)/(2*N)
1577 1577 #Error with Jacobian
1578 1578 error1 = self.dataOut.library.errorFunction(minp,constants,LT)
1579 1579 except:
1580 1580 minp = p0*numpy.nan
1581 1581 error0 = numpy.nan
1582 1582 error1 = p0*numpy.nan
1583 1583
1584 1584 #Save
1585 1585 if self.dataOut.data_param is None:
1586 1586 self.dataOut.data_param = numpy.zeros((nGroups, p0.size, nHeights))*numpy.nan
1587 1587 self.dataOut.data_error = numpy.zeros((nGroups, p0.size + 1, nHeights))*numpy.nan
1588 1588
1589 1589 self.dataOut.data_error[i,:,h] = numpy.hstack((error0,error1))
1590 1590 self.dataOut.data_param[i,:,h] = minp
1591 1591 return
1592 1592
1593 1593 def __residFunction(self, p, dp, LT, constants):
1594 1594
1595 1595 fm = self.dataOut.library.modelFunction(p, constants)
1596 1596 fmp=numpy.dot(LT,fm)
1597 1597
1598 1598 return dp-fmp
1599 1599
1600 1600 def __getSNR(self, z, noise):
1601 1601
1602 1602 avg = numpy.average(z, axis=1)
1603 1603 SNR = (avg.T-noise)/noise
1604 1604 SNR = SNR.T
1605 1605 return SNR
1606 1606
1607 1607 def __chisq(p,chindex,hindex):
1608 1608 #similar to Resid but calculates CHI**2
1609 1609 [LT,d,fm]=setupLTdfm(p,chindex,hindex)
1610 1610 dp=numpy.dot(LT,d)
1611 1611 fmp=numpy.dot(LT,fm)
1612 1612 chisq=numpy.dot((dp-fmp).T,(dp-fmp))
1613 1613 return chisq
1614 1614
1615 1615 class WindProfiler(Operation):
1616 1616
1617 1617 __isConfig = False
1618 1618
1619 1619 __initime = None
1620 1620 __lastdatatime = None
1621 1621 __integrationtime = None
1622 1622
1623 1623 __buffer = None
1624 1624
1625 1625 __dataReady = False
1626 1626
1627 1627 __firstdata = None
1628 1628
1629 1629 n = None
1630 1630
1631 1631 def __init__(self):
1632 1632 Operation.__init__(self)
1633 1633
1634 1634 def __calculateCosDir(self, elev, azim):
1635 1635 zen = (90 - elev)*numpy.pi/180
1636 1636 azim = azim*numpy.pi/180
1637 1637 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
1638 1638 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
1639 1639
1640 1640 signX = numpy.sign(numpy.cos(azim))
1641 1641 signY = numpy.sign(numpy.sin(azim))
1642 1642
1643 1643 cosDirX = numpy.copysign(cosDirX, signX)
1644 1644 cosDirY = numpy.copysign(cosDirY, signY)
1645 1645 return cosDirX, cosDirY
1646 1646
1647 1647 def __calculateAngles(self, theta_x, theta_y, azimuth):
1648 1648
1649 1649 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
1650 1650 zenith_arr = numpy.arccos(dir_cosw)
1651 1651 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
1652 1652
1653 1653 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
1654 1654 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
1655 1655
1656 1656 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
1657 1657
1658 1658 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
1659 1659
1660 1660 #
1661 1661 if horOnly:
1662 1662 A = numpy.c_[dir_cosu,dir_cosv]
1663 1663 else:
1664 1664 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
1665 1665 A = numpy.asmatrix(A)
1666 1666 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
1667 1667
1668 1668 return A1
1669 1669
1670 1670 def __correctValues(self, heiRang, phi, velRadial, SNR):
1671 1671 listPhi = phi.tolist()
1672 1672 maxid = listPhi.index(max(listPhi))
1673 1673 minid = listPhi.index(min(listPhi))
1674 1674
1675 1675 rango = list(range(len(phi)))
1676 1676 # rango = numpy.delete(rango,maxid)
1677 1677
1678 1678 heiRang1 = heiRang*math.cos(phi[maxid])
1679 1679 heiRangAux = heiRang*math.cos(phi[minid])
1680 1680 indOut = (heiRang1 < heiRangAux[0]).nonzero()
1681 1681 heiRang1 = numpy.delete(heiRang1,indOut)
1682 1682
1683 1683 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
1684 1684 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
1685 1685
1686 1686 for i in rango:
1687 1687 x = heiRang*math.cos(phi[i])
1688 1688 y1 = velRadial[i,:]
1689 1689 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
1690 1690
1691 1691 x1 = heiRang1
1692 1692 y11 = f1(x1)
1693 1693
1694 1694 y2 = SNR[i,:]
1695 1695 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
1696 1696 y21 = f2(x1)
1697 1697
1698 1698 velRadial1[i,:] = y11
1699 1699 SNR1[i,:] = y21
1700 1700
1701 1701 return heiRang1, velRadial1, SNR1
1702 1702
1703 1703 def __calculateVelUVW(self, A, velRadial):
1704 1704
1705 1705 #Operacion Matricial
1706 1706 # velUVW = numpy.zeros((velRadial.shape[1],3))
1707 1707 # for ind in range(velRadial.shape[1]):
1708 1708 # velUVW[ind,:] = numpy.dot(A,velRadial[:,ind])
1709 1709 # velUVW = velUVW.transpose()
1710 1710 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
1711 1711 velUVW[:,:] = numpy.dot(A,velRadial)
1712 1712
1713 1713
1714 1714 return velUVW
1715 1715
1716 1716 # def techniqueDBS(self, velRadial0, dirCosx, disrCosy, azimuth, correct, horizontalOnly, heiRang, SNR0):
1717 1717
1718 1718 def techniqueDBS(self, kwargs):
1719 1719 """
1720 1720 Function that implements Doppler Beam Swinging (DBS) technique.
1721 1721
1722 1722 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1723 1723 Direction correction (if necessary), Ranges and SNR
1724 1724
1725 1725 Output: Winds estimation (Zonal, Meridional and Vertical)
1726 1726
1727 1727 Parameters affected: Winds, height range, SNR
1728 1728 """
1729 1729 velRadial0 = kwargs['velRadial']
1730 1730 heiRang = kwargs['heightList']
1731 1731 SNR0 = kwargs['SNR']
1732 1732
1733 1733 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
1734 1734 theta_x = numpy.array(kwargs['dirCosx'])
1735 1735 theta_y = numpy.array(kwargs['dirCosy'])
1736 1736 else:
1737 1737 elev = numpy.array(kwargs['elevation'])
1738 1738 azim = numpy.array(kwargs['azimuth'])
1739 1739 theta_x, theta_y = self.__calculateCosDir(elev, azim)
1740 1740 azimuth = kwargs['correctAzimuth']
1741 1741 if 'horizontalOnly' in kwargs:
1742 1742 horizontalOnly = kwargs['horizontalOnly']
1743 1743 else: horizontalOnly = False
1744 1744 if 'correctFactor' in kwargs:
1745 1745 correctFactor = kwargs['correctFactor']
1746 1746 else: correctFactor = 1
1747 1747 if 'channelList' in kwargs:
1748 1748 channelList = kwargs['channelList']
1749 1749 if len(channelList) == 2:
1750 1750 horizontalOnly = True
1751 1751 arrayChannel = numpy.array(channelList)
1752 1752 param = param[arrayChannel,:,:]
1753 1753 theta_x = theta_x[arrayChannel]
1754 1754 theta_y = theta_y[arrayChannel]
1755 1755
1756 1756 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
1757 1757 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
1758 1758 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
1759 1759
1760 1760 #Calculo de Componentes de la velocidad con DBS
1761 1761 winds = self.__calculateVelUVW(A,velRadial1)
1762 1762
1763 1763 return winds, heiRang1, SNR1
1764 1764
1765 1765 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
1766 1766
1767 1767 nPairs = len(pairs_ccf)
1768 1768 posx = numpy.asarray(posx)
1769 1769 posy = numpy.asarray(posy)
1770 1770
1771 1771 #Rotacion Inversa para alinear con el azimuth
1772 1772 if azimuth!= None:
1773 1773 azimuth = azimuth*math.pi/180
1774 1774 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
1775 1775 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
1776 1776 else:
1777 1777 posx1 = posx
1778 1778 posy1 = posy
1779 1779
1780 1780 #Calculo de Distancias
1781 1781 distx = numpy.zeros(nPairs)
1782 1782 disty = numpy.zeros(nPairs)
1783 1783 dist = numpy.zeros(nPairs)
1784 1784 ang = numpy.zeros(nPairs)
1785 1785
1786 1786 for i in range(nPairs):
1787 1787 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
1788 1788 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
1789 1789 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
1790 1790 ang[i] = numpy.arctan2(disty[i],distx[i])
1791 1791
1792 1792 return distx, disty, dist, ang
1793 1793 #Calculo de Matrices
1794 1794 # nPairs = len(pairs)
1795 1795 # ang1 = numpy.zeros((nPairs, 2, 1))
1796 1796 # dist1 = numpy.zeros((nPairs, 2, 1))
1797 1797 #
1798 1798 # for j in range(nPairs):
1799 1799 # dist1[j,0,0] = dist[pairs[j][0]]
1800 1800 # dist1[j,1,0] = dist[pairs[j][1]]
1801 1801 # ang1[j,0,0] = ang[pairs[j][0]]
1802 1802 # ang1[j,1,0] = ang[pairs[j][1]]
1803 1803 #
1804 1804 # return distx,disty, dist1,ang1
1805 1805
1806 1806
1807 1807 def __calculateVelVer(self, phase, lagTRange, _lambda):
1808 1808
1809 1809 Ts = lagTRange[1] - lagTRange[0]
1810 1810 velW = -_lambda*phase/(4*math.pi*Ts)
1811 1811
1812 1812 return velW
1813 1813
1814 1814 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
1815 1815 nPairs = tau1.shape[0]
1816 1816 nHeights = tau1.shape[1]
1817 1817 vel = numpy.zeros((nPairs,3,nHeights))
1818 1818 dist1 = numpy.reshape(dist, (dist.size,1))
1819 1819
1820 1820 angCos = numpy.cos(ang)
1821 1821 angSin = numpy.sin(ang)
1822 1822
1823 1823 vel0 = dist1*tau1/(2*tau2**2)
1824 1824 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
1825 1825 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
1826 1826
1827 1827 ind = numpy.where(numpy.isinf(vel))
1828 1828 vel[ind] = numpy.nan
1829 1829
1830 1830 return vel
1831 1831
1832 1832 # def __getPairsAutoCorr(self, pairsList, nChannels):
1833 1833 #
1834 1834 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1835 1835 #
1836 1836 # for l in range(len(pairsList)):
1837 1837 # firstChannel = pairsList[l][0]
1838 1838 # secondChannel = pairsList[l][1]
1839 1839 #
1840 1840 # #Obteniendo pares de Autocorrelacion
1841 1841 # if firstChannel == secondChannel:
1842 1842 # pairsAutoCorr[firstChannel] = int(l)
1843 1843 #
1844 1844 # pairsAutoCorr = pairsAutoCorr.astype(int)
1845 1845 #
1846 1846 # pairsCrossCorr = range(len(pairsList))
1847 1847 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1848 1848 #
1849 1849 # return pairsAutoCorr, pairsCrossCorr
1850 1850
1851 1851 # def techniqueSA(self, pairsSelected, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, lagTRange, correctFactor):
1852 1852 def techniqueSA(self, kwargs):
1853 1853
1854 1854 """
1855 1855 Function that implements Spaced Antenna (SA) technique.
1856 1856
1857 1857 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1858 1858 Direction correction (if necessary), Ranges and SNR
1859 1859
1860 1860 Output: Winds estimation (Zonal, Meridional and Vertical)
1861 1861
1862 1862 Parameters affected: Winds
1863 1863 """
1864 1864 position_x = kwargs['positionX']
1865 1865 position_y = kwargs['positionY']
1866 1866 azimuth = kwargs['azimuth']
1867 1867
1868 1868 if 'correctFactor' in kwargs:
1869 1869 correctFactor = kwargs['correctFactor']
1870 1870 else:
1871 1871 correctFactor = 1
1872 1872
1873 1873 groupList = kwargs['groupList']
1874 1874 pairs_ccf = groupList[1]
1875 1875 tau = kwargs['tau']
1876 1876 _lambda = kwargs['_lambda']
1877 1877
1878 1878 #Cross Correlation pairs obtained
1879 1879 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairssList, nChannels)
1880 1880 # pairsArray = numpy.array(pairsList)[pairsCrossCorr]
1881 1881 # pairsSelArray = numpy.array(pairsSelected)
1882 1882 # pairs = []
1883 1883 #
1884 1884 # #Wind estimation pairs obtained
1885 1885 # for i in range(pairsSelArray.shape[0]/2):
1886 1886 # ind1 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i], axis = 1))[0][0]
1887 1887 # ind2 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i + 1], axis = 1))[0][0]
1888 1888 # pairs.append((ind1,ind2))
1889 1889
1890 1890 indtau = tau.shape[0]/2
1891 1891 tau1 = tau[:indtau,:]
1892 1892 tau2 = tau[indtau:-1,:]
1893 1893 # tau1 = tau1[pairs,:]
1894 1894 # tau2 = tau2[pairs,:]
1895 1895 phase1 = tau[-1,:]
1896 1896
1897 1897 #---------------------------------------------------------------------
1898 1898 #Metodo Directo
1899 1899 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
1900 1900 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
1901 1901 winds = stats.nanmean(winds, axis=0)
1902 1902 #---------------------------------------------------------------------
1903 1903 #Metodo General
1904 1904 # distx, disty, dist = self.calculateDistance(position_x,position_y,pairsCrossCorr, pairsList, azimuth)
1905 1905 # #Calculo Coeficientes de Funcion de Correlacion
1906 1906 # F,G,A,B,H = self.calculateCoef(tau1,tau2,distx,disty,n)
1907 1907 # #Calculo de Velocidades
1908 1908 # winds = self.calculateVelUV(F,G,A,B,H)
1909 1909
1910 1910 #---------------------------------------------------------------------
1911 1911 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
1912 1912 winds = correctFactor*winds
1913 1913 return winds
1914 1914
1915 1915 def __checkTime(self, currentTime, paramInterval, outputInterval):
1916 1916
1917 1917 dataTime = currentTime + paramInterval
1918 1918 deltaTime = dataTime - self.__initime
1919 1919
1920 1920 if deltaTime >= outputInterval or deltaTime < 0:
1921 1921 self.__dataReady = True
1922 1922 return
1923 1923
1924 1924 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
1925 1925 '''
1926 1926 Function that implements winds estimation technique with detected meteors.
1927 1927
1928 1928 Input: Detected meteors, Minimum meteor quantity to wind estimation
1929 1929
1930 1930 Output: Winds estimation (Zonal and Meridional)
1931 1931
1932 1932 Parameters affected: Winds
1933 1933 '''
1934 1934 #Settings
1935 1935 nInt = (heightMax - heightMin)/2
1936 1936 nInt = int(nInt)
1937 1937 winds = numpy.zeros((2,nInt))*numpy.nan
1938 1938
1939 1939 #Filter errors
1940 1940 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
1941 1941 finalMeteor = arrayMeteor[error,:]
1942 1942
1943 1943 #Meteor Histogram
1944 1944 finalHeights = finalMeteor[:,2]
1945 1945 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
1946 1946 nMeteorsPerI = hist[0]
1947 1947 heightPerI = hist[1]
1948 1948
1949 1949 #Sort of meteors
1950 1950 indSort = finalHeights.argsort()
1951 1951 finalMeteor2 = finalMeteor[indSort,:]
1952 1952
1953 1953 # Calculating winds
1954 1954 ind1 = 0
1955 1955 ind2 = 0
1956 1956
1957 1957 for i in range(nInt):
1958 1958 nMet = nMeteorsPerI[i]
1959 1959 ind1 = ind2
1960 1960 ind2 = ind1 + nMet
1961 1961
1962 1962 meteorAux = finalMeteor2[ind1:ind2,:]
1963 1963
1964 1964 if meteorAux.shape[0] >= meteorThresh:
1965 1965 vel = meteorAux[:, 6]
1966 1966 zen = meteorAux[:, 4]*numpy.pi/180
1967 1967 azim = meteorAux[:, 3]*numpy.pi/180
1968 1968
1969 1969 n = numpy.cos(zen)
1970 1970 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
1971 1971 # l = m*numpy.tan(azim)
1972 1972 l = numpy.sin(zen)*numpy.sin(azim)
1973 1973 m = numpy.sin(zen)*numpy.cos(azim)
1974 1974
1975 1975 A = numpy.vstack((l, m)).transpose()
1976 1976 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
1977 1977 windsAux = numpy.dot(A1, vel)
1978 1978
1979 1979 winds[0,i] = windsAux[0]
1980 1980 winds[1,i] = windsAux[1]
1981 1981
1982 1982 return winds, heightPerI[:-1]
1983 1983
1984 1984 def techniqueNSM_SA(self, **kwargs):
1985 1985 metArray = kwargs['metArray']
1986 1986 heightList = kwargs['heightList']
1987 1987 timeList = kwargs['timeList']
1988 1988
1989 1989 rx_location = kwargs['rx_location']
1990 1990 groupList = kwargs['groupList']
1991 1991 azimuth = kwargs['azimuth']
1992 1992 dfactor = kwargs['dfactor']
1993 1993 k = kwargs['k']
1994 1994
1995 1995 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
1996 1996 d = dist*dfactor
1997 1997 #Phase calculation
1998 1998 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
1999 1999
2000 2000 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
2001 2001
2002 2002 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2003 2003 azimuth1 = azimuth1*numpy.pi/180
2004 2004
2005 2005 for i in range(heightList.size):
2006 2006 h = heightList[i]
2007 2007 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
2008 2008 metHeight = metArray1[indH,:]
2009 2009 if metHeight.shape[0] >= 2:
2010 2010 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
2011 2011 iazim = metHeight[:,1].astype(int)
2012 2012 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
2013 2013 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
2014 2014 A = numpy.asmatrix(A)
2015 2015 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
2016 2016 velHor = numpy.dot(A1,velAux)
2017 2017
2018 2018 velEst[i,:] = numpy.squeeze(velHor)
2019 2019 return velEst
2020 2020
2021 2021 def __getPhaseSlope(self, metArray, heightList, timeList):
2022 2022 meteorList = []
2023 2023 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
2024 2024 #Putting back together the meteor matrix
2025 2025 utctime = metArray[:,0]
2026 2026 uniqueTime = numpy.unique(utctime)
2027 2027
2028 2028 phaseDerThresh = 0.5
2029 2029 ippSeconds = timeList[1] - timeList[0]
2030 2030 sec = numpy.where(timeList>1)[0][0]
2031 2031 nPairs = metArray.shape[1] - 6
2032 2032 nHeights = len(heightList)
2033 2033
2034 2034 for t in uniqueTime:
2035 2035 metArray1 = metArray[utctime==t,:]
2036 2036 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
2037 2037 tmet = metArray1[:,1].astype(int)
2038 2038 hmet = metArray1[:,2].astype(int)
2039 2039
2040 2040 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
2041 2041 metPhase[:,:] = numpy.nan
2042 2042 metPhase[:,hmet,tmet] = metArray1[:,6:].T
2043 2043
2044 2044 #Delete short trails
2045 2045 metBool = ~numpy.isnan(metPhase[0,:,:])
2046 2046 heightVect = numpy.sum(metBool, axis = 1)
2047 2047 metBool[heightVect<sec,:] = False
2048 2048 metPhase[:,heightVect<sec,:] = numpy.nan
2049 2049
2050 2050 #Derivative
2051 2051 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
2052 2052 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
2053 2053 metPhase[phDerAux] = numpy.nan
2054 2054
2055 2055 #--------------------------METEOR DETECTION -----------------------------------------
2056 2056 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
2057 2057
2058 2058 for p in numpy.arange(nPairs):
2059 2059 phase = metPhase[p,:,:]
2060 2060 phDer = metDer[p,:,:]
2061 2061
2062 2062 for h in indMet:
2063 2063 height = heightList[h]
2064 2064 phase1 = phase[h,:] #82
2065 2065 phDer1 = phDer[h,:]
2066 2066
2067 2067 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
2068 2068
2069 2069 indValid = numpy.where(~numpy.isnan(phase1))[0]
2070 2070 initMet = indValid[0]
2071 2071 endMet = 0
2072 2072
2073 2073 for i in range(len(indValid)-1):
2074 2074
2075 2075 #Time difference
2076 2076 inow = indValid[i]
2077 2077 inext = indValid[i+1]
2078 2078 idiff = inext - inow
2079 2079 #Phase difference
2080 2080 phDiff = numpy.abs(phase1[inext] - phase1[inow])
2081 2081
2082 2082 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
2083 2083 sizeTrail = inow - initMet + 1
2084 2084 if sizeTrail>3*sec: #Too short meteors
2085 2085 x = numpy.arange(initMet,inow+1)*ippSeconds
2086 2086 y = phase1[initMet:inow+1]
2087 2087 ynnan = ~numpy.isnan(y)
2088 2088 x = x[ynnan]
2089 2089 y = y[ynnan]
2090 2090 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
2091 2091 ylin = x*slope + intercept
2092 2092 rsq = r_value**2
2093 2093 if rsq > 0.5:
2094 2094 vel = slope#*height*1000/(k*d)
2095 2095 estAux = numpy.array([utctime,p,height, vel, rsq])
2096 2096 meteorList.append(estAux)
2097 2097 initMet = inext
2098 2098 metArray2 = numpy.array(meteorList)
2099 2099
2100 2100 return metArray2
2101 2101
2102 2102 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
2103 2103
2104 2104 azimuth1 = numpy.zeros(len(pairslist))
2105 2105 dist = numpy.zeros(len(pairslist))
2106 2106
2107 2107 for i in range(len(rx_location)):
2108 2108 ch0 = pairslist[i][0]
2109 2109 ch1 = pairslist[i][1]
2110 2110
2111 2111 diffX = rx_location[ch0][0] - rx_location[ch1][0]
2112 2112 diffY = rx_location[ch0][1] - rx_location[ch1][1]
2113 2113 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
2114 2114 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
2115 2115
2116 2116 azimuth1 -= azimuth0
2117 2117 return azimuth1, dist
2118 2118
2119 2119 def techniqueNSM_DBS(self, **kwargs):
2120 2120 metArray = kwargs['metArray']
2121 2121 heightList = kwargs['heightList']
2122 2122 timeList = kwargs['timeList']
2123 2123 azimuth = kwargs['azimuth']
2124 2124 theta_x = numpy.array(kwargs['theta_x'])
2125 2125 theta_y = numpy.array(kwargs['theta_y'])
2126 2126
2127 2127 utctime = metArray[:,0]
2128 2128 cmet = metArray[:,1].astype(int)
2129 2129 hmet = metArray[:,3].astype(int)
2130 2130 SNRmet = metArray[:,4]
2131 2131 vmet = metArray[:,5]
2132 2132 spcmet = metArray[:,6]
2133 2133
2134 2134 nChan = numpy.max(cmet) + 1
2135 2135 nHeights = len(heightList)
2136 2136
2137 2137 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
2138 2138 hmet = heightList[hmet]
2139 2139 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
2140 2140
2141 2141 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2142 2142
2143 2143 for i in range(nHeights - 1):
2144 2144 hmin = heightList[i]
2145 2145 hmax = heightList[i + 1]
2146 2146
2147 2147 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
2148 2148 indthisH = numpy.where(thisH)
2149 2149
2150 2150 if numpy.size(indthisH) > 3:
2151 2151
2152 2152 vel_aux = vmet[thisH]
2153 2153 chan_aux = cmet[thisH]
2154 2154 cosu_aux = dir_cosu[chan_aux]
2155 2155 cosv_aux = dir_cosv[chan_aux]
2156 2156 cosw_aux = dir_cosw[chan_aux]
2157 2157
2158 2158 nch = numpy.size(numpy.unique(chan_aux))
2159 2159 if nch > 1:
2160 2160 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
2161 2161 velEst[i,:] = numpy.dot(A,vel_aux)
2162 2162
2163 2163 return velEst
2164 2164
2165 2165 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
2166 2166
2167 2167 param = dataOut.data_param
2168 2168 if dataOut.abscissaList != None:
2169 2169 absc = dataOut.abscissaList[:-1]
2170 2170 # noise = dataOut.noise
2171 2171 heightList = dataOut.heightList
2172 2172 SNR = dataOut.data_snr
2173 2173
2174 2174 if technique == 'DBS':
2175 2175
2176 2176 kwargs['velRadial'] = param[:,1,:] #Radial velocity
2177 2177 kwargs['heightList'] = heightList
2178 2178 kwargs['SNR'] = SNR
2179 2179
2180 2180 dataOut.data_output, dataOut.heightList, dataOut.data_snr = self.techniqueDBS(kwargs) #DBS Function
2181 2181 dataOut.utctimeInit = dataOut.utctime
2182 2182 dataOut.outputInterval = dataOut.paramInterval
2183 2183
2184 2184 elif technique == 'SA':
2185 2185
2186 2186 #Parameters
2187 2187 # position_x = kwargs['positionX']
2188 2188 # position_y = kwargs['positionY']
2189 2189 # azimuth = kwargs['azimuth']
2190 2190 #
2191 2191 # if kwargs.has_key('crosspairsList'):
2192 2192 # pairs = kwargs['crosspairsList']
2193 2193 # else:
2194 2194 # pairs = None
2195 2195 #
2196 2196 # if kwargs.has_key('correctFactor'):
2197 2197 # correctFactor = kwargs['correctFactor']
2198 2198 # else:
2199 2199 # correctFactor = 1
2200 2200
2201 2201 # tau = dataOut.data_param
2202 2202 # _lambda = dataOut.C/dataOut.frequency
2203 2203 # pairsList = dataOut.groupList
2204 2204 # nChannels = dataOut.nChannels
2205 2205
2206 2206 kwargs['groupList'] = dataOut.groupList
2207 2207 kwargs['tau'] = dataOut.data_param
2208 2208 kwargs['_lambda'] = dataOut.C/dataOut.frequency
2209 2209 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
2210 2210 dataOut.data_output = self.techniqueSA(kwargs)
2211 2211 dataOut.utctimeInit = dataOut.utctime
2212 2212 dataOut.outputInterval = dataOut.timeInterval
2213 2213
2214 2214 elif technique == 'Meteors':
2215 2215 dataOut.flagNoData = True
2216 2216 self.__dataReady = False
2217 2217
2218 2218 if 'nHours' in kwargs:
2219 2219 nHours = kwargs['nHours']
2220 2220 else:
2221 2221 nHours = 1
2222 2222
2223 2223 if 'meteorsPerBin' in kwargs:
2224 2224 meteorThresh = kwargs['meteorsPerBin']
2225 2225 else:
2226 2226 meteorThresh = 6
2227 2227
2228 2228 if 'hmin' in kwargs:
2229 2229 hmin = kwargs['hmin']
2230 2230 else: hmin = 70
2231 2231 if 'hmax' in kwargs:
2232 2232 hmax = kwargs['hmax']
2233 2233 else: hmax = 110
2234 2234
2235 2235 dataOut.outputInterval = nHours*3600
2236 2236
2237 2237 if self.__isConfig == False:
2238 2238 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2239 2239 #Get Initial LTC time
2240 2240 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2241 2241 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2242 2242
2243 2243 self.__isConfig = True
2244 2244
2245 2245 if self.__buffer is None:
2246 2246 self.__buffer = dataOut.data_param
2247 2247 self.__firstdata = copy.copy(dataOut)
2248 2248
2249 2249 else:
2250 2250 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2251 2251
2252 2252 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2253 2253
2254 2254 if self.__dataReady:
2255 2255 dataOut.utctimeInit = self.__initime
2256 2256
2257 2257 self.__initime += dataOut.outputInterval #to erase time offset
2258 2258
2259 2259 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
2260 2260 dataOut.flagNoData = False
2261 2261 self.__buffer = None
2262 2262
2263 2263 elif technique == 'Meteors1':
2264 2264 dataOut.flagNoData = True
2265 2265 self.__dataReady = False
2266 2266
2267 2267 if 'nMins' in kwargs:
2268 2268 nMins = kwargs['nMins']
2269 2269 else: nMins = 20
2270 2270 if 'rx_location' in kwargs:
2271 2271 rx_location = kwargs['rx_location']
2272 2272 else: rx_location = [(0,1),(1,1),(1,0)]
2273 2273 if 'azimuth' in kwargs:
2274 2274 azimuth = kwargs['azimuth']
2275 2275 else: azimuth = 51.06
2276 2276 if 'dfactor' in kwargs:
2277 2277 dfactor = kwargs['dfactor']
2278 2278 if 'mode' in kwargs:
2279 2279 mode = kwargs['mode']
2280 2280 if 'theta_x' in kwargs:
2281 2281 theta_x = kwargs['theta_x']
2282 2282 if 'theta_y' in kwargs:
2283 2283 theta_y = kwargs['theta_y']
2284 2284 else: mode = 'SA'
2285 2285
2286 2286 #Borrar luego esto
2287 2287 if dataOut.groupList is None:
2288 2288 dataOut.groupList = [(0,1),(0,2),(1,2)]
2289 2289 groupList = dataOut.groupList
2290 2290 C = 3e8
2291 2291 freq = 50e6
2292 2292 lamb = C/freq
2293 2293 k = 2*numpy.pi/lamb
2294 2294
2295 2295 timeList = dataOut.abscissaList
2296 2296 heightList = dataOut.heightList
2297 2297
2298 2298 if self.__isConfig == False:
2299 2299 dataOut.outputInterval = nMins*60
2300 2300 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2301 2301 #Get Initial LTC time
2302 2302 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2303 2303 minuteAux = initime.minute
2304 2304 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
2305 2305 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2306 2306
2307 2307 self.__isConfig = True
2308 2308
2309 2309 if self.__buffer is None:
2310 2310 self.__buffer = dataOut.data_param
2311 2311 self.__firstdata = copy.copy(dataOut)
2312 2312
2313 2313 else:
2314 2314 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2315 2315
2316 2316 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2317 2317
2318 2318 if self.__dataReady:
2319 2319 dataOut.utctimeInit = self.__initime
2320 2320 self.__initime += dataOut.outputInterval #to erase time offset
2321 2321
2322 2322 metArray = self.__buffer
2323 2323 if mode == 'SA':
2324 2324 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
2325 2325 elif mode == 'DBS':
2326 2326 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
2327 2327 dataOut.data_output = dataOut.data_output.T
2328 2328 dataOut.flagNoData = False
2329 2329 self.__buffer = None
2330 2330
2331 2331 return
2332 2332
2333 2333 class EWDriftsEstimation(Operation):
2334 2334
2335 2335 def __init__(self):
2336 2336 Operation.__init__(self)
2337 2337
2338 2338 def __correctValues(self, heiRang, phi, velRadial, SNR):
2339 2339 listPhi = phi.tolist()
2340 2340 maxid = listPhi.index(max(listPhi))
2341 2341 minid = listPhi.index(min(listPhi))
2342 2342
2343 2343 rango = list(range(len(phi)))
2344 2344 # rango = numpy.delete(rango,maxid)
2345 2345
2346 2346 heiRang1 = heiRang*math.cos(phi[maxid])
2347 2347 heiRangAux = heiRang*math.cos(phi[minid])
2348 2348 indOut = (heiRang1 < heiRangAux[0]).nonzero()
2349 2349 heiRang1 = numpy.delete(heiRang1,indOut)
2350 2350
2351 2351 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
2352 2352 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
2353 2353
2354 2354 for i in rango:
2355 2355 x = heiRang*math.cos(phi[i])
2356 2356 y1 = velRadial[i,:]
2357 2357 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
2358 2358
2359 2359 x1 = heiRang1
2360 2360 y11 = f1(x1)
2361 2361
2362 2362 y2 = SNR[i,:]
2363 2363 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
2364 2364 y21 = f2(x1)
2365 2365
2366 2366 velRadial1[i,:] = y11
2367 2367 SNR1[i,:] = y21
2368 2368
2369 2369 return heiRang1, velRadial1, SNR1
2370 2370
2371 2371 def run(self, dataOut, zenith, zenithCorrection):
2372 2372 heiRang = dataOut.heightList
2373 2373 velRadial = dataOut.data_param[:,3,:]
2374 2374 SNR = dataOut.data_snr
2375 2375
2376 2376 zenith = numpy.array(zenith)
2377 2377 zenith -= zenithCorrection
2378 2378 zenith *= numpy.pi/180
2379 2379
2380 2380 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
2381 2381
2382 2382 alp = zenith[0]
2383 2383 bet = zenith[1]
2384 2384
2385 2385 w_w = velRadial1[0,:]
2386 2386 w_e = velRadial1[1,:]
2387 2387
2388 2388 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
2389 2389 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
2390 2390
2391 2391 winds = numpy.vstack((u,w))
2392 2392
2393 2393 dataOut.heightList = heiRang1
2394 2394 dataOut.data_output = winds
2395 2395 dataOut.data_snr = SNR1
2396 2396
2397 2397 dataOut.utctimeInit = dataOut.utctime
2398 2398 dataOut.outputInterval = dataOut.timeInterval
2399 2399 return
2400 2400
2401 2401 #--------------- Non Specular Meteor ----------------
2402 2402
2403 2403 class NonSpecularMeteorDetection(Operation):
2404 2404
2405 2405 def run(self, dataOut, mode, SNRthresh=8, phaseDerThresh=0.5, cohThresh=0.8, allData = False):
2406 2406 data_acf = dataOut.data_pre[0]
2407 2407 data_ccf = dataOut.data_pre[1]
2408 2408 pairsList = dataOut.groupList[1]
2409 2409
2410 2410 lamb = dataOut.C/dataOut.frequency
2411 2411 tSamp = dataOut.ippSeconds*dataOut.nCohInt
2412 2412 paramInterval = dataOut.paramInterval
2413 2413
2414 2414 nChannels = data_acf.shape[0]
2415 2415 nLags = data_acf.shape[1]
2416 2416 nProfiles = data_acf.shape[2]
2417 2417 nHeights = dataOut.nHeights
2418 2418 nCohInt = dataOut.nCohInt
2419 2419 sec = numpy.round(nProfiles/dataOut.paramInterval)
2420 2420 heightList = dataOut.heightList
2421 2421 ippSeconds = dataOut.ippSeconds*dataOut.nCohInt*dataOut.nAvg
2422 2422 utctime = dataOut.utctime
2423 2423
2424 2424 dataOut.abscissaList = numpy.arange(0,paramInterval+ippSeconds,ippSeconds)
2425 2425
2426 2426 #------------------------ SNR --------------------------------------
2427 2427 power = data_acf[:,0,:,:].real
2428 2428 noise = numpy.zeros(nChannels)
2429 2429 SNR = numpy.zeros(power.shape)
2430 2430 for i in range(nChannels):
2431 2431 noise[i] = hildebrand_sekhon(power[i,:], nCohInt)
2432 2432 SNR[i] = (power[i]-noise[i])/noise[i]
2433 2433 SNRm = numpy.nanmean(SNR, axis = 0)
2434 2434 SNRdB = 10*numpy.log10(SNR)
2435 2435
2436 2436 if mode == 'SA':
2437 2437 dataOut.groupList = dataOut.groupList[1]
2438 2438 nPairs = data_ccf.shape[0]
2439 2439 #---------------------- Coherence and Phase --------------------------
2440 2440 phase = numpy.zeros(data_ccf[:,0,:,:].shape)
2441 2441 # phase1 = numpy.copy(phase)
2442 2442 coh1 = numpy.zeros(data_ccf[:,0,:,:].shape)
2443 2443
2444 2444 for p in range(nPairs):
2445 2445 ch0 = pairsList[p][0]
2446 2446 ch1 = pairsList[p][1]
2447 2447 ccf = data_ccf[p,0,:,:]/numpy.sqrt(data_acf[ch0,0,:,:]*data_acf[ch1,0,:,:])
2448 2448 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
2449 2449 # phase1[p,:,:] = numpy.angle(ccf) #median filter
2450 2450 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
2451 2451 # coh1[p,:,:] = numpy.abs(ccf) #median filter
2452 2452 coh = numpy.nanmax(coh1, axis = 0)
2453 2453 # struc = numpy.ones((5,1))
2454 2454 # coh = ndimage.morphology.grey_dilation(coh, size=(10,1))
2455 2455 #---------------------- Radial Velocity ----------------------------
2456 2456 phaseAux = numpy.mean(numpy.angle(data_acf[:,1,:,:]), axis = 0)
2457 2457 velRad = phaseAux*lamb/(4*numpy.pi*tSamp)
2458 2458
2459 2459 if allData:
2460 2460 boolMetFin = ~numpy.isnan(SNRm)
2461 2461 # coh[:-1,:] = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2462 2462 else:
2463 2463 #------------------------ Meteor mask ---------------------------------
2464 2464 # #SNR mask
2465 2465 # boolMet = (SNRdB>SNRthresh)#|(~numpy.isnan(SNRdB))
2466 2466 #
2467 2467 # #Erase small objects
2468 2468 # boolMet1 = self.__erase_small(boolMet, 2*sec, 5)
2469 2469 #
2470 2470 # auxEEJ = numpy.sum(boolMet1,axis=0)
2471 2471 # indOver = auxEEJ>nProfiles*0.8 #Use this later
2472 2472 # indEEJ = numpy.where(indOver)[0]
2473 2473 # indNEEJ = numpy.where(~indOver)[0]
2474 2474 #
2475 2475 # boolMetFin = boolMet1
2476 2476 #
2477 2477 # if indEEJ.size > 0:
2478 2478 # boolMet1[:,indEEJ] = False #Erase heights with EEJ
2479 2479 #
2480 2480 # boolMet2 = coh > cohThresh
2481 2481 # boolMet2 = self.__erase_small(boolMet2, 2*sec,5)
2482 2482 #
2483 2483 # #Final Meteor mask
2484 2484 # boolMetFin = boolMet1|boolMet2
2485 2485
2486 2486 #Coherence mask
2487 2487 boolMet1 = coh > 0.75
2488 2488 struc = numpy.ones((30,1))
2489 2489 boolMet1 = ndimage.morphology.binary_dilation(boolMet1, structure=struc)
2490 2490
2491 2491 #Derivative mask
2492 2492 derPhase = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2493 2493 boolMet2 = derPhase < 0.2
2494 2494 # boolMet2 = ndimage.morphology.binary_opening(boolMet2)
2495 2495 # boolMet2 = ndimage.morphology.binary_closing(boolMet2, structure = numpy.ones((10,1)))
2496 2496 boolMet2 = ndimage.median_filter(boolMet2,size=5)
2497 2497 boolMet2 = numpy.vstack((boolMet2,numpy.full((1,nHeights), True, dtype=bool)))
2498 2498 # #Final mask
2499 2499 # boolMetFin = boolMet2
2500 2500 boolMetFin = boolMet1&boolMet2
2501 2501 # boolMetFin = ndimage.morphology.binary_dilation(boolMetFin)
2502 2502 #Creating data_param
2503 2503 coordMet = numpy.where(boolMetFin)
2504 2504
2505 2505 tmet = coordMet[0]
2506 2506 hmet = coordMet[1]
2507 2507
2508 2508 data_param = numpy.zeros((tmet.size, 6 + nPairs))
2509 2509 data_param[:,0] = utctime
2510 2510 data_param[:,1] = tmet
2511 2511 data_param[:,2] = hmet
2512 2512 data_param[:,3] = SNRm[tmet,hmet]
2513 2513 data_param[:,4] = velRad[tmet,hmet]
2514 2514 data_param[:,5] = coh[tmet,hmet]
2515 2515 data_param[:,6:] = phase[:,tmet,hmet].T
2516 2516
2517 2517 elif mode == 'DBS':
2518 2518 dataOut.groupList = numpy.arange(nChannels)
2519 2519
2520 2520 #Radial Velocities
2521 2521 phase = numpy.angle(data_acf[:,1,:,:])
2522 2522 # phase = ndimage.median_filter(numpy.angle(data_acf[:,1,:,:]), size = (1,5,1))
2523 2523 velRad = phase*lamb/(4*numpy.pi*tSamp)
2524 2524
2525 2525 #Spectral width
2526 2526 # acf1 = ndimage.median_filter(numpy.abs(data_acf[:,1,:,:]), size = (1,5,1))
2527 2527 # acf2 = ndimage.median_filter(numpy.abs(data_acf[:,2,:,:]), size = (1,5,1))
2528 2528 acf1 = data_acf[:,1,:,:]
2529 2529 acf2 = data_acf[:,2,:,:]
2530 2530
2531 2531 spcWidth = (lamb/(2*numpy.sqrt(6)*numpy.pi*tSamp))*numpy.sqrt(numpy.log(acf1/acf2))
2532 2532 # velRad = ndimage.median_filter(velRad, size = (1,5,1))
2533 2533 if allData:
2534 2534 boolMetFin = ~numpy.isnan(SNRdB)
2535 2535 else:
2536 2536 #SNR
2537 2537 boolMet1 = (SNRdB>SNRthresh) #SNR mask
2538 2538 boolMet1 = ndimage.median_filter(boolMet1, size=(1,5,5))
2539 2539
2540 2540 #Radial velocity
2541 2541 boolMet2 = numpy.abs(velRad) < 20
2542 2542 boolMet2 = ndimage.median_filter(boolMet2, (1,5,5))
2543 2543
2544 2544 #Spectral Width
2545 2545 boolMet3 = spcWidth < 30
2546 2546 boolMet3 = ndimage.median_filter(boolMet3, (1,5,5))
2547 2547 # boolMetFin = self.__erase_small(boolMet1, 10,5)
2548 2548 boolMetFin = boolMet1&boolMet2&boolMet3
2549 2549
2550 2550 #Creating data_param
2551 2551 coordMet = numpy.where(boolMetFin)
2552 2552
2553 2553 cmet = coordMet[0]
2554 2554 tmet = coordMet[1]
2555 2555 hmet = coordMet[2]
2556 2556
2557 2557 data_param = numpy.zeros((tmet.size, 7))
2558 2558 data_param[:,0] = utctime
2559 2559 data_param[:,1] = cmet
2560 2560 data_param[:,2] = tmet
2561 2561 data_param[:,3] = hmet
2562 2562 data_param[:,4] = SNR[cmet,tmet,hmet].T
2563 2563 data_param[:,5] = velRad[cmet,tmet,hmet].T
2564 2564 data_param[:,6] = spcWidth[cmet,tmet,hmet].T
2565 2565
2566 2566 # self.dataOut.data_param = data_int
2567 2567 if len(data_param) == 0:
2568 2568 dataOut.flagNoData = True
2569 2569 else:
2570 2570 dataOut.data_param = data_param
2571 2571
2572 2572 def __erase_small(self, binArray, threshX, threshY):
2573 2573 labarray, numfeat = ndimage.measurements.label(binArray)
2574 2574 binArray1 = numpy.copy(binArray)
2575 2575
2576 2576 for i in range(1,numfeat + 1):
2577 2577 auxBin = (labarray==i)
2578 2578 auxSize = auxBin.sum()
2579 2579
2580 2580 x,y = numpy.where(auxBin)
2581 2581 widthX = x.max() - x.min()
2582 2582 widthY = y.max() - y.min()
2583 2583
2584 2584 #width X: 3 seg -> 12.5*3
2585 2585 #width Y:
2586 2586
2587 2587 if (auxSize < 50) or (widthX < threshX) or (widthY < threshY):
2588 2588 binArray1[auxBin] = False
2589 2589
2590 2590 return binArray1
2591 2591
2592 2592 #--------------- Specular Meteor ----------------
2593 2593
2594 2594 class SMDetection(Operation):
2595 2595 '''
2596 2596 Function DetectMeteors()
2597 2597 Project developed with paper:
2598 2598 HOLDSWORTH ET AL. 2004
2599 2599
2600 2600 Input:
2601 2601 self.dataOut.data_pre
2602 2602
2603 2603 centerReceiverIndex: From the channels, which is the center receiver
2604 2604
2605 2605 hei_ref: Height reference for the Beacon signal extraction
2606 2606 tauindex:
2607 2607 predefinedPhaseShifts: Predefined phase offset for the voltge signals
2608 2608
2609 2609 cohDetection: Whether to user Coherent detection or not
2610 2610 cohDet_timeStep: Coherent Detection calculation time step
2611 2611 cohDet_thresh: Coherent Detection phase threshold to correct phases
2612 2612
2613 2613 noise_timeStep: Noise calculation time step
2614 2614 noise_multiple: Noise multiple to define signal threshold
2615 2615
2616 2616 multDet_timeLimit: Multiple Detection Removal time limit in seconds
2617 2617 multDet_rangeLimit: Multiple Detection Removal range limit in km
2618 2618
2619 2619 phaseThresh: Maximum phase difference between receiver to be consider a meteor
2620 2620 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
2621 2621
2622 2622 hmin: Minimum Height of the meteor to use it in the further wind estimations
2623 2623 hmax: Maximum Height of the meteor to use it in the further wind estimations
2624 2624 azimuth: Azimuth angle correction
2625 2625
2626 2626 Affected:
2627 2627 self.dataOut.data_param
2628 2628
2629 2629 Rejection Criteria (Errors):
2630 2630 0: No error; analysis OK
2631 2631 1: SNR < SNR threshold
2632 2632 2: angle of arrival (AOA) ambiguously determined
2633 2633 3: AOA estimate not feasible
2634 2634 4: Large difference in AOAs obtained from different antenna baselines
2635 2635 5: echo at start or end of time series
2636 2636 6: echo less than 5 examples long; too short for analysis
2637 2637 7: echo rise exceeds 0.3s
2638 2638 8: echo decay time less than twice rise time
2639 2639 9: large power level before echo
2640 2640 10: large power level after echo
2641 2641 11: poor fit to amplitude for estimation of decay time
2642 2642 12: poor fit to CCF phase variation for estimation of radial drift velocity
2643 2643 13: height unresolvable echo: not valid height within 70 to 110 km
2644 2644 14: height ambiguous echo: more then one possible height within 70 to 110 km
2645 2645 15: radial drift velocity or projected horizontal velocity exceeds 200 m/s
2646 2646 16: oscilatory echo, indicating event most likely not an underdense echo
2647 2647
2648 2648 17: phase difference in meteor Reestimation
2649 2649
2650 2650 Data Storage:
2651 2651 Meteors for Wind Estimation (8):
2652 2652 Utc Time | Range Height
2653 2653 Azimuth Zenith errorCosDir
2654 2654 VelRad errorVelRad
2655 2655 Phase0 Phase1 Phase2 Phase3
2656 2656 TypeError
2657 2657
2658 2658 '''
2659 2659
2660 2660 def run(self, dataOut, hei_ref = None, tauindex = 0,
2661 2661 phaseOffsets = None,
2662 2662 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
2663 2663 noise_timeStep = 4, noise_multiple = 4,
2664 2664 multDet_timeLimit = 1, multDet_rangeLimit = 3,
2665 2665 phaseThresh = 20, SNRThresh = 5,
2666 2666 hmin = 50, hmax=150, azimuth = 0,
2667 2667 channelPositions = None) :
2668 2668
2669 2669
2670 2670 #Getting Pairslist
2671 2671 if channelPositions is None:
2672 2672 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
2673 2673 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
2674 2674 meteorOps = SMOperations()
2675 2675 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
2676 2676 heiRang = dataOut.heightList
2677 2677 #Get Beacon signal - No Beacon signal anymore
2678 2678 # newheis = numpy.where(self.dataOut.heightList>self.dataOut.radarControllerHeaderObj.Taus[tauindex])
2679 2679 #
2680 2680 # if hei_ref != None:
2681 2681 # newheis = numpy.where(self.dataOut.heightList>hei_ref)
2682 2682 #
2683 2683
2684 2684
2685 2685 #****************REMOVING HARDWARE PHASE DIFFERENCES***************
2686 2686 # see if the user put in pre defined phase shifts
2687 2687 voltsPShift = dataOut.data_pre.copy()
2688 2688
2689 2689 # if predefinedPhaseShifts != None:
2690 2690 # hardwarePhaseShifts = numpy.array(predefinedPhaseShifts)*numpy.pi/180
2691 2691 #
2692 2692 # # elif beaconPhaseShifts:
2693 2693 # # #get hardware phase shifts using beacon signal
2694 2694 # # hardwarePhaseShifts = self.__getHardwarePhaseDiff(self.dataOut.data_pre, pairslist, newheis, 10)
2695 2695 # # hardwarePhaseShifts = numpy.insert(hardwarePhaseShifts,centerReceiverIndex,0)
2696 2696 #
2697 2697 # else:
2698 2698 # hardwarePhaseShifts = numpy.zeros(5)
2699 2699 #
2700 2700 # voltsPShift = numpy.zeros((self.dataOut.data_pre.shape[0],self.dataOut.data_pre.shape[1],self.dataOut.data_pre.shape[2]), dtype = 'complex')
2701 2701 # for i in range(self.dataOut.data_pre.shape[0]):
2702 2702 # voltsPShift[i,:,:] = self.__shiftPhase(self.dataOut.data_pre[i,:,:], hardwarePhaseShifts[i])
2703 2703
2704 2704 #******************END OF REMOVING HARDWARE PHASE DIFFERENCES*********
2705 2705
2706 2706 #Remove DC
2707 2707 voltsDC = numpy.mean(voltsPShift,1)
2708 2708 voltsDC = numpy.mean(voltsDC,1)
2709 2709 for i in range(voltsDC.shape[0]):
2710 2710 voltsPShift[i] = voltsPShift[i] - voltsDC[i]
2711 2711
2712 2712 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
2713 2713 # voltsPShift = voltsPShift[:,:,:newheis[0][0]]
2714 2714
2715 2715 #************ FIND POWER OF DATA W/COH OR NON COH DETECTION (3.4) **********
2716 2716 #Coherent Detection
2717 2717 if cohDetection:
2718 2718 #use coherent detection to get the net power
2719 2719 cohDet_thresh = cohDet_thresh*numpy.pi/180
2720 2720 voltsPShift = self.__coherentDetection(voltsPShift, cohDet_timeStep, dataOut.timeInterval, pairslist0, cohDet_thresh)
2721 2721
2722 2722 #Non-coherent detection!
2723 2723 powerNet = numpy.nansum(numpy.abs(voltsPShift[:,:,:])**2,0)
2724 2724 #********** END OF COH/NON-COH POWER CALCULATION**********************
2725 2725
2726 2726 #********** FIND THE NOISE LEVEL AND POSSIBLE METEORS ****************
2727 2727 #Get noise
2728 2728 noise, noise1 = self.__getNoise(powerNet, noise_timeStep, dataOut.timeInterval)
2729 2729 # noise = self.getNoise1(powerNet, noise_timeStep, self.dataOut.timeInterval)
2730 2730 #Get signal threshold
2731 2731 signalThresh = noise_multiple*noise
2732 2732 #Meteor echoes detection
2733 2733 listMeteors = self.__findMeteors(powerNet, signalThresh)
2734 2734 #******* END OF NOISE LEVEL AND POSSIBLE METEORS CACULATION **********
2735 2735
2736 2736 #************** REMOVE MULTIPLE DETECTIONS (3.5) ***************************
2737 2737 #Parameters
2738 2738 heiRange = dataOut.heightList
2739 2739 rangeInterval = heiRange[1] - heiRange[0]
2740 2740 rangeLimit = multDet_rangeLimit/rangeInterval
2741 2741 timeLimit = multDet_timeLimit/dataOut.timeInterval
2742 2742 #Multiple detection removals
2743 2743 listMeteors1 = self.__removeMultipleDetections(listMeteors, rangeLimit, timeLimit)
2744 2744 #************ END OF REMOVE MULTIPLE DETECTIONS **********************
2745 2745
2746 2746 #********************* METEOR REESTIMATION (3.7, 3.8, 3.9, 3.10) ********************
2747 2747 #Parameters
2748 2748 phaseThresh = phaseThresh*numpy.pi/180
2749 2749 thresh = [phaseThresh, noise_multiple, SNRThresh]
2750 2750 #Meteor reestimation (Errors N 1, 6, 12, 17)
2751 2751 listMeteors2, listMeteorsPower, listMeteorsVolts = self.__meteorReestimation(listMeteors1, voltsPShift, pairslist0, thresh, noise, dataOut.timeInterval, dataOut.frequency)
2752 2752 # listMeteors2, listMeteorsPower, listMeteorsVolts = self.meteorReestimation3(listMeteors2, listMeteorsPower, listMeteorsVolts, voltsPShift, pairslist, thresh, noise)
2753 2753 #Estimation of decay times (Errors N 7, 8, 11)
2754 2754 listMeteors3 = self.__estimateDecayTime(listMeteors2, listMeteorsPower, dataOut.timeInterval, dataOut.frequency)
2755 2755 #******************* END OF METEOR REESTIMATION *******************
2756 2756
2757 2757 #********************* METEOR PARAMETERS CALCULATION (3.11, 3.12, 3.13) **************************
2758 2758 #Calculating Radial Velocity (Error N 15)
2759 2759 radialStdThresh = 10
2760 2760 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
2761 2761
2762 2762 if len(listMeteors4) > 0:
2763 2763 #Setting New Array
2764 2764 date = dataOut.utctime
2765 2765 arrayParameters = self.__setNewArrays(listMeteors4, date, heiRang)
2766 2766
2767 2767 #Correcting phase offset
2768 2768 if phaseOffsets != None:
2769 2769 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
2770 2770 arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
2771 2771
2772 2772 #Second Pairslist
2773 2773 pairsList = []
2774 2774 pairx = (0,1)
2775 2775 pairy = (2,3)
2776 2776 pairsList.append(pairx)
2777 2777 pairsList.append(pairy)
2778 2778
2779 2779 jph = numpy.array([0,0,0,0])
2780 2780 h = (hmin,hmax)
2781 2781 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
2782 2782
2783 2783 # #Calculate AOA (Error N 3, 4)
2784 2784 # #JONES ET AL. 1998
2785 2785 # error = arrayParameters[:,-1]
2786 2786 # AOAthresh = numpy.pi/8
2787 2787 # phases = -arrayParameters[:,9:13]
2788 2788 # arrayParameters[:,4:7], arrayParameters[:,-1] = meteorOps.getAOA(phases, pairsList, error, AOAthresh, azimuth)
2789 2789 #
2790 2790 # #Calculate Heights (Error N 13 and 14)
2791 2791 # error = arrayParameters[:,-1]
2792 2792 # Ranges = arrayParameters[:,2]
2793 2793 # zenith = arrayParameters[:,5]
2794 2794 # arrayParameters[:,3], arrayParameters[:,-1] = meteorOps.getHeights(Ranges, zenith, error, hmin, hmax)
2795 2795 # error = arrayParameters[:,-1]
2796 2796 #********************* END OF PARAMETERS CALCULATION **************************
2797 2797
2798 2798 #***************************+ PASS DATA TO NEXT STEP **********************
2799 2799 # arrayFinal = arrayParameters.reshape((1,arrayParameters.shape[0],arrayParameters.shape[1]))
2800 2800 dataOut.data_param = arrayParameters
2801 2801
2802 2802 if arrayParameters is None:
2803 2803 dataOut.flagNoData = True
2804 2804 else:
2805 2805 dataOut.flagNoData = True
2806 2806
2807 2807 return
2808 2808
2809 2809 def __getHardwarePhaseDiff(self, voltage0, pairslist, newheis, n):
2810 2810
2811 2811 minIndex = min(newheis[0])
2812 2812 maxIndex = max(newheis[0])
2813 2813
2814 2814 voltage = voltage0[:,:,minIndex:maxIndex+1]
2815 2815 nLength = voltage.shape[1]/n
2816 2816 nMin = 0
2817 2817 nMax = 0
2818 2818 phaseOffset = numpy.zeros((len(pairslist),n))
2819 2819
2820 2820 for i in range(n):
2821 2821 nMax += nLength
2822 2822 phaseCCF = -numpy.angle(self.__calculateCCF(voltage[:,nMin:nMax,:], pairslist, [0]))
2823 2823 phaseCCF = numpy.mean(phaseCCF, axis = 2)
2824 2824 phaseOffset[:,i] = phaseCCF.transpose()
2825 2825 nMin = nMax
2826 2826 # phaseDiff, phaseArrival = self.estimatePhaseDifference(voltage, pairslist)
2827 2827
2828 2828 #Remove Outliers
2829 2829 factor = 2
2830 2830 wt = phaseOffset - signal.medfilt(phaseOffset,(1,5))
2831 2831 dw = numpy.std(wt,axis = 1)
2832 2832 dw = dw.reshape((dw.size,1))
2833 2833 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
2834 2834 phaseOffset[ind] = numpy.nan
2835 2835 phaseOffset = stats.nanmean(phaseOffset, axis=1)
2836 2836
2837 2837 return phaseOffset
2838 2838
2839 2839 def __shiftPhase(self, data, phaseShift):
2840 2840 #this will shift the phase of a complex number
2841 2841 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
2842 2842 return dataShifted
2843 2843
2844 2844 def __estimatePhaseDifference(self, array, pairslist):
2845 2845 nChannel = array.shape[0]
2846 2846 nHeights = array.shape[2]
2847 2847 numPairs = len(pairslist)
2848 2848 # phaseCCF = numpy.zeros((nChannel, 5, nHeights))
2849 2849 phaseCCF = numpy.angle(self.__calculateCCF(array, pairslist, [-2,-1,0,1,2]))
2850 2850
2851 2851 #Correct phases
2852 2852 derPhaseCCF = phaseCCF[:,1:,:] - phaseCCF[:,0:-1,:]
2853 2853 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
2854 2854
2855 2855 if indDer[0].shape[0] > 0:
2856 2856 for i in range(indDer[0].shape[0]):
2857 2857 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i],indDer[2][i]])
2858 2858 phaseCCF[indDer[0][i],indDer[1][i]+1:,:] += signo*2*numpy.pi
2859 2859
2860 2860 # for j in range(numSides):
2861 2861 # phaseCCFAux = self.calculateCCF(arrayCenter, arraySides[j,:,:], [-2,1,0,1,2])
2862 2862 # phaseCCF[j,:,:] = numpy.angle(phaseCCFAux)
2863 2863 #
2864 2864 #Linear
2865 2865 phaseInt = numpy.zeros((numPairs,1))
2866 2866 angAllCCF = phaseCCF[:,[0,1,3,4],0]
2867 2867 for j in range(numPairs):
2868 2868 fit = stats.linregress([-2,-1,1,2],angAllCCF[j,:])
2869 2869 phaseInt[j] = fit[1]
2870 2870 #Phase Differences
2871 2871 phaseDiff = phaseInt - phaseCCF[:,2,:]
2872 2872 phaseArrival = phaseInt.reshape(phaseInt.size)
2873 2873
2874 2874 #Dealias
2875 2875 phaseArrival = numpy.angle(numpy.exp(1j*phaseArrival))
2876 2876 # indAlias = numpy.where(phaseArrival > numpy.pi)
2877 2877 # phaseArrival[indAlias] -= 2*numpy.pi
2878 2878 # indAlias = numpy.where(phaseArrival < -numpy.pi)
2879 2879 # phaseArrival[indAlias] += 2*numpy.pi
2880 2880
2881 2881 return phaseDiff, phaseArrival
2882 2882
2883 2883 def __coherentDetection(self, volts, timeSegment, timeInterval, pairslist, thresh):
2884 2884 #this function will run the coherent detection used in Holdworth et al. 2004 and return the net power
2885 2885 #find the phase shifts of each channel over 1 second intervals
2886 2886 #only look at ranges below the beacon signal
2887 2887 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
2888 2888 numBlocks = int(volts.shape[1]/numProfPerBlock)
2889 2889 numHeights = volts.shape[2]
2890 2890 nChannel = volts.shape[0]
2891 2891 voltsCohDet = volts.copy()
2892 2892
2893 2893 pairsarray = numpy.array(pairslist)
2894 2894 indSides = pairsarray[:,1]
2895 2895 # indSides = numpy.array(range(nChannel))
2896 2896 # indSides = numpy.delete(indSides, indCenter)
2897 2897 #
2898 2898 # listCenter = numpy.array_split(volts[indCenter,:,:], numBlocks, 0)
2899 2899 listBlocks = numpy.array_split(volts, numBlocks, 1)
2900 2900
2901 2901 startInd = 0
2902 2902 endInd = 0
2903 2903
2904 2904 for i in range(numBlocks):
2905 2905 startInd = endInd
2906 2906 endInd = endInd + listBlocks[i].shape[1]
2907 2907
2908 2908 arrayBlock = listBlocks[i]
2909 2909 # arrayBlockCenter = listCenter[i]
2910 2910
2911 2911 #Estimate the Phase Difference
2912 2912 phaseDiff, aux = self.__estimatePhaseDifference(arrayBlock, pairslist)
2913 2913 #Phase Difference RMS
2914 2914 arrayPhaseRMS = numpy.abs(phaseDiff)
2915 2915 phaseRMSaux = numpy.sum(arrayPhaseRMS < thresh,0)
2916 2916 indPhase = numpy.where(phaseRMSaux==4)
2917 2917 #Shifting
2918 2918 if indPhase[0].shape[0] > 0:
2919 2919 for j in range(indSides.size):
2920 2920 arrayBlock[indSides[j],:,indPhase] = self.__shiftPhase(arrayBlock[indSides[j],:,indPhase], phaseDiff[j,indPhase].transpose())
2921 2921 voltsCohDet[:,startInd:endInd,:] = arrayBlock
2922 2922
2923 2923 return voltsCohDet
2924 2924
2925 2925 def __calculateCCF(self, volts, pairslist ,laglist):
2926 2926
2927 2927 nHeights = volts.shape[2]
2928 2928 nPoints = volts.shape[1]
2929 2929 voltsCCF = numpy.zeros((len(pairslist), len(laglist), nHeights),dtype = 'complex')
2930 2930
2931 2931 for i in range(len(pairslist)):
2932 2932 volts1 = volts[pairslist[i][0]]
2933 2933 volts2 = volts[pairslist[i][1]]
2934 2934
2935 2935 for t in range(len(laglist)):
2936 2936 idxT = laglist[t]
2937 2937 if idxT >= 0:
2938 2938 vStacked = numpy.vstack((volts2[idxT:,:],
2939 2939 numpy.zeros((idxT, nHeights),dtype='complex')))
2940 2940 else:
2941 2941 vStacked = numpy.vstack((numpy.zeros((-idxT, nHeights),dtype='complex'),
2942 2942 volts2[:(nPoints + idxT),:]))
2943 2943 voltsCCF[i,t,:] = numpy.sum((numpy.conjugate(volts1)*vStacked),axis=0)
2944 2944
2945 2945 vStacked = None
2946 2946 return voltsCCF
2947 2947
2948 2948 def __getNoise(self, power, timeSegment, timeInterval):
2949 2949 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
2950 2950 numBlocks = int(power.shape[0]/numProfPerBlock)
2951 2951 numHeights = power.shape[1]
2952 2952
2953 2953 listPower = numpy.array_split(power, numBlocks, 0)
2954 2954 noise = numpy.zeros((power.shape[0], power.shape[1]))
2955 2955 noise1 = numpy.zeros((power.shape[0], power.shape[1]))
2956 2956
2957 2957 startInd = 0
2958 2958 endInd = 0
2959 2959
2960 2960 for i in range(numBlocks): #split por canal
2961 2961 startInd = endInd
2962 2962 endInd = endInd + listPower[i].shape[0]
2963 2963
2964 2964 arrayBlock = listPower[i]
2965 2965 noiseAux = numpy.mean(arrayBlock, 0)
2966 2966 # noiseAux = numpy.median(noiseAux)
2967 2967 # noiseAux = numpy.mean(arrayBlock)
2968 2968 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
2969 2969
2970 2970 noiseAux1 = numpy.mean(arrayBlock)
2971 2971 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
2972 2972
2973 2973 return noise, noise1
2974 2974
2975 2975 def __findMeteors(self, power, thresh):
2976 2976 nProf = power.shape[0]
2977 2977 nHeights = power.shape[1]
2978 2978 listMeteors = []
2979 2979
2980 2980 for i in range(nHeights):
2981 2981 powerAux = power[:,i]
2982 2982 threshAux = thresh[:,i]
2983 2983
2984 2984 indUPthresh = numpy.where(powerAux > threshAux)[0]
2985 2985 indDNthresh = numpy.where(powerAux <= threshAux)[0]
2986 2986
2987 2987 j = 0
2988 2988
2989 2989 while (j < indUPthresh.size - 2):
2990 2990 if (indUPthresh[j + 2] == indUPthresh[j] + 2):
2991 2991 indDNAux = numpy.where(indDNthresh > indUPthresh[j])
2992 2992 indDNthresh = indDNthresh[indDNAux]
2993 2993
2994 2994 if (indDNthresh.size > 0):
2995 2995 indEnd = indDNthresh[0] - 1
2996 2996 indInit = indUPthresh[j]
2997 2997
2998 2998 meteor = powerAux[indInit:indEnd + 1]
2999 2999 indPeak = meteor.argmax() + indInit
3000 3000 FLA = sum(numpy.conj(meteor)*numpy.hstack((meteor[1:],0)))
3001 3001
3002 3002 listMeteors.append(numpy.array([i,indInit,indPeak,indEnd,FLA])) #CHEQUEAR!!!!!
3003 3003 j = numpy.where(indUPthresh == indEnd)[0] + 1
3004 3004 else: j+=1
3005 3005 else: j+=1
3006 3006
3007 3007 return listMeteors
3008 3008
3009 3009 def __removeMultipleDetections(self,listMeteors, rangeLimit, timeLimit):
3010 3010
3011 3011 arrayMeteors = numpy.asarray(listMeteors)
3012 3012 listMeteors1 = []
3013 3013
3014 3014 while arrayMeteors.shape[0] > 0:
3015 3015 FLAs = arrayMeteors[:,4]
3016 3016 maxFLA = FLAs.argmax()
3017 3017 listMeteors1.append(arrayMeteors[maxFLA,:])
3018 3018
3019 3019 MeteorInitTime = arrayMeteors[maxFLA,1]
3020 3020 MeteorEndTime = arrayMeteors[maxFLA,3]
3021 3021 MeteorHeight = arrayMeteors[maxFLA,0]
3022 3022
3023 3023 #Check neighborhood
3024 3024 maxHeightIndex = MeteorHeight + rangeLimit
3025 3025 minHeightIndex = MeteorHeight - rangeLimit
3026 3026 minTimeIndex = MeteorInitTime - timeLimit
3027 3027 maxTimeIndex = MeteorEndTime + timeLimit
3028 3028
3029 3029 #Check Heights
3030 3030 indHeight = numpy.logical_and(arrayMeteors[:,0] >= minHeightIndex, arrayMeteors[:,0] <= maxHeightIndex)
3031 3031 indTime = numpy.logical_and(arrayMeteors[:,3] >= minTimeIndex, arrayMeteors[:,1] <= maxTimeIndex)
3032 3032 indBoth = numpy.where(numpy.logical_and(indTime,indHeight))
3033 3033
3034 3034 arrayMeteors = numpy.delete(arrayMeteors, indBoth, axis = 0)
3035 3035
3036 3036 return listMeteors1
3037 3037
3038 3038 def __meteorReestimation(self, listMeteors, volts, pairslist, thresh, noise, timeInterval,frequency):
3039 3039 numHeights = volts.shape[2]
3040 3040 nChannel = volts.shape[0]
3041 3041
3042 3042 thresholdPhase = thresh[0]
3043 3043 thresholdNoise = thresh[1]
3044 3044 thresholdDB = float(thresh[2])
3045 3045
3046 3046 thresholdDB1 = 10**(thresholdDB/10)
3047 3047 pairsarray = numpy.array(pairslist)
3048 3048 indSides = pairsarray[:,1]
3049 3049
3050 3050 pairslist1 = list(pairslist)
3051 3051 pairslist1.append((0,1))
3052 3052 pairslist1.append((3,4))
3053 3053
3054 3054 listMeteors1 = []
3055 3055 listPowerSeries = []
3056 3056 listVoltageSeries = []
3057 3057 #volts has the war data
3058 3058
3059 3059 if frequency == 30e6:
3060 3060 timeLag = 45*10**-3
3061 3061 else:
3062 3062 timeLag = 15*10**-3
3063 3063 lag = numpy.ceil(timeLag/timeInterval)
3064 3064
3065 3065 for i in range(len(listMeteors)):
3066 3066
3067 3067 ###################### 3.6 - 3.7 PARAMETERS REESTIMATION #########################
3068 3068 meteorAux = numpy.zeros(16)
3069 3069
3070 3070 #Loading meteor Data (mHeight, mStart, mPeak, mEnd)
3071 3071 mHeight = listMeteors[i][0]
3072 3072 mStart = listMeteors[i][1]
3073 3073 mPeak = listMeteors[i][2]
3074 3074 mEnd = listMeteors[i][3]
3075 3075
3076 3076 #get the volt data between the start and end times of the meteor
3077 3077 meteorVolts = volts[:,mStart:mEnd+1,mHeight]
3078 3078 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3079 3079
3080 3080 #3.6. Phase Difference estimation
3081 3081 phaseDiff, aux = self.__estimatePhaseDifference(meteorVolts, pairslist)
3082 3082
3083 3083 #3.7. Phase difference removal & meteor start, peak and end times reestimated
3084 3084 #meteorVolts0.- all Channels, all Profiles
3085 3085 meteorVolts0 = volts[:,:,mHeight]
3086 3086 meteorThresh = noise[:,mHeight]*thresholdNoise
3087 3087 meteorNoise = noise[:,mHeight]
3088 3088 meteorVolts0[indSides,:] = self.__shiftPhase(meteorVolts0[indSides,:], phaseDiff) #Phase Shifting
3089 3089 powerNet0 = numpy.nansum(numpy.abs(meteorVolts0)**2, axis = 0) #Power
3090 3090
3091 3091 #Times reestimation
3092 3092 mStart1 = numpy.where(powerNet0[:mPeak] < meteorThresh[:mPeak])[0]
3093 3093 if mStart1.size > 0:
3094 3094 mStart1 = mStart1[-1] + 1
3095 3095
3096 3096 else:
3097 3097 mStart1 = mPeak
3098 3098
3099 3099 mEnd1 = numpy.where(powerNet0[mPeak:] < meteorThresh[mPeak:])[0][0] + mPeak - 1
3100 3100 mEndDecayTime1 = numpy.where(powerNet0[mPeak:] < meteorNoise[mPeak:])[0]
3101 3101 if mEndDecayTime1.size == 0:
3102 3102 mEndDecayTime1 = powerNet0.size
3103 3103 else:
3104 3104 mEndDecayTime1 = mEndDecayTime1[0] + mPeak - 1
3105 3105 # mPeak1 = meteorVolts0[mStart1:mEnd1 + 1].argmax()
3106 3106
3107 3107 #meteorVolts1.- all Channels, from start to end
3108 3108 meteorVolts1 = meteorVolts0[:,mStart1:mEnd1 + 1]
3109 3109 meteorVolts2 = meteorVolts0[:,mPeak + lag:mEnd1 + 1]
3110 3110 if meteorVolts2.shape[1] == 0:
3111 3111 meteorVolts2 = meteorVolts0[:,mPeak:mEnd1 + 1]
3112 3112 meteorVolts1 = meteorVolts1.reshape(meteorVolts1.shape[0], meteorVolts1.shape[1], 1)
3113 3113 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1], 1)
3114 3114 ##################### END PARAMETERS REESTIMATION #########################
3115 3115
3116 3116 ##################### 3.8 PHASE DIFFERENCE REESTIMATION ########################
3117 3117 # if mEnd1 - mStart1 > 4: #Error Number 6: echo less than 5 samples long; too short for analysis
3118 3118 if meteorVolts2.shape[1] > 0:
3119 3119 #Phase Difference re-estimation
3120 3120 phaseDiff1, phaseDiffint = self.__estimatePhaseDifference(meteorVolts2, pairslist1) #Phase Difference Estimation
3121 3121 # phaseDiff1, phaseDiffint = self.estimatePhaseDifference(meteorVolts2, pairslist)
3122 3122 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1])
3123 3123 phaseDiff11 = numpy.reshape(phaseDiff1, (phaseDiff1.shape[0],1))
3124 3124 meteorVolts2[indSides,:] = self.__shiftPhase(meteorVolts2[indSides,:], phaseDiff11[0:4]) #Phase Shifting
3125 3125
3126 3126 #Phase Difference RMS
3127 3127 phaseRMS1 = numpy.sqrt(numpy.mean(numpy.square(phaseDiff1)))
3128 3128 powerNet1 = numpy.nansum(numpy.abs(meteorVolts1[:,:])**2,0)
3129 3129 #Data from Meteor
3130 3130 mPeak1 = powerNet1.argmax() + mStart1
3131 3131 mPeakPower1 = powerNet1.max()
3132 3132 noiseAux = sum(noise[mStart1:mEnd1 + 1,mHeight])
3133 3133 mSNR1 = (sum(powerNet1)-noiseAux)/noiseAux
3134 3134 Meteor1 = numpy.array([mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1])
3135 3135 Meteor1 = numpy.hstack((Meteor1,phaseDiffint))
3136 3136 PowerSeries = powerNet0[mStart1:mEndDecayTime1 + 1]
3137 3137 #Vectorize
3138 3138 meteorAux[0:7] = [mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1]
3139 3139 meteorAux[7:11] = phaseDiffint[0:4]
3140 3140
3141 3141 #Rejection Criterions
3142 3142 if phaseRMS1 > thresholdPhase: #Error Number 17: Phase variation
3143 3143 meteorAux[-1] = 17
3144 3144 elif mSNR1 < thresholdDB1: #Error Number 1: SNR < threshold dB
3145 3145 meteorAux[-1] = 1
3146 3146
3147 3147
3148 3148 else:
3149 3149 meteorAux[0:4] = [mHeight, mStart, mPeak, mEnd]
3150 3150 meteorAux[-1] = 6 #Error Number 6: echo less than 5 samples long; too short for analysis
3151 3151 PowerSeries = 0
3152 3152
3153 3153 listMeteors1.append(meteorAux)
3154 3154 listPowerSeries.append(PowerSeries)
3155 3155 listVoltageSeries.append(meteorVolts1)
3156 3156
3157 3157 return listMeteors1, listPowerSeries, listVoltageSeries
3158 3158
3159 3159 def __estimateDecayTime(self, listMeteors, listPower, timeInterval, frequency):
3160 3160
3161 3161 threshError = 10
3162 3162 #Depending if it is 30 or 50 MHz
3163 3163 if frequency == 30e6:
3164 3164 timeLag = 45*10**-3
3165 3165 else:
3166 3166 timeLag = 15*10**-3
3167 3167 lag = numpy.ceil(timeLag/timeInterval)
3168 3168
3169 3169 listMeteors1 = []
3170 3170
3171 3171 for i in range(len(listMeteors)):
3172 3172 meteorPower = listPower[i]
3173 3173 meteorAux = listMeteors[i]
3174 3174
3175 3175 if meteorAux[-1] == 0:
3176 3176
3177 3177 try:
3178 3178 indmax = meteorPower.argmax()
3179 3179 indlag = indmax + lag
3180 3180
3181 3181 y = meteorPower[indlag:]
3182 3182 x = numpy.arange(0, y.size)*timeLag
3183 3183
3184 3184 #first guess
3185 3185 a = y[0]
3186 3186 tau = timeLag
3187 3187 #exponential fit
3188 3188 popt, pcov = optimize.curve_fit(self.__exponential_function, x, y, p0 = [a, tau])
3189 3189 y1 = self.__exponential_function(x, *popt)
3190 3190 #error estimation
3191 3191 error = sum((y - y1)**2)/(numpy.var(y)*(y.size - popt.size))
3192 3192
3193 3193 decayTime = popt[1]
3194 3194 riseTime = indmax*timeInterval
3195 3195 meteorAux[11:13] = [decayTime, error]
3196 3196
3197 3197 #Table items 7, 8 and 11
3198 3198 if (riseTime > 0.3): #Number 7: Echo rise exceeds 0.3s
3199 3199 meteorAux[-1] = 7
3200 3200 elif (decayTime < 2*riseTime) : #Number 8: Echo decay time less than than twice rise time
3201 3201 meteorAux[-1] = 8
3202 3202 if (error > threshError): #Number 11: Poor fit to amplitude for estimation of decay time
3203 3203 meteorAux[-1] = 11
3204 3204
3205 3205
3206 3206 except:
3207 3207 meteorAux[-1] = 11
3208 3208
3209 3209
3210 3210 listMeteors1.append(meteorAux)
3211 3211
3212 3212 return listMeteors1
3213 3213
3214 3214 #Exponential Function
3215 3215
3216 3216 def __exponential_function(self, x, a, tau):
3217 3217 y = a*numpy.exp(-x/tau)
3218 3218 return y
3219 3219
3220 3220 def __getRadialVelocity(self, listMeteors, listVolts, radialStdThresh, pairslist, timeInterval):
3221 3221
3222 3222 pairslist1 = list(pairslist)
3223 3223 pairslist1.append((0,1))
3224 3224 pairslist1.append((3,4))
3225 3225 numPairs = len(pairslist1)
3226 3226 #Time Lag
3227 3227 timeLag = 45*10**-3
3228 3228 c = 3e8
3229 3229 lag = numpy.ceil(timeLag/timeInterval)
3230 3230 freq = 30e6
3231 3231
3232 3232 listMeteors1 = []
3233 3233
3234 3234 for i in range(len(listMeteors)):
3235 3235 meteorAux = listMeteors[i]
3236 3236 if meteorAux[-1] == 0:
3237 3237 mStart = listMeteors[i][1]
3238 3238 mPeak = listMeteors[i][2]
3239 3239 mLag = mPeak - mStart + lag
3240 3240
3241 3241 #get the volt data between the start and end times of the meteor
3242 3242 meteorVolts = listVolts[i]
3243 3243 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3244 3244
3245 3245 #Get CCF
3246 3246 allCCFs = self.__calculateCCF(meteorVolts, pairslist1, [-2,-1,0,1,2])
3247 3247
3248 3248 #Method 2
3249 3249 slopes = numpy.zeros(numPairs)
3250 3250 time = numpy.array([-2,-1,1,2])*timeInterval
3251 3251 angAllCCF = numpy.angle(allCCFs[:,[0,1,3,4],0])
3252 3252
3253 3253 #Correct phases
3254 3254 derPhaseCCF = angAllCCF[:,1:] - angAllCCF[:,0:-1]
3255 3255 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
3256 3256
3257 3257 if indDer[0].shape[0] > 0:
3258 3258 for i in range(indDer[0].shape[0]):
3259 3259 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i]])
3260 3260 angAllCCF[indDer[0][i],indDer[1][i]+1:] += signo*2*numpy.pi
3261 3261
3262 3262 # fit = scipy.stats.linregress(numpy.array([-2,-1,1,2])*timeInterval, numpy.array([phaseLagN2s[i],phaseLagN1s[i],phaseLag1s[i],phaseLag2s[i]]))
3263 3263 for j in range(numPairs):
3264 3264 fit = stats.linregress(time, angAllCCF[j,:])
3265 3265 slopes[j] = fit[0]
3266 3266
3267 3267 #Remove Outlier
3268 3268 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3269 3269 # slopes = numpy.delete(slopes,indOut)
3270 3270 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3271 3271 # slopes = numpy.delete(slopes,indOut)
3272 3272
3273 3273 radialVelocity = -numpy.mean(slopes)*(0.25/numpy.pi)*(c/freq)
3274 3274 radialError = numpy.std(slopes)*(0.25/numpy.pi)*(c/freq)
3275 3275 meteorAux[-2] = radialError
3276 3276 meteorAux[-3] = radialVelocity
3277 3277
3278 3278 #Setting Error
3279 3279 #Number 15: Radial Drift velocity or projected horizontal velocity exceeds 200 m/s
3280 3280 if numpy.abs(radialVelocity) > 200:
3281 3281 meteorAux[-1] = 15
3282 3282 #Number 12: Poor fit to CCF variation for estimation of radial drift velocity
3283 3283 elif radialError > radialStdThresh:
3284 3284 meteorAux[-1] = 12
3285 3285
3286 3286 listMeteors1.append(meteorAux)
3287 3287 return listMeteors1
3288 3288
3289 3289 def __setNewArrays(self, listMeteors, date, heiRang):
3290 3290
3291 3291 #New arrays
3292 3292 arrayMeteors = numpy.array(listMeteors)
3293 3293 arrayParameters = numpy.zeros((len(listMeteors), 13))
3294 3294
3295 3295 #Date inclusion
3296 3296 # date = re.findall(r'\((.*?)\)', date)
3297 3297 # date = date[0].split(',')
3298 3298 # date = map(int, date)
3299 3299 #
3300 3300 # if len(date)<6:
3301 3301 # date.append(0)
3302 3302 #
3303 3303 # date = [date[0]*10000 + date[1]*100 + date[2], date[3]*10000 + date[4]*100 + date[5]]
3304 3304 # arrayDate = numpy.tile(date, (len(listMeteors), 1))
3305 3305 arrayDate = numpy.tile(date, (len(listMeteors)))
3306 3306
3307 3307 #Meteor array
3308 3308 # arrayMeteors[:,0] = heiRang[arrayMeteors[:,0].astype(int)]
3309 3309 # arrayMeteors = numpy.hstack((arrayDate, arrayMeteors))
3310 3310
3311 3311 #Parameters Array
3312 3312 arrayParameters[:,0] = arrayDate #Date
3313 3313 arrayParameters[:,1] = heiRang[arrayMeteors[:,0].astype(int)] #Range
3314 3314 arrayParameters[:,6:8] = arrayMeteors[:,-3:-1] #Radial velocity and its error
3315 3315 arrayParameters[:,8:12] = arrayMeteors[:,7:11] #Phases
3316 3316 arrayParameters[:,-1] = arrayMeteors[:,-1] #Error
3317 3317
3318 3318
3319 3319 return arrayParameters
3320 3320
3321 3321 class CorrectSMPhases(Operation):
3322 3322
3323 3323 def run(self, dataOut, phaseOffsets, hmin = 50, hmax = 150, azimuth = 45, channelPositions = None):
3324 3324
3325 3325 arrayParameters = dataOut.data_param
3326 3326 pairsList = []
3327 3327 pairx = (0,1)
3328 3328 pairy = (2,3)
3329 3329 pairsList.append(pairx)
3330 3330 pairsList.append(pairy)
3331 3331 jph = numpy.zeros(4)
3332 3332
3333 3333 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
3334 3334 # arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
3335 3335 arrayParameters[:,8:12] = numpy.angle(numpy.exp(1j*(arrayParameters[:,8:12] + phaseOffsets)))
3336 3336
3337 3337 meteorOps = SMOperations()
3338 3338 if channelPositions is None:
3339 3339 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3340 3340 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3341 3341
3342 3342 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3343 3343 h = (hmin,hmax)
3344 3344
3345 3345 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
3346 3346
3347 3347 dataOut.data_param = arrayParameters
3348 3348 return
3349 3349
3350 3350 class SMPhaseCalibration(Operation):
3351 3351
3352 3352 __buffer = None
3353 3353
3354 3354 __initime = None
3355 3355
3356 3356 __dataReady = False
3357 3357
3358 3358 __isConfig = False
3359 3359
3360 3360 def __checkTime(self, currentTime, initTime, paramInterval, outputInterval):
3361 3361
3362 3362 dataTime = currentTime + paramInterval
3363 3363 deltaTime = dataTime - initTime
3364 3364
3365 3365 if deltaTime >= outputInterval or deltaTime < 0:
3366 3366 return True
3367 3367
3368 3368 return False
3369 3369
3370 3370 def __getGammas(self, pairs, d, phases):
3371 3371 gammas = numpy.zeros(2)
3372 3372
3373 3373 for i in range(len(pairs)):
3374 3374
3375 3375 pairi = pairs[i]
3376 3376
3377 3377 phip3 = phases[:,pairi[0]]
3378 3378 d3 = d[pairi[0]]
3379 3379 phip2 = phases[:,pairi[1]]
3380 3380 d2 = d[pairi[1]]
3381 3381 #Calculating gamma
3382 3382 # jdcos = alp1/(k*d1)
3383 3383 # jgamma = numpy.angle(numpy.exp(1j*(d0*alp1/d1 - alp0)))
3384 3384 jgamma = -phip2*d3/d2 - phip3
3385 3385 jgamma = numpy.angle(numpy.exp(1j*jgamma))
3386 3386 # jgamma[jgamma>numpy.pi] -= 2*numpy.pi
3387 3387 # jgamma[jgamma<-numpy.pi] += 2*numpy.pi
3388 3388
3389 3389 #Revised distribution
3390 3390 jgammaArray = numpy.hstack((jgamma,jgamma+0.5*numpy.pi,jgamma-0.5*numpy.pi))
3391 3391
3392 3392 #Histogram
3393 3393 nBins = 64
3394 3394 rmin = -0.5*numpy.pi
3395 3395 rmax = 0.5*numpy.pi
3396 3396 phaseHisto = numpy.histogram(jgammaArray, bins=nBins, range=(rmin,rmax))
3397 3397
3398 3398 meteorsY = phaseHisto[0]
3399 3399 phasesX = phaseHisto[1][:-1]
3400 3400 width = phasesX[1] - phasesX[0]
3401 3401 phasesX += width/2
3402 3402
3403 3403 #Gaussian aproximation
3404 3404 bpeak = meteorsY.argmax()
3405 3405 peak = meteorsY.max()
3406 3406 jmin = bpeak - 5
3407 3407 jmax = bpeak + 5 + 1
3408 3408
3409 3409 if jmin<0:
3410 3410 jmin = 0
3411 3411 jmax = 6
3412 3412 elif jmax > meteorsY.size:
3413 3413 jmin = meteorsY.size - 6
3414 3414 jmax = meteorsY.size
3415 3415
3416 3416 x0 = numpy.array([peak,bpeak,50])
3417 3417 coeff = optimize.leastsq(self.__residualFunction, x0, args=(meteorsY[jmin:jmax], phasesX[jmin:jmax]))
3418 3418
3419 3419 #Gammas
3420 3420 gammas[i] = coeff[0][1]
3421 3421
3422 3422 return gammas
3423 3423
3424 3424 def __residualFunction(self, coeffs, y, t):
3425 3425
3426 3426 return y - self.__gauss_function(t, coeffs)
3427 3427
3428 3428 def __gauss_function(self, t, coeffs):
3429 3429
3430 3430 return coeffs[0]*numpy.exp(-0.5*((t - coeffs[1]) / coeffs[2])**2)
3431 3431
3432 3432 def __getPhases(self, azimuth, h, pairsList, d, gammas, meteorsArray):
3433 3433 meteorOps = SMOperations()
3434 3434 nchan = 4
3435 3435 pairx = pairsList[0] #x es 0
3436 3436 pairy = pairsList[1] #y es 1
3437 3437 center_xangle = 0
3438 3438 center_yangle = 0
3439 3439 range_angle = numpy.array([10*numpy.pi,numpy.pi,numpy.pi/2,numpy.pi/4])
3440 3440 ntimes = len(range_angle)
3441 3441
3442 3442 nstepsx = 20
3443 3443 nstepsy = 20
3444 3444
3445 3445 for iz in range(ntimes):
3446 3446 min_xangle = -range_angle[iz]/2 + center_xangle
3447 3447 max_xangle = range_angle[iz]/2 + center_xangle
3448 3448 min_yangle = -range_angle[iz]/2 + center_yangle
3449 3449 max_yangle = range_angle[iz]/2 + center_yangle
3450 3450
3451 3451 inc_x = (max_xangle-min_xangle)/nstepsx
3452 3452 inc_y = (max_yangle-min_yangle)/nstepsy
3453 3453
3454 3454 alpha_y = numpy.arange(nstepsy)*inc_y + min_yangle
3455 3455 alpha_x = numpy.arange(nstepsx)*inc_x + min_xangle
3456 3456 penalty = numpy.zeros((nstepsx,nstepsy))
3457 3457 jph_array = numpy.zeros((nchan,nstepsx,nstepsy))
3458 3458 jph = numpy.zeros(nchan)
3459 3459
3460 3460 # Iterations looking for the offset
3461 3461 for iy in range(int(nstepsy)):
3462 3462 for ix in range(int(nstepsx)):
3463 3463 d3 = d[pairsList[1][0]]
3464 3464 d2 = d[pairsList[1][1]]
3465 3465 d5 = d[pairsList[0][0]]
3466 3466 d4 = d[pairsList[0][1]]
3467 3467
3468 3468 alp2 = alpha_y[iy] #gamma 1
3469 3469 alp4 = alpha_x[ix] #gamma 0
3470 3470
3471 3471 alp3 = -alp2*d3/d2 - gammas[1]
3472 3472 alp5 = -alp4*d5/d4 - gammas[0]
3473 3473 # jph[pairy[1]] = alpha_y[iy]
3474 3474 # jph[pairy[0]] = -gammas[1] - alpha_y[iy]*d[pairy[1]]/d[pairy[0]]
3475 3475
3476 3476 # jph[pairx[1]] = alpha_x[ix]
3477 3477 # jph[pairx[0]] = -gammas[0] - alpha_x[ix]*d[pairx[1]]/d[pairx[0]]
3478 3478 jph[pairsList[0][1]] = alp4
3479 3479 jph[pairsList[0][0]] = alp5
3480 3480 jph[pairsList[1][0]] = alp3
3481 3481 jph[pairsList[1][1]] = alp2
3482 3482 jph_array[:,ix,iy] = jph
3483 3483 # d = [2.0,2.5,2.5,2.0]
3484 3484 #falta chequear si va a leer bien los meteoros
3485 3485 meteorsArray1 = meteorOps.getMeteorParams(meteorsArray, azimuth, h, pairsList, d, jph)
3486 3486 error = meteorsArray1[:,-1]
3487 3487 ind1 = numpy.where(error==0)[0]
3488 3488 penalty[ix,iy] = ind1.size
3489 3489
3490 3490 i,j = numpy.unravel_index(penalty.argmax(), penalty.shape)
3491 3491 phOffset = jph_array[:,i,j]
3492 3492
3493 3493 center_xangle = phOffset[pairx[1]]
3494 3494 center_yangle = phOffset[pairy[1]]
3495 3495
3496 3496 phOffset = numpy.angle(numpy.exp(1j*jph_array[:,i,j]))
3497 3497 phOffset = phOffset*180/numpy.pi
3498 3498 return phOffset
3499 3499
3500 3500
3501 3501 def run(self, dataOut, hmin, hmax, channelPositions=None, nHours = 1):
3502 3502
3503 3503 dataOut.flagNoData = True
3504 3504 self.__dataReady = False
3505 3505 dataOut.outputInterval = nHours*3600
3506 3506
3507 3507 if self.__isConfig == False:
3508 3508 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
3509 3509 #Get Initial LTC time
3510 3510 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
3511 3511 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
3512 3512
3513 3513 self.__isConfig = True
3514 3514
3515 3515 if self.__buffer is None:
3516 3516 self.__buffer = dataOut.data_param.copy()
3517 3517
3518 3518 else:
3519 3519 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
3520 3520
3521 3521 self.__dataReady = self.__checkTime(dataOut.utctime, self.__initime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
3522 3522
3523 3523 if self.__dataReady:
3524 3524 dataOut.utctimeInit = self.__initime
3525 3525 self.__initime += dataOut.outputInterval #to erase time offset
3526 3526
3527 3527 freq = dataOut.frequency
3528 3528 c = dataOut.C #m/s
3529 3529 lamb = c/freq
3530 3530 k = 2*numpy.pi/lamb
3531 3531 azimuth = 0
3532 3532 h = (hmin, hmax)
3533 3533 # pairs = ((0,1),(2,3)) #Estrella
3534 3534 # pairs = ((1,0),(2,3)) #T
3535 3535
3536 3536 if channelPositions is None:
3537 3537 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3538 3538 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3539 3539 meteorOps = SMOperations()
3540 3540 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3541 3541
3542 3542 #Checking correct order of pairs
3543 3543 pairs = []
3544 3544 if distances[1] > distances[0]:
3545 3545 pairs.append((1,0))
3546 3546 else:
3547 3547 pairs.append((0,1))
3548 3548
3549 3549 if distances[3] > distances[2]:
3550 3550 pairs.append((3,2))
3551 3551 else:
3552 3552 pairs.append((2,3))
3553 3553 # distances1 = [-distances[0]*lamb, distances[1]*lamb, -distances[2]*lamb, distances[3]*lamb]
3554 3554
3555 3555 meteorsArray = self.__buffer
3556 3556 error = meteorsArray[:,-1]
3557 3557 boolError = (error==0)|(error==3)|(error==4)|(error==13)|(error==14)
3558 3558 ind1 = numpy.where(boolError)[0]
3559 3559 meteorsArray = meteorsArray[ind1,:]
3560 3560 meteorsArray[:,-1] = 0
3561 3561 phases = meteorsArray[:,8:12]
3562 3562
3563 3563 #Calculate Gammas
3564 3564 gammas = self.__getGammas(pairs, distances, phases)
3565 3565 # gammas = numpy.array([-21.70409463,45.76935864])*numpy.pi/180
3566 3566 #Calculate Phases
3567 3567 phasesOff = self.__getPhases(azimuth, h, pairs, distances, gammas, meteorsArray)
3568 3568 phasesOff = phasesOff.reshape((1,phasesOff.size))
3569 3569 dataOut.data_output = -phasesOff
3570 3570 dataOut.flagNoData = False
3571 3571 self.__buffer = None
3572 3572
3573 3573
3574 3574 return
3575 3575
3576 3576 class SMOperations():
3577 3577
3578 3578 def __init__(self):
3579 3579
3580 3580 return
3581 3581
3582 3582 def getMeteorParams(self, arrayParameters0, azimuth, h, pairsList, distances, jph):
3583 3583
3584 3584 arrayParameters = arrayParameters0.copy()
3585 3585 hmin = h[0]
3586 3586 hmax = h[1]
3587 3587
3588 3588 #Calculate AOA (Error N 3, 4)
3589 3589 #JONES ET AL. 1998
3590 3590 AOAthresh = numpy.pi/8
3591 3591 error = arrayParameters[:,-1]
3592 3592 phases = -arrayParameters[:,8:12] + jph
3593 3593 # phases = numpy.unwrap(phases)
3594 3594 arrayParameters[:,3:6], arrayParameters[:,-1] = self.__getAOA(phases, pairsList, distances, error, AOAthresh, azimuth)
3595 3595
3596 3596 #Calculate Heights (Error N 13 and 14)
3597 3597 error = arrayParameters[:,-1]
3598 3598 Ranges = arrayParameters[:,1]
3599 3599 zenith = arrayParameters[:,4]
3600 3600 arrayParameters[:,2], arrayParameters[:,-1] = self.__getHeights(Ranges, zenith, error, hmin, hmax)
3601 3601
3602 3602 #----------------------- Get Final data ------------------------------------
3603 3603 # error = arrayParameters[:,-1]
3604 3604 # ind1 = numpy.where(error==0)[0]
3605 3605 # arrayParameters = arrayParameters[ind1,:]
3606 3606
3607 3607 return arrayParameters
3608 3608
3609 3609 def __getAOA(self, phases, pairsList, directions, error, AOAthresh, azimuth):
3610 3610
3611 3611 arrayAOA = numpy.zeros((phases.shape[0],3))
3612 3612 cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList,directions)
3613 3613
3614 3614 arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3615 3615 cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3616 3616 arrayAOA[:,2] = cosDirError
3617 3617
3618 3618 azimuthAngle = arrayAOA[:,0]
3619 3619 zenithAngle = arrayAOA[:,1]
3620 3620
3621 3621 #Setting Error
3622 3622 indError = numpy.where(numpy.logical_or(error == 3, error == 4))[0]
3623 3623 error[indError] = 0
3624 3624 #Number 3: AOA not fesible
3625 3625 indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3626 3626 error[indInvalid] = 3
3627 3627 #Number 4: Large difference in AOAs obtained from different antenna baselines
3628 3628 indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3629 3629 error[indInvalid] = 4
3630 3630 return arrayAOA, error
3631 3631
3632 3632 def __getDirectionCosines(self, arrayPhase, pairsList, distances):
3633 3633
3634 3634 #Initializing some variables
3635 3635 ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3636 3636 ang_aux = ang_aux.reshape(1,ang_aux.size)
3637 3637
3638 3638 cosdir = numpy.zeros((arrayPhase.shape[0],2))
3639 3639 cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3640 3640
3641 3641
3642 3642 for i in range(2):
3643 3643 ph0 = arrayPhase[:,pairsList[i][0]]
3644 3644 ph1 = arrayPhase[:,pairsList[i][1]]
3645 3645 d0 = distances[pairsList[i][0]]
3646 3646 d1 = distances[pairsList[i][1]]
3647 3647
3648 3648 ph0_aux = ph0 + ph1
3649 3649 ph0_aux = numpy.angle(numpy.exp(1j*ph0_aux))
3650 3650 # ph0_aux[ph0_aux > numpy.pi] -= 2*numpy.pi
3651 3651 # ph0_aux[ph0_aux < -numpy.pi] += 2*numpy.pi
3652 3652 #First Estimation
3653 3653 cosdir0[:,i] = (ph0_aux)/(2*numpy.pi*(d0 - d1))
3654 3654
3655 3655 #Most-Accurate Second Estimation
3656 3656 phi1_aux = ph0 - ph1
3657 3657 phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3658 3658 #Direction Cosine 1
3659 3659 cosdir1 = (phi1_aux + ang_aux)/(2*numpy.pi*(d0 + d1))
3660 3660
3661 3661 #Searching the correct Direction Cosine
3662 3662 cosdir0_aux = cosdir0[:,i]
3663 3663 cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3664 3664 #Minimum Distance
3665 3665 cosDiff = (cosdir1 - cosdir0_aux)**2
3666 3666 indcos = cosDiff.argmin(axis = 1)
3667 3667 #Saving Value obtained
3668 3668 cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3669 3669
3670 3670 return cosdir0, cosdir
3671 3671
3672 3672 def __calculateAOA(self, cosdir, azimuth):
3673 3673 cosdirX = cosdir[:,0]
3674 3674 cosdirY = cosdir[:,1]
3675 3675
3676 3676 zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3677 3677 azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth#0 deg north, 90 deg east
3678 3678 angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3679 3679
3680 3680 return angles
3681 3681
3682 3682 def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3683 3683
3684 3684 Ramb = 375 #Ramb = c/(2*PRF)
3685 3685 Re = 6371 #Earth Radius
3686 3686 heights = numpy.zeros(Ranges.shape)
3687 3687
3688 3688 R_aux = numpy.array([0,1,2])*Ramb
3689 3689 R_aux = R_aux.reshape(1,R_aux.size)
3690 3690
3691 3691 Ranges = Ranges.reshape(Ranges.size,1)
3692 3692
3693 3693 Ri = Ranges + R_aux
3694 3694 hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3695 3695
3696 3696 #Check if there is a height between 70 and 110 km
3697 3697 h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3698 3698 ind_h = numpy.where(h_bool == 1)[0]
3699 3699
3700 3700 hCorr = hi[ind_h, :]
3701 3701 ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3702 3702
3703 3703 hCorr = hi[ind_hCorr][:len(ind_h)]
3704 3704 heights[ind_h] = hCorr
3705 3705
3706 3706 #Setting Error
3707 3707 #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3708 3708 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3709 3709 indError = numpy.where(numpy.logical_or(error == 13, error == 14))[0]
3710 3710 error[indError] = 0
3711 3711 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3712 3712 error[indInvalid2] = 14
3713 3713 indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3714 3714 error[indInvalid1] = 13
3715 3715
3716 3716 return heights, error
3717 3717
3718 3718 def getPhasePairs(self, channelPositions):
3719 3719 chanPos = numpy.array(channelPositions)
3720 3720 listOper = list(itertools.combinations(list(range(5)),2))
3721 3721
3722 3722 distances = numpy.zeros(4)
3723 3723 axisX = []
3724 3724 axisY = []
3725 3725 distX = numpy.zeros(3)
3726 3726 distY = numpy.zeros(3)
3727 3727 ix = 0
3728 3728 iy = 0
3729 3729
3730 3730 pairX = numpy.zeros((2,2))
3731 3731 pairY = numpy.zeros((2,2))
3732 3732
3733 3733 for i in range(len(listOper)):
3734 3734 pairi = listOper[i]
3735 3735
3736 3736 posDif = numpy.abs(chanPos[pairi[0],:] - chanPos[pairi[1],:])
3737 3737
3738 3738 if posDif[0] == 0:
3739 3739 axisY.append(pairi)
3740 3740 distY[iy] = posDif[1]
3741 3741 iy += 1
3742 3742 elif posDif[1] == 0:
3743 3743 axisX.append(pairi)
3744 3744 distX[ix] = posDif[0]
3745 3745 ix += 1
3746 3746
3747 3747 for i in range(2):
3748 3748 if i==0:
3749 3749 dist0 = distX
3750 3750 axis0 = axisX
3751 3751 else:
3752 3752 dist0 = distY
3753 3753 axis0 = axisY
3754 3754
3755 3755 side = numpy.argsort(dist0)[:-1]
3756 3756 axis0 = numpy.array(axis0)[side,:]
3757 3757 chanC = int(numpy.intersect1d(axis0[0,:], axis0[1,:])[0])
3758 3758 axis1 = numpy.unique(numpy.reshape(axis0,4))
3759 3759 side = axis1[axis1 != chanC]
3760 3760 diff1 = chanPos[chanC,i] - chanPos[side[0],i]
3761 3761 diff2 = chanPos[chanC,i] - chanPos[side[1],i]
3762 3762 if diff1<0:
3763 3763 chan2 = side[0]
3764 3764 d2 = numpy.abs(diff1)
3765 3765 chan1 = side[1]
3766 3766 d1 = numpy.abs(diff2)
3767 3767 else:
3768 3768 chan2 = side[1]
3769 3769 d2 = numpy.abs(diff2)
3770 3770 chan1 = side[0]
3771 3771 d1 = numpy.abs(diff1)
3772 3772
3773 3773 if i==0:
3774 3774 chanCX = chanC
3775 3775 chan1X = chan1
3776 3776 chan2X = chan2
3777 3777 distances[0:2] = numpy.array([d1,d2])
3778 3778 else:
3779 3779 chanCY = chanC
3780 3780 chan1Y = chan1
3781 3781 chan2Y = chan2
3782 3782 distances[2:4] = numpy.array([d1,d2])
3783 3783 # axisXsides = numpy.reshape(axisX[ix,:],4)
3784 3784 #
3785 3785 # channelCentX = int(numpy.intersect1d(pairX[0,:], pairX[1,:])[0])
3786 3786 # channelCentY = int(numpy.intersect1d(pairY[0,:], pairY[1,:])[0])
3787 3787 #
3788 3788 # ind25X = numpy.where(pairX[0,:] != channelCentX)[0][0]
3789 3789 # ind20X = numpy.where(pairX[1,:] != channelCentX)[0][0]
3790 3790 # channel25X = int(pairX[0,ind25X])
3791 3791 # channel20X = int(pairX[1,ind20X])
3792 3792 # ind25Y = numpy.where(pairY[0,:] != channelCentY)[0][0]
3793 3793 # ind20Y = numpy.where(pairY[1,:] != channelCentY)[0][0]
3794 3794 # channel25Y = int(pairY[0,ind25Y])
3795 3795 # channel20Y = int(pairY[1,ind20Y])
3796 3796
3797 3797 # pairslist = [(channelCentX, channel25X),(channelCentX, channel20X),(channelCentY,channel25Y),(channelCentY, channel20Y)]
3798 3798 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
3799 3799
3800 3800 return pairslist, distances
3801 3801 # def __getAOA(self, phases, pairsList, error, AOAthresh, azimuth):
3802 3802 #
3803 3803 # arrayAOA = numpy.zeros((phases.shape[0],3))
3804 3804 # cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList)
3805 3805 #
3806 3806 # arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3807 3807 # cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3808 3808 # arrayAOA[:,2] = cosDirError
3809 3809 #
3810 3810 # azimuthAngle = arrayAOA[:,0]
3811 3811 # zenithAngle = arrayAOA[:,1]
3812 3812 #
3813 3813 # #Setting Error
3814 3814 # #Number 3: AOA not fesible
3815 3815 # indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3816 3816 # error[indInvalid] = 3
3817 3817 # #Number 4: Large difference in AOAs obtained from different antenna baselines
3818 3818 # indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3819 3819 # error[indInvalid] = 4
3820 3820 # return arrayAOA, error
3821 3821 #
3822 3822 # def __getDirectionCosines(self, arrayPhase, pairsList):
3823 3823 #
3824 3824 # #Initializing some variables
3825 3825 # ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3826 3826 # ang_aux = ang_aux.reshape(1,ang_aux.size)
3827 3827 #
3828 3828 # cosdir = numpy.zeros((arrayPhase.shape[0],2))
3829 3829 # cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3830 3830 #
3831 3831 #
3832 3832 # for i in range(2):
3833 3833 # #First Estimation
3834 3834 # phi0_aux = arrayPhase[:,pairsList[i][0]] + arrayPhase[:,pairsList[i][1]]
3835 3835 # #Dealias
3836 3836 # indcsi = numpy.where(phi0_aux > numpy.pi)
3837 3837 # phi0_aux[indcsi] -= 2*numpy.pi
3838 3838 # indcsi = numpy.where(phi0_aux < -numpy.pi)
3839 3839 # phi0_aux[indcsi] += 2*numpy.pi
3840 3840 # #Direction Cosine 0
3841 3841 # cosdir0[:,i] = -(phi0_aux)/(2*numpy.pi*0.5)
3842 3842 #
3843 3843 # #Most-Accurate Second Estimation
3844 3844 # phi1_aux = arrayPhase[:,pairsList[i][0]] - arrayPhase[:,pairsList[i][1]]
3845 3845 # phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3846 3846 # #Direction Cosine 1
3847 3847 # cosdir1 = -(phi1_aux + ang_aux)/(2*numpy.pi*4.5)
3848 3848 #
3849 3849 # #Searching the correct Direction Cosine
3850 3850 # cosdir0_aux = cosdir0[:,i]
3851 3851 # cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3852 3852 # #Minimum Distance
3853 3853 # cosDiff = (cosdir1 - cosdir0_aux)**2
3854 3854 # indcos = cosDiff.argmin(axis = 1)
3855 3855 # #Saving Value obtained
3856 3856 # cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3857 3857 #
3858 3858 # return cosdir0, cosdir
3859 3859 #
3860 3860 # def __calculateAOA(self, cosdir, azimuth):
3861 3861 # cosdirX = cosdir[:,0]
3862 3862 # cosdirY = cosdir[:,1]
3863 3863 #
3864 3864 # zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3865 3865 # azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth #0 deg north, 90 deg east
3866 3866 # angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3867 3867 #
3868 3868 # return angles
3869 3869 #
3870 3870 # def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3871 3871 #
3872 3872 # Ramb = 375 #Ramb = c/(2*PRF)
3873 3873 # Re = 6371 #Earth Radius
3874 3874 # heights = numpy.zeros(Ranges.shape)
3875 3875 #
3876 3876 # R_aux = numpy.array([0,1,2])*Ramb
3877 3877 # R_aux = R_aux.reshape(1,R_aux.size)
3878 3878 #
3879 3879 # Ranges = Ranges.reshape(Ranges.size,1)
3880 3880 #
3881 3881 # Ri = Ranges + R_aux
3882 3882 # hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3883 3883 #
3884 3884 # #Check if there is a height between 70 and 110 km
3885 3885 # h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3886 3886 # ind_h = numpy.where(h_bool == 1)[0]
3887 3887 #
3888 3888 # hCorr = hi[ind_h, :]
3889 3889 # ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3890 3890 #
3891 3891 # hCorr = hi[ind_hCorr]
3892 3892 # heights[ind_h] = hCorr
3893 3893 #
3894 3894 # #Setting Error
3895 3895 # #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3896 3896 # #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3897 3897 #
3898 3898 # indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3899 3899 # error[indInvalid2] = 14
3900 3900 # indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3901 3901 # error[indInvalid1] = 13
3902 3902 #
3903 3903 # return heights, error
3904 3904
3905 3905
3906 3906 class WeatherRadar(Operation):
3907 3907 '''
3908 3908 Function tat implements Weather Radar operations-
3909 3909 Input:
3910 3910 Output:
3911 3911 Parameters affected:
3912 3912 '''
3913 3913 isConfig = False
3914 3914
3915 3915 def __init__(self):
3916 3916 Operation.__init__(self)
3917 3917
3918 3918 def setup(self,dataOut,Pt=0,Gt=0,Gr=0,lambda_=0, aL=0,
3919 3919 tauW= 0,thetaT=0,thetaR=0,Km =0):
3920 3920 self.nCh = dataOut.nChannels
3921 3921 self.nHeis = dataOut.nHeights
3922 3922 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
3923 3923 self.Range = numpy.arange(dataOut.nHeights)*deltaHeight + dataOut.heightList[0]
3924 3924 self.Range = self.Range.reshape(1,self.nHeis)
3925 3925 self.Range = numpy.tile(self.Range,[self.nCh,1])
3926 3926 '''-----------1 Constante del Radar----------'''
3927 3927 self.Pt = Pt
3928 3928 self.Gt = Gt
3929 3929 self.Gr = Gr
3930 3930 self.lambda_ = lambda_
3931 3931 self.aL = aL
3932 3932 self.tauW = tauW
3933 3933 self.thetaT = thetaT
3934 3934 self.thetaR = thetaR
3935 3935 self.Km = Km
3936 3936 Numerator = ((4*numpy.pi)**3 * aL**2 * 16 *numpy.log(2))
3937 3937 Denominator = (Pt * Gt * Gr * lambda_**2 * SPEED_OF_LIGHT * tauW * numpy.pi*thetaT*thetaR)
3938 3938 self.RadarConstant = Numerator/Denominator
3939 3939 '''-----------2 Reflectividad del Radar y Factor de Reflectividad------'''
3940 3940 self.n_radar = numpy.zeros((self.nCh,self.nHeis))
3941 3941 self.Z_radar = numpy.zeros((self.nCh,self.nHeis))
3942 3942
3943 3943 def setMoments(self,dataOut,i):
3944 3944
3945 3945 type = dataOut.inputUnit
3946 3946 nCh = dataOut.nChannels
3947 3947 nHeis= dataOut.nHeights
3948 3948 data_param = numpy.zeros((nCh,4,nHeis))
3949 3949 if type == "Voltage":
3950 3950 data_param[:,0,:] = dataOut.dataPP_POW/(dataOut.nCohInt**2)
3951 3951 data_param[:,1,:] = dataOut.dataPP_DOP
3952 3952 data_param[:,2,:] = dataOut.dataPP_WIDTH
3953 3953 data_param[:,3,:] = dataOut.dataPP_SNR
3954 3954 if type == "Spectra":
3955 3955 data_param[:,0,:] = dataOut.data_POW
3956 3956 data_param[:,1,:] = dataOut.data_DOP
3957 3957 data_param[:,2,:] = dataOut.data_WIDTH
3958 3958 def setMoments(self,dataOut,i):
3959 3959 data_param[:,3,:] = dataOut.data_SNR
3960 3960
3961 3961 return data_param[:,i,:]
3962 3962
3963 3963
3964 3964 def run(self,dataOut,Pt=25,Gt=200.0,Gr=50.0,lambda_=0.32, aL=2.5118,
3965 3965 tauW= 4.0e-6,thetaT=0.165,thetaR=0.367,Km =0.93):
3966 3966
3967 3967 if not self.isConfig:
3968 3968 self.setup(dataOut= dataOut,Pt=25,Gt=200.0,Gr=50.0,lambda_=0.32, aL=2.5118,
3969 3969 tauW= 4.0e-6,thetaT=0.165,thetaR=0.367,Km =0.93)
3970 3970 self.isConfig = True
3971 3971 '''-----------------------------Potencia de Radar -Signal S-----------------------------'''
3972 3972 Pr = self.setMoments(dataOut,0)
3973 3973
3974 3974 for R in range(self.nHeis):
3975 3975 self.n_radar[:,R] = self.RadarConstant*Pr[:,R]* (self.Range[:,R])**2
3976 3976
3977 3977 self.Z_radar[:,R] = self.n_radar[:,R]* self.lambda_**4/( numpy.pi**5 * self.Km**2)
3978 3978
3979 3979 '''----------- Factor de Reflectividad Equivalente lamda_ < 10 cm , lamda_= 3.2cm-------'''
3980 3980 Zeh = self.Z_radar
3981 3981 dBZeh = 10*numpy.log10(Zeh)
3982 3982 dataOut.factor_Zeh= dBZeh
3983 3983 self.n_radar = numpy.zeros((self.nCh,self.nHeis))
3984 3984 self.Z_radar = numpy.zeros((self.nCh,self.nHeis))
3985 3985
3986 3986 return dataOut
3987 3987
3988 3988 class PedestalInformation(Operation):
3989 3989 path_ped = None
3990 3990 path_adq = None
3991 3991 t_Interval_p = None
3992 3992 n_Muestras_p = None
3993 3993 isConfig = False
3994 3994 blocksPerfile= None
3995 3995 f_a_p = None
3996 3996 online = None
3997 3997 angulo_adq = None
3998 3998 nro_file = None
3999 3999 nro_key_p = None
4000 4000 tmp = None
4001 4001
4002 4002
4003 4003 def __init__(self):
4004 4004 Operation.__init__(self)
4005 4005
4006 4006 def getfirstFilefromPath(self,path,meta,ext):
4007 4007 validFilelist = []
4008 4008 #print("SEARH",path)
4009 4009 try:
4010 4010 fileList = os.listdir(path)
4011 4011 except:
4012 4012 print("check path - fileList")
4013 4013 if len(fileList)<1:
4014 4014 return None
4015 4015 # meta 1234 567 8-18 BCDE
4016 4016 # H,D,PE YYYY DDD EPOC .ext
4017 4017
4018 4018 for thisFile in fileList:
4019 4019 #print("HI",thisFile)
4020 4020 if meta =="PE":
4021 4021 try:
4022 4022 number= int(thisFile[len(meta)+7:len(meta)+17])
4023 4023 except:
4024 4024 print("There is a file or folder with different format")
4025 4025 if meta == "D":
4026 4026 try:
4027 4027 number= int(thisFile[8:11])
4028 4028 except:
4029 4029 print("There is a file or folder with different format")
4030 4030
4031 4031 if not isNumber(str=number):
4032 4032 continue
4033 4033 if (os.path.splitext(thisFile)[-1].lower() != ext.lower()):
4034 4034 continue
4035 4035 validFilelist.sort()
4036 4036 validFilelist.append(thisFile)
4037 4037 if len(validFilelist)>0:
4038 4038 validFilelist = sorted(validFilelist,key=str.lower)
4039 4039 return validFilelist
4040 4040 return None
4041 4041
4042 4042 def gettimeutcfromDirFilename(self,path,file):
4043 4043 dir_file= path+"/"+file
4044 4044 fp = h5py.File(dir_file,'r')
4045 4045 #epoc = fp['Metadata'].get('utctimeInit')[()]
4046 4046 epoc = fp['Data'].get('utc')[()]
4047 4047 fp.close()
4048 4048 return epoc
4049 4049
4050 4050 def gettimeutcadqfromDirFilename(self,path,file):
4051 4051 dir_file= path+"/"+file
4052 4052 fp = h5py.File(dir_file,'r')
4053 4053 epoc = fp['Metadata'].get('utctimeInit')[()]
4054 4054 #epoc = fp['Data'].get('utc')[()]
4055 4055 fp.close()
4056 4056 return epoc
4057 4057
4058 4058 def getDatavaluefromDirFilename(self,path,file,value):
4059 4059 dir_file= path+"/"+file
4060 4060 fp = h5py.File(dir_file,'r')
4061 4061 array = fp['Data'].get(value)[()]
4062 4062 fp.close()
4063 4063 return array
4064 4064
4065 4065 def getFile_KeyP(self,list_pedestal,list_adq):
4066 4066 print(list_pedestal)
4067 4067 print(list_adq)
4068 4068
4069 4069 def getNROFile(self,utc_adq,utc_ped_list):
4070 4070 c=0
4071 4071 print("insidegetNROFile")
4072 4072 print(utc_adq)
4073 4073 print(len(utc_ped_list))
4074 4074 for i in range(len(utc_ped_list)):
4075 4075 if utc_adq>utc_ped_list[i]:
4076 4076 #print("mayor")
4077 4077 #print("utc_ped_list",utc_ped_list[i])
4078 4078 c +=1
4079 4079
4080 4080 return c-1,utc_ped_list[c-1],utc_ped_list[c]
4081 4081
4082 4082 def verificarNROFILE(self,dataOut,utc_ped,f_a_p,n_Muestras_p):
4083 4083 var =int(f_a_p/n_Muestras_p)
4084 4084 flag=0
4085 4085 for i in range(var):
4086 4086 if dataOut.utctime+i==utc_ped:
4087 4087 flag==1
4088 4088 break
4089 4089 return flag
4090 4090
4091 4091 #def setup_offline(self,dataOut,list_pedestal,list_adq):
4092 4092 def setup_offline(self,dataOut,list_pedestal):
4093 4093
4094 4094 print("SETUP OFFLINE")
4095 4095 print(self.path_ped)
4096 4096 #print(self.path_adq)
4097 4097 print(len(self.list_pedestal))
4098 4098 #print(len(self.list_adq))
4099 4099 utc_ped_list=[]
4100 4100 for i in range(len(self.list_pedestal)):
4101 4101 #print(i)# OJO IDENTIFICADOR DE SINCRONISMO
4102 4102 utc_ped_list.append(self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[i]))
4103 4103
4104 4104 #utc_ped_list= utc_ped_list
4105 4105 ###utc_adq = self.gettimeutcadqfromDirFilename(path=self.path_adq,file=self.list_adq[0])
4106 4106 print("dios existe donde esta")
4107 4107
4108 4108 #print("utc_ped_list",utc_ped_list)
4109 4109 ###print("utc_adq",utc_adq)
4110 4110 # utc_adq_dataOut
4111 4111 utc_adq_dataOut =dataOut.utctime
4112 4112 print("Offline-utc_adq_dataout",utc_adq_dataOut)
4113 4113
4114 4114 nro_file,utc_ped,utc_ped_1 = self.getNROFile(utc_adq=utc_adq_dataOut, utc_ped_list= utc_ped_list)
4115 4115
4116 4116 print("nro_file",nro_file,"utc_ped",utc_ped)
4117 4117 print("nro_file",i)
4118 4118 nro_key_p = int((utc_adq_dataOut-utc_ped)/self.t_Interval_p)-1 # ojito al -1 estimado alex
4119 4119 print("nro_key_p",nro_key_p)
4120 4120
4121 4121 ff_pedestal = self.list_pedestal[nro_file]
4122 4122 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4123 4123 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4124 4124
4125 4125 print("utc_pedestal_init :",utc_ped+nro_key_p*self.t_Interval_p)
4126 4126 print("angulo_array :",angulo[nro_key_p])
4127 4127 self.nro_file = nro_file
4128 4128 self.nro_key_p = nro_key_p
4129 4129
4130 4130 def setup_online(self,dataOut):
4131 4131 utc_adq =dataOut.utctime
4132 4132 print("Online-utc_adq",utc_adq)
4133 4133 print(len(self.list_pedestal))
4134 4134 utc_ped_list=[]
4135 4135 for i in range(len(self.list_pedestal)):
4136 4136 utc_ped_list.append(self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[i]))
4137 4137 print(utc_ped_list[:20])
4138 4138 #print(utc_ped_list[488:498])
4139 4139 print("ultimo UTC-PEDESTAL",utc_ped_list[-1])
4140 4140 nro_file,utc_ped,utc_ped_1 = self.getNROFile(utc_adq=utc_adq, utc_ped_list= utc_ped_list)
4141 4141 print("nro_file",nro_file,"utc_ped",utc_ped,"utc_ped_1",utc_ped_1)
4142 4142 print("name_PEDESTAL",self.list_pedestal[nro_file])
4143 4143 nro_key_p = int((utc_adq-utc_ped)/self.t_Interval_p)-1
4144 4144 print("nro_key_p",nro_key_p)
4145 4145 ff_pedestal = self.list_pedestal[nro_file]
4146 4146 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4147 4147 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4148 4148
4149 4149 print("utc_pedestal_init :",utc_ped+nro_key_p*self.t_Interval_p)
4150 4150 print("angulo_array :",angulo[nro_key_p])
4151 4151 self.nro_file = nro_file
4152 4152 self.nro_key_p = nro_key_p
4153 4153
4154 4154 #def setup(self,dataOut,path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4155 4155 def setup(self,dataOut,path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4156 4156 print("SETUP PEDESTAL")
4157 4157 self.__dataReady = False
4158 4158 self.path_ped = path_ped
4159 4159 #self.path_adq = path_adq
4160 4160 self.t_Interval_p = t_Interval_p
4161 4161 self.n_Muestras_p = n_Muestras_p
4162 4162 self.blocksPerfile= blocksPerfile
4163 4163 self.f_a_p = f_a_p
4164 4164 self.online = online
4165 4165 self.angulo_adq = numpy.zeros(self.blocksPerfile)
4166 4166 self.__profIndex = 0
4167 4167 self.tmp = 0
4168 4168 self.c_ped = 0
4169 4169 print(self.path_ped)
4170 4170 #print(self.path_adq)
4171 4171 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4172 4172 print("LIST NEW", self.list_pedestal[:20])
4173 4173 #self.list_adq = self.getfirstFilefromPath(path=self.path_adq,meta="D",ext=".hdf5")
4174 4174 print("*************Longitud list pedestal****************",len(self.list_pedestal))
4175 4175
4176 4176 if self.online:
4177 4177 print("Enable Online")
4178 4178 self.setup_online(dataOut)
4179 4179 else:
4180 4180 #self.setup_offline(dataOut,list_pedestal=self.list_pedestal,list_adq=self.list_adq)
4181 4181 self.setup_offline(dataOut,list_pedestal=self.list_pedestal)
4182 4182
4183 4183
4184 4184 def setNextFileP(self,dataOut):
4185 4185 if self.online:
4186 4186 data_pedestal = self.setNextFileonline()
4187 4187 else:
4188 4188 data_pedestal = self.setNextFileoffline(dataOut)
4189 4189
4190 4190 return data_pedestal
4191 4191
4192 4192
4193 4193 def setNextFileoffline(self,dataOut):
4194 4194 ##tmp=0
4195 4195 for j in range(self.blocksPerfile):
4196 4196 ###print("NUMERO DEL BLOQUE---->",j)
4197 4197 ###print("nro_key_p",self.nro_key_p)
4198 4198
4199 4199 #iterador = self.nro_key_p +self.f_a_p*(j-tmp)
4200 4200 iterador = self.nro_key_p +self.f_a_p*self.c_ped
4201 4201 self.c_ped = self.c_ped +1
4202 4202
4203 4203 print("iterador------------->",iterador)
4204 4204 if iterador < self.n_Muestras_p:
4205 4205 self.nro_file = self.nro_file
4206 4206 else:
4207 4207 self.nro_file = self.nro_file+1
4208 4208 print("PRUEBA-------------")
4209 4209 utc_ped_setnext=self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[self.nro_file])
4210 4210 utc_adq_setnext=dataOut.utctime
4211 4211 print("utc_pedestal",utc_ped_setnext)
4212 4212 print("utc_adq",utc_adq_setnext)
4213 4213
4214 4214 print("self.c_ped",self.c_ped)
4215 4215 #dif = self.blocksPerfile-(self.nro_key_p+self.f_a_p*(self.c_ped-2))
4216 4216 dif = self.n_Muestras_p-(self.nro_key_p+self.f_a_p*(self.c_ped-2))
4217 4217
4218 4218 self.c_ped = 1
4219 4219 ##tmp = j
4220 4220 ##print("tmp else",tmp)
4221 4221 self.nro_key_p= self.f_a_p-dif
4222 4222 iterador = self.nro_key_p
4223 4223 print("iterador else",iterador)
4224 4224 #self.c_ped = self.c_ped +1
4225 4225
4226 4226 print("nro_file",self.nro_file)
4227 4227 #print("tmp",tmp)
4228 4228 try:
4229 4229 ff_pedestal = self.list_pedestal[self.nro_file]
4230 4230 print("ff_pedestal",ff_pedestal)
4231 4231 except:
4232 4232 print("############# EXCEPCION ######################")
4233 4233 return numpy.ones(self.blocksPerfile)*numpy.nan
4234 4234
4235 4235 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4236 4236 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4237 4237
4238 4238 self.angulo_adq[j]= angulo[iterador]
4239 4239
4240 4240 return self.angulo_adq
4241 4241
4242 4242 def setNextFileonline(self):
4243 4243 tmp = 0
4244 4244 self.nTries_p = 3
4245 4245 self.delay = 3
4246 4246 ready = 1
4247 4247 for j in range(self.blocksPerfile):
4248 4248 iterador = self.nro_key_p +self.f_a_p*(j-tmp)
4249 4249 if iterador < self.n_Muestras_p:
4250 4250 self.nro_file = self.nro_file
4251 4251 else:
4252 4252 self.nro_file = self.nro_file+1
4253 4253 dif = self.blocksPerfile-(self.nro_key_p+self.f_a_p*(j-tmp-1))
4254 4254 tmp = j
4255 4255 self.nro_key_p= self.f_a_p-dif
4256 4256 iterador = self.nro_key_p
4257 4257 #print("nro_file---------------- :",self.nro_file)
4258 4258 try:
4259 4259 # update list_pedestal
4260 4260 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4261 4261 ff_pedestal = self.list_pedestal[self.nro_file]
4262 4262 except:
4263 4263 ff_pedestal = None
4264 4264 ready = 0
4265 4265 for nTries_p in range(self.nTries_p):
4266 4266 try:
4267 4267 # update list_pedestal
4268 4268 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4269 4269 ff_pedestal = self.list_pedestal[self.nro_file]
4270 4270 except:
4271 4271 ff_pedestal = None
4272 4272 if ff_pedestal is not None:
4273 4273 ready=1
4274 4274 break
4275 4275 log.warning("Waiting %0.2f sec for the next file: \"%s\" , try %02d ..." % (self.delay, self.nro_file, nTries_p + 1))
4276 4276 time.sleep(self.delay)
4277 4277 continue
4278 4278 #return numpy.ones(self.blocksPerfile)*numpy.nan
4279 4279
4280 4280 if ready == 1:
4281 4281 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4282 4282 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4283 4283
4284 4284 else:
4285 4285 print("there is no pedestal file")
4286 4286 angulo = numpy.ones(self.n_Muestras_p)*numpy.nan
4287 4287 self.angulo_adq[j]= angulo[iterador]
4288 4288 ####print("Angulo",self.angulo_adq)
4289 4289 ####print("Angulo",len(self.angulo_adq))
4290 4290 #self.nro_key_p=iterador + self.f_a_p
4291 4291 #if self.nro_key_p< self.n_Muestras_p:
4292 4292 # self.nro_file = self.nro_file
4293 4293 #else:
4294 4294 # self.nro_file = self.nro_file+1
4295 4295 # self.nro_key_p= self.nro_key_p
4296 4296 return self.angulo_adq
4297 4297
4298 4298
4299 4299 #def run(self, dataOut,path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4300 4300 def run(self, dataOut,path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4301 4301
4302 4302 if not self.isConfig:
4303 4303 print("######################SETUP#########################################")
4304 4304 #self.setup( dataOut, path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online)
4305 4305 self.setup( dataOut, path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online)
4306 4306 self.isConfig = True
4307 4307
4308 4308 dataOut.flagNoData = True
4309 print("profIndex",self.__profIndex)
4309 ###print("profIndex",self.__profIndex)
4310 4310
4311 4311 if self.__profIndex==0:
4312 4312 angulo_adq = self.setNextFileP(dataOut)
4313 4313 dataOut.azimuth = angulo_adq
4314 print("TIEMPO:",dataOut.utctime)
4314 ######print("TIEMPO:",dataOut.utctime)
4315 4315 ##print("####################################################################")
4316 print("angulos",dataOut.azimuth,len(dataOut.azimuth))
4316 ######print("angulos",dataOut.azimuth,len(dataOut.azimuth))
4317 4317 self.__dataReady = True
4318 4318 self.__profIndex += 1
4319 print("TIEMPO_bucle:",dataOut.utctime)
4320 print("profIndex",self.__profIndex)
4319 ####print("TIEMPO_bucle:",dataOut.utctime)
4320 ####print("profIndex",self.__profIndex)
4321 4321 if self.__profIndex== blocksPerfile:
4322 4322 self.__profIndex = 0
4323 4323 if self.__dataReady:
4324 4324 #print(self.__profIndex,dataOut.azimuth[:10])
4325 4325 dataOut.flagNoData = False
4326 4326 return dataOut
4327 4327
4328 4328
4329 4329 class Block360(Operation):
4330 4330 '''
4331 4331 '''
4332 4332 isConfig = False
4333 4333 __profIndex = 0
4334 4334 __initime = None
4335 4335 __lastdatatime = None
4336 4336 __buffer = None
4337 4337 __dataReady = False
4338 4338 n = None
4339 4339 __nch = 0
4340 4340 __nHeis = 0
4341 4341 index = 0
4342 4342 mode = 0
4343 4343
4344 4344 def __init__(self,**kwargs):
4345 4345 Operation.__init__(self,**kwargs)
4346 4346
4347 4347 def setup(self, dataOut, n = None, mode = None):
4348 4348 '''
4349 4349 n= Numero de PRF's de entrada
4350 4350 '''
4351 4351 self.__initime = None
4352 4352 self.__lastdatatime = 0
4353 4353 self.__dataReady = False
4354 4354 self.__buffer = 0
4355 4355 self.__buffer_1D = 0
4356 4356 self.__profIndex = 0
4357 4357 self.index = 0
4358 4358 self.__nch = dataOut.nChannels
4359 4359 self.__nHeis = dataOut.nHeights
4360 4360 ##print("ELVALOR DE n es:", n)
4361 4361 if n == None:
4362 4362 raise ValueError("n should be specified.")
4363 4363
4364 4364 if mode == None:
4365 4365 raise ValueError("mode should be specified.")
4366 4366
4367 4367 if n != None:
4368 4368 if n<1:
4369 4369 print("n should be greater than 2")
4370 4370 raise ValueError("n should be greater than 2")
4371 4371
4372 4372 self.n = n
4373 4373 self.mode = mode
4374 4374 print("self.mode",self.mode)
4375 4375 #print("nHeights")
4376 4376 self.__buffer = numpy.zeros(( dataOut.nChannels,n, dataOut.nHeights))
4377 4377 self.__buffer2= numpy.zeros(n)
4378 4378
4379 4379 def putData(self,data,mode):
4380 4380 '''
4381 4381 Add a profile to he __buffer and increase in one the __profiel Index
4382 4382 '''
4383 4383 #print("line 4049",data.dataPP_POW.shape,data.dataPP_POW[:10])
4384 4384 #print("line 4049",data.azimuth.shape,data.azimuth)
4385 4385 if self.mode==0:
4386 4386 self.__buffer[:,self.__profIndex,:]= data.dataPP_POWER# PRIMER MOMENTO
4387 4387 if self.mode==1:
4388 4388 self.__buffer[:,self.__profIndex,:]= data.data_pow
4389 4389 #print("me casi",self.index,data.azimuth[self.index])
4390 4390 #print(self.__profIndex, self.index , data.azimuth[self.index] )
4391 4391 #print("magic",data.profileIndex)
4392 4392 #print(data.azimuth[self.index])
4393 4393 #print("index",self.index)
4394 4394
4395 4395 self.__buffer2[self.__profIndex] = data.azimuth[self.index]
4396 4396 #print("q pasa")
4397 4397 self.index+=1
4398 4398 #print("index",self.index,data.azimuth[:10])
4399 4399 self.__profIndex += 1
4400 4400 return #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Remove DCΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
4401 4401
4402 4402 def pushData(self,data):
4403 4403 '''
4404 4404 Return the PULSEPAIR and the profiles used in the operation
4405 4405 Affected : self.__profileIndex
4406 4406 '''
4407 4407 #print("pushData")
4408 4408
4409 4409 data_360 = self.__buffer
4410 4410 data_p = self.__buffer2
4411 4411 n = self.__profIndex
4412 4412
4413 4413 self.__buffer = numpy.zeros((self.__nch, self.n,self.__nHeis))
4414 4414 self.__buffer2 = numpy.zeros(self.n)
4415 4415 self.__profIndex = 0
4416 4416 #print("pushData")
4417 4417 return data_360,n,data_p
4418 4418
4419 4419
4420 4420 def byProfiles(self,dataOut):
4421 4421
4422 4422 self.__dataReady = False
4423 4423 data_360 = None
4424 4424 data_p = None
4425 4425 #print("dataOu",dataOut.dataPP_POW)
4426 4426 self.putData(data=dataOut,mode = self.mode)
4427 4427 #print("profIndex",self.__profIndex)
4428 4428 if self.__profIndex == self.n:
4429 4429 data_360,n,data_p = self.pushData(data=dataOut)
4430 4430 self.__dataReady = True
4431 4431
4432 4432 return data_360,data_p
4433 4433
4434 4434
4435 4435 def blockOp(self, dataOut, datatime= None):
4436 4436 if self.__initime == None:
4437 4437 self.__initime = datatime
4438 4438 data_360,data_p = self.byProfiles(dataOut)
4439 4439 self.__lastdatatime = datatime
4440 4440
4441 4441 if data_360 is None:
4442 4442 return None, None,None
4443 4443
4444 4444 avgdatatime = self.__initime
4445 4445 deltatime = datatime - self.__lastdatatime
4446 4446 self.__initime = datatime
4447 4447 #print(data_360.shape,avgdatatime,data_p.shape)
4448 4448 return data_360,avgdatatime,data_p
4449 4449
4450 4450 def run(self, dataOut,n = None,mode=None,**kwargs):
4451 print("BLOCK 360 HERE WE GO MOMENTOS")
4451 ####print("BLOCK 360 HERE WE GO MOMENTOS")
4452 4452 if not self.isConfig:
4453 4453 self.setup(dataOut = dataOut, n = n ,mode= mode ,**kwargs)
4454 4454 self.index = 0
4455 4455 #print("comova",self.isConfig)
4456 4456 self.isConfig = True
4457 4457 if self.index==dataOut.azimuth.shape[0]:
4458 4458 self.index=0
4459 4459 data_360, avgdatatime,data_p = self.blockOp(dataOut, dataOut.utctime)
4460 4460 dataOut.flagNoData = True
4461 4461
4462 4462 if self.__dataReady:
4463 4463 dataOut.data_360 = data_360 # S
4464 4464 ##print("---------------------------------------------------------------------------------")
4465 4465 ##print("---------------------------DATAREADY---------------------------------------------")
4466 4466 ##print("---------------------------------------------------------------------------------")
4467 4467 ##print("data_360",dataOut.data_360.shape)
4468 4468 dataOut.data_azi = data_p
4469 4469 ##print("azi: ",dataOut.data_azi)
4470 4470 #print("jroproc_parameters",data_p[0],data_p[-1])#,data_360.shape,avgdatatime)
4471 4471 dataOut.utctime = avgdatatime
4472 4472 dataOut.flagNoData = False
4473 4473 return dataOut
@@ -1,1628 +1,1627
1 1 import sys
2 2 import numpy,math
3 3 from scipy import interpolate
4 4 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
5 5 from schainpy.model.data.jrodata import Voltage,hildebrand_sekhon
6 6 from schainpy.utils import log
7 7 from time import time
8 8
9 9
10 10
11 11 class VoltageProc(ProcessingUnit):
12 12
13 13 def __init__(self):
14 14
15 15 ProcessingUnit.__init__(self)
16 16
17 17 self.dataOut = Voltage()
18 18 self.flip = 1
19 19 self.setupReq = False
20 20
21 21 def run(self):
22 22
23 23 if self.dataIn.type == 'AMISR':
24 24 self.__updateObjFromAmisrInput()
25 25
26 26 if self.dataIn.type == 'Voltage':
27 27 self.dataOut.copy(self.dataIn)
28 28
29 29 def __updateObjFromAmisrInput(self):
30 30
31 31 self.dataOut.timeZone = self.dataIn.timeZone
32 32 self.dataOut.dstFlag = self.dataIn.dstFlag
33 33 self.dataOut.errorCount = self.dataIn.errorCount
34 34 self.dataOut.useLocalTime = self.dataIn.useLocalTime
35 35
36 36 self.dataOut.flagNoData = self.dataIn.flagNoData
37 37 self.dataOut.data = self.dataIn.data
38 38 self.dataOut.utctime = self.dataIn.utctime
39 39 self.dataOut.channelList = self.dataIn.channelList
40 40 #self.dataOut.timeInterval = self.dataIn.timeInterval
41 41 self.dataOut.heightList = self.dataIn.heightList
42 42 self.dataOut.nProfiles = self.dataIn.nProfiles
43 43
44 44 self.dataOut.nCohInt = self.dataIn.nCohInt
45 45 self.dataOut.ippSeconds = self.dataIn.ippSeconds
46 46 self.dataOut.frequency = self.dataIn.frequency
47 47
48 48 self.dataOut.azimuth = self.dataIn.azimuth
49 49 self.dataOut.zenith = self.dataIn.zenith
50 50
51 51 self.dataOut.beam.codeList = self.dataIn.beam.codeList
52 52 self.dataOut.beam.azimuthList = self.dataIn.beam.azimuthList
53 53 self.dataOut.beam.zenithList = self.dataIn.beam.zenithList
54 54
55 55
56 56 class selectChannels(Operation):
57 57
58 58 def run(self, dataOut, channelList):
59 59
60 60 channelIndexList = []
61 61 self.dataOut = dataOut
62 62 for channel in channelList:
63 63 if channel not in self.dataOut.channelList:
64 64 raise ValueError("Channel %d is not in %s" %(channel, str(self.dataOut.channelList)))
65 65
66 66 index = self.dataOut.channelList.index(channel)
67 67 channelIndexList.append(index)
68 68 self.selectChannelsByIndex(channelIndexList)
69 69 return self.dataOut
70 70
71 71 def selectChannelsByIndex(self, channelIndexList):
72 72 """
73 73 Selecciona un bloque de datos en base a canales segun el channelIndexList
74 74
75 75 Input:
76 76 channelIndexList : lista sencilla de canales a seleccionar por ej. [2,3,7]
77 77
78 78 Affected:
79 79 self.dataOut.data
80 80 self.dataOut.channelIndexList
81 81 self.dataOut.nChannels
82 82 self.dataOut.m_ProcessingHeader.totalSpectra
83 83 self.dataOut.systemHeaderObj.numChannels
84 84 self.dataOut.m_ProcessingHeader.blockSize
85 85
86 86 Return:
87 87 None
88 88 """
89 89
90 90 for channelIndex in channelIndexList:
91 91 if channelIndex not in self.dataOut.channelIndexList:
92 92 raise ValueError("The value %d in channelIndexList is not valid" %channelIndex)
93 93
94 94 if self.dataOut.type == 'Voltage':
95 95 if self.dataOut.flagDataAsBlock:
96 96 """
97 97 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
98 98 """
99 99 data = self.dataOut.data[channelIndexList,:,:]
100 100 else:
101 101 data = self.dataOut.data[channelIndexList,:]
102 102
103 103 self.dataOut.data = data
104 104 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
105 105 self.dataOut.channelList = range(len(channelIndexList))
106 106
107 107 elif self.dataOut.type == 'Spectra':
108 108 data_spc = self.dataOut.data_spc[channelIndexList, :]
109 109 data_dc = self.dataOut.data_dc[channelIndexList, :]
110 110
111 111 self.dataOut.data_spc = data_spc
112 112 self.dataOut.data_dc = data_dc
113 113
114 114 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
115 115 self.dataOut.channelList = range(len(channelIndexList))
116 116 self.__selectPairsByChannel(channelIndexList)
117 117
118 118 return 1
119 119
120 120 def __selectPairsByChannel(self, channelList=None):
121 121
122 122 if channelList == None:
123 123 return
124 124
125 125 pairsIndexListSelected = []
126 126 for pairIndex in self.dataOut.pairsIndexList:
127 127 # First pair
128 128 if self.dataOut.pairsList[pairIndex][0] not in channelList:
129 129 continue
130 130 # Second pair
131 131 if self.dataOut.pairsList[pairIndex][1] not in channelList:
132 132 continue
133 133
134 134 pairsIndexListSelected.append(pairIndex)
135 135
136 136 if not pairsIndexListSelected:
137 137 self.dataOut.data_cspc = None
138 138 self.dataOut.pairsList = []
139 139 return
140 140
141 141 self.dataOut.data_cspc = self.dataOut.data_cspc[pairsIndexListSelected]
142 142 self.dataOut.pairsList = [self.dataOut.pairsList[i]
143 143 for i in pairsIndexListSelected]
144 144
145 145 return
146 146
147 147 class selectHeights(Operation):
148 148
149 149 def run(self, dataOut, minHei=None, maxHei=None, minIndex=None, maxIndex=None):
150 150 """
151 151 Selecciona un bloque de datos en base a un grupo de valores de alturas segun el rango
152 152 minHei <= height <= maxHei
153 153
154 154 Input:
155 155 minHei : valor minimo de altura a considerar
156 156 maxHei : valor maximo de altura a considerar
157 157
158 158 Affected:
159 159 Indirectamente son cambiados varios valores a travez del metodo selectHeightsByIndex
160 160
161 161 Return:
162 162 1 si el metodo se ejecuto con exito caso contrario devuelve 0
163 163 """
164 164
165 165 self.dataOut = dataOut
166 166
167 167 if minHei and maxHei:
168 168
169 169 if (minHei < self.dataOut.heightList[0]):
170 170 minHei = self.dataOut.heightList[0]
171 171
172 172 if (maxHei > self.dataOut.heightList[-1]):
173 173 maxHei = self.dataOut.heightList[-1]
174 174
175 175 minIndex = 0
176 176 maxIndex = 0
177 177 heights = self.dataOut.heightList
178 178
179 179 inda = numpy.where(heights >= minHei)
180 180 indb = numpy.where(heights <= maxHei)
181 181
182 182 try:
183 183 minIndex = inda[0][0]
184 184 except:
185 185 minIndex = 0
186 186
187 187 try:
188 188 maxIndex = indb[0][-1]
189 189 except:
190 190 maxIndex = len(heights)
191 191
192 192 self.selectHeightsByIndex(minIndex, maxIndex)
193 193
194 194 return self.dataOut
195 195
196 196 def selectHeightsByIndex(self, minIndex, maxIndex):
197 197 """
198 198 Selecciona un bloque de datos en base a un grupo indices de alturas segun el rango
199 199 minIndex <= index <= maxIndex
200 200
201 201 Input:
202 202 minIndex : valor de indice minimo de altura a considerar
203 203 maxIndex : valor de indice maximo de altura a considerar
204 204
205 205 Affected:
206 206 self.dataOut.data
207 207 self.dataOut.heightList
208 208
209 209 Return:
210 210 1 si el metodo se ejecuto con exito caso contrario devuelve 0
211 211 """
212 212
213 213 if self.dataOut.type == 'Voltage':
214 214 if (minIndex < 0) or (minIndex > maxIndex):
215 215 raise ValueError("Height index range (%d,%d) is not valid" % (minIndex, maxIndex))
216 216
217 217 if (maxIndex >= self.dataOut.nHeights):
218 218 maxIndex = self.dataOut.nHeights
219 219
220 220 #voltage
221 221 if self.dataOut.flagDataAsBlock:
222 222 """
223 223 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
224 224 """
225 225 data = self.dataOut.data[:,:, minIndex:maxIndex]
226 226 else:
227 227 data = self.dataOut.data[:, minIndex:maxIndex]
228 228
229 229 # firstHeight = self.dataOut.heightList[minIndex]
230 230
231 231 self.dataOut.data = data
232 232 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex]
233 233
234 234 if self.dataOut.nHeights <= 1:
235 235 raise ValueError("selectHeights: Too few heights. Current number of heights is %d" %(self.dataOut.nHeights))
236 236 elif self.dataOut.type == 'Spectra':
237 237 if (minIndex < 0) or (minIndex > maxIndex):
238 238 raise ValueError("Error selecting heights: Index range (%d,%d) is not valid" % (
239 239 minIndex, maxIndex))
240 240
241 241 if (maxIndex >= self.dataOut.nHeights):
242 242 maxIndex = self.dataOut.nHeights - 1
243 243
244 244 # Spectra
245 245 data_spc = self.dataOut.data_spc[:, :, minIndex:maxIndex + 1]
246 246
247 247 data_cspc = None
248 248 if self.dataOut.data_cspc is not None:
249 249 data_cspc = self.dataOut.data_cspc[:, :, minIndex:maxIndex + 1]
250 250
251 251 data_dc = None
252 252 if self.dataOut.data_dc is not None:
253 253 data_dc = self.dataOut.data_dc[:, minIndex:maxIndex + 1]
254 254
255 255 self.dataOut.data_spc = data_spc
256 256 self.dataOut.data_cspc = data_cspc
257 257 self.dataOut.data_dc = data_dc
258 258
259 259 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex + 1]
260 260
261 261 return 1
262 262
263 263
264 264 class filterByHeights(Operation):
265 265
266 266 def run(self, dataOut, window):
267 267
268 268 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
269 269
270 270 if window == None:
271 271 window = (dataOut.radarControllerHeaderObj.txA/dataOut.radarControllerHeaderObj.nBaud) / deltaHeight
272 272
273 273 newdelta = deltaHeight * window
274 274 r = dataOut.nHeights % window
275 275 newheights = (dataOut.nHeights-r)/window
276 276
277 277 if newheights <= 1:
278 278 raise ValueError("filterByHeights: Too few heights. Current number of heights is %d and window is %d" %(dataOut.nHeights, window))
279 279
280 280 if dataOut.flagDataAsBlock:
281 281 """
282 282 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
283 283 """
284 284 buffer = dataOut.data[:, :, 0:int(dataOut.nHeights-r)]
285 285 buffer = buffer.reshape(dataOut.nChannels, dataOut.nProfiles, int(dataOut.nHeights/window), window)
286 286 buffer = numpy.sum(buffer,3)
287 287
288 288 else:
289 289 buffer = dataOut.data[:,0:int(dataOut.nHeights-r)]
290 290 buffer = buffer.reshape(dataOut.nChannels,int(dataOut.nHeights/window),int(window))
291 291 buffer = numpy.sum(buffer,2)
292 292
293 293 dataOut.data = buffer
294 294 dataOut.heightList = dataOut.heightList[0] + numpy.arange( newheights )*newdelta
295 295 dataOut.windowOfFilter = window
296 296
297 297 return dataOut
298 298
299 299
300 300 class setH0(Operation):
301 301
302 302 def run(self, dataOut, h0, deltaHeight = None):
303 303
304 304 if not deltaHeight:
305 305 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
306 306
307 307 nHeights = dataOut.nHeights
308 308
309 309 newHeiRange = h0 + numpy.arange(nHeights)*deltaHeight
310 310
311 311 dataOut.heightList = newHeiRange
312 312
313 313 return dataOut
314 314
315 315
316 316 class deFlip(Operation):
317 317
318 318 def run(self, dataOut, channelList = []):
319 319
320 320 data = dataOut.data.copy()
321 321
322 322 if dataOut.flagDataAsBlock:
323 323 flip = self.flip
324 324 profileList = list(range(dataOut.nProfiles))
325 325
326 326 if not channelList:
327 327 for thisProfile in profileList:
328 328 data[:,thisProfile,:] = data[:,thisProfile,:]*flip
329 329 flip *= -1.0
330 330 else:
331 331 for thisChannel in channelList:
332 332 if thisChannel not in dataOut.channelList:
333 333 continue
334 334
335 335 for thisProfile in profileList:
336 336 data[thisChannel,thisProfile,:] = data[thisChannel,thisProfile,:]*flip
337 337 flip *= -1.0
338 338
339 339 self.flip = flip
340 340
341 341 else:
342 342 if not channelList:
343 343 data[:,:] = data[:,:]*self.flip
344 344 else:
345 345 for thisChannel in channelList:
346 346 if thisChannel not in dataOut.channelList:
347 347 continue
348 348
349 349 data[thisChannel,:] = data[thisChannel,:]*self.flip
350 350
351 351 self.flip *= -1.
352 352
353 353 dataOut.data = data
354 354
355 355 return dataOut
356 356
357 357
358 358 class setAttribute(Operation):
359 359 '''
360 360 Set an arbitrary attribute(s) to dataOut
361 361 '''
362 362
363 363 def __init__(self):
364 364
365 365 Operation.__init__(self)
366 366 self._ready = False
367 367
368 368 def run(self, dataOut, **kwargs):
369 369
370 370 for key, value in kwargs.items():
371 371 setattr(dataOut, key, value)
372 372
373 373 return dataOut
374 374
375 375
376 376 @MPDecorator
377 377 class printAttribute(Operation):
378 378 '''
379 379 Print an arbitrary attribute of dataOut
380 380 '''
381 381
382 382 def __init__(self):
383 383
384 384 Operation.__init__(self)
385 385
386 386 def run(self, dataOut, attributes):
387 387
388 388 if isinstance(attributes, str):
389 389 attributes = [attributes]
390 390 for attr in attributes:
391 391 if hasattr(dataOut, attr):
392 392 log.log(getattr(dataOut, attr), attr)
393 393
394 394
395 395 class interpolateHeights(Operation):
396 396
397 397 def run(self, dataOut, topLim, botLim):
398 398 #69 al 72 para julia
399 399 #82-84 para meteoros
400 400 if len(numpy.shape(dataOut.data))==2:
401 401 sampInterp = (dataOut.data[:,botLim-1] + dataOut.data[:,topLim+1])/2
402 402 sampInterp = numpy.transpose(numpy.tile(sampInterp,(topLim-botLim + 1,1)))
403 403 #dataOut.data[:,botLim:limSup+1] = sampInterp
404 404 dataOut.data[:,botLim:topLim+1] = sampInterp
405 405 else:
406 406 nHeights = dataOut.data.shape[2]
407 407 x = numpy.hstack((numpy.arange(botLim),numpy.arange(topLim+1,nHeights)))
408 408 y = dataOut.data[:,:,list(range(botLim))+list(range(topLim+1,nHeights))]
409 409 f = interpolate.interp1d(x, y, axis = 2)
410 410 xnew = numpy.arange(botLim,topLim+1)
411 411 ynew = f(xnew)
412 412 dataOut.data[:,:,botLim:topLim+1] = ynew
413 413
414 414 return dataOut
415 415
416 416
417 417 class CohInt(Operation):
418 418
419 419 isConfig = False
420 420 __profIndex = 0
421 421 __byTime = False
422 422 __initime = None
423 423 __lastdatatime = None
424 424 __integrationtime = None
425 425 __buffer = None
426 426 __bufferStride = []
427 427 __dataReady = False
428 428 __profIndexStride = 0
429 429 __dataToPutStride = False
430 430 n = None
431 431
432 432 def __init__(self, **kwargs):
433 433
434 434 Operation.__init__(self, **kwargs)
435 435
436 436 def setup(self, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False):
437 437 """
438 438 Set the parameters of the integration class.
439 439
440 440 Inputs:
441 441
442 442 n : Number of coherent integrations
443 443 timeInterval : Time of integration. If the parameter "n" is selected this one does not work
444 444 overlapping :
445 445 """
446 446
447 447 self.__initime = None
448 448 self.__lastdatatime = 0
449 449 self.__buffer = None
450 450 self.__dataReady = False
451 451 self.byblock = byblock
452 452 self.stride = stride
453 453
454 454 if n == None and timeInterval == None:
455 455 raise ValueError("n or timeInterval should be specified ...")
456 456
457 457 if n != None:
458 458 self.n = n
459 459 self.__byTime = False
460 460 else:
461 461 self.__integrationtime = timeInterval #* 60. #if (type(timeInterval)!=integer) -> change this line
462 462 self.n = 9999
463 463 self.__byTime = True
464 464
465 465 if overlapping:
466 466 self.__withOverlapping = True
467 467 self.__buffer = None
468 468 else:
469 469 self.__withOverlapping = False
470 470 self.__buffer = 0
471 471
472 472 self.__profIndex = 0
473 473
474 474 def putData(self, data):
475 475
476 476 """
477 477 Add a profile to the __buffer and increase in one the __profileIndex
478 478
479 479 """
480 480
481 481 if not self.__withOverlapping:
482 482 self.__buffer += data.copy()
483 483 self.__profIndex += 1
484 484 return
485 485
486 486 #Overlapping data
487 487 nChannels, nHeis = data.shape
488 488 data = numpy.reshape(data, (1, nChannels, nHeis))
489 489
490 490 #If the buffer is empty then it takes the data value
491 491 if self.__buffer is None:
492 492 self.__buffer = data
493 493 self.__profIndex += 1
494 494 return
495 495
496 496 #If the buffer length is lower than n then stakcing the data value
497 497 if self.__profIndex < self.n:
498 498 self.__buffer = numpy.vstack((self.__buffer, data))
499 499 self.__profIndex += 1
500 500 return
501 501
502 502 #If the buffer length is equal to n then replacing the last buffer value with the data value
503 503 self.__buffer = numpy.roll(self.__buffer, -1, axis=0)
504 504 self.__buffer[self.n-1] = data
505 505 self.__profIndex = self.n
506 506 return
507 507
508 508
509 509 def pushData(self):
510 510 """
511 511 Return the sum of the last profiles and the profiles used in the sum.
512 512
513 513 Affected:
514 514
515 515 self.__profileIndex
516 516
517 517 """
518 518
519 519 if not self.__withOverlapping:
520 520 data = self.__buffer
521 521 n = self.__profIndex
522 522
523 523 self.__buffer = 0
524 524 self.__profIndex = 0
525 525
526 526 return data, n
527 527
528 528 #Integration with Overlapping
529 529 data = numpy.sum(self.__buffer, axis=0)
530 530 # print data
531 531 # raise
532 532 n = self.__profIndex
533 533
534 534 return data, n
535 535
536 536 def byProfiles(self, data):
537 537
538 538 self.__dataReady = False
539 539 avgdata = None
540 540 # n = None
541 541 # print data
542 542 # raise
543 543 self.putData(data)
544 544
545 545 if self.__profIndex == self.n:
546 546 avgdata, n = self.pushData()
547 547 self.__dataReady = True
548 548
549 549 return avgdata
550 550
551 551 def byTime(self, data, datatime):
552 552
553 553 self.__dataReady = False
554 554 avgdata = None
555 555 n = None
556 556
557 557 self.putData(data)
558 558
559 559 if (datatime - self.__initime) >= self.__integrationtime:
560 560 avgdata, n = self.pushData()
561 561 self.n = n
562 562 self.__dataReady = True
563 563
564 564 return avgdata
565 565
566 566 def integrateByStride(self, data, datatime):
567 567 # print data
568 568 if self.__profIndex == 0:
569 569 self.__buffer = [[data.copy(), datatime]]
570 570 else:
571 571 self.__buffer.append([data.copy(),datatime])
572 572 self.__profIndex += 1
573 573 self.__dataReady = False
574 574
575 575 if self.__profIndex == self.n * self.stride :
576 576 self.__dataToPutStride = True
577 577 self.__profIndexStride = 0
578 578 self.__profIndex = 0
579 579 self.__bufferStride = []
580 580 for i in range(self.stride):
581 581 current = self.__buffer[i::self.stride]
582 582 data = numpy.sum([t[0] for t in current], axis=0)
583 583 avgdatatime = numpy.average([t[1] for t in current])
584 584 # print data
585 585 self.__bufferStride.append((data, avgdatatime))
586 586
587 587 if self.__dataToPutStride:
588 588 self.__dataReady = True
589 589 self.__profIndexStride += 1
590 590 if self.__profIndexStride == self.stride:
591 591 self.__dataToPutStride = False
592 592 # print self.__bufferStride[self.__profIndexStride - 1]
593 593 # raise
594 594 return self.__bufferStride[self.__profIndexStride - 1]
595 595
596 596
597 597 return None, None
598 598
599 599 def integrate(self, data, datatime=None):
600 600
601 601 if self.__initime == None:
602 602 self.__initime = datatime
603 603
604 604 if self.__byTime:
605 605 avgdata = self.byTime(data, datatime)
606 606 else:
607 607 avgdata = self.byProfiles(data)
608 608
609 609
610 610 self.__lastdatatime = datatime
611 611
612 612 if avgdata is None:
613 613 return None, None
614 614
615 615 avgdatatime = self.__initime
616 616
617 617 deltatime = datatime - self.__lastdatatime
618 618
619 619 if not self.__withOverlapping:
620 620 self.__initime = datatime
621 621 else:
622 622 self.__initime += deltatime
623 623
624 624 return avgdata, avgdatatime
625 625
626 626 def integrateByBlock(self, dataOut):
627 627
628 628 times = int(dataOut.data.shape[1]/self.n)
629 629 avgdata = numpy.zeros((dataOut.nChannels, times, dataOut.nHeights), dtype=numpy.complex)
630 630
631 631 id_min = 0
632 632 id_max = self.n
633 633
634 634 for i in range(times):
635 635 junk = dataOut.data[:,id_min:id_max,:]
636 636 avgdata[:,i,:] = junk.sum(axis=1)
637 637 id_min += self.n
638 638 id_max += self.n
639 639
640 640 timeInterval = dataOut.ippSeconds*self.n
641 641 avgdatatime = (times - 1) * timeInterval + dataOut.utctime
642 642 self.__dataReady = True
643 643 return avgdata, avgdatatime
644 644
645 645 def run(self, dataOut, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False, **kwargs):
646 646
647 647 if not self.isConfig:
648 648 self.setup(n=n, stride=stride, timeInterval=timeInterval, overlapping=overlapping, byblock=byblock, **kwargs)
649 649 self.isConfig = True
650 650
651 651 if dataOut.flagDataAsBlock:
652 652 """
653 653 Si la data es leida por bloques, dimension = [nChannels, nProfiles, nHeis]
654 654 """
655 655 avgdata, avgdatatime = self.integrateByBlock(dataOut)
656 656 dataOut.nProfiles /= self.n
657 657 else:
658 658 if stride is None:
659 659 avgdata, avgdatatime = self.integrate(dataOut.data, dataOut.utctime)
660 660 else:
661 661 avgdata, avgdatatime = self.integrateByStride(dataOut.data, dataOut.utctime)
662 662
663 663
664 664 # dataOut.timeInterval *= n
665 665 dataOut.flagNoData = True
666 666
667 667 if self.__dataReady:
668 668 dataOut.data = avgdata
669 669 if not dataOut.flagCohInt:
670 670 dataOut.nCohInt *= self.n
671 671 dataOut.flagCohInt = True
672 672 dataOut.utctime = avgdatatime
673 673 # print avgdata, avgdatatime
674 674 # raise
675 675 # dataOut.timeInterval = dataOut.ippSeconds * dataOut.nCohInt
676 676 dataOut.flagNoData = False
677 677 return dataOut
678 678
679 679 class Decoder(Operation):
680 680
681 681 isConfig = False
682 682 __profIndex = 0
683 683
684 684 code = None
685 685
686 686 nCode = None
687 687 nBaud = None
688 688
689 689 def __init__(self, **kwargs):
690 690
691 691 Operation.__init__(self, **kwargs)
692 692
693 693 self.times = None
694 694 self.osamp = None
695 695 # self.__setValues = False
696 696 self.isConfig = False
697 697 self.setupReq = False
698 698 def setup(self, code, osamp, dataOut):
699 699
700 700 self.__profIndex = 0
701 701
702 702 self.code = code
703 703
704 704 self.nCode = len(code)
705 705 self.nBaud = len(code[0])
706 706
707 707 if (osamp != None) and (osamp >1):
708 708 self.osamp = osamp
709 709 self.code = numpy.repeat(code, repeats=self.osamp, axis=1)
710 710 self.nBaud = self.nBaud*self.osamp
711 711
712 712 self.__nChannels = dataOut.nChannels
713 713 self.__nProfiles = dataOut.nProfiles
714 714 self.__nHeis = dataOut.nHeights
715 715
716 716 if self.__nHeis < self.nBaud:
717 717 raise ValueError('Number of heights (%d) should be greater than number of bauds (%d)' %(self.__nHeis, self.nBaud))
718 718
719 719 #Frequency
720 720 __codeBuffer = numpy.zeros((self.nCode, self.__nHeis), dtype=numpy.complex)
721 721
722 722 __codeBuffer[:,0:self.nBaud] = self.code
723 723
724 724 self.fft_code = numpy.conj(numpy.fft.fft(__codeBuffer, axis=1))
725 725
726 726 if dataOut.flagDataAsBlock:
727 727
728 728 self.ndatadec = self.__nHeis #- self.nBaud + 1
729 729
730 730 self.datadecTime = numpy.zeros((self.__nChannels, self.__nProfiles, self.ndatadec), dtype=numpy.complex)
731 731
732 732 else:
733 733
734 734 #Time
735 735 self.ndatadec = self.__nHeis #- self.nBaud + 1
736 736
737 737 self.datadecTime = numpy.zeros((self.__nChannels, self.ndatadec), dtype=numpy.complex)
738 738
739 739 def __convolutionInFreq(self, data):
740 740
741 741 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
742 742
743 743 fft_data = numpy.fft.fft(data, axis=1)
744 744
745 745 conv = fft_data*fft_code
746 746
747 747 data = numpy.fft.ifft(conv,axis=1)
748 748
749 749 return data
750 750
751 751 def __convolutionInFreqOpt(self, data):
752 752
753 753 raise NotImplementedError
754 754
755 755 def __convolutionInTime(self, data):
756 756
757 757 code = self.code[self.__profIndex]
758 758 for i in range(self.__nChannels):
759 759 self.datadecTime[i,:] = numpy.correlate(data[i,:], code, mode='full')[self.nBaud-1:]
760 760
761 761 return self.datadecTime
762 762
763 763 def __convolutionByBlockInTime(self, data):
764 764
765 765 repetitions = int(self.__nProfiles / self.nCode)
766 766 junk = numpy.lib.stride_tricks.as_strided(self.code, (repetitions, self.code.size), (0, self.code.itemsize))
767 767 junk = junk.flatten()
768 768 code_block = numpy.reshape(junk, (self.nCode*repetitions, self.nBaud))
769 769 profilesList = range(self.__nProfiles)
770 770
771 771 for i in range(self.__nChannels):
772 772 for j in profilesList:
773 773 self.datadecTime[i,j,:] = numpy.correlate(data[i,j,:], code_block[j,:], mode='full')[self.nBaud-1:]
774 774 return self.datadecTime
775 775
776 776 def __convolutionByBlockInFreq(self, data):
777 777
778 778 raise NotImplementedError("Decoder by frequency fro Blocks not implemented")
779 779
780 780
781 781 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
782 782
783 783 fft_data = numpy.fft.fft(data, axis=2)
784 784
785 785 conv = fft_data*fft_code
786 786
787 787 data = numpy.fft.ifft(conv,axis=2)
788 788
789 789 return data
790 790
791 791
792 792 def run(self, dataOut, code=None, nCode=None, nBaud=None, mode = 0, osamp=None, times=None):
793 793
794 794 if dataOut.flagDecodeData:
795 795 print("This data is already decoded, recoding again ...")
796 796
797 797 if not self.isConfig:
798 798
799 799 if code is None:
800 800 if dataOut.code is None:
801 801 raise ValueError("Code could not be read from %s instance. Enter a value in Code parameter" %dataOut.type)
802 802
803 803 code = dataOut.code
804 804 else:
805 805 code = numpy.array(code).reshape(nCode,nBaud)
806 806 self.setup(code, osamp, dataOut)
807 807
808 808 self.isConfig = True
809 809
810 810 if mode == 3:
811 811 sys.stderr.write("Decoder Warning: mode=%d is not valid, using mode=0\n" %mode)
812 812
813 813 if times != None:
814 814 sys.stderr.write("Decoder Warning: Argument 'times' in not used anymore\n")
815 815
816 816 if self.code is None:
817 817 print("Fail decoding: Code is not defined.")
818 818 return
819 819
820 820 self.__nProfiles = dataOut.nProfiles
821 821 datadec = None
822 822
823 823 if mode == 3:
824 824 mode = 0
825 825
826 826 if dataOut.flagDataAsBlock:
827 827 """
828 828 Decoding when data have been read as block,
829 829 """
830 830
831 831 if mode == 0:
832 832 datadec = self.__convolutionByBlockInTime(dataOut.data)
833 833 if mode == 1:
834 834 datadec = self.__convolutionByBlockInFreq(dataOut.data)
835 835 else:
836 836 """
837 837 Decoding when data have been read profile by profile
838 838 """
839 839 if mode == 0:
840 840 datadec = self.__convolutionInTime(dataOut.data)
841 841
842 842 if mode == 1:
843 843 datadec = self.__convolutionInFreq(dataOut.data)
844 844
845 845 if mode == 2:
846 846 datadec = self.__convolutionInFreqOpt(dataOut.data)
847 847
848 848 if datadec is None:
849 849 raise ValueError("Codification mode selected is not valid: mode=%d. Try selecting 0 or 1" %mode)
850 850
851 851 dataOut.code = self.code
852 852 dataOut.nCode = self.nCode
853 853 dataOut.nBaud = self.nBaud
854 854
855 855 dataOut.data = datadec
856 856
857 857 dataOut.heightList = dataOut.heightList[0:datadec.shape[-1]]
858 858
859 859 dataOut.flagDecodeData = True #asumo q la data esta decodificada
860 860
861 861 if self.__profIndex == self.nCode-1:
862 862 self.__profIndex = 0
863 863 return dataOut
864 864
865 865 self.__profIndex += 1
866 866
867 867 return dataOut
868 868 # dataOut.flagDeflipData = True #asumo q la data no esta sin flip
869 869
870 870
871 871 class ProfileConcat(Operation):
872 872
873 873 isConfig = False
874 874 buffer = None
875 875
876 876 def __init__(self, **kwargs):
877 877
878 878 Operation.__init__(self, **kwargs)
879 879 self.profileIndex = 0
880 880
881 881 def reset(self):
882 882 self.buffer = numpy.zeros_like(self.buffer)
883 883 self.start_index = 0
884 884 self.times = 1
885 885
886 886 def setup(self, data, m, n=1):
887 887 self.buffer = numpy.zeros((data.shape[0],data.shape[1]*m),dtype=type(data[0,0]))
888 888 self.nHeights = data.shape[1]#.nHeights
889 889 self.start_index = 0
890 890 self.times = 1
891 891
892 892 def concat(self, data):
893 893
894 894 self.buffer[:,self.start_index:self.nHeights*self.times] = data.copy()
895 895 self.start_index = self.start_index + self.nHeights
896 896
897 897 def run(self, dataOut, m):
898 898 dataOut.flagNoData = True
899 899
900 900 if not self.isConfig:
901 901 self.setup(dataOut.data, m, 1)
902 902 self.isConfig = True
903 903
904 904 if dataOut.flagDataAsBlock:
905 905 raise ValueError("ProfileConcat can only be used when voltage have been read profile by profile, getBlock = False")
906 906
907 907 else:
908 908 self.concat(dataOut.data)
909 909 self.times += 1
910 910 if self.times > m:
911 911 dataOut.data = self.buffer
912 912 self.reset()
913 913 dataOut.flagNoData = False
914 914 # se deben actualizar mas propiedades del header y del objeto dataOut, por ejemplo, las alturas
915 915 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
916 916 xf = dataOut.heightList[0] + dataOut.nHeights * deltaHeight * m
917 917 dataOut.heightList = numpy.arange(dataOut.heightList[0], xf, deltaHeight)
918 918 dataOut.ippSeconds *= m
919 919 return dataOut
920 920
921 921 class ProfileSelector(Operation):
922 922
923 923 profileIndex = None
924 924 # Tamanho total de los perfiles
925 925 nProfiles = None
926 926
927 927 def __init__(self, **kwargs):
928 928
929 929 Operation.__init__(self, **kwargs)
930 930 self.profileIndex = 0
931 931
932 932 def incProfileIndex(self):
933 933
934 934 self.profileIndex += 1
935 935
936 936 if self.profileIndex >= self.nProfiles:
937 937 self.profileIndex = 0
938 938
939 939 def isThisProfileInRange(self, profileIndex, minIndex, maxIndex):
940 940
941 941 if profileIndex < minIndex:
942 942 return False
943 943
944 944 if profileIndex > maxIndex:
945 945 return False
946 946
947 947 return True
948 948
949 949 def isThisProfileInList(self, profileIndex, profileList):
950 950
951 951 if profileIndex not in profileList:
952 952 return False
953 953
954 954 return True
955 955
956 956 def run(self, dataOut, profileList=None, profileRangeList=None, beam=None, byblock=False, rangeList = None, nProfiles=None):
957 957
958 958 """
959 959 ProfileSelector:
960 960
961 961 Inputs:
962 962 profileList : Index of profiles selected. Example: profileList = (0,1,2,7,8)
963 963
964 964 profileRangeList : Minimum and maximum profile indexes. Example: profileRangeList = (4, 30)
965 965
966 966 rangeList : List of profile ranges. Example: rangeList = ((4, 30), (32, 64), (128, 256))
967 967
968 968 """
969 969
970 970 if rangeList is not None:
971 971 if type(rangeList[0]) not in (tuple, list):
972 972 rangeList = [rangeList]
973 973
974 974 dataOut.flagNoData = True
975 975
976 976 if dataOut.flagDataAsBlock:
977 977 """
978 978 data dimension = [nChannels, nProfiles, nHeis]
979 979 """
980 980 if profileList != None:
981 981 dataOut.data = dataOut.data[:,profileList,:]
982 982
983 983 if profileRangeList != None:
984 984 minIndex = profileRangeList[0]
985 985 maxIndex = profileRangeList[1]
986 986 profileList = list(range(minIndex, maxIndex+1))
987 987
988 988 dataOut.data = dataOut.data[:,minIndex:maxIndex+1,:]
989 989
990 990 if rangeList != None:
991 991
992 992 profileList = []
993 993
994 994 for thisRange in rangeList:
995 995 minIndex = thisRange[0]
996 996 maxIndex = thisRange[1]
997 997
998 998 profileList.extend(list(range(minIndex, maxIndex+1)))
999 999
1000 1000 dataOut.data = dataOut.data[:,profileList,:]
1001 1001
1002 1002 dataOut.nProfiles = len(profileList)
1003 1003 dataOut.profileIndex = dataOut.nProfiles - 1
1004 1004 dataOut.flagNoData = False
1005 1005
1006 1006 return dataOut
1007 1007
1008 1008 """
1009 1009 data dimension = [nChannels, nHeis]
1010 1010 """
1011 1011
1012 1012 if profileList != None:
1013 1013
1014 1014 if self.isThisProfileInList(dataOut.profileIndex, profileList):
1015 1015
1016 1016 self.nProfiles = len(profileList)
1017 1017 dataOut.nProfiles = self.nProfiles
1018 1018 dataOut.profileIndex = self.profileIndex
1019 1019 dataOut.flagNoData = False
1020 1020
1021 1021 self.incProfileIndex()
1022 1022 return dataOut
1023 1023
1024 1024 if profileRangeList != None:
1025 1025
1026 1026 minIndex = profileRangeList[0]
1027 1027 maxIndex = profileRangeList[1]
1028 1028
1029 1029 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1030 1030
1031 1031 self.nProfiles = maxIndex - minIndex + 1
1032 1032 dataOut.nProfiles = self.nProfiles
1033 1033 dataOut.profileIndex = self.profileIndex
1034 1034 dataOut.flagNoData = False
1035 1035
1036 1036 self.incProfileIndex()
1037 1037 return dataOut
1038 1038
1039 1039 if rangeList != None:
1040 1040
1041 1041 nProfiles = 0
1042 1042
1043 1043 for thisRange in rangeList:
1044 1044 minIndex = thisRange[0]
1045 1045 maxIndex = thisRange[1]
1046 1046
1047 1047 nProfiles += maxIndex - minIndex + 1
1048 1048
1049 1049 for thisRange in rangeList:
1050 1050
1051 1051 minIndex = thisRange[0]
1052 1052 maxIndex = thisRange[1]
1053 1053
1054 1054 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1055 1055
1056 1056 self.nProfiles = nProfiles
1057 1057 dataOut.nProfiles = self.nProfiles
1058 1058 dataOut.profileIndex = self.profileIndex
1059 1059 dataOut.flagNoData = False
1060 1060
1061 1061 self.incProfileIndex()
1062 1062
1063 1063 break
1064 1064
1065 1065 return dataOut
1066 1066
1067 1067
1068 1068 if beam != None: #beam is only for AMISR data
1069 1069 if self.isThisProfileInList(dataOut.profileIndex, dataOut.beamRangeDict[beam]):
1070 1070 dataOut.flagNoData = False
1071 1071 dataOut.profileIndex = self.profileIndex
1072 1072
1073 1073 self.incProfileIndex()
1074 1074
1075 1075 return dataOut
1076 1076
1077 1077 raise ValueError("ProfileSelector needs profileList, profileRangeList or rangeList parameter")
1078 1078
1079 1079
1080 1080 class Reshaper(Operation):
1081 1081
1082 1082 def __init__(self, **kwargs):
1083 1083
1084 1084 Operation.__init__(self, **kwargs)
1085 1085
1086 1086 self.__buffer = None
1087 1087 self.__nitems = 0
1088 1088
1089 1089 def __appendProfile(self, dataOut, nTxs):
1090 1090
1091 1091 if self.__buffer is None:
1092 1092 shape = (dataOut.nChannels, int(dataOut.nHeights/nTxs) )
1093 1093 self.__buffer = numpy.empty(shape, dtype = dataOut.data.dtype)
1094 1094
1095 1095 ini = dataOut.nHeights * self.__nitems
1096 1096 end = ini + dataOut.nHeights
1097 1097
1098 1098 self.__buffer[:, ini:end] = dataOut.data
1099 1099
1100 1100 self.__nitems += 1
1101 1101
1102 1102 return int(self.__nitems*nTxs)
1103 1103
1104 1104 def __getBuffer(self):
1105 1105
1106 1106 if self.__nitems == int(1./self.__nTxs):
1107 1107
1108 1108 self.__nitems = 0
1109 1109
1110 1110 return self.__buffer.copy()
1111 1111
1112 1112 return None
1113 1113
1114 1114 def __checkInputs(self, dataOut, shape, nTxs):
1115 1115
1116 1116 if shape is None and nTxs is None:
1117 1117 raise ValueError("Reshaper: shape of factor should be defined")
1118 1118
1119 1119 if nTxs:
1120 1120 if nTxs < 0:
1121 1121 raise ValueError("nTxs should be greater than 0")
1122 1122
1123 1123 if nTxs < 1 and dataOut.nProfiles % (1./nTxs) != 0:
1124 1124 raise ValueError("nProfiles= %d is not divisibled by (1./nTxs) = %f" %(dataOut.nProfiles, (1./nTxs)))
1125 1125
1126 1126 shape = [dataOut.nChannels, dataOut.nProfiles*nTxs, dataOut.nHeights/nTxs]
1127 1127
1128 1128 return shape, nTxs
1129 1129
1130 1130 if len(shape) != 2 and len(shape) != 3:
1131 1131 raise ValueError("shape dimension should be equal to 2 or 3. shape = (nProfiles, nHeis) or (nChannels, nProfiles, nHeis). Actually shape = (%d, %d, %d)" %(dataOut.nChannels, dataOut.nProfiles, dataOut.nHeights))
1132 1132
1133 1133 if len(shape) == 2:
1134 1134 shape_tuple = [dataOut.nChannels]
1135 1135 shape_tuple.extend(shape)
1136 1136 else:
1137 1137 shape_tuple = list(shape)
1138 1138
1139 1139 nTxs = 1.0*shape_tuple[1]/dataOut.nProfiles
1140 1140
1141 1141 return shape_tuple, nTxs
1142 1142
1143 1143 def run(self, dataOut, shape=None, nTxs=None):
1144 1144
1145 1145 shape_tuple, self.__nTxs = self.__checkInputs(dataOut, shape, nTxs)
1146 1146
1147 1147 dataOut.flagNoData = True
1148 1148 profileIndex = None
1149 1149
1150 1150 if dataOut.flagDataAsBlock:
1151 1151
1152 1152 dataOut.data = numpy.reshape(dataOut.data, shape_tuple)
1153 1153 dataOut.flagNoData = False
1154 1154
1155 1155 profileIndex = int(dataOut.nProfiles*self.__nTxs) - 1
1156 1156
1157 1157 else:
1158 1158
1159 1159 if self.__nTxs < 1:
1160 1160
1161 1161 self.__appendProfile(dataOut, self.__nTxs)
1162 1162 new_data = self.__getBuffer()
1163 1163
1164 1164 if new_data is not None:
1165 1165 dataOut.data = new_data
1166 1166 dataOut.flagNoData = False
1167 1167
1168 1168 profileIndex = dataOut.profileIndex*nTxs
1169 1169
1170 1170 else:
1171 1171 raise ValueError("nTxs should be greater than 0 and lower than 1, or use VoltageReader(..., getblock=True)")
1172 1172
1173 1173 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1174 1174
1175 1175 dataOut.heightList = numpy.arange(dataOut.nHeights/self.__nTxs) * deltaHeight + dataOut.heightList[0]
1176 1176
1177 1177 dataOut.nProfiles = int(dataOut.nProfiles*self.__nTxs)
1178 1178
1179 1179 dataOut.profileIndex = profileIndex
1180 1180
1181 1181 dataOut.ippSeconds /= self.__nTxs
1182 1182
1183 1183 return dataOut
1184 1184
1185 1185 class SplitProfiles(Operation):
1186 1186
1187 1187 def __init__(self, **kwargs):
1188 1188
1189 1189 Operation.__init__(self, **kwargs)
1190 1190
1191 1191 def run(self, dataOut, n):
1192 1192
1193 1193 dataOut.flagNoData = True
1194 1194 profileIndex = None
1195 1195
1196 1196 if dataOut.flagDataAsBlock:
1197 1197
1198 1198 #nchannels, nprofiles, nsamples
1199 1199 shape = dataOut.data.shape
1200 1200
1201 1201 if shape[2] % n != 0:
1202 1202 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[2]))
1203 1203
1204 1204 new_shape = shape[0], shape[1]*n, int(shape[2]/n)
1205 1205
1206 1206 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1207 1207 dataOut.flagNoData = False
1208 1208
1209 1209 profileIndex = int(dataOut.nProfiles/n) - 1
1210 1210
1211 1211 else:
1212 1212
1213 1213 raise ValueError("Could not split the data when is read Profile by Profile. Use VoltageReader(..., getblock=True)")
1214 1214
1215 1215 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1216 1216
1217 1217 dataOut.heightList = numpy.arange(dataOut.nHeights/n) * deltaHeight + dataOut.heightList[0]
1218 1218
1219 1219 dataOut.nProfiles = int(dataOut.nProfiles*n)
1220 1220
1221 1221 dataOut.profileIndex = profileIndex
1222 1222
1223 1223 dataOut.ippSeconds /= n
1224 1224
1225 1225 return dataOut
1226 1226
1227 1227 class CombineProfiles(Operation):
1228 1228 def __init__(self, **kwargs):
1229 1229
1230 1230 Operation.__init__(self, **kwargs)
1231 1231
1232 1232 self.__remData = None
1233 1233 self.__profileIndex = 0
1234 1234
1235 1235 def run(self, dataOut, n):
1236 1236
1237 1237 dataOut.flagNoData = True
1238 1238 profileIndex = None
1239 1239
1240 1240 if dataOut.flagDataAsBlock:
1241 1241
1242 1242 #nchannels, nprofiles, nsamples
1243 1243 shape = dataOut.data.shape
1244 1244 new_shape = shape[0], shape[1]/n, shape[2]*n
1245 1245
1246 1246 if shape[1] % n != 0:
1247 1247 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[1]))
1248 1248
1249 1249 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1250 1250 dataOut.flagNoData = False
1251 1251
1252 1252 profileIndex = int(dataOut.nProfiles*n) - 1
1253 1253
1254 1254 else:
1255 1255
1256 1256 #nchannels, nsamples
1257 1257 if self.__remData is None:
1258 1258 newData = dataOut.data
1259 1259 else:
1260 1260 newData = numpy.concatenate((self.__remData, dataOut.data), axis=1)
1261 1261
1262 1262 self.__profileIndex += 1
1263 1263
1264 1264 if self.__profileIndex < n:
1265 1265 self.__remData = newData
1266 1266 #continue
1267 1267 return
1268 1268
1269 1269 self.__profileIndex = 0
1270 1270 self.__remData = None
1271 1271
1272 1272 dataOut.data = newData
1273 1273 dataOut.flagNoData = False
1274 1274
1275 1275 profileIndex = dataOut.profileIndex/n
1276 1276
1277 1277
1278 1278 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1279 1279
1280 1280 dataOut.heightList = numpy.arange(dataOut.nHeights*n) * deltaHeight + dataOut.heightList[0]
1281 1281
1282 1282 dataOut.nProfiles = int(dataOut.nProfiles/n)
1283 1283
1284 1284 dataOut.profileIndex = profileIndex
1285 1285
1286 1286 dataOut.ippSeconds *= n
1287 1287
1288 1288 return dataOut
1289 1289
1290 1290 class PulsePair(Operation):
1291 1291 '''
1292 1292 Function PulsePair(Signal Power, Velocity)
1293 1293 The real component of Lag[0] provides Intensity Information
1294 1294 The imag component of Lag[1] Phase provides Velocity Information
1295 1295
1296 1296 Configuration Parameters:
1297 1297 nPRF = Number of Several PRF
1298 1298 theta = Degree Azimuth angel Boundaries
1299 1299
1300 1300 Input:
1301 1301 self.dataOut
1302 1302 lag[N]
1303 1303 Affected:
1304 1304 self.dataOut.spc
1305 1305 '''
1306 1306 isConfig = False
1307 1307 __profIndex = 0
1308 1308 __initime = None
1309 1309 __lastdatatime = None
1310 1310 __buffer = None
1311 1311 noise = None
1312 1312 __dataReady = False
1313 1313 n = None
1314 1314 __nch = 0
1315 1315 __nHeis = 0
1316 1316 removeDC = False
1317 1317 ipp = None
1318 1318 lambda_ = 0
1319 1319
1320 1320 def __init__(self,**kwargs):
1321 1321 Operation.__init__(self,**kwargs)
1322 1322
1323 1323 def setup(self, dataOut, n = None, removeDC=False):
1324 1324 '''
1325 1325 n= Numero de PRF's de entrada
1326 1326 '''
1327 1327 print("[INICIO]-setup del METODO PULSE PAIR")
1328 1328 self.__initime = None
1329 1329 self.__lastdatatime = 0
1330 1330 self.__dataReady = False
1331 1331 self.__buffer = 0
1332 1332 self.__profIndex = 0
1333 1333 self.noise = None
1334 1334 self.__nch = dataOut.nChannels
1335 1335 self.__nHeis = dataOut.nHeights
1336 1336 self.removeDC = removeDC
1337 1337 self.lambda_ = 3.0e8/(9345.0e6)
1338 1338 self.ippSec = dataOut.ippSeconds
1339 1339 self.nCohInt = dataOut.nCohInt
1340 1340 print("IPPseconds",dataOut.ippSeconds)
1341 1341
1342 1342 print("ELVALOR DE n es:", n)
1343 1343 if n == None:
1344 1344 raise ValueError("n should be specified.")
1345 1345
1346 1346 if n != None:
1347 1347 if n<2:
1348 1348 raise ValueError("n should be greater than 2")
1349 1349
1350 1350 self.n = n
1351 1351 self.__nProf = n
1352 1352
1353 1353 self.__buffer = numpy.zeros((dataOut.nChannels,
1354 1354 n,
1355 1355 dataOut.nHeights),
1356 1356 dtype='complex')
1357 1357
1358 1358 def putData(self,data):
1359 1359 '''
1360 1360 Add a profile to he __buffer and increase in one the __profiel Index
1361 1361 '''
1362 1362 self.__buffer[:,self.__profIndex,:]= data
1363 1363 self.__profIndex += 1
1364 1364 return
1365 1365
1366 1366 def pushData(self,dataOut):
1367 1367 '''
1368 1368 Return the PULSEPAIR and the profiles used in the operation
1369 1369 Affected : self.__profileIndex
1370 1370 '''
1371 1371 #----------------- Remove DC-----------------------------------
1372 1372 if self.removeDC==True:
1373 1373 mean = numpy.mean(self.__buffer,1)
1374 1374 tmp = mean.reshape(self.__nch,1,self.__nHeis)
1375 1375 dc= numpy.tile(tmp,[1,self.__nProf,1])
1376 1376 self.__buffer = self.__buffer - dc
1377 1377 #------------------Calculo de Potencia ------------------------
1378 1378 pair0 = self.__buffer*numpy.conj(self.__buffer)
1379 1379 pair0 = pair0.real
1380 1380 lag_0 = numpy.sum(pair0,1)
1381 1381 #------------------Calculo de Ruido x canal--------------------
1382 1382 self.noise = numpy.zeros(self.__nch)
1383 1383 for i in range(self.__nch):
1384 1384 daux = numpy.sort(pair0[i,:,:],axis= None)
1385 1385 self.noise[i]=hildebrand_sekhon( daux ,self.nCohInt)
1386 1386
1387 1387 self.noise = self.noise.reshape(self.__nch,1)
1388 1388 self.noise = numpy.tile(self.noise,[1,self.__nHeis])
1389 1389 noise_buffer = self.noise.reshape(self.__nch,1,self.__nHeis)
1390 1390 noise_buffer = numpy.tile(noise_buffer,[1,self.__nProf,1])
1391 1391 #------------------ Potencia recibida= P , Potencia senal = S , Ruido= N--
1392 1392 #------------------ P= S+N ,P=lag_0/N ---------------------------------
1393 1393 #-------------------- Power --------------------------------------------------
1394 1394 data_power = lag_0/(self.n*self.nCohInt)
1395 1395 #------------------ Senal ---------------------------------------------------
1396 1396 data_intensity = pair0 - noise_buffer
1397 1397 data_intensity = numpy.sum(data_intensity,axis=1)*(self.n*self.nCohInt)#*self.nCohInt)
1398 1398 #data_intensity = (lag_0-self.noise*self.n)*(self.n*self.nCohInt)
1399 1399 for i in range(self.__nch):
1400 1400 for j in range(self.__nHeis):
1401 1401 if data_intensity[i][j] < 0:
1402 1402 data_intensity[i][j] = numpy.min(numpy.absolute(data_intensity[i][j]))
1403 1403
1404 1404 #----------------- Calculo de Frecuencia y Velocidad doppler--------
1405 1405 pair1 = self.__buffer[:,:-1,:]*numpy.conjugate(self.__buffer[:,1:,:])
1406 1406 lag_1 = numpy.sum(pair1,1)
1407 1407 data_freq = (-1/(2.0*math.pi*self.ippSec*self.nCohInt))*numpy.angle(lag_1)
1408 1408 data_velocity = (self.lambda_/2.0)*data_freq
1409 1409
1410 1410 #---------------- Potencia promedio estimada de la Senal-----------
1411 1411 lag_0 = lag_0/self.n
1412 1412 S = lag_0-self.noise
1413 1413
1414 1414 #---------------- Frecuencia Doppler promedio ---------------------
1415 1415 lag_1 = lag_1/(self.n-1)
1416 1416 R1 = numpy.abs(lag_1)
1417 1417
1418 1418 #---------------- Calculo del SNR----------------------------------
1419 1419 data_snrPP = S/self.noise
1420 1420 for i in range(self.__nch):
1421 1421 for j in range(self.__nHeis):
1422 1422 if data_snrPP[i][j] < 1.e-20:
1423 1423 data_snrPP[i][j] = 1.e-20
1424 1424
1425 1425 #----------------- Calculo del ancho espectral ----------------------
1426 1426 L = S/R1
1427 1427 L = numpy.where(L<0,1,L)
1428 1428 L = numpy.log(L)
1429 1429 tmp = numpy.sqrt(numpy.absolute(L))
1430 1430 data_specwidth = (self.lambda_/(2*math.sqrt(2)*math.pi*self.ippSec*self.nCohInt))*tmp*numpy.sign(L)
1431 1431 n = self.__profIndex
1432 1432
1433 1433 self.__buffer = numpy.zeros((self.__nch, self.__nProf,self.__nHeis), dtype='complex')
1434 1434 self.__profIndex = 0
1435 1435 return data_power,data_intensity,data_velocity,data_snrPP,data_specwidth,n
1436 1436
1437 1437
1438 1438 def pulsePairbyProfiles(self,dataOut):
1439 1439
1440 1440 self.__dataReady = False
1441 1441 data_power = None
1442 1442 data_intensity = None
1443 1443 data_velocity = None
1444 1444 data_specwidth = None
1445 1445 data_snrPP = None
1446 1446 self.putData(data=dataOut.data)
1447 1447 if self.__profIndex == self.n:
1448 1448 data_power,data_intensity, data_velocity,data_snrPP,data_specwidth, n = self.pushData(dataOut=dataOut)
1449 1449 self.__dataReady = True
1450 1450
1451 1451 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth
1452 1452
1453 1453
1454 1454 def pulsePairOp(self, dataOut, datatime= None):
1455 1455
1456 1456 if self.__initime == None:
1457 1457 self.__initime = datatime
1458 1458 data_power, data_intensity, data_velocity, data_snrPP, data_specwidth = self.pulsePairbyProfiles(dataOut)
1459 1459 self.__lastdatatime = datatime
1460 1460
1461 1461 if data_power is None:
1462 1462 return None, None, None,None,None,None
1463 1463
1464 1464 avgdatatime = self.__initime
1465 1465 deltatime = datatime - self.__lastdatatime
1466 1466 self.__initime = datatime
1467 1467
1468 1468 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth, avgdatatime
1469 1469
1470 1470 def run(self, dataOut,n = None,removeDC= False, overlapping= False,**kwargs):
1471 1471
1472 1472 if not self.isConfig:
1473 1473 self.setup(dataOut = dataOut, n = n , removeDC=removeDC , **kwargs)
1474 1474 self.isConfig = True
1475 1475 data_power, data_intensity, data_velocity,data_snrPP,data_specwidth, avgdatatime = self.pulsePairOp(dataOut, dataOut.utctime)
1476 1476 dataOut.flagNoData = True
1477 1477
1478 1478 if self.__dataReady:
1479 1479 dataOut.nCohInt *= self.n
1480 1480 dataOut.dataPP_POW = data_intensity # S
1481 print("help",data_power)
1482 dataOut.dataPP_POWER = data_power # P
1481 dataOut.dataPP_POWER = data_power # P valor que corresponde a POTENCIA MOMENTO
1483 1482 dataOut.dataPP_DOP = data_velocity
1484 1483 dataOut.dataPP_SNR = data_snrPP
1485 1484 dataOut.dataPP_WIDTH = data_specwidth
1486 1485 dataOut.PRFbyAngle = self.n #numero de PRF*cada angulo rotado que equivale a un tiempo.
1487 1486 dataOut.nProfiles = int(dataOut.nProfiles/n)
1488 1487 dataOut.utctime = avgdatatime
1489 1488 dataOut.flagNoData = False
1490 1489 return dataOut
1491 1490
1492 1491
1493 1492
1494 1493 # import collections
1495 1494 # from scipy.stats import mode
1496 1495 #
1497 1496 # class Synchronize(Operation):
1498 1497 #
1499 1498 # isConfig = False
1500 1499 # __profIndex = 0
1501 1500 #
1502 1501 # def __init__(self, **kwargs):
1503 1502 #
1504 1503 # Operation.__init__(self, **kwargs)
1505 1504 # # self.isConfig = False
1506 1505 # self.__powBuffer = None
1507 1506 # self.__startIndex = 0
1508 1507 # self.__pulseFound = False
1509 1508 #
1510 1509 # def __findTxPulse(self, dataOut, channel=0, pulse_with = None):
1511 1510 #
1512 1511 # #Read data
1513 1512 #
1514 1513 # powerdB = dataOut.getPower(channel = channel)
1515 1514 # noisedB = dataOut.getNoise(channel = channel)[0]
1516 1515 #
1517 1516 # self.__powBuffer.extend(powerdB.flatten())
1518 1517 #
1519 1518 # dataArray = numpy.array(self.__powBuffer)
1520 1519 #
1521 1520 # filteredPower = numpy.correlate(dataArray, dataArray[0:self.__nSamples], "same")
1522 1521 #
1523 1522 # maxValue = numpy.nanmax(filteredPower)
1524 1523 #
1525 1524 # if maxValue < noisedB + 10:
1526 1525 # #No se encuentra ningun pulso de transmision
1527 1526 # return None
1528 1527 #
1529 1528 # maxValuesIndex = numpy.where(filteredPower > maxValue - 0.1*abs(maxValue))[0]
1530 1529 #
1531 1530 # if len(maxValuesIndex) < 2:
1532 1531 # #Solo se encontro un solo pulso de transmision de un baudio, esperando por el siguiente TX
1533 1532 # return None
1534 1533 #
1535 1534 # phasedMaxValuesIndex = maxValuesIndex - self.__nSamples
1536 1535 #
1537 1536 # #Seleccionar solo valores con un espaciamiento de nSamples
1538 1537 # pulseIndex = numpy.intersect1d(maxValuesIndex, phasedMaxValuesIndex)
1539 1538 #
1540 1539 # if len(pulseIndex) < 2:
1541 1540 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1542 1541 # return None
1543 1542 #
1544 1543 # spacing = pulseIndex[1:] - pulseIndex[:-1]
1545 1544 #
1546 1545 # #remover senales que se distancien menos de 10 unidades o muestras
1547 1546 # #(No deberian existir IPP menor a 10 unidades)
1548 1547 #
1549 1548 # realIndex = numpy.where(spacing > 10 )[0]
1550 1549 #
1551 1550 # if len(realIndex) < 2:
1552 1551 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1553 1552 # return None
1554 1553 #
1555 1554 # #Eliminar pulsos anchos (deja solo la diferencia entre IPPs)
1556 1555 # realPulseIndex = pulseIndex[realIndex]
1557 1556 #
1558 1557 # period = mode(realPulseIndex[1:] - realPulseIndex[:-1])[0][0]
1559 1558 #
1560 1559 # print "IPP = %d samples" %period
1561 1560 #
1562 1561 # self.__newNSamples = dataOut.nHeights #int(period)
1563 1562 # self.__startIndex = int(realPulseIndex[0])
1564 1563 #
1565 1564 # return 1
1566 1565 #
1567 1566 #
1568 1567 # def setup(self, nSamples, nChannels, buffer_size = 4):
1569 1568 #
1570 1569 # self.__powBuffer = collections.deque(numpy.zeros( buffer_size*nSamples,dtype=numpy.float),
1571 1570 # maxlen = buffer_size*nSamples)
1572 1571 #
1573 1572 # bufferList = []
1574 1573 #
1575 1574 # for i in range(nChannels):
1576 1575 # bufferByChannel = collections.deque(numpy.zeros( buffer_size*nSamples, dtype=numpy.complex) + numpy.NAN,
1577 1576 # maxlen = buffer_size*nSamples)
1578 1577 #
1579 1578 # bufferList.append(bufferByChannel)
1580 1579 #
1581 1580 # self.__nSamples = nSamples
1582 1581 # self.__nChannels = nChannels
1583 1582 # self.__bufferList = bufferList
1584 1583 #
1585 1584 # def run(self, dataOut, channel = 0):
1586 1585 #
1587 1586 # if not self.isConfig:
1588 1587 # nSamples = dataOut.nHeights
1589 1588 # nChannels = dataOut.nChannels
1590 1589 # self.setup(nSamples, nChannels)
1591 1590 # self.isConfig = True
1592 1591 #
1593 1592 # #Append new data to internal buffer
1594 1593 # for thisChannel in range(self.__nChannels):
1595 1594 # bufferByChannel = self.__bufferList[thisChannel]
1596 1595 # bufferByChannel.extend(dataOut.data[thisChannel])
1597 1596 #
1598 1597 # if self.__pulseFound:
1599 1598 # self.__startIndex -= self.__nSamples
1600 1599 #
1601 1600 # #Finding Tx Pulse
1602 1601 # if not self.__pulseFound:
1603 1602 # indexFound = self.__findTxPulse(dataOut, channel)
1604 1603 #
1605 1604 # if indexFound == None:
1606 1605 # dataOut.flagNoData = True
1607 1606 # return
1608 1607 #
1609 1608 # self.__arrayBuffer = numpy.zeros((self.__nChannels, self.__newNSamples), dtype = numpy.complex)
1610 1609 # self.__pulseFound = True
1611 1610 # self.__startIndex = indexFound
1612 1611 #
1613 1612 # #If pulse was found ...
1614 1613 # for thisChannel in range(self.__nChannels):
1615 1614 # bufferByChannel = self.__bufferList[thisChannel]
1616 1615 # #print self.__startIndex
1617 1616 # x = numpy.array(bufferByChannel)
1618 1617 # self.__arrayBuffer[thisChannel] = x[self.__startIndex:self.__startIndex+self.__newNSamples]
1619 1618 #
1620 1619 # deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1621 1620 # dataOut.heightList = numpy.arange(self.__newNSamples)*deltaHeight
1622 1621 # # dataOut.ippSeconds = (self.__newNSamples / deltaHeight)/1e6
1623 1622 #
1624 1623 # dataOut.data = self.__arrayBuffer
1625 1624 #
1626 1625 # self.__startIndex += self.__newNSamples
1627 1626 #
1628 1627 # return
@@ -1,217 +1,217
1 1 # Ing. AVP
2 2 # 06/10/2021
3 3 # ARCHIVO DE LECTURA
4 4 import os, sys
5 5 import datetime
6 6 import time
7 7 from schainpy.controller import Project
8 8 #### NOTA###########################################
9 9 # INPUT :
10 10 # VELOCIDAD PARAMETRO : V = 2Β°/seg
11 11 # MODO PULSE PAIR O MOMENTOS: 0 : Pulse Pair ,1 : Momentos
12 12 ######################################################
13 13 ##### PROCESAMIENTO ##################################
14 14 ##### OJO TENER EN CUENTA EL n= para el Pulse Pair ##
15 15 ##### O EL n= nFFTPoints ###
16 16 ######################################################
17 17 ######## BUSCAMOS EL numero de IPP equivalente 1Β°#####
18 18 ######## Sea V la velocidad del Pedestal en Β°/seg#####
19 19 ######## 1Β° sera Recorrido en un tiempo de 1/V ######
20 20 ######## IPP del Radar 400 useg --> 60 Km ############
21 21 ######## n = 1/(V(Β°/seg)*IPP(Km)) , NUMERO DE IPP ##
22 22 ######## n = 1/(V*IPP) #############################
23 23 ######## VELOCIDAD DEL PEDESTAL ######################
24 24 print("SETUP- RADAR METEOROLOGICO")
25 25 V = 10
26 mode = 1
26 mode = 0
27 27 #path = '/DATA_RM/23/6v'
28 28 #path = '/DATA_RM/TEST_INTEGRACION_2M'
29 29 path = '/DATA_RM/WR_20_OCT'
30 30
31 31 #path_ped='/DATA_RM/TEST_PEDESTAL/P20211012-082745'
32 32 path_ped='/DATA_RM/TEST_PEDESTAL/P20211020-131248'
33 33
34 34 figpath_pp = "/home/soporte/Pictures/TEST_PP"
35 35 figpath_mom = "/home/soporte/Pictures/TEST_MOM"
36 36 plot = 0
37 37 integration = 1
38 38 save = 0
39 39 if save == 1:
40 40 if mode==0:
41 41 path_save = '/DATA_RM/TEST_HDF5_PP_23/6v'
42 42 path_save = '/DATA_RM/TEST_HDF5_PP'
43 43 path_save = '/DATA_RM/TEST_HDF5_PP_100'
44 44 else:
45 45 path_save = '/DATA_RM/TEST_HDF5_SPEC_23_V2/6v'
46 46
47 47 print("* PATH data ADQ :", path)
48 48 print("* Velocidad Pedestal :",V,"Β°/seg")
49 49 ############################ NRO Perfiles PROCESAMIENTO ###################
50 50 V=V
51 51 IPP=400*1e-6
52 52 n= int(1/(V*IPP))
53 53 print("* n - NRO Perfiles Proc:", n )
54 54 ################################## MODE ###################################
55 55 print("* Modo de Operacion :",mode)
56 56 if mode ==0:
57 57 print("* Met. Seleccionado : Pulse Pair")
58 58 else:
59 59 print("* Met. Momentos : Momentos")
60 60
61 61 ################################## MODE ###################################
62 62 print("* Grabado de datos :",save)
63 63 if save ==1:
64 64 if mode==0:
65 65 ope= "Pulse Pair"
66 66 else:
67 67 ope= "Momentos"
68 68 print("* Path-Save Data -", ope , path_save)
69 69
70 70 print("* Integracion de datos :",integration)
71 71
72 72 time.sleep(5)
73 73 #remotefolder = "/home/wmaster/graficos"
74 74 #######################################################################
75 75 ################# RANGO DE PLOTEO######################################
76 76 dBmin = '1'
77 77 dBmax = '85'
78 78 xmin = '15'
79 79 xmax = '15.25'
80 80 ymin = '0'
81 81 ymax = '600'
82 82 #######################################################################
83 83 ########################FECHA##########################################
84 84 str = datetime.date.today()
85 85 today = str.strftime("%Y/%m/%d")
86 86 str2 = str - datetime.timedelta(days=1)
87 87 yesterday = str2.strftime("%Y/%m/%d")
88 88 #######################################################################
89 89 ########################SIGNAL CHAIN ##################################
90 90 #######################################################################
91 91 desc = "USRP_test"
92 92 filename = "USRP_processing.xml"
93 93 controllerObj = Project()
94 94 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
95 95 #######################################################################
96 96 ######################## UNIDAD DE LECTURA#############################
97 97 #######################################################################
98 98 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
99 99 path=path,
100 100 startDate="2021/01/01",#today,
101 101 endDate="2021/12/30",#today,
102 102 startTime='00:00:00',
103 103 endTime='23:59:59',
104 104 delay=0,
105 105 #set=0,
106 106 online=0,
107 107 walk=1,
108 108 ippKm = 60)
109 109
110 110 opObj11 = readUnitConfObj.addOperation(name='printInfo')
111 111
112 112 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
113 113
114 114 if mode ==0:
115 115 ####################### METODO PULSE PAIR ######################################################################
116 116 opObj11 = procUnitConfObjA.addOperation(name='PulsePair', optype='other')
117 117 opObj11.addParameter(name='n', value=int(n), format='int')#10 VOY A USAR 250 DADO QUE LA VELOCIDAD ES 10 GRADOS
118 118 #opObj11.addParameter(name='removeDC', value=1, format='int')
119 119 ####################### METODO Parametros ######################################################################
120 120 procUnitConfObjB= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjA.getId())
121 121 if plot==1:
122 122 opObj11 = procUnitConfObjB.addOperation(name='GenericRTIPlot',optype='external')
123 123 opObj11.addParameter(name='attr_data', value='dataPP_POW')
124 124 opObj11.addParameter(name='colormap', value='jet')
125 125 opObj11.addParameter(name='xmin', value=xmin)
126 126 opObj11.addParameter(name='xmax', value=xmax)
127 127 opObj11.addParameter(name='zmin', value=dBmin)
128 128 opObj11.addParameter(name='zmax', value=dBmax)
129 129 opObj11.addParameter(name='save', value=figpath_pp)
130 130 opObj11.addParameter(name='showprofile', value=0)
131 131 opObj11.addParameter(name='save_period', value=50)
132 132
133 133 ####################### METODO ESCRITURA #######################################################################
134 134 if save==1:
135 135 opObj10 = procUnitConfObjB.addOperation(name='HDFWriter')
136 136 opObj10.addParameter(name='path',value=path_save)
137 137 #opObj10.addParameter(name='mode',value=0)
138 138 opObj10.addParameter(name='blocksPerFile',value='100',format='int')
139 139 opObj10.addParameter(name='metadataList',value='utctimeInit,timeZone,paramInterval,profileIndex,channelList,heightList,flagDataAsBlock',format='list')
140 140 opObj10.addParameter(name='dataList',value='dataPP_POW,dataPP_DOP,utctime',format='list')#,format='list'
141 141 if integration==1:
142 142 V=10
143 143 blocksPerfile=360
144 144 print("* Velocidad del Pedestal:",V)
145 145 tmp_blocksPerfile = 100
146 146 f_a_p= int(tmp_blocksPerfile/V)
147 147
148 148 opObj11 = procUnitConfObjB.addOperation(name='PedestalInformation')
149 149 opObj11.addParameter(name='path_ped', value=path_ped)
150 150 #opObj11.addParameter(name='path_adq', value=path_adq)
151 151 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
152 152 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
153 153 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
154 154 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
155 155 opObj11.addParameter(name='online', value='0', format='int')
156 156
157 157 opObj11 = procUnitConfObjB.addOperation(name='Block360')
158 158 opObj11.addParameter(name='n', value='10', format='int')
159 159 opObj11.addParameter(name='mode', value=mode, format='int')
160 160
161 161 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
162 162
163 163 opObj11= procUnitConfObjB.addOperation(name='WeatherPlot',optype='other')
164 164
165 165
166 166 else:
167 167 ####################### METODO SPECTROS ######################################################################
168 168 procUnitConfObjB = controllerObj.addProcUnit(datatype='SpectraProc', inputId=procUnitConfObjA.getId())
169 169 procUnitConfObjB.addParameter(name='nFFTPoints', value=n, format='int')
170 170 procUnitConfObjB.addParameter(name='nProfiles' , value=n, format='int')
171 171
172 172 procUnitConfObjC = controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjB.getId())
173 173 procUnitConfObjC.addOperation(name='SpectralMoments')
174 174 if plot==1:
175 175 dBmin = '1'
176 176 dBmax = '65'
177 177 opObj11 = procUnitConfObjC.addOperation(name='PowerPlot',optype='external')
178 178 opObj11.addParameter(name='xmin', value=xmin)
179 179 opObj11.addParameter(name='xmax', value=xmax)
180 180 opObj11.addParameter(name='zmin', value=dBmin)
181 181 opObj11.addParameter(name='zmax', value=dBmax)
182 182 opObj11.addParameter(name='save', value=figpath_mom)
183 183 opObj11.addParameter(name='showprofile', value=0)
184 184 opObj11.addParameter(name='save_period', value=100)
185 185
186 186 if save==1:
187 187 opObj10 = procUnitConfObjC.addOperation(name='HDFWriter')
188 188 opObj10.addParameter(name='path',value=path_save)
189 189 #opObj10.addParameter(name='mode',value=0)
190 190 opObj10.addParameter(name='blocksPerFile',value='360',format='int')
191 191 #opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
192 192 opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
193 193 opObj10.addParameter(name='dataList',value='data_pow,data_dop,utctime',format='list')#,format='list'
194 194
195 195 if integration==1:
196 196 V=10
197 197 blocksPerfile=360
198 198 print("* Velocidad del Pedestal:",V)
199 199 tmp_blocksPerfile = 100
200 200 f_a_p= int(tmp_blocksPerfile/V)
201 201
202 202 opObj11 = procUnitConfObjC.addOperation(name='PedestalInformation')
203 203 opObj11.addParameter(name='path_ped', value=path_ped)
204 204 #opObj11.addParameter(name='path_adq', value=path_adq)
205 205 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
206 206 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
207 207 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
208 208 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
209 209 opObj11.addParameter(name='online', value='0', format='int')
210 210
211 211 opObj11 = procUnitConfObjC.addOperation(name='Block360')
212 212 opObj11.addParameter(name='n', value='10', format='int')
213 213 opObj11.addParameter(name='mode', value=mode, format='int')
214 214
215 215 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
216 216 opObj11= procUnitConfObjC.addOperation(name='WeatherPlot',optype='other')
217 217 controllerObj.start()
General Comments 0
You need to be logged in to leave comments. Login now