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