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