##// END OF EJS Templates
LAST CHANGE WR
avaldez -
r1393:ccbe99dfcead
parent child
Show More
@@ -0,0 +1,217
1 # Ing. AVP
2 # 06/10/2021
3 # ARCHIVO DE LECTURA
4 import os, sys
5 import datetime
6 import time
7 from schainpy.controller import Project
8 #### NOTA###########################################
9 # INPUT :
10 # VELOCIDAD PARAMETRO : V = 2Β°/seg
11 # MODO PULSE PAIR O MOMENTOS: 0 : Pulse Pair ,1 : Momentos
12 ######################################################
13 ##### PROCESAMIENTO ##################################
14 ##### OJO TENER EN CUENTA EL n= para el Pulse Pair ##
15 ##### O EL n= nFFTPoints ###
16 ######################################################
17 ######## BUSCAMOS EL numero de IPP equivalente 1Β°#####
18 ######## Sea V la velocidad del Pedestal en Β°/seg#####
19 ######## 1Β° sera Recorrido en un tiempo de 1/V ######
20 ######## IPP del Radar 400 useg --> 60 Km ############
21 ######## n = 1/(V(Β°/seg)*IPP(Km)) , NUMERO DE IPP ##
22 ######## n = 1/(V*IPP) #############################
23 ######## VELOCIDAD DEL PEDESTAL ######################
24 print("SETUP- RADAR METEOROLOGICO")
25 V = 10
26 mode = 1
27 #path = '/DATA_RM/23/6v'
28 #path = '/DATA_RM/TEST_INTEGRACION_2M'
29 path = '/DATA_RM/WR_20_OCT'
30
31 #path_ped='/DATA_RM/TEST_PEDESTAL/P20211012-082745'
32 path_ped='/DATA_RM/TEST_PEDESTAL/P20211020-131248'
33
34 figpath_pp = "/home/soporte/Pictures/TEST_PP"
35 figpath_mom = "/home/soporte/Pictures/TEST_MOM"
36 plot = 0
37 integration = 1
38 save = 0
39 if save == 1:
40 if mode==0:
41 path_save = '/DATA_RM/TEST_HDF5_PP_23/6v'
42 path_save = '/DATA_RM/TEST_HDF5_PP'
43 path_save = '/DATA_RM/TEST_HDF5_PP_100'
44 else:
45 path_save = '/DATA_RM/TEST_HDF5_SPEC_23_V2/6v'
46
47 print("* PATH data ADQ :", path)
48 print("* Velocidad Pedestal :",V,"Β°/seg")
49 ############################ NRO Perfiles PROCESAMIENTO ###################
50 V=V
51 IPP=400*1e-6
52 n= int(1/(V*IPP))
53 print("* n - NRO Perfiles Proc:", n )
54 ################################## MODE ###################################
55 print("* Modo de Operacion :",mode)
56 if mode ==0:
57 print("* Met. Seleccionado : Pulse Pair")
58 else:
59 print("* Met. Momentos : Momentos")
60
61 ################################## MODE ###################################
62 print("* Grabado de datos :",save)
63 if save ==1:
64 if mode==0:
65 ope= "Pulse Pair"
66 else:
67 ope= "Momentos"
68 print("* Path-Save Data -", ope , path_save)
69
70 print("* Integracion de datos :",integration)
71
72 time.sleep(15)
73 #remotefolder = "/home/wmaster/graficos"
74 #######################################################################
75 ################# RANGO DE PLOTEO######################################
76 dBmin = '1'
77 dBmax = '85'
78 xmin = '15'
79 xmax = '15.25'
80 ymin = '0'
81 ymax = '600'
82 #######################################################################
83 ########################FECHA##########################################
84 str = datetime.date.today()
85 today = str.strftime("%Y/%m/%d")
86 str2 = str - datetime.timedelta(days=1)
87 yesterday = str2.strftime("%Y/%m/%d")
88 #######################################################################
89 ########################SIGNAL CHAIN ##################################
90 #######################################################################
91 desc = "USRP_test"
92 filename = "USRP_processing.xml"
93 controllerObj = Project()
94 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
95 #######################################################################
96 ######################## UNIDAD DE LECTURA#############################
97 #######################################################################
98 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
99 path=path,
100 startDate="2021/01/01",#today,
101 endDate="2021/12/30",#today,
102 startTime='00:00:00',
103 endTime='23:59:59',
104 delay=0,
105 #set=0,
106 online=0,
107 walk=1,
108 ippKm = 60)
109
110 opObj11 = readUnitConfObj.addOperation(name='printInfo')
111
112 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
113
114 if mode ==0:
115 ####################### METODO PULSE PAIR ######################################################################
116 opObj11 = procUnitConfObjA.addOperation(name='PulsePair', optype='other')
117 opObj11.addParameter(name='n', value=int(n), format='int')#10 VOY A USAR 250 DADO QUE LA VELOCIDAD ES 10 GRADOS
118 #opObj11.addParameter(name='removeDC', value=1, format='int')
119 ####################### METODO Parametros ######################################################################
120 procUnitConfObjB= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjA.getId())
121 if plot==1:
122 opObj11 = procUnitConfObjB.addOperation(name='GenericRTIPlot',optype='external')
123 opObj11.addParameter(name='attr_data', value='dataPP_POW')
124 opObj11.addParameter(name='colormap', value='jet')
125 opObj11.addParameter(name='xmin', value=xmin)
126 opObj11.addParameter(name='xmax', value=xmax)
127 opObj11.addParameter(name='zmin', value=dBmin)
128 opObj11.addParameter(name='zmax', value=dBmax)
129 opObj11.addParameter(name='save', value=figpath_pp)
130 opObj11.addParameter(name='showprofile', value=0)
131 opObj11.addParameter(name='save_period', value=50)
132
133 ####################### METODO ESCRITURA #######################################################################
134 if save==1:
135 opObj10 = procUnitConfObjB.addOperation(name='HDFWriter')
136 opObj10.addParameter(name='path',value=path_save)
137 #opObj10.addParameter(name='mode',value=0)
138 opObj10.addParameter(name='blocksPerFile',value='100',format='int')
139 opObj10.addParameter(name='metadataList',value='utctimeInit,timeZone,paramInterval,profileIndex,channelList,heightList,flagDataAsBlock',format='list')
140 opObj10.addParameter(name='dataList',value='dataPP_POW,dataPP_DOP,utctime',format='list')#,format='list'
141 if integration==1:
142 V=10
143 blocksPerfile=360
144 print("* Velocidad del Pedestal:",V)
145 tmp_blocksPerfile = 100
146 f_a_p= int(tmp_blocksPerfile/V)
147
148 opObj11 = procUnitConfObjB.addOperation(name='PedestalInformation')
149 opObj11.addParameter(name='path_ped', value=path_ped)
150 #opObj11.addParameter(name='path_adq', value=path_adq)
151 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
152 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
153 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
154 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
155 opObj11.addParameter(name='online', value='0', format='int')
156
157 opObj11 = procUnitConfObjB.addOperation(name='Block360')
158 opObj11.addParameter(name='n', value='10', format='int')
159 opObj11.addParameter(name='mode', value=mode, format='int')
160
161 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
162
163 opObj11= procUnitConfObjB.addOperation(name='WeatherPlot',optype='other')
164
165
166 else:
167 ####################### METODO SPECTROS ######################################################################
168 procUnitConfObjB = controllerObj.addProcUnit(datatype='SpectraProc', inputId=procUnitConfObjA.getId())
169 procUnitConfObjB.addParameter(name='nFFTPoints', value=n, format='int')
170 procUnitConfObjB.addParameter(name='nProfiles' , value=n, format='int')
171
172 procUnitConfObjC = controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjB.getId())
173 procUnitConfObjC.addOperation(name='SpectralMoments')
174 if plot==1:
175 dBmin = '1'
176 dBmax = '65'
177 opObj11 = procUnitConfObjC.addOperation(name='PowerPlot',optype='external')
178 opObj11.addParameter(name='xmin', value=xmin)
179 opObj11.addParameter(name='xmax', value=xmax)
180 opObj11.addParameter(name='zmin', value=dBmin)
181 opObj11.addParameter(name='zmax', value=dBmax)
182 opObj11.addParameter(name='save', value=figpath_mom)
183 opObj11.addParameter(name='showprofile', value=0)
184 opObj11.addParameter(name='save_period', value=100)
185
186 if save==1:
187 opObj10 = procUnitConfObjC.addOperation(name='HDFWriter')
188 opObj10.addParameter(name='path',value=path_save)
189 #opObj10.addParameter(name='mode',value=0)
190 opObj10.addParameter(name='blocksPerFile',value='360',format='int')
191 #opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
192 opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
193 opObj10.addParameter(name='dataList',value='data_pow,data_dop,utctime',format='list')#,format='list'
194
195 if integration==1:
196 V=10
197 blocksPerfile=360
198 print("* Velocidad del Pedestal:",V)
199 tmp_blocksPerfile = 100
200 f_a_p= int(tmp_blocksPerfile/V)
201
202 opObj11 = procUnitConfObjC.addOperation(name='PedestalInformation')
203 opObj11.addParameter(name='path_ped', value=path_ped)
204 #opObj11.addParameter(name='path_adq', value=path_adq)
205 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
206 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
207 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
208 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
209 opObj11.addParameter(name='online', value='0', format='int')
210
211 opObj11 = procUnitConfObjC.addOperation(name='Block360')
212 opObj11.addParameter(name='n', value='30', format='int')
213 opObj11.addParameter(name='mode', value=mode, format='int')
214
215 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
216 opObj11= procUnitConfObjC.addOperation(name='WeatherPlot',optype='other')
217 controllerObj.start()
@@ -0,0 +1,13
1
2 PULSE PAIR
3 help [[1.364 1.376 1.28 ... 1.352 1.372 1.332]
4 [2.912 3.012 3.06 ... 3.056 2.6 2.936]]
5 help [[1.256 1.304 1.212 ... 1.228 1.328 1.528]
6 [2.744 2.604 2.492 ... 2.544 2.916 2.644]]
7 help [[1.176 1.248 1.48 ... 1.388 1.396 1.216]
8 [2.564 2.524 2.756 ... 2.772 2.7 2.684]]
9
10 help [[1.312 1.328 1.28 ... 1.28 1.444 1.532]
11 [3. 2.964 3.092 ... 3.104 3.016 2.984]]
12
13 MOMENTOS
@@ -0,0 +1,69
1 # Ing. AVP
2 # 06/10/2021
3 # ARCHIVO DE LECTURA
4 import os, sys
5 import datetime
6 import time
7 from schainpy.controller import Project
8
9 print("SETUP- RADAR METEOROLOGICO")
10 V = 10
11 #######################################################################
12 ################# RANGO DE PLOTEO######################################
13 dBmin = '1'
14 dBmax = '65'
15 xmin = '13.2'
16 xmax = '13.5'
17 ymin = '0'
18 ymax = '60'
19
20 path = '/DATA_RM/WR_20_OCT'
21 figpath_pp = "/home/soporte/Pictures/TEST_PP"
22
23
24 IPP=400*1e-6
25 n= int(1/(V*IPP))
26 #n=250
27 print("* n - NRO Perfiles Proc:", n )
28
29 desc = "USRP_test"
30 filename = "USRP_processing.xml"
31 controllerObj = Project()
32 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
33 #######################################################################
34 ######################## UNIDAD DE LECTURA#############################
35 #######################################################################
36 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
37 path=path,
38 startDate="2021/01/01",#today,
39 endDate="2021/12/30",#today,
40 startTime='00:00:00',
41 endTime='23:59:59',
42 delay=0,
43 #set=0,
44 online=0,
45 walk=1,
46 ippKm = 60)
47
48 opObj11 = readUnitConfObj.addOperation(name='printInfo')
49
50 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
51
52 opObj11 = procUnitConfObjA.addOperation(name='PulsePair', optype='other')
53 opObj11.addParameter(name='n', value=int(n), format='int')#10 VOY A USAR 250 DADO QUE LA VELOCIDAD ES 10 GRADOS
54 #opObj11.addParameter(name='removeDC', value=1, format='int')
55
56 procUnitConfObjB= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjA.getId())
57
58 opObj11 = procUnitConfObjB.addOperation(name='GenericRTIPlot',optype='external')
59 opObj11.addParameter(name='attr_data', value='dataPP_POWER')
60 opObj11.addParameter(name='colormap', value='jet')
61 opObj11.addParameter(name='xmin', value=xmin)
62 opObj11.addParameter(name='xmax', value=xmax)
63 opObj11.addParameter(name='zmin', value=dBmin)
64 opObj11.addParameter(name='zmax', value=dBmax)
65 opObj11.addParameter(name='save', value=figpath_pp)
66 opObj11.addParameter(name='showprofile', value=0)
67 #opObj11.addParameter(name='save_period', value=10)
68
69 controllerObj.start()
@@ -0,0 +1,80
1 # Ing. AVP
2 # 06/10/2021
3 # ARCHIVO DE LECTURA
4 import os, sys
5 import datetime
6 import time
7 from schainpy.controller import Project
8
9 print("SETUP- RADAR METEOROLOGICO")
10 V = 10
11 #######################################################################
12 ################# RANGO DE PLOTEO######################################
13 dBmin = '1'
14 dBmax = '65'
15 xmin = '13.2'
16 xmax = '13.5'
17 ymin = '0'
18 ymax = '60'
19
20 path = '/DATA_RM/WR_20_OCT'
21 figpath_spec = "/home/soporte/Pictures/TEST_MOM"
22
23
24 IPP=400*1e-6
25 n= int(1/(V*IPP))
26 print("* n - NRO Perfiles Proc:", n )
27 time.sleep(5)
28 desc = "USRP_test"
29 filename = "USRP_processing.xml"
30 controllerObj = Project()
31 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
32 #######################################################################
33 ######################## UNIDAD DE LECTURA#############################
34 #######################################################################
35 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
36 path=path,
37 startDate="2021/01/01",#today,
38 endDate="2021/12/30",#today,
39 startTime='00:00:00',
40 endTime='23:59:59',
41 delay=0,
42 #set=0,
43 online=0,
44 walk=1,
45 ippKm = 60)
46
47 opObj11 = readUnitConfObj.addOperation(name='printInfo')
48
49 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
50
51 procUnitConfObjB = controllerObj.addProcUnit(datatype='SpectraProc', inputId=procUnitConfObjA.getId())
52 procUnitConfObjB.addParameter(name='nFFTPoints', value=n, format='int')
53 procUnitConfObjB.addParameter(name='nProfiles' , value=n, format='int')
54 '''
55 opObj11 = procUnitConfObjB.addOperation(name='RTIPlot', optype='external')
56 #.addParameter(name='id', value='2', format='int')
57 opObj11.addParameter(name='wintitle', value='RTIPlot', format='str')
58 opObj11.addParameter(name='xmin', value=xmin)
59 opObj11.addParameter(name='xmax', value=xmax)
60 opObj11.addParameter(name='zmin', value=dBmin, format='int')
61 opObj11.addParameter(name='zmax', value=dBmax, format='int')
62 '''
63 #opObj13 = procUnitConfObjB.addOperation(name='removeDC')
64 #opObj13.addParameter(name='mode', value='2', format='int')
65
66 procUnitConfObjC = controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjB.getId())
67 procUnitConfObjC.addOperation(name='SpectralMoments')
68
69 dBmin = '1'
70 dBmax = '65'
71 opObj11 = procUnitConfObjC.addOperation(name='PowerPlot',optype='external')
72 opObj11.addParameter(name='xmin', value=xmin)
73 opObj11.addParameter(name='xmax', value=xmax)
74 opObj11.addParameter(name='zmin', value=dBmin)
75 opObj11.addParameter(name='zmax', value=dBmax)
76 opObj11.addParameter(name='save', value=figpath_spec)
77 opObj11.addParameter(name='showprofile', value=0)
78 #opObj11.addParameter(name='save_period', value=10)
79
80 controllerObj.start()
@@ -1,1069 +1,1068
1 1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 2 # All rights reserved.
3 3 #
4 4 # Distributed under the terms of the BSD 3-clause license.
5 5 """Definition of diferent Data objects for different types of data
6 6
7 7 Here you will find the diferent data objects for the different types
8 8 of data, this data objects must be used as dataIn or dataOut objects in
9 9 processing units and operations. Currently the supported data objects are:
10 10 Voltage, Spectra, SpectraHeis, Fits, Correlation and Parameters
11 11 """
12 12
13 13 import copy
14 14 import numpy
15 15 import datetime
16 16 import json
17 17
18 18 import schainpy.admin
19 19 from schainpy.utils import log
20 20 from .jroheaderIO import SystemHeader, RadarControllerHeader
21 21 from schainpy.model.data import _noise
22 22
23 23
24 24 def getNumpyDtype(dataTypeCode):
25 25
26 26 if dataTypeCode == 0:
27 27 numpyDtype = numpy.dtype([('real', '<i1'), ('imag', '<i1')])
28 28 elif dataTypeCode == 1:
29 29 numpyDtype = numpy.dtype([('real', '<i2'), ('imag', '<i2')])
30 30 elif dataTypeCode == 2:
31 31 numpyDtype = numpy.dtype([('real', '<i4'), ('imag', '<i4')])
32 32 elif dataTypeCode == 3:
33 33 numpyDtype = numpy.dtype([('real', '<i8'), ('imag', '<i8')])
34 34 elif dataTypeCode == 4:
35 35 numpyDtype = numpy.dtype([('real', '<f4'), ('imag', '<f4')])
36 36 elif dataTypeCode == 5:
37 37 numpyDtype = numpy.dtype([('real', '<f8'), ('imag', '<f8')])
38 38 else:
39 39 raise ValueError('dataTypeCode was not defined')
40 40
41 41 return numpyDtype
42 42
43 43
44 44 def getDataTypeCode(numpyDtype):
45 45
46 46 if numpyDtype == numpy.dtype([('real', '<i1'), ('imag', '<i1')]):
47 47 datatype = 0
48 48 elif numpyDtype == numpy.dtype([('real', '<i2'), ('imag', '<i2')]):
49 49 datatype = 1
50 50 elif numpyDtype == numpy.dtype([('real', '<i4'), ('imag', '<i4')]):
51 51 datatype = 2
52 52 elif numpyDtype == numpy.dtype([('real', '<i8'), ('imag', '<i8')]):
53 53 datatype = 3
54 54 elif numpyDtype == numpy.dtype([('real', '<f4'), ('imag', '<f4')]):
55 55 datatype = 4
56 56 elif numpyDtype == numpy.dtype([('real', '<f8'), ('imag', '<f8')]):
57 57 datatype = 5
58 58 else:
59 59 datatype = None
60 60
61 61 return datatype
62 62
63 63
64 64 def hildebrand_sekhon(data, navg):
65 65 """
66 66 This method is for the objective determination of the noise level in Doppler spectra. This
67 67 implementation technique is based on the fact that the standard deviation of the spectral
68 68 densities is equal to the mean spectral density for white Gaussian noise
69 69
70 70 Inputs:
71 71 Data : heights
72 72 navg : numbers of averages
73 73
74 74 Return:
75 75 mean : noise's level
76 76 """
77 77
78 78 sortdata = numpy.sort(data, axis=None)
79 79 '''
80 80 lenOfData = len(sortdata)
81 81 nums_min = lenOfData*0.2
82 82
83 83 if nums_min <= 5:
84 84
85 85 nums_min = 5
86 86
87 87 sump = 0.
88 88 sumq = 0.
89 89
90 90 j = 0
91 91 cont = 1
92 92
93 93 while((cont == 1)and(j < lenOfData)):
94 94
95 95 sump += sortdata[j]
96 96 sumq += sortdata[j]**2
97 97
98 98 if j > nums_min:
99 99 rtest = float(j)/(j-1) + 1.0/navg
100 100 if ((sumq*j) > (rtest*sump**2)):
101 101 j = j - 1
102 102 sump = sump - sortdata[j]
103 103 sumq = sumq - sortdata[j]**2
104 104 cont = 0
105 105
106 106 j += 1
107 107
108 108 lnoise = sump / j
109 109 '''
110 110 return _noise.hildebrand_sekhon(sortdata, navg)
111 111
112 112
113 113 class Beam:
114 114
115 115 def __init__(self):
116 116 self.codeList = []
117 117 self.azimuthList = []
118 118 self.zenithList = []
119 119
120 120
121 121 class GenericData(object):
122 122
123 123 flagNoData = True
124 124
125 125 def copy(self, inputObj=None):
126 126
127 127 if inputObj == None:
128 128 return copy.deepcopy(self)
129 129
130 130 for key in list(inputObj.__dict__.keys()):
131 131
132 132 attribute = inputObj.__dict__[key]
133 133
134 134 # If this attribute is a tuple or list
135 135 if type(inputObj.__dict__[key]) in (tuple, list):
136 136 self.__dict__[key] = attribute[:]
137 137 continue
138 138
139 139 # If this attribute is another object or instance
140 140 if hasattr(attribute, '__dict__'):
141 141 self.__dict__[key] = attribute.copy()
142 142 continue
143 143
144 144 self.__dict__[key] = inputObj.__dict__[key]
145 145
146 146 def deepcopy(self):
147 147
148 148 return copy.deepcopy(self)
149 149
150 150 def isEmpty(self):
151 151
152 152 return self.flagNoData
153 153
154 154 def isReady(self):
155 155
156 156 return not self.flagNoData
157 157
158 158
159 159 class JROData(GenericData):
160 160
161 161 systemHeaderObj = SystemHeader()
162 162 radarControllerHeaderObj = RadarControllerHeader()
163 163 type = None
164 164 datatype = None # dtype but in string
165 165 nProfiles = None
166 166 heightList = None
167 167 channelList = None
168 168 flagDiscontinuousBlock = False
169 169 useLocalTime = False
170 170 utctime = None
171 171 timeZone = None
172 172 dstFlag = None
173 173 errorCount = None
174 174 blocksize = None
175 175 flagDecodeData = False # asumo q la data no esta decodificada
176 176 flagDeflipData = False # asumo q la data no esta sin flip
177 177 flagShiftFFT = False
178 178 nCohInt = None
179 179 windowOfFilter = 1
180 180 C = 3e8
181 181 frequency = 49.92e6
182 182 realtime = False
183 183 beacon_heiIndexList = None
184 184 last_block = None
185 185 blocknow = None
186 186 azimuth = None
187 187 zenith = None
188 188 beam = Beam()
189 189 profileIndex = None
190 190 error = None
191 191 data = None
192 192 nmodes = None
193 193 metadata_list = ['heightList', 'timeZone', 'type']
194 194
195 195 def __str__(self):
196 196
197 197 return '{} - {}'.format(self.type, self.datatime())
198 198
199 199 def getNoise(self):
200 200
201 201 raise NotImplementedError
202 202
203 203 @property
204 204 def nChannels(self):
205 205
206 206 return len(self.channelList)
207 207
208 208 @property
209 209 def channelIndexList(self):
210 210
211 211 return list(range(self.nChannels))
212 212
213 213 @property
214 214 def nHeights(self):
215 215
216 216 return len(self.heightList)
217 217
218 218 def getDeltaH(self):
219 219
220 220 return self.heightList[1] - self.heightList[0]
221 221
222 222 @property
223 223 def ltctime(self):
224 224
225 225 if self.useLocalTime:
226 226 return self.utctime - self.timeZone * 60
227 227
228 228 return self.utctime
229 229
230 230 @property
231 231 def datatime(self):
232 232
233 233 datatimeValue = datetime.datetime.utcfromtimestamp(self.ltctime)
234 234 return datatimeValue
235 235
236 236 def getTimeRange(self):
237 237
238 238 datatime = []
239 239
240 240 datatime.append(self.ltctime)
241 241 datatime.append(self.ltctime + self.timeInterval + 1)
242 242
243 243 datatime = numpy.array(datatime)
244 244
245 245 return datatime
246 246
247 247 def getFmaxTimeResponse(self):
248 248
249 249 period = (10**-6) * self.getDeltaH() / (0.15)
250 250
251 251 PRF = 1. / (period * self.nCohInt)
252 252
253 253 fmax = PRF
254 254
255 255 return fmax
256 256
257 257 def getFmax(self):
258 258 PRF = 1. / (self.ippSeconds * self.nCohInt)
259 259
260 260 fmax = PRF
261 261 return fmax
262 262
263 263 def getVmax(self):
264 264
265 265 _lambda = self.C / self.frequency
266 266
267 267 vmax = self.getFmax() * _lambda / 2
268 268
269 269 return vmax
270 270
271 271 @property
272 272 def ippSeconds(self):
273 273 '''
274 274 '''
275 275 return self.radarControllerHeaderObj.ippSeconds
276 276
277 277 @ippSeconds.setter
278 278 def ippSeconds(self, ippSeconds):
279 279 '''
280 280 '''
281 281 self.radarControllerHeaderObj.ippSeconds = ippSeconds
282 282
283 283 @property
284 284 def code(self):
285 285 '''
286 286 '''
287 287 return self.radarControllerHeaderObj.code
288 288
289 289 @code.setter
290 290 def code(self, code):
291 291 '''
292 292 '''
293 293 self.radarControllerHeaderObj.code = code
294 294
295 295 @property
296 296 def nCode(self):
297 297 '''
298 298 '''
299 299 return self.radarControllerHeaderObj.nCode
300 300
301 301 @nCode.setter
302 302 def nCode(self, ncode):
303 303 '''
304 304 '''
305 305 self.radarControllerHeaderObj.nCode = ncode
306 306
307 307 @property
308 308 def nBaud(self):
309 309 '''
310 310 '''
311 311 return self.radarControllerHeaderObj.nBaud
312 312
313 313 @nBaud.setter
314 314 def nBaud(self, nbaud):
315 315 '''
316 316 '''
317 317 self.radarControllerHeaderObj.nBaud = nbaud
318 318
319 319 @property
320 320 def ipp(self):
321 321 '''
322 322 '''
323 323 return self.radarControllerHeaderObj.ipp
324 324
325 325 @ipp.setter
326 326 def ipp(self, ipp):
327 327 '''
328 328 '''
329 329 self.radarControllerHeaderObj.ipp = ipp
330 330
331 331 @property
332 332 def metadata(self):
333 333 '''
334 334 '''
335 335
336 336 return {attr: getattr(self, attr) for attr in self.metadata_list}
337 337
338 338
339 339 class Voltage(JROData):
340 340
341 341 dataPP_POW = None
342 342 dataPP_DOP = None
343 343 dataPP_WIDTH = None
344 344 dataPP_SNR = None
345 345
346 346 def __init__(self):
347 347 '''
348 348 Constructor
349 349 '''
350 350
351 351 self.useLocalTime = True
352 352 self.radarControllerHeaderObj = RadarControllerHeader()
353 353 self.systemHeaderObj = SystemHeader()
354 354 self.type = "Voltage"
355 355 self.data = None
356 356 self.nProfiles = None
357 357 self.heightList = None
358 358 self.channelList = None
359 359 self.flagNoData = True
360 360 self.flagDiscontinuousBlock = False
361 361 self.utctime = None
362 362 self.timeZone = 0
363 363 self.dstFlag = None
364 364 self.errorCount = None
365 365 self.nCohInt = None
366 366 self.blocksize = None
367 367 self.flagCohInt = False
368 368 self.flagDecodeData = False # asumo q la data no esta decodificada
369 369 self.flagDeflipData = False # asumo q la data no esta sin flip
370 370 self.flagShiftFFT = False
371 371 self.flagDataAsBlock = False # Asumo que la data es leida perfil a perfil
372 372 self.profileIndex = 0
373 373 self.metadata_list = ['type', 'heightList', 'timeZone', 'nProfiles', 'channelList', 'nCohInt',
374 374 'code', 'nCode', 'nBaud', 'ippSeconds', 'ipp']
375 375
376 376 def getNoisebyHildebrand(self, channel=None):
377 377 """
378 378 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
379 379
380 380 Return:
381 381 noiselevel
382 382 """
383 383
384 384 if channel != None:
385 385 data = self.data[channel]
386 386 nChannels = 1
387 387 else:
388 388 data = self.data
389 389 nChannels = self.nChannels
390 390
391 391 noise = numpy.zeros(nChannels)
392 392 power = data * numpy.conjugate(data)
393 393
394 394 for thisChannel in range(nChannels):
395 395 if nChannels == 1:
396 396 daux = power[:].real
397 397 else:
398 398 daux = power[thisChannel, :].real
399 399 noise[thisChannel] = hildebrand_sekhon(daux, self.nCohInt)
400 400
401 401 return noise
402 402
403 403 def getNoise(self, type=1, channel=None):
404 404
405 405 if type == 1:
406 406 noise = self.getNoisebyHildebrand(channel)
407 407
408 408 return noise
409 409
410 410 def getPower(self, channel=None):
411 411
412 412 if channel != None:
413 413 data = self.data[channel]
414 414 else:
415 415 data = self.data
416 416
417 417 power = data * numpy.conjugate(data)
418 418 powerdB = 10 * numpy.log10(power.real)
419 419 powerdB = numpy.squeeze(powerdB)
420 420
421 421 return powerdB
422 422
423 423 @property
424 424 def timeInterval(self):
425 425
426 426 return self.ippSeconds * self.nCohInt
427 427
428 428 noise = property(getNoise, "I'm the 'nHeights' property.")
429 429
430 430
431 431 class Spectra(JROData):
432 432
433 433 def __init__(self):
434 434 '''
435 435 Constructor
436 436 '''
437 437
438 438 self.data_dc = None
439 439 self.data_spc = None
440 440 self.data_cspc = None
441 441 self.useLocalTime = True
442 442 self.radarControllerHeaderObj = RadarControllerHeader()
443 443 self.systemHeaderObj = SystemHeader()
444 444 self.type = "Spectra"
445 445 self.timeZone = 0
446 446 self.nProfiles = None
447 447 self.heightList = None
448 448 self.channelList = None
449 449 self.pairsList = None
450 450 self.flagNoData = True
451 451 self.flagDiscontinuousBlock = False
452 452 self.utctime = None
453 453 self.nCohInt = None
454 454 self.nIncohInt = None
455 455 self.blocksize = None
456 456 self.nFFTPoints = None
457 457 self.wavelength = None
458 458 self.flagDecodeData = False # asumo q la data no esta decodificada
459 459 self.flagDeflipData = False # asumo q la data no esta sin flip
460 460 self.flagShiftFFT = False
461 461 self.ippFactor = 1
462 462 self.beacon_heiIndexList = []
463 463 self.noise_estimation = None
464 464 self.metadata_list = ['type', 'heightList', 'timeZone', 'pairsList', 'channelList', 'nCohInt',
465 465 'code', 'nCode', 'nBaud', 'ippSeconds', 'ipp','nIncohInt', 'nFFTPoints', 'nProfiles']
466 466
467 467 def getNoisebyHildebrand(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
468 468 """
469 469 Determino el nivel de ruido usando el metodo Hildebrand-Sekhon
470 470
471 471 Return:
472 472 noiselevel
473 473 """
474 474
475 475 noise = numpy.zeros(self.nChannels)
476 476
477 477 for channel in range(self.nChannels):
478 478 daux = self.data_spc[channel,
479 479 xmin_index:xmax_index, ymin_index:ymax_index]
480 480 noise[channel] = hildebrand_sekhon(daux, self.nIncohInt)
481 481
482 482 return noise
483 483
484 484 def getNoise(self, xmin_index=None, xmax_index=None, ymin_index=None, ymax_index=None):
485 485
486 486 if self.noise_estimation is not None:
487 487 # this was estimated by getNoise Operation defined in jroproc_spectra.py
488 488 return self.noise_estimation
489 489 else:
490 490 noise = self.getNoisebyHildebrand(
491 491 xmin_index, xmax_index, ymin_index, ymax_index)
492 492 return noise
493 493
494 494 def getFreqRangeTimeResponse(self, extrapoints=0):
495 495
496 496 deltafreq = self.getFmaxTimeResponse() / (self.nFFTPoints * self.ippFactor)
497 497 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.) - deltafreq / 2
498 498
499 499 return freqrange
500 500
501 501 def getAcfRange(self, extrapoints=0):
502 502
503 503 deltafreq = 10. / (self.getFmax() / (self.nFFTPoints * self.ippFactor))
504 504 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
505 505
506 506 return freqrange
507 507
508 508 def getFreqRange(self, extrapoints=0):
509 509
510 510 deltafreq = self.getFmax() / (self.nFFTPoints * self.ippFactor)
511 511 freqrange = deltafreq * (numpy.arange(self.nFFTPoints + extrapoints) -self.nFFTPoints / 2.) - deltafreq / 2
512 512
513 513 return freqrange
514 514
515 515 def getVelRange(self, extrapoints=0):
516 516
517 517 deltav = self.getVmax() / (self.nFFTPoints * self.ippFactor)
518 518 velrange = deltav * (numpy.arange(self.nFFTPoints + extrapoints) - self.nFFTPoints / 2.)
519 519
520 520 if self.nmodes:
521 521 return velrange/self.nmodes
522 522 else:
523 523 return velrange
524 524
525 525 @property
526 526 def nPairs(self):
527 527
528 528 return len(self.pairsList)
529 529
530 530 @property
531 531 def pairsIndexList(self):
532 532
533 533 return list(range(self.nPairs))
534 534
535 535 @property
536 536 def normFactor(self):
537 537
538 538 pwcode = 1
539 539
540 540 if self.flagDecodeData:
541 541 pwcode = numpy.sum(self.code[0]**2)
542 542 #normFactor = min(self.nFFTPoints,self.nProfiles)*self.nIncohInt*self.nCohInt*pwcode*self.windowOfFilter
543 543 normFactor = self.nProfiles * self.nIncohInt * self.nCohInt * pwcode * self.windowOfFilter
544 544
545 545 return normFactor
546 546
547 547 @property
548 548 def flag_cspc(self):
549 549
550 550 if self.data_cspc is None:
551 551 return True
552 552
553 553 return False
554 554
555 555 @property
556 556 def flag_dc(self):
557 557
558 558 if self.data_dc is None:
559 559 return True
560 560
561 561 return False
562 562
563 563 @property
564 564 def timeInterval(self):
565 565
566 566 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt * self.nProfiles * self.ippFactor
567 567 if self.nmodes:
568 568 return self.nmodes*timeInterval
569 569 else:
570 570 return timeInterval
571 571
572 572 def getPower(self):
573 573
574 574 factor = self.normFactor
575 575 z = self.data_spc / factor
576 576 z = numpy.where(numpy.isfinite(z), z, numpy.NAN)
577 577 avg = numpy.average(z, axis=1)
578
579 578 return 10 * numpy.log10(avg)
580 579
581 580 def getCoherence(self, pairsList=None, phase=False):
582 581
583 582 z = []
584 583 if pairsList is None:
585 584 pairsIndexList = self.pairsIndexList
586 585 else:
587 586 pairsIndexList = []
588 587 for pair in pairsList:
589 588 if pair not in self.pairsList:
590 589 raise ValueError("Pair %s is not in dataOut.pairsList" % (
591 590 pair))
592 591 pairsIndexList.append(self.pairsList.index(pair))
593 592 for i in range(len(pairsIndexList)):
594 593 pair = self.pairsList[pairsIndexList[i]]
595 594 ccf = numpy.average(self.data_cspc[pairsIndexList[i], :, :], axis=0)
596 595 powa = numpy.average(self.data_spc[pair[0], :, :], axis=0)
597 596 powb = numpy.average(self.data_spc[pair[1], :, :], axis=0)
598 597 avgcoherenceComplex = ccf / numpy.sqrt(powa * powb)
599 598 if phase:
600 599 data = numpy.arctan2(avgcoherenceComplex.imag,
601 600 avgcoherenceComplex.real) * 180 / numpy.pi
602 601 else:
603 602 data = numpy.abs(avgcoherenceComplex)
604 603
605 604 z.append(data)
606 605
607 606 return numpy.array(z)
608 607
609 608 def setValue(self, value):
610 609
611 610 print("This property should not be initialized")
612 611
613 612 return
614 613
615 614 noise = property(getNoise, setValue, "I'm the 'nHeights' property.")
616 615
617 616
618 617 class SpectraHeis(Spectra):
619 618
620 619 def __init__(self):
621 620
622 621 self.radarControllerHeaderObj = RadarControllerHeader()
623 622 self.systemHeaderObj = SystemHeader()
624 623 self.type = "SpectraHeis"
625 624 self.nProfiles = None
626 625 self.heightList = None
627 626 self.channelList = None
628 627 self.flagNoData = True
629 628 self.flagDiscontinuousBlock = False
630 629 self.utctime = None
631 630 self.blocksize = None
632 631 self.profileIndex = 0
633 632 self.nCohInt = 1
634 633 self.nIncohInt = 1
635 634
636 635 @property
637 636 def normFactor(self):
638 637 pwcode = 1
639 638 if self.flagDecodeData:
640 639 pwcode = numpy.sum(self.code[0]**2)
641 640
642 641 normFactor = self.nIncohInt * self.nCohInt * pwcode
643 642
644 643 return normFactor
645 644
646 645 @property
647 646 def timeInterval(self):
648 647
649 648 return self.ippSeconds * self.nCohInt * self.nIncohInt
650 649
651 650
652 651 class Fits(JROData):
653 652
654 653 def __init__(self):
655 654
656 655 self.type = "Fits"
657 656 self.nProfiles = None
658 657 self.heightList = None
659 658 self.channelList = None
660 659 self.flagNoData = True
661 660 self.utctime = None
662 661 self.nCohInt = 1
663 662 self.nIncohInt = 1
664 663 self.useLocalTime = True
665 664 self.profileIndex = 0
666 665 self.timeZone = 0
667 666
668 667 def getTimeRange(self):
669 668
670 669 datatime = []
671 670
672 671 datatime.append(self.ltctime)
673 672 datatime.append(self.ltctime + self.timeInterval)
674 673
675 674 datatime = numpy.array(datatime)
676 675
677 676 return datatime
678 677
679 678 def getChannelIndexList(self):
680 679
681 680 return list(range(self.nChannels))
682 681
683 682 def getNoise(self, type=1):
684 683
685 684
686 685 if type == 1:
687 686 noise = self.getNoisebyHildebrand()
688 687
689 688 if type == 2:
690 689 noise = self.getNoisebySort()
691 690
692 691 if type == 3:
693 692 noise = self.getNoisebyWindow()
694 693
695 694 return noise
696 695
697 696 @property
698 697 def timeInterval(self):
699 698
700 699 timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
701 700
702 701 return timeInterval
703 702
704 703 @property
705 704 def ippSeconds(self):
706 705 '''
707 706 '''
708 707 return self.ipp_sec
709 708
710 709 noise = property(getNoise, "I'm the 'nHeights' property.")
711 710
712 711
713 712 class Correlation(JROData):
714 713
715 714 def __init__(self):
716 715 '''
717 716 Constructor
718 717 '''
719 718 self.radarControllerHeaderObj = RadarControllerHeader()
720 719 self.systemHeaderObj = SystemHeader()
721 720 self.type = "Correlation"
722 721 self.data = None
723 722 self.dtype = None
724 723 self.nProfiles = None
725 724 self.heightList = None
726 725 self.channelList = None
727 726 self.flagNoData = True
728 727 self.flagDiscontinuousBlock = False
729 728 self.utctime = None
730 729 self.timeZone = 0
731 730 self.dstFlag = None
732 731 self.errorCount = None
733 732 self.blocksize = None
734 733 self.flagDecodeData = False # asumo q la data no esta decodificada
735 734 self.flagDeflipData = False # asumo q la data no esta sin flip
736 735 self.pairsList = None
737 736 self.nPoints = None
738 737
739 738 def getPairsList(self):
740 739
741 740 return self.pairsList
742 741
743 742 def getNoise(self, mode=2):
744 743
745 744 indR = numpy.where(self.lagR == 0)[0][0]
746 745 indT = numpy.where(self.lagT == 0)[0][0]
747 746
748 747 jspectra0 = self.data_corr[:, :, indR, :]
749 748 jspectra = copy.copy(jspectra0)
750 749
751 750 num_chan = jspectra.shape[0]
752 751 num_hei = jspectra.shape[2]
753 752
754 753 freq_dc = jspectra.shape[1] / 2
755 754 ind_vel = numpy.array([-2, -1, 1, 2]) + freq_dc
756 755
757 756 if ind_vel[0] < 0:
758 757 ind_vel[list(range(0, 1))] = ind_vel[list(
759 758 range(0, 1))] + self.num_prof
760 759
761 760 if mode == 1:
762 761 jspectra[:, freq_dc, :] = (
763 762 jspectra[:, ind_vel[1], :] + jspectra[:, ind_vel[2], :]) / 2 # CORRECCION
764 763
765 764 if mode == 2:
766 765
767 766 vel = numpy.array([-2, -1, 1, 2])
768 767 xx = numpy.zeros([4, 4])
769 768
770 769 for fil in range(4):
771 770 xx[fil, :] = vel[fil]**numpy.asarray(list(range(4)))
772 771
773 772 xx_inv = numpy.linalg.inv(xx)
774 773 xx_aux = xx_inv[0, :]
775 774
776 775 for ich in range(num_chan):
777 776 yy = jspectra[ich, ind_vel, :]
778 777 jspectra[ich, freq_dc, :] = numpy.dot(xx_aux, yy)
779 778
780 779 junkid = jspectra[ich, freq_dc, :] <= 0
781 780 cjunkid = sum(junkid)
782 781
783 782 if cjunkid.any():
784 783 jspectra[ich, freq_dc, junkid.nonzero()] = (
785 784 jspectra[ich, ind_vel[1], junkid] + jspectra[ich, ind_vel[2], junkid]) / 2
786 785
787 786 noise = jspectra0[:, freq_dc, :] - jspectra[:, freq_dc, :]
788 787
789 788 return noise
790 789
791 790 @property
792 791 def timeInterval(self):
793 792
794 793 return self.ippSeconds * self.nCohInt * self.nProfiles
795 794
796 795 def splitFunctions(self):
797 796
798 797 pairsList = self.pairsList
799 798 ccf_pairs = []
800 799 acf_pairs = []
801 800 ccf_ind = []
802 801 acf_ind = []
803 802 for l in range(len(pairsList)):
804 803 chan0 = pairsList[l][0]
805 804 chan1 = pairsList[l][1]
806 805
807 806 # Obteniendo pares de Autocorrelacion
808 807 if chan0 == chan1:
809 808 acf_pairs.append(chan0)
810 809 acf_ind.append(l)
811 810 else:
812 811 ccf_pairs.append(pairsList[l])
813 812 ccf_ind.append(l)
814 813
815 814 data_acf = self.data_cf[acf_ind]
816 815 data_ccf = self.data_cf[ccf_ind]
817 816
818 817 return acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf
819 818
820 819 @property
821 820 def normFactor(self):
822 821 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.splitFunctions()
823 822 acf_pairs = numpy.array(acf_pairs)
824 823 normFactor = numpy.zeros((self.nPairs, self.nHeights))
825 824
826 825 for p in range(self.nPairs):
827 826 pair = self.pairsList[p]
828 827
829 828 ch0 = pair[0]
830 829 ch1 = pair[1]
831 830
832 831 ch0_max = numpy.max(data_acf[acf_pairs == ch0, :, :], axis=1)
833 832 ch1_max = numpy.max(data_acf[acf_pairs == ch1, :, :], axis=1)
834 833 normFactor[p, :] = numpy.sqrt(ch0_max * ch1_max)
835 834
836 835 return normFactor
837 836
838 837
839 838 class Parameters(Spectra):
840 839
841 840 groupList = None # List of Pairs, Groups, etc
842 841 data_param = None # Parameters obtained
843 842 data_pre = None # Data Pre Parametrization
844 843 data_SNR = None # Signal to Noise Ratio
845 844 abscissaList = None # Abscissa, can be velocities, lags or time
846 845 utctimeInit = None # Initial UTC time
847 846 paramInterval = None # Time interval to calculate Parameters in seconds
848 847 useLocalTime = True
849 848 # Fitting
850 849 data_error = None # Error of the estimation
851 850 constants = None
852 851 library = None
853 852 # Output signal
854 853 outputInterval = None # Time interval to calculate output signal in seconds
855 854 data_output = None # Out signal
856 855 nAvg = None
857 856 noise_estimation = None
858 857 GauSPC = None # Fit gaussian SPC
859 858
860 859 def __init__(self):
861 860 '''
862 861 Constructor
863 862 '''
864 863 self.radarControllerHeaderObj = RadarControllerHeader()
865 864 self.systemHeaderObj = SystemHeader()
866 865 self.type = "Parameters"
867 866 self.timeZone = 0
868 867
869 868 def getTimeRange1(self, interval):
870 869
871 870 datatime = []
872 871
873 872 if self.useLocalTime:
874 873 time1 = self.utctimeInit - self.timeZone * 60
875 874 else:
876 875 time1 = self.utctimeInit
877 876
878 877 datatime.append(time1)
879 878 datatime.append(time1 + interval)
880 879 datatime = numpy.array(datatime)
881 880
882 881 return datatime
883 882
884 883 @property
885 884 def timeInterval(self):
886 885
887 886 if hasattr(self, 'timeInterval1'):
888 887 return self.timeInterval1
889 888 else:
890 889 return self.paramInterval
891 890
892 891 def setValue(self, value):
893 892
894 893 print("This property should not be initialized")
895 894
896 895 return
897 896
898 897 def getNoise(self):
899 898
900 899 return self.spc_noise
901 900
902 901 noise = property(getNoise, setValue, "I'm the 'Noise' property.")
903 902
904 903
905 904 class PlotterData(object):
906 905 '''
907 906 Object to hold data to be plotted
908 907 '''
909 908
910 909 MAXNUMX = 200
911 910 MAXNUMY = 200
912 911
913 912 def __init__(self, code, exp_code, localtime=True):
914 913
915 914 self.key = code
916 915 self.exp_code = exp_code
917 916 self.ready = False
918 917 self.flagNoData = False
919 918 self.localtime = localtime
920 919 self.data = {}
921 920 self.meta = {}
922 921 self.__heights = []
923 922
924 923 def __str__(self):
925 924 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
926 925 return 'Data[{}][{}]'.format(';'.join(dum), len(self.times))
927 926
928 927 def __len__(self):
929 928 return len(self.data)
930 929
931 930 def __getitem__(self, key):
932 931 if isinstance(key, int):
933 932 return self.data[self.times[key]]
934 933 elif isinstance(key, str):
935 934 ret = numpy.array([self.data[x][key] for x in self.times])
936 935 if ret.ndim > 1:
937 936 ret = numpy.swapaxes(ret, 0, 1)
938 937 return ret
939 938
940 939 def __contains__(self, key):
941 940 return key in self.data[self.min_time]
942 941
943 942 def setup(self):
944 943 '''
945 944 Configure object
946 945 '''
947 946 self.type = ''
948 947 self.ready = False
949 948 del self.data
950 949 self.data = {}
951 950 self.__heights = []
952 951 self.__all_heights = set()
953 952
954 953 def shape(self, key):
955 954 '''
956 955 Get the shape of the one-element data for the given key
957 956 '''
958 957
959 958 if len(self.data[self.min_time][key]):
960 959 return self.data[self.min_time][key].shape
961 960 return (0,)
962 961
963 962 def update(self, data, tm, meta={}):
964 963 '''
965 964 Update data object with new dataOut
966 965 '''
967 966
968 967 self.data[tm] = data
969 968
970 969 for key, value in meta.items():
971 970 setattr(self, key, value)
972 971
973 972 def normalize_heights(self):
974 973 '''
975 974 Ensure same-dimension of the data for different heighList
976 975 '''
977 976
978 977 H = numpy.array(list(self.__all_heights))
979 978 H.sort()
980 979 for key in self.data:
981 980 shape = self.shape(key)[:-1] + H.shape
982 981 for tm, obj in list(self.data[key].items()):
983 982 h = self.__heights[self.times.tolist().index(tm)]
984 983 if H.size == h.size:
985 984 continue
986 985 index = numpy.where(numpy.in1d(H, h))[0]
987 986 dummy = numpy.zeros(shape) + numpy.nan
988 987 if len(shape) == 2:
989 988 dummy[:, index] = obj
990 989 else:
991 990 dummy[index] = obj
992 991 self.data[key][tm] = dummy
993 992
994 993 self.__heights = [H for tm in self.times]
995 994
996 995 def jsonify(self, tm, plot_name, plot_type, decimate=False):
997 996 '''
998 997 Convert data to json
999 998 '''
1000 999
1001 1000 meta = {}
1002 1001 meta['xrange'] = []
1003 1002 dy = int(len(self.yrange)/self.MAXNUMY) + 1
1004 1003 tmp = self.data[tm][self.key]
1005 1004 shape = tmp.shape
1006 1005 if len(shape) == 2:
1007 1006 data = self.roundFloats(self.data[tm][self.key][::, ::dy].tolist())
1008 1007 elif len(shape) == 3:
1009 1008 dx = int(self.data[tm][self.key].shape[1]/self.MAXNUMX) + 1
1010 1009 data = self.roundFloats(
1011 1010 self.data[tm][self.key][::, ::dx, ::dy].tolist())
1012 1011 meta['xrange'] = self.roundFloats(self.xrange[2][::dx].tolist())
1013 1012 else:
1014 1013 data = self.roundFloats(self.data[tm][self.key].tolist())
1015 1014
1016 1015 ret = {
1017 1016 'plot': plot_name,
1018 1017 'code': self.exp_code,
1019 1018 'time': float(tm),
1020 1019 'data': data,
1021 1020 }
1022 1021 meta['type'] = plot_type
1023 1022 meta['interval'] = float(self.interval)
1024 1023 meta['localtime'] = self.localtime
1025 1024 meta['yrange'] = self.roundFloats(self.yrange[::dy].tolist())
1026 1025 meta.update(self.meta)
1027 1026 ret['metadata'] = meta
1028 1027 return json.dumps(ret)
1029 1028
1030 1029 @property
1031 1030 def times(self):
1032 1031 '''
1033 1032 Return the list of times of the current data
1034 1033 '''
1035 1034
1036 1035 ret = [t for t in self.data]
1037 1036 ret.sort()
1038 1037 return numpy.array(ret)
1039 1038
1040 1039 @property
1041 1040 def min_time(self):
1042 1041 '''
1043 1042 Return the minimun time value
1044 1043 '''
1045 1044
1046 1045 return self.times[0]
1047 1046
1048 1047 @property
1049 1048 def max_time(self):
1050 1049 '''
1051 1050 Return the maximun time value
1052 1051 '''
1053 1052
1054 1053 return self.times[-1]
1055 1054
1056 1055 # @property
1057 1056 # def heights(self):
1058 1057 # '''
1059 1058 # Return the list of heights of the current data
1060 1059 # '''
1061 1060
1062 1061 # return numpy.array(self.__heights[-1])
1063 1062
1064 1063 @staticmethod
1065 1064 def roundFloats(obj):
1066 1065 if isinstance(obj, list):
1067 1066 return list(map(PlotterData.roundFloats, obj))
1068 1067 elif isinstance(obj, float):
1069 1068 return round(obj, 2)
@@ -1,519 +1,509
1 1 import os
2 2 import datetime
3 3 import numpy
4 4
5 5 from schainpy.model.graphics.jroplot_base import Plot, plt
6 6 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot
7 7 from schainpy.utils import log
8 8 # libreria wradlib
9 9 import wradlib as wrl
10 10
11 11 EARTH_RADIUS = 6.3710e3
12 12
13 13
14 14 def ll2xy(lat1, lon1, lat2, lon2):
15 15
16 16 p = 0.017453292519943295
17 17 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
18 18 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
19 19 r = 12742 * numpy.arcsin(numpy.sqrt(a))
20 20 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
21 21 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
22 22 theta = -theta + numpy.pi/2
23 23 return r*numpy.cos(theta), r*numpy.sin(theta)
24 24
25 25
26 26 def km2deg(km):
27 27 '''
28 28 Convert distance in km to degrees
29 29 '''
30 30
31 31 return numpy.rad2deg(km/EARTH_RADIUS)
32 32
33 33
34 34
35 35 class SpectralMomentsPlot(SpectraPlot):
36 36 '''
37 37 Plot for Spectral Moments
38 38 '''
39 39 CODE = 'spc_moments'
40 40 # colormap = 'jet'
41 41 # plot_type = 'pcolor'
42 42
43 43 class DobleGaussianPlot(SpectraPlot):
44 44 '''
45 45 Plot for Double Gaussian Plot
46 46 '''
47 47 CODE = 'gaussian_fit'
48 48 # colormap = 'jet'
49 49 # plot_type = 'pcolor'
50 50
51 51 class DoubleGaussianSpectraCutPlot(SpectraCutPlot):
52 52 '''
53 53 Plot SpectraCut with Double Gaussian Fit
54 54 '''
55 55 CODE = 'cut_gaussian_fit'
56 56
57 57 class SnrPlot(RTIPlot):
58 58 '''
59 59 Plot for SNR Data
60 60 '''
61 61
62 62 CODE = 'snr'
63 63 colormap = 'jet'
64 64
65 65 def update(self, dataOut):
66 66
67 67 data = {
68 68 'snr': 10*numpy.log10(dataOut.data_snr)
69 69 }
70 70
71 71 return data, {}
72 72
73 73 class DopplerPlot(RTIPlot):
74 74 '''
75 75 Plot for DOPPLER Data (1st moment)
76 76 '''
77 77
78 78 CODE = 'dop'
79 79 colormap = 'jet'
80 80
81 81 def update(self, dataOut):
82 82
83 83 data = {
84 84 'dop': 10*numpy.log10(dataOut.data_dop)
85 85 }
86 86
87 87 return data, {}
88 88
89 89 class PowerPlot(RTIPlot):
90 90 '''
91 91 Plot for Power Data (0 moment)
92 92 '''
93 93
94 94 CODE = 'pow'
95 95 colormap = 'jet'
96 96
97 97 def update(self, dataOut):
98
99 98 data = {
100 99 'pow': 10*numpy.log10(dataOut.data_pow/dataOut.normFactor)
101 100 }
102
103 101 return data, {}
104 102
105 103 class SpectralWidthPlot(RTIPlot):
106 104 '''
107 105 Plot for Spectral Width Data (2nd moment)
108 106 '''
109 107
110 108 CODE = 'width'
111 109 colormap = 'jet'
112 110
113 111 def update(self, dataOut):
114 112
115 113 data = {
116 114 'width': dataOut.data_width
117 115 }
118 116
119 117 return data, {}
120 118
121 119 class SkyMapPlot(Plot):
122 120 '''
123 121 Plot for meteors detection data
124 122 '''
125 123
126 124 CODE = 'param'
127 125
128 126 def setup(self):
129 127
130 128 self.ncols = 1
131 129 self.nrows = 1
132 130 self.width = 7.2
133 131 self.height = 7.2
134 132 self.nplots = 1
135 133 self.xlabel = 'Zonal Zenith Angle (deg)'
136 134 self.ylabel = 'Meridional Zenith Angle (deg)'
137 135 self.polar = True
138 136 self.ymin = -180
139 137 self.ymax = 180
140 138 self.colorbar = False
141 139
142 140 def plot(self):
143 141
144 142 arrayParameters = numpy.concatenate(self.data['param'])
145 143 error = arrayParameters[:, -1]
146 144 indValid = numpy.where(error == 0)[0]
147 145 finalMeteor = arrayParameters[indValid, :]
148 146 finalAzimuth = finalMeteor[:, 3]
149 147 finalZenith = finalMeteor[:, 4]
150 148
151 149 x = finalAzimuth * numpy.pi / 180
152 150 y = finalZenith
153 151
154 152 ax = self.axes[0]
155 153
156 154 if ax.firsttime:
157 155 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
158 156 else:
159 157 ax.plot.set_data(x, y)
160 158
161 159 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
162 160 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
163 161 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
164 162 dt2,
165 163 len(x))
166 164 self.titles[0] = title
167 165
168 166
169 167 class GenericRTIPlot(Plot):
170 168 '''
171 169 Plot for data_xxxx object
172 170 '''
173 171
174 172 CODE = 'param'
175 173 colormap = 'viridis'
176 174 plot_type = 'pcolorbuffer'
177 175
178 176 def setup(self):
179 177 self.xaxis = 'time'
180 178 self.ncols = 1
181 179 self.nrows = self.data.shape('param')[0]
182 180 self.nplots = self.nrows
183 181 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
184 182
185 183 if not self.xlabel:
186 184 self.xlabel = 'Time'
187 185
188 186 self.ylabel = 'Range [km]'
189 187 if not self.titles:
190 188 self.titles = ['Param {}'.format(x) for x in range(self.nrows)]
191 189
192 190 def update(self, dataOut):
193 191
194 192 data = {
195 193 'param' : numpy.concatenate([getattr(dataOut, attr) for attr in self.attr_data], axis=0)
196 194 }
197 195
198 196 meta = {}
199 197
200 198 return data, meta
201 199
202 200 def plot(self):
203 201 # self.data.normalize_heights()
204 202 self.x = self.data.times
205 203 self.y = self.data.yrange
206 204 self.z = self.data['param']
207
208 205 self.z = 10*numpy.log10(self.z)
209
210 206 self.z = numpy.ma.masked_invalid(self.z)
211 207
212 208 if self.decimation is None:
213 209 x, y, z = self.fill_gaps(self.x, self.y, self.z)
214 210 else:
215 211 x, y, z = self.fill_gaps(*self.decimate())
216 212
217 213 for n, ax in enumerate(self.axes):
218 214
219 215 self.zmax = self.zmax if self.zmax is not None else numpy.max(
220 216 self.z[n])
221 217 self.zmin = self.zmin if self.zmin is not None else numpy.min(
222 218 self.z[n])
223 219
224 220 if ax.firsttime:
225 221 if self.zlimits is not None:
226 222 self.zmin, self.zmax = self.zlimits[n]
227 223
228 224 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
229 225 vmin=self.zmin,
230 226 vmax=self.zmax,
231 227 cmap=self.cmaps[n]
232 228 )
233 229 else:
234 230 if self.zlimits is not None:
235 231 self.zmin, self.zmax = self.zlimits[n]
236 232 ax.collections.remove(ax.collections[0])
237 233 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
238 234 vmin=self.zmin,
239 235 vmax=self.zmax,
240 236 cmap=self.cmaps[n]
241 237 )
242 238
243 239
244 240 class PolarMapPlot(Plot):
245 241 '''
246 242 Plot for weather radar
247 243 '''
248 244
249 245 CODE = 'param'
250 246 colormap = 'seismic'
251 247
252 248 def setup(self):
253 249 self.ncols = 1
254 250 self.nrows = 1
255 251 self.width = 9
256 252 self.height = 8
257 253 self.mode = self.data.meta['mode']
258 254 if self.channels is not None:
259 255 self.nplots = len(self.channels)
260 256 self.nrows = len(self.channels)
261 257 else:
262 258 self.nplots = self.data.shape(self.CODE)[0]
263 259 self.nrows = self.nplots
264 260 self.channels = list(range(self.nplots))
265 261 if self.mode == 'E':
266 262 self.xlabel = 'Longitude'
267 263 self.ylabel = 'Latitude'
268 264 else:
269 265 self.xlabel = 'Range (km)'
270 266 self.ylabel = 'Height (km)'
271 267 self.bgcolor = 'white'
272 268 self.cb_labels = self.data.meta['units']
273 269 self.lat = self.data.meta['latitude']
274 270 self.lon = self.data.meta['longitude']
275 271 self.xmin, self.xmax = float(
276 272 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
277 273 self.ymin, self.ymax = float(
278 274 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
279 275 # self.polar = True
280 276
281 277 def plot(self):
282 278
283 279 for n, ax in enumerate(self.axes):
284 280 data = self.data['param'][self.channels[n]]
285 281
286 282 zeniths = numpy.linspace(
287 283 0, self.data.meta['max_range'], data.shape[1])
288 284 if self.mode == 'E':
289 285 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
290 286 r, theta = numpy.meshgrid(zeniths, azimuths)
291 287 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
292 288 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
293 289 x = km2deg(x) + self.lon
294 290 y = km2deg(y) + self.lat
295 291 else:
296 292 azimuths = numpy.radians(self.data.yrange)
297 293 r, theta = numpy.meshgrid(zeniths, azimuths)
298 294 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
299 295 self.y = zeniths
300 296
301 297 if ax.firsttime:
302 298 if self.zlimits is not None:
303 299 self.zmin, self.zmax = self.zlimits[n]
304 300 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
305 301 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
306 302 vmin=self.zmin,
307 303 vmax=self.zmax,
308 304 cmap=self.cmaps[n])
309 305 else:
310 306 if self.zlimits is not None:
311 307 self.zmin, self.zmax = self.zlimits[n]
312 308 ax.collections.remove(ax.collections[0])
313 309 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
314 310 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
315 311 vmin=self.zmin,
316 312 vmax=self.zmax,
317 313 cmap=self.cmaps[n])
318 314
319 315 if self.mode == 'A':
320 316 continue
321 317
322 318 # plot district names
323 319 f = open('/data/workspace/schain_scripts/distrito.csv')
324 320 for line in f:
325 321 label, lon, lat = [s.strip() for s in line.split(',') if s]
326 322 lat = float(lat)
327 323 lon = float(lon)
328 324 # ax.plot(lon, lat, '.b', ms=2)
329 325 ax.text(lon, lat, label.decode('utf8'), ha='center',
330 326 va='bottom', size='8', color='black')
331 327
332 328 # plot limites
333 329 limites = []
334 330 tmp = []
335 331 for line in open('/data/workspace/schain_scripts/lima.csv'):
336 332 if '#' in line:
337 333 if tmp:
338 334 limites.append(tmp)
339 335 tmp = []
340 336 continue
341 337 values = line.strip().split(',')
342 338 tmp.append((float(values[0]), float(values[1])))
343 339 for points in limites:
344 340 ax.add_patch(
345 341 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
346 342
347 343 # plot Cuencas
348 344 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
349 345 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
350 346 values = [line.strip().split(',') for line in f]
351 347 points = [(float(s[0]), float(s[1])) for s in values]
352 348 ax.add_patch(Polygon(points, ec='b', fc='none'))
353 349
354 350 # plot grid
355 351 for r in (15, 30, 45, 60):
356 352 ax.add_artist(plt.Circle((self.lon, self.lat),
357 353 km2deg(r), color='0.6', fill=False, lw=0.2))
358 354 ax.text(
359 355 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
360 356 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
361 357 '{}km'.format(r),
362 358 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
363 359
364 360 if self.mode == 'E':
365 361 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
366 362 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
367 363 else:
368 364 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
369 365 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
370 366
371 367 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
372 368 self.titles = ['{} {}'.format(
373 369 self.data.parameters[x], title) for x in self.channels]
374 370
375 371 class WeatherPlot(Plot):
376 372 CODE = 'weather'
377 373 plot_name = 'weather'
378 374 plot_type = 'ppistyle'
379 375 buffering = False
380 376
381 377 def setup(self):
382 378 self.ncols = 1
383 379 self.nrows = 1
384 380 self.nplots= 1
385 381 self.ylabel= 'Range [Km]'
386 382 self.titles= ['Weather']
387 383 self.colorbar=False
388 384 self.width =8
389 385 self.height =8
390 386 self.ini =0
391 387 self.len_azi =0
392 388 self.buffer_ini = None
393 389 self.buffer_azi = None
394 390 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
395 391 self.flag =0
396 392 self.indicador= 0
397 393
398 394 def update(self, dataOut):
399 395
400 396 data = {}
401 397 meta = {}
402 print("aprox",dataOut.data_360[0])
403 398 data['weather'] = 10*numpy.log10(dataOut.data_360[0]/(250.0))
404 #print(data['weather'])
405 399 data['azi'] = dataOut.data_azi
406 print("UPDATE",data['azi'])
407 400 return data, meta
408 401
409 402 def const_ploteo(self,data_weather,data_azi,step,res):
410 #print("data_weather",data_weather)
411 print("data_azi",data_azi)
412 print("step",step)
413 403 if self.ini==0:
414 404 #------- AZIMUTH
415 405 n = (360/res)-len(data_azi)
416 406 start = data_azi[-1] + res
417 407 end = data_azi[0] - res
418 408 if start>end:
419 409 end = end + 360
420 410 azi_vacia = numpy.linspace(start,end,int(n))
421 411 azi_vacia = numpy.where(azi_vacia>360,azi_vacia-360,azi_vacia)
422 412 data_azi = numpy.hstack((data_azi,azi_vacia))
423 413 # RADAR
424 414 val_mean = numpy.mean(data_weather[:,0])
425 415 data_weather_cmp = numpy.ones([(360-data_weather.shape[0]),data_weather.shape[1]])*val_mean
426 416 data_weather = numpy.vstack((data_weather,data_weather_cmp))
427 417 else:
428 418 # azimuth
429 419 flag=0
430 420 start_azi = self.res_azi[0]
431 421 start = data_azi[0]
432 422 end = data_azi[-1]
433 423 print("start",start)
434 424 print("end",end)
435 425 if start< start_azi:
436 426 start = start +360
437 427 if end <start_azi:
438 428 end = end +360
439 429
440 430 print("start",start)
441 431 print("end",end)
442 432 #### AQUI SERA LA MAGIA
443 433 pos_ini = int((start-start_azi)/res)
444 434 len_azi = len(data_azi)
445 435 if (360-pos_ini)<len_azi:
446 436 if pos_ini+1==360:
447 437 pos_ini=0
448 438 else:
449 439 flag=1
450 440 dif= 360-pos_ini
451 441 comp= len_azi-dif
452 442
453 443 print(pos_ini)
454 444 print(len_azi)
455 445 print("shape",self.res_azi.shape)
456 446 if flag==0:
457 447 # AZIMUTH
458 448 self.res_azi[pos_ini:pos_ini+len_azi] = data_azi
459 449 # RADAR
460 450 self.res_weather[pos_ini:pos_ini+len_azi,:] = data_weather
461 451 else:
462 452 # AZIMUTH
463 453 self.res_azi[pos_ini:pos_ini+dif] = data_azi[0:dif]
464 454 self.res_azi[0:comp] = data_azi[dif:]
465 455 # RADAR
466 456 self.res_weather[pos_ini:pos_ini+dif,:] = data_weather[0:dif,:]
467 457 self.res_weather[0:comp,:] = data_weather[dif:,:]
468 458 flag=0
469 459 data_azi = self.res_azi
470 460 data_weather = self.res_weather
471 461
472 462 return data_weather,data_azi
473 463
474 464 def plot(self):
475 465 print("--------------------------------------",self.ini,"-----------------------------------")
476 466 #numpy.set_printoptions(suppress=True)
477 467 #print(self.data.times)
478 468 thisDatetime = datetime.datetime.utcfromtimestamp(self.data.times[-1])
479 469 data = self.data[-1]
480 470 # ALTURA altura_tmp_h
481 471 altura_h = (data['weather'].shape[1])/10.0
482 472 stoprange = float(altura_h*1.5)#stoprange = float(33*1.5) por ahora 400
483 473 rangestep = float(0.15)
484 474 r = numpy.arange(0, stoprange, rangestep)
485 475 self.y = 2*r
486 476 # RADAR
487 477 #data_weather = data['weather']
488 478 # PEDESTAL
489 479 #data_azi = data['azi']
490 480 res = 1
491 481 # STEP
492 482 step = (360/(res*data['weather'].shape[0]))
493 483 #print("shape wr_data", wr_data.shape)
494 484 #print("shape wr_azi",wr_azi.shape)
495 485 #print("step",step)
496 486 print("Time---->",self.data.times[-1],thisDatetime)
497 487 #print("alturas", len(self.y))
498 488 self.res_weather, self.res_azi = self.const_ploteo(data_weather=data['weather'],data_azi=data['azi'],step=step,res=res)
499 489 #numpy.set_printoptions(suppress=True)
500 490 #print("resultado",self.res_azi)
501 491 ##########################################################
502 492 ################# PLOTEO ###################
503 493 ##########################################################
504 494
505 495 for i,ax in enumerate(self.axes):
506 496 if ax.firsttime:
507 497 plt.clf()
508 498 cgax, pm = wrl.vis.plot_ppi(self.res_weather,r=r,az=self.res_azi,fig=self.figures[0], proj='cg', vmin=1, vmax=60)
509 499 else:
510 500 plt.clf()
511 501 cgax, pm = wrl.vis.plot_ppi(self.res_weather,r=r,az=self.res_azi,fig=self.figures[0], proj='cg', vmin=0, vmax=60)
512 502 caax = cgax.parasites[0]
513 503 paax = cgax.parasites[1]
514 504 cbar = plt.gcf().colorbar(pm, pad=0.075)
515 505 caax.set_xlabel('x_range [km]')
516 506 caax.set_ylabel('y_range [km]')
517 507 plt.text(1.0, 1.05, 'azimuth '+str(thisDatetime)+"step"+str(self.ini), transform=caax.transAxes, va='bottom',ha='right')
518 508
519 509 self.ini= self.ini+1
@@ -1,745 +1,743
1 1 # Copyright (c) 2012-2021 Jicamarca Radio Observatory
2 2 # All rights reserved.
3 3 #
4 4 # Distributed under the terms of the BSD 3-clause license.
5 5 """Classes to plot Spectra data
6 6
7 7 """
8 8
9 9 import os
10 10 import numpy
11 11
12 12 from schainpy.model.graphics.jroplot_base import Plot, plt, log
13 13
14 14
15 15 class SpectraPlot(Plot):
16 16 '''
17 17 Plot for Spectra data
18 18 '''
19 19
20 20 CODE = 'spc'
21 21 colormap = 'jet'
22 22 plot_type = 'pcolor'
23 23 buffering = False
24 24
25 25 def setup(self):
26 26 self.nplots = len(self.data.channels)
27 27 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
28 28 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
29 29 self.height = 2.6 * self.nrows
30 30 self.cb_label = 'dB'
31 31 if self.showprofile:
32 32 self.width = 4 * self.ncols
33 33 else:
34 34 self.width = 3.5 * self.ncols
35 35 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
36 36 self.ylabel = 'Range [km]'
37 37
38 38 def update(self, dataOut):
39 39
40 40 data = {}
41 41 meta = {}
42 42 spc = 10*numpy.log10(dataOut.data_spc/dataOut.normFactor)
43 43 data['spc'] = spc
44 44 data['rti'] = dataOut.getPower()
45 45 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
46 46 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
47 47
48 48 if self.CODE == 'spc_moments':
49 49 data['moments'] = dataOut.moments
50 50 # data['spc'] = 10*numpy.log10(dataOut.data_pre[0]/dataOut.normFactor)
51 51 if self.CODE == 'gaussian_fit':
52 52 # data['moments'] = dataOut.moments
53 53 data['gaussfit'] = dataOut.DGauFitParams
54 54 # data['spc'] = 10*numpy.log10(dataOut.data_pre[0]/dataOut.normFactor)
55 55
56 56 return data, meta
57 57
58 58 def plot(self):
59 59 if self.xaxis == "frequency":
60 60 x = self.data.xrange[0]
61 61 self.xlabel = "Frequency (kHz)"
62 62 elif self.xaxis == "time":
63 63 x = self.data.xrange[1]
64 64 self.xlabel = "Time (ms)"
65 65 else:
66 66 x = self.data.xrange[2]
67 67 self.xlabel = "Velocity (m/s)"
68 68
69 69 if (self.CODE == 'spc_moments') | (self.CODE == 'gaussian_fit'):
70 70 x = self.data.xrange[2]
71 71 self.xlabel = "Velocity (m/s)"
72 72
73 73 self.titles = []
74 74
75 75 y = self.data.yrange
76 76 self.y = y
77 77
78 78 data = self.data[-1]
79 79 z = data['spc']
80 80
81 81 for n, ax in enumerate(self.axes):
82 82 noise = data['noise'][n]
83 83 if self.CODE == 'spc_moments':
84 84 mean = data['moments'][n, 1]
85 85 if self.CODE == 'gaussian_fit':
86 86 # mean = data['moments'][n, 1]
87 87 gau0 = data['gaussfit'][n][2,:,0]
88 88 gau1 = data['gaussfit'][n][2,:,1]
89 89 if ax.firsttime:
90 90 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
91 91 self.xmin = self.xmin if self.xmin else -self.xmax
92 92 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
93 93 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
94 94 ax.plt = ax.pcolormesh(x, y, z[n].T,
95 95 vmin=self.zmin,
96 96 vmax=self.zmax,
97 97 cmap=plt.get_cmap(self.colormap)
98 98 )
99 99
100 100 if self.showprofile:
101 101 ax.plt_profile = self.pf_axes[n].plot(
102 102 data['rti'][n], y)[0]
103 103 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
104 104 color="k", linestyle="dashed", lw=1)[0]
105 105 if self.CODE == 'spc_moments':
106 106 ax.plt_mean = ax.plot(mean, y, color='k', lw=1)[0]
107 107 if self.CODE == 'gaussian_fit':
108 108 # ax.plt_mean = ax.plot(mean, y, color='k', lw=1)[0]
109 109 ax.plt_gau0 = ax.plot(gau0, y, color='r', lw=1)[0]
110 110 ax.plt_gau1 = ax.plot(gau1, y, color='y', lw=1)[0]
111 111 else:
112 112 ax.plt.set_array(z[n].T.ravel())
113 113 if self.showprofile:
114 114 ax.plt_profile.set_data(data['rti'][n], y)
115 115 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
116 116 if self.CODE == 'spc_moments':
117 117 ax.plt_mean.set_data(mean, y)
118 118 if self.CODE == 'gaussian_fit':
119 119 # ax.plt_mean.set_data(mean, y)
120 120 ax.plt_gau0.set_data(gau0, y)
121 121 ax.plt_gau1.set_data(gau1, y)
122 122 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
123 123
124 124
125 125 class CrossSpectraPlot(Plot):
126 126
127 127 CODE = 'cspc'
128 128 colormap = 'jet'
129 129 plot_type = 'pcolor'
130 130 zmin_coh = None
131 131 zmax_coh = None
132 132 zmin_phase = None
133 133 zmax_phase = None
134 134
135 135 def setup(self):
136 136
137 137 self.ncols = 4
138 138 self.nplots = len(self.data.pairs) * 2
139 139 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
140 140 self.width = 3.1 * self.ncols
141 141 self.height = 2.6 * self.nrows
142 142 self.ylabel = 'Range [km]'
143 143 self.showprofile = False
144 144 self.plots_adjust.update({'left': 0.08, 'right': 0.92, 'wspace': 0.5, 'hspace':0.4, 'top':0.95, 'bottom': 0.08})
145 145
146 146 def update(self, dataOut):
147 147
148 148 data = {}
149 149 meta = {}
150 150
151 151 spc = dataOut.data_spc
152 152 cspc = dataOut.data_cspc
153 153 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
154 154 meta['pairs'] = dataOut.pairsList
155 155
156 156 tmp = []
157 157
158 158 for n, pair in enumerate(meta['pairs']):
159 159 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
160 160 coh = numpy.abs(out)
161 161 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
162 162 tmp.append(coh)
163 163 tmp.append(phase)
164 164
165 165 data['cspc'] = numpy.array(tmp)
166 166
167 167 return data, meta
168 168
169 169 def plot(self):
170 170
171 171 if self.xaxis == "frequency":
172 172 x = self.data.xrange[0]
173 173 self.xlabel = "Frequency (kHz)"
174 174 elif self.xaxis == "time":
175 175 x = self.data.xrange[1]
176 176 self.xlabel = "Time (ms)"
177 177 else:
178 178 x = self.data.xrange[2]
179 179 self.xlabel = "Velocity (m/s)"
180 180
181 181 self.titles = []
182 182
183 183 y = self.data.yrange
184 184 self.y = y
185 185
186 186 data = self.data[-1]
187 187 cspc = data['cspc']
188 188
189 189 for n in range(len(self.data.pairs)):
190 190 pair = self.data.pairs[n]
191 191 coh = cspc[n*2]
192 192 phase = cspc[n*2+1]
193 193 ax = self.axes[2 * n]
194 194 if ax.firsttime:
195 195 ax.plt = ax.pcolormesh(x, y, coh.T,
196 196 vmin=0,
197 197 vmax=1,
198 198 cmap=plt.get_cmap(self.colormap_coh)
199 199 )
200 200 else:
201 201 ax.plt.set_array(coh.T.ravel())
202 202 self.titles.append(
203 203 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
204 204
205 205 ax = self.axes[2 * n + 1]
206 206 if ax.firsttime:
207 207 ax.plt = ax.pcolormesh(x, y, phase.T,
208 208 vmin=-180,
209 209 vmax=180,
210 210 cmap=plt.get_cmap(self.colormap_phase)
211 211 )
212 212 else:
213 213 ax.plt.set_array(phase.T.ravel())
214 214 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
215 215
216 216
217 217 class RTIPlot(Plot):
218 218 '''
219 219 Plot for RTI data
220 220 '''
221 221
222 222 CODE = 'rti'
223 223 colormap = 'jet'
224 224 plot_type = 'pcolorbuffer'
225 225
226 226 def setup(self):
227 227 self.xaxis = 'time'
228 228 self.ncols = 1
229 print("ch",self.data.channels)
230 229 self.nrows = len(self.data.channels)
231 230 self.nplots = len(self.data.channels)
232 231 self.ylabel = 'Range [km]'
233 232 self.xlabel = 'Time'
234 233 self.cb_label = 'dB'
235 234 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95})
236 235 self.titles = ['{} Channel {}'.format(
237 236 self.CODE.upper(), x) for x in range(self.nrows)]
238 237
239 238 def update(self, dataOut):
240 239
241 240 data = {}
242 241 meta = {}
243 242 data['rti'] = dataOut.getPower()
244 243 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
245 244
246 245 return data, meta
247 246
248 247 def plot(self):
249 248 self.x = self.data.times
250 249 self.y = self.data.yrange
251 250 self.z = self.data[self.CODE]
252 251 self.z = numpy.ma.masked_invalid(self.z)
253 252
254 253 if self.decimation is None:
255 254 x, y, z = self.fill_gaps(self.x, self.y, self.z)
256 255 else:
257 256 x, y, z = self.fill_gaps(*self.decimate())
258 257
259 258 for n, ax in enumerate(self.axes):
260 259 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
261 260 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
262 261 data = self.data[-1]
263 262 if ax.firsttime:
264 263 ax.plt = ax.pcolormesh(x, y, z[n].T,
265 264 vmin=self.zmin,
266 265 vmax=self.zmax,
267 266 cmap=plt.get_cmap(self.colormap)
268 267 )
269 268 if self.showprofile:
270 print("test-------------------------------------1")
271 269 ax.plot_profile = self.pf_axes[n].plot(
272 270 data['rti'][n], self.y)[0]
273 271 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(data['noise'][n], len(self.y)), self.y,
274 272 color="k", linestyle="dashed", lw=1)[0]
275 273 else:
276 274 ax.collections.remove(ax.collections[0])
277 275 ax.plt = ax.pcolormesh(x, y, z[n].T,
278 276 vmin=self.zmin,
279 277 vmax=self.zmax,
280 278 cmap=plt.get_cmap(self.colormap)
281 279 )
282 280 if self.showprofile:
283 281 ax.plot_profile.set_data(data['rti'][n], self.y)
284 282 ax.plot_noise.set_data(numpy.repeat(
285 283 data['noise'][n], len(self.y)), self.y)
286 284
287 285
288 286 class CoherencePlot(RTIPlot):
289 287 '''
290 288 Plot for Coherence data
291 289 '''
292 290
293 291 CODE = 'coh'
294 292
295 293 def setup(self):
296 294 self.xaxis = 'time'
297 295 self.ncols = 1
298 296 self.nrows = len(self.data.pairs)
299 297 self.nplots = len(self.data.pairs)
300 298 self.ylabel = 'Range [km]'
301 299 self.xlabel = 'Time'
302 300 self.plots_adjust.update({'hspace':0.6, 'left': 0.1, 'bottom': 0.1,'right':0.95})
303 301 if self.CODE == 'coh':
304 302 self.cb_label = ''
305 303 self.titles = [
306 304 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
307 305 else:
308 306 self.cb_label = 'Degrees'
309 307 self.titles = [
310 308 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
311 309
312 310 def update(self, dataOut):
313 311
314 312 data = {}
315 313 meta = {}
316 314 data['coh'] = dataOut.getCoherence()
317 315 meta['pairs'] = dataOut.pairsList
318 316
319 317 return data, meta
320 318
321 319 class PhasePlot(CoherencePlot):
322 320 '''
323 321 Plot for Phase map data
324 322 '''
325 323
326 324 CODE = 'phase'
327 325 colormap = 'seismic'
328 326
329 327 def update(self, dataOut):
330 328
331 329 data = {}
332 330 meta = {}
333 331 data['phase'] = dataOut.getCoherence(phase=True)
334 332 meta['pairs'] = dataOut.pairsList
335 333
336 334 return data, meta
337 335
338 336 class NoisePlot(Plot):
339 337 '''
340 338 Plot for noise
341 339 '''
342 340
343 341 CODE = 'noise'
344 342 plot_type = 'scatterbuffer'
345 343
346 344 def setup(self):
347 345 self.xaxis = 'time'
348 346 self.ncols = 1
349 347 self.nrows = 1
350 348 self.nplots = 1
351 349 self.ylabel = 'Intensity [dB]'
352 350 self.xlabel = 'Time'
353 351 self.titles = ['Noise']
354 352 self.colorbar = False
355 353 self.plots_adjust.update({'right': 0.85 })
356 354
357 355 def update(self, dataOut):
358 356
359 357 data = {}
360 358 meta = {}
361 359 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor).reshape(dataOut.nChannels, 1)
362 360 meta['yrange'] = numpy.array([])
363 361
364 362 return data, meta
365 363
366 364 def plot(self):
367 365
368 366 x = self.data.times
369 367 xmin = self.data.min_time
370 368 xmax = xmin + self.xrange * 60 * 60
371 369 Y = self.data['noise']
372 370
373 371 if self.axes[0].firsttime:
374 372 self.ymin = numpy.nanmin(Y) - 5
375 373 self.ymax = numpy.nanmax(Y) + 5
376 374 for ch in self.data.channels:
377 375 y = Y[ch]
378 376 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
379 377 plt.legend(bbox_to_anchor=(1.18, 1.0))
380 378 else:
381 379 for ch in self.data.channels:
382 380 y = Y[ch]
383 381 self.axes[0].lines[ch].set_data(x, y)
384 382
385 383
386 384 class PowerProfilePlot(Plot):
387 385
388 386 CODE = 'pow_profile'
389 387 plot_type = 'scatter'
390 388
391 389 def setup(self):
392 390
393 391 self.ncols = 1
394 392 self.nrows = 1
395 393 self.nplots = 1
396 394 self.height = 4
397 395 self.width = 3
398 396 self.ylabel = 'Range [km]'
399 397 self.xlabel = 'Intensity [dB]'
400 398 self.titles = ['Power Profile']
401 399 self.colorbar = False
402 400
403 401 def update(self, dataOut):
404 402
405 403 data = {}
406 404 meta = {}
407 405 data[self.CODE] = dataOut.getPower()
408 406
409 407 return data, meta
410 408
411 409 def plot(self):
412 410
413 411 y = self.data.yrange
414 412 self.y = y
415 413
416 414 x = self.data[-1][self.CODE]
417 415
418 416 if self.xmin is None: self.xmin = numpy.nanmin(x)*0.9
419 417 if self.xmax is None: self.xmax = numpy.nanmax(x)*1.1
420 418
421 419 if self.axes[0].firsttime:
422 420 for ch in self.data.channels:
423 421 self.axes[0].plot(x[ch], y, lw=1, label='Ch{}'.format(ch))
424 422 plt.legend()
425 423 else:
426 424 for ch in self.data.channels:
427 425 self.axes[0].lines[ch].set_data(x[ch], y)
428 426
429 427
430 428 class SpectraCutPlot(Plot):
431 429
432 430 CODE = 'spc_cut'
433 431 plot_type = 'scatter'
434 432 buffering = False
435 433
436 434 def setup(self):
437 435
438 436 self.nplots = len(self.data.channels)
439 437 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
440 438 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
441 439 self.width = 3.4 * self.ncols + 1.5
442 440 self.height = 3 * self.nrows
443 441 self.ylabel = 'Power [dB]'
444 442 self.colorbar = False
445 443 self.plots_adjust.update({'left':0.1, 'hspace':0.3, 'right': 0.75, 'bottom':0.08})
446 444
447 445 def update(self, dataOut):
448 446
449 447 data = {}
450 448 meta = {}
451 449 spc = 10*numpy.log10(dataOut.data_pre[0]/dataOut.normFactor)
452 450 data['spc'] = spc
453 451 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
454 452 if self.CODE == 'cut_gaussian_fit':
455 453 data['gauss_fit0'] = 10*numpy.log10(dataOut.GaussFit0/dataOut.normFactor)
456 454 data['gauss_fit1'] = 10*numpy.log10(dataOut.GaussFit1/dataOut.normFactor)
457 455 return data, meta
458 456
459 457 def plot(self):
460 458 if self.xaxis == "frequency":
461 459 x = self.data.xrange[0][1:]
462 460 self.xlabel = "Frequency (kHz)"
463 461 elif self.xaxis == "time":
464 462 x = self.data.xrange[1]
465 463 self.xlabel = "Time (ms)"
466 464 else:
467 465 x = self.data.xrange[2][:-1]
468 466 self.xlabel = "Velocity (m/s)"
469 467
470 468 if self.CODE == 'cut_gaussian_fit':
471 469 x = self.data.xrange[2][:-1]
472 470 self.xlabel = "Velocity (m/s)"
473 471
474 472 self.titles = []
475 473
476 474 y = self.data.yrange
477 475 data = self.data[-1]
478 476 z = data['spc']
479 477
480 478 if self.height_index:
481 479 index = numpy.array(self.height_index)
482 480 else:
483 481 index = numpy.arange(0, len(y), int((len(y))/9))
484 482
485 483 for n, ax in enumerate(self.axes):
486 484 if self.CODE == 'cut_gaussian_fit':
487 485 gau0 = data['gauss_fit0']
488 486 gau1 = data['gauss_fit1']
489 487 if ax.firsttime:
490 488 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
491 489 self.xmin = self.xmin if self.xmin else -self.xmax
492 490 self.ymin = self.ymin if self.ymin else numpy.nanmin(z)
493 491 self.ymax = self.ymax if self.ymax else numpy.nanmax(z)
494 492 ax.plt = ax.plot(x, z[n, :, index].T, lw=0.25)
495 493 if self.CODE == 'cut_gaussian_fit':
496 494 ax.plt_gau0 = ax.plot(x, gau0[n, :, index].T, lw=1, linestyle='-.')
497 495 for i, line in enumerate(ax.plt_gau0):
498 496 line.set_color(ax.plt[i].get_color())
499 497 ax.plt_gau1 = ax.plot(x, gau1[n, :, index].T, lw=1, linestyle='--')
500 498 for i, line in enumerate(ax.plt_gau1):
501 499 line.set_color(ax.plt[i].get_color())
502 500 labels = ['Range = {:2.1f}km'.format(y[i]) for i in index]
503 501 self.figures[0].legend(ax.plt, labels, loc='center right')
504 502 else:
505 503 for i, line in enumerate(ax.plt):
506 504 line.set_data(x, z[n, :, index[i]].T)
507 505 for i, line in enumerate(ax.plt_gau0):
508 506 line.set_data(x, gau0[n, :, index[i]].T)
509 507 line.set_color(ax.plt[i].get_color())
510 508 for i, line in enumerate(ax.plt_gau1):
511 509 line.set_data(x, gau1[n, :, index[i]].T)
512 510 line.set_color(ax.plt[i].get_color())
513 511 self.titles.append('CH {}'.format(n))
514 512
515 513
516 514 class BeaconPhase(Plot):
517 515
518 516 __isConfig = None
519 517 __nsubplots = None
520 518
521 519 PREFIX = 'beacon_phase'
522 520
523 521 def __init__(self):
524 522 Plot.__init__(self)
525 523 self.timerange = 24*60*60
526 524 self.isConfig = False
527 525 self.__nsubplots = 1
528 526 self.counter_imagwr = 0
529 527 self.WIDTH = 800
530 528 self.HEIGHT = 400
531 529 self.WIDTHPROF = 120
532 530 self.HEIGHTPROF = 0
533 531 self.xdata = None
534 532 self.ydata = None
535 533
536 534 self.PLOT_CODE = BEACON_CODE
537 535
538 536 self.FTP_WEI = None
539 537 self.EXP_CODE = None
540 538 self.SUB_EXP_CODE = None
541 539 self.PLOT_POS = None
542 540
543 541 self.filename_phase = None
544 542
545 543 self.figfile = None
546 544
547 545 self.xmin = None
548 546 self.xmax = None
549 547
550 548 def getSubplots(self):
551 549
552 550 ncol = 1
553 551 nrow = 1
554 552
555 553 return nrow, ncol
556 554
557 555 def setup(self, id, nplots, wintitle, showprofile=True, show=True):
558 556
559 557 self.__showprofile = showprofile
560 558 self.nplots = nplots
561 559
562 560 ncolspan = 7
563 561 colspan = 6
564 562 self.__nsubplots = 2
565 563
566 564 self.createFigure(id = id,
567 565 wintitle = wintitle,
568 566 widthplot = self.WIDTH+self.WIDTHPROF,
569 567 heightplot = self.HEIGHT+self.HEIGHTPROF,
570 568 show=show)
571 569
572 570 nrow, ncol = self.getSubplots()
573 571
574 572 self.addAxes(nrow, ncol*ncolspan, 0, 0, colspan, 1)
575 573
576 574 def save_phase(self, filename_phase):
577 575 f = open(filename_phase,'w+')
578 576 f.write('\n\n')
579 577 f.write('JICAMARCA RADIO OBSERVATORY - Beacon Phase \n')
580 578 f.write('DD MM YYYY HH MM SS pair(2,0) pair(2,1) pair(2,3) pair(2,4)\n\n' )
581 579 f.close()
582 580
583 581 def save_data(self, filename_phase, data, data_datetime):
584 582 f=open(filename_phase,'a')
585 583 timetuple_data = data_datetime.timetuple()
586 584 day = str(timetuple_data.tm_mday)
587 585 month = str(timetuple_data.tm_mon)
588 586 year = str(timetuple_data.tm_year)
589 587 hour = str(timetuple_data.tm_hour)
590 588 minute = str(timetuple_data.tm_min)
591 589 second = str(timetuple_data.tm_sec)
592 590 f.write(day+' '+month+' '+year+' '+hour+' '+minute+' '+second+' '+str(data[0])+' '+str(data[1])+' '+str(data[2])+' '+str(data[3])+'\n')
593 591 f.close()
594 592
595 593 def plot(self):
596 594 log.warning('TODO: Not yet implemented...')
597 595
598 596 def run(self, dataOut, id, wintitle="", pairsList=None, showprofile='True',
599 597 xmin=None, xmax=None, ymin=None, ymax=None, hmin=None, hmax=None,
600 598 timerange=None,
601 599 save=False, figpath='./', figfile=None, show=True, ftp=False, wr_period=1,
602 600 server=None, folder=None, username=None, password=None,
603 601 ftp_wei=0, exp_code=0, sub_exp_code=0, plot_pos=0):
604 602
605 603 if dataOut.flagNoData:
606 604 return dataOut
607 605
608 606 if not isTimeInHourRange(dataOut.datatime, xmin, xmax):
609 607 return
610 608
611 609 if pairsList == None:
612 610 pairsIndexList = dataOut.pairsIndexList[:10]
613 611 else:
614 612 pairsIndexList = []
615 613 for pair in pairsList:
616 614 if pair not in dataOut.pairsList:
617 615 raise ValueError("Pair %s is not in dataOut.pairsList" %(pair))
618 616 pairsIndexList.append(dataOut.pairsList.index(pair))
619 617
620 618 if pairsIndexList == []:
621 619 return
622 620
623 621 # if len(pairsIndexList) > 4:
624 622 # pairsIndexList = pairsIndexList[0:4]
625 623
626 624 hmin_index = None
627 625 hmax_index = None
628 626
629 627 if hmin != None and hmax != None:
630 628 indexes = numpy.arange(dataOut.nHeights)
631 629 hmin_list = indexes[dataOut.heightList >= hmin]
632 630 hmax_list = indexes[dataOut.heightList <= hmax]
633 631
634 632 if hmin_list.any():
635 633 hmin_index = hmin_list[0]
636 634
637 635 if hmax_list.any():
638 636 hmax_index = hmax_list[-1]+1
639 637
640 638 x = dataOut.getTimeRange()
641 639
642 640 thisDatetime = dataOut.datatime
643 641
644 642 title = wintitle + " Signal Phase" # : %s" %(thisDatetime.strftime("%d-%b-%Y"))
645 643 xlabel = "Local Time"
646 644 ylabel = "Phase (degrees)"
647 645
648 646 update_figfile = False
649 647
650 648 nplots = len(pairsIndexList)
651 649 #phase = numpy.zeros((len(pairsIndexList),len(dataOut.beacon_heiIndexList)))
652 650 phase_beacon = numpy.zeros(len(pairsIndexList))
653 651 for i in range(nplots):
654 652 pair = dataOut.pairsList[pairsIndexList[i]]
655 653 ccf = numpy.average(dataOut.data_cspc[pairsIndexList[i], :, hmin_index:hmax_index], axis=0)
656 654 powa = numpy.average(dataOut.data_spc[pair[0], :, hmin_index:hmax_index], axis=0)
657 655 powb = numpy.average(dataOut.data_spc[pair[1], :, hmin_index:hmax_index], axis=0)
658 656 avgcoherenceComplex = ccf/numpy.sqrt(powa*powb)
659 657 phase = numpy.arctan2(avgcoherenceComplex.imag, avgcoherenceComplex.real)*180/numpy.pi
660 658
661 659 if dataOut.beacon_heiIndexList:
662 660 phase_beacon[i] = numpy.average(phase[dataOut.beacon_heiIndexList])
663 661 else:
664 662 phase_beacon[i] = numpy.average(phase)
665 663
666 664 if not self.isConfig:
667 665
668 666 nplots = len(pairsIndexList)
669 667
670 668 self.setup(id=id,
671 669 nplots=nplots,
672 670 wintitle=wintitle,
673 671 showprofile=showprofile,
674 672 show=show)
675 673
676 674 if timerange != None:
677 675 self.timerange = timerange
678 676
679 677 self.xmin, self.xmax = self.getTimeLim(x, xmin, xmax, timerange)
680 678
681 679 if ymin == None: ymin = 0
682 680 if ymax == None: ymax = 360
683 681
684 682 self.FTP_WEI = ftp_wei
685 683 self.EXP_CODE = exp_code
686 684 self.SUB_EXP_CODE = sub_exp_code
687 685 self.PLOT_POS = plot_pos
688 686
689 687 self.name = thisDatetime.strftime("%Y%m%d_%H%M%S")
690 688 self.isConfig = True
691 689 self.figfile = figfile
692 690 self.xdata = numpy.array([])
693 691 self.ydata = numpy.array([])
694 692
695 693 update_figfile = True
696 694
697 695 #open file beacon phase
698 696 path = '%s%03d' %(self.PREFIX, self.id)
699 697 beacon_file = os.path.join(path,'%s.txt'%self.name)
700 698 self.filename_phase = os.path.join(figpath,beacon_file)
701 699 #self.save_phase(self.filename_phase)
702 700
703 701
704 702 #store data beacon phase
705 703 #self.save_data(self.filename_phase, phase_beacon, thisDatetime)
706 704
707 705 self.setWinTitle(title)
708 706
709 707
710 708 title = "Phase Plot %s" %(thisDatetime.strftime("%Y/%m/%d %H:%M:%S"))
711 709
712 710 legendlabels = ["Pair (%d,%d)"%(pair[0], pair[1]) for pair in dataOut.pairsList]
713 711
714 712 axes = self.axesList[0]
715 713
716 714 self.xdata = numpy.hstack((self.xdata, x[0:1]))
717 715
718 716 if len(self.ydata)==0:
719 717 self.ydata = phase_beacon.reshape(-1,1)
720 718 else:
721 719 self.ydata = numpy.hstack((self.ydata, phase_beacon.reshape(-1,1)))
722 720
723 721
724 722 axes.pmultilineyaxis(x=self.xdata, y=self.ydata,
725 723 xmin=self.xmin, xmax=self.xmax, ymin=ymin, ymax=ymax,
726 724 xlabel=xlabel, ylabel=ylabel, title=title, legendlabels=legendlabels, marker='x', markersize=8, linestyle="solid",
727 725 XAxisAsTime=True, grid='both'
728 726 )
729 727
730 728 self.draw()
731 729
732 730 if dataOut.ltctime >= self.xmax:
733 731 self.counter_imagwr = wr_period
734 732 self.isConfig = False
735 733 update_figfile = True
736 734
737 735 self.save(figpath=figpath,
738 736 figfile=figfile,
739 737 save=save,
740 738 ftp=ftp,
741 739 wr_period=wr_period,
742 740 thisDatetime=thisDatetime,
743 741 update_figfile=update_figfile)
744 742
745 743 return dataOut
@@ -1,4475 +1,4474
1 1 import numpy,os,h5py
2 2 import math
3 3 from scipy import optimize, interpolate, signal, stats, ndimage
4 4 import scipy
5 5 import re
6 6 import datetime
7 7 import copy
8 8 import sys
9 9 import importlib
10 10 import itertools
11 11 from multiprocessing import Pool, TimeoutError
12 12 from multiprocessing.pool import ThreadPool
13 13 import time
14 14
15 15 from scipy.optimize import fmin_l_bfgs_b #optimize with bounds on state papameters
16 16 from .jroproc_base import ProcessingUnit, Operation, MPDecorator
17 17 from schainpy.model.data.jrodata import Parameters, hildebrand_sekhon
18 18 from scipy import asarray as ar,exp
19 19 from scipy.optimize import curve_fit
20 20 from schainpy.utils import log
21 21 import warnings
22 22 from numpy import NaN
23 23 from scipy.optimize.optimize import OptimizeWarning
24 24 warnings.filterwarnings('ignore')
25 25
26 26 import matplotlib.pyplot as plt
27 27
28 28 SPEED_OF_LIGHT = 299792458
29 29
30 30 '''solving pickling issue'''
31 31
32 32 def _pickle_method(method):
33 33 func_name = method.__func__.__name__
34 34 obj = method.__self__
35 35 cls = method.__self__.__class__
36 36 return _unpickle_method, (func_name, obj, cls)
37 37
38 38 def _unpickle_method(func_name, obj, cls):
39 39 for cls in cls.mro():
40 40 try:
41 41 func = cls.__dict__[func_name]
42 42 except KeyError:
43 43 pass
44 44 else:
45 45 break
46 46 return func.__get__(obj, cls)
47 47
48 48 def isNumber(str):
49 49 try:
50 50 float(str)
51 51 return True
52 52 except:
53 53 return False
54 54
55 55 class ParametersProc(ProcessingUnit):
56 56
57 57 METHODS = {}
58 58 nSeconds = None
59 59
60 60 def __init__(self):
61 61 ProcessingUnit.__init__(self)
62 62
63 63 # self.objectDict = {}
64 64 self.buffer = None
65 65 self.firstdatatime = None
66 66 self.profIndex = 0
67 67 self.dataOut = Parameters()
68 68 self.setupReq = False #Agregar a todas las unidades de proc
69 69
70 70 def __updateObjFromInput(self):
71 71
72 72 self.dataOut.inputUnit = self.dataIn.type
73 73
74 74 self.dataOut.timeZone = self.dataIn.timeZone
75 75 self.dataOut.dstFlag = self.dataIn.dstFlag
76 76 self.dataOut.errorCount = self.dataIn.errorCount
77 77 self.dataOut.useLocalTime = self.dataIn.useLocalTime
78 78
79 79 self.dataOut.radarControllerHeaderObj = self.dataIn.radarControllerHeaderObj.copy()
80 80 self.dataOut.systemHeaderObj = self.dataIn.systemHeaderObj.copy()
81 81 self.dataOut.channelList = self.dataIn.channelList
82 82 self.dataOut.heightList = self.dataIn.heightList
83 83 self.dataOut.dtype = numpy.dtype([('real','<f4'),('imag','<f4')])
84 84 # self.dataOut.nHeights = self.dataIn.nHeights
85 85 # self.dataOut.nChannels = self.dataIn.nChannels
86 86 # self.dataOut.nBaud = self.dataIn.nBaud
87 87 # self.dataOut.nCode = self.dataIn.nCode
88 88 # self.dataOut.code = self.dataIn.code
89 89 # self.dataOut.nProfiles = self.dataOut.nFFTPoints
90 90 self.dataOut.flagDiscontinuousBlock = self.dataIn.flagDiscontinuousBlock
91 91 # self.dataOut.utctime = self.firstdatatime
92 92 self.dataOut.utctime = self.dataIn.utctime
93 93 self.dataOut.flagDecodeData = self.dataIn.flagDecodeData #asumo q la data esta decodificada
94 94 self.dataOut.flagDeflipData = self.dataIn.flagDeflipData #asumo q la data esta sin flip
95 95 self.dataOut.nCohInt = self.dataIn.nCohInt
96 96 # self.dataOut.nIncohInt = 1
97 97 # self.dataOut.ippSeconds = self.dataIn.ippSeconds
98 98 # self.dataOut.windowOfFilter = self.dataIn.windowOfFilter
99 99 self.dataOut.timeInterval1 = self.dataIn.timeInterval
100 100 self.dataOut.heightList = self.dataIn.heightList
101 101 self.dataOut.frequency = self.dataIn.frequency
102 102 # self.dataOut.noise = self.dataIn.noise
103 103
104 104 def run(self):
105 105
106 106
107 107 #print("HOLA MUNDO SOY YO")
108 108 #---------------------- Voltage Data ---------------------------
109 109
110 110 if self.dataIn.type == "Voltage":
111 111
112 112 self.__updateObjFromInput()
113 113 self.dataOut.data_pre = self.dataIn.data.copy()
114 114 self.dataOut.flagNoData = False
115 115 self.dataOut.utctimeInit = self.dataIn.utctime
116 116 self.dataOut.paramInterval = self.dataIn.nProfiles*self.dataIn.nCohInt*self.dataIn.ippSeconds
117 117
118 118 if hasattr(self.dataIn, 'flagDataAsBlock'):
119 119 self.dataOut.flagDataAsBlock = self.dataIn.flagDataAsBlock
120 120
121 121 if hasattr(self.dataIn, 'profileIndex'):
122 122 self.dataOut.profileIndex = self.dataIn.profileIndex
123 123
124 124 if hasattr(self.dataIn, 'dataPP_POW'):
125 125 self.dataOut.dataPP_POW = self.dataIn.dataPP_POW
126 126
127 127 if hasattr(self.dataIn, 'dataPP_POWER'):
128 128 self.dataOut.dataPP_POWER = self.dataIn.dataPP_POWER
129 129
130 130 if hasattr(self.dataIn, 'dataPP_DOP'):
131 131 self.dataOut.dataPP_DOP = self.dataIn.dataPP_DOP
132 132
133 133 if hasattr(self.dataIn, 'dataPP_SNR'):
134 134 self.dataOut.dataPP_SNR = self.dataIn.dataPP_SNR
135 135
136 136 if hasattr(self.dataIn, 'dataPP_WIDTH'):
137 137 self.dataOut.dataPP_WIDTH = self.dataIn.dataPP_WIDTH
138 138 return
139 139
140 140 #---------------------- Spectra Data ---------------------------
141 141
142 142 if self.dataIn.type == "Spectra":
143 143 #print("que paso en spectra")
144 144 self.dataOut.data_pre = [self.dataIn.data_spc, self.dataIn.data_cspc]
145 145 self.dataOut.data_spc = self.dataIn.data_spc
146 146 self.dataOut.data_cspc = self.dataIn.data_cspc
147 147 self.dataOut.nProfiles = self.dataIn.nProfiles
148 148 self.dataOut.nIncohInt = self.dataIn.nIncohInt
149 149 self.dataOut.nFFTPoints = self.dataIn.nFFTPoints
150 150 self.dataOut.ippFactor = self.dataIn.ippFactor
151 151 self.dataOut.abscissaList = self.dataIn.getVelRange(1)
152 152 self.dataOut.spc_noise = self.dataIn.getNoise()
153 153 self.dataOut.spc_range = (self.dataIn.getFreqRange(1) , self.dataIn.getAcfRange(1) , self.dataIn.getVelRange(1))
154 154 # self.dataOut.normFactor = self.dataIn.normFactor
155 155 self.dataOut.pairsList = self.dataIn.pairsList
156 156 self.dataOut.groupList = self.dataIn.pairsList
157 157 self.dataOut.flagNoData = False
158 158
159 159 if hasattr(self.dataIn, 'flagDataAsBlock'):
160 160 self.dataOut.flagDataAsBlock = self.dataIn.flagDataAsBlock
161 161
162 162 if hasattr(self.dataIn, 'ChanDist'): #Distances of receiver channels
163 163 self.dataOut.ChanDist = self.dataIn.ChanDist
164 164 else: self.dataOut.ChanDist = None
165 165
166 166 #if hasattr(self.dataIn, 'VelRange'): #Velocities range
167 167 # self.dataOut.VelRange = self.dataIn.VelRange
168 168 #else: self.dataOut.VelRange = None
169 169
170 170 if hasattr(self.dataIn, 'RadarConst'): #Radar Constant
171 171 self.dataOut.RadarConst = self.dataIn.RadarConst
172 172
173 173 if hasattr(self.dataIn, 'NPW'): #NPW
174 174 self.dataOut.NPW = self.dataIn.NPW
175 175
176 176 if hasattr(self.dataIn, 'COFA'): #COFA
177 177 self.dataOut.COFA = self.dataIn.COFA
178 178
179 179
180 180
181 181 #---------------------- Correlation Data ---------------------------
182 182
183 183 if self.dataIn.type == "Correlation":
184 184 acf_ind, ccf_ind, acf_pairs, ccf_pairs, data_acf, data_ccf = self.dataIn.splitFunctions()
185 185
186 186 self.dataOut.data_pre = (self.dataIn.data_cf[acf_ind,:], self.dataIn.data_cf[ccf_ind,:,:])
187 187 self.dataOut.normFactor = (self.dataIn.normFactor[acf_ind,:], self.dataIn.normFactor[ccf_ind,:])
188 188 self.dataOut.groupList = (acf_pairs, ccf_pairs)
189 189
190 190 self.dataOut.abscissaList = self.dataIn.lagRange
191 191 self.dataOut.noise = self.dataIn.noise
192 192 self.dataOut.data_snr = self.dataIn.SNR
193 193 self.dataOut.flagNoData = False
194 194 self.dataOut.nAvg = self.dataIn.nAvg
195 195
196 196 #---------------------- Parameters Data ---------------------------
197 197
198 198 if self.dataIn.type == "Parameters":
199 199 self.dataOut.copy(self.dataIn)
200 200 self.dataOut.flagNoData = False
201 201 #print("yo si entre")
202 202
203 203 return True
204 204
205 205 self.__updateObjFromInput()
206 206 #print("yo si entre2")
207 207
208 208 self.dataOut.utctimeInit = self.dataIn.utctime
209 209 self.dataOut.paramInterval = self.dataIn.timeInterval
210 210 #print("soy spectra ",self.dataOut.utctimeInit)
211 211 return
212 212
213 213
214 214 def target(tups):
215 215
216 216 obj, args = tups
217 217
218 218 return obj.FitGau(args)
219 219
220 220 class RemoveWideGC(Operation):
221 221 ''' This class remove the wide clutter and replace it with a simple interpolation points
222 222 This mainly applies to CLAIRE radar
223 223
224 224 ClutterWidth : Width to look for the clutter peak
225 225
226 226 Input:
227 227
228 228 self.dataOut.data_pre : SPC and CSPC
229 229 self.dataOut.spc_range : To select wind and rainfall velocities
230 230
231 231 Affected:
232 232
233 233 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
234 234
235 235 Written by D. ScipiΓ³n 25.02.2021
236 236 '''
237 237 def __init__(self):
238 238 Operation.__init__(self)
239 239 self.i = 0
240 240 self.ich = 0
241 241 self.ir = 0
242 242
243 243 def run(self, dataOut, ClutterWidth=2.5):
244 244 # print ('Entering RemoveWideGC ... ')
245 245
246 246 self.spc = dataOut.data_pre[0].copy()
247 247 self.spc_out = dataOut.data_pre[0].copy()
248 248 self.Num_Chn = self.spc.shape[0]
249 249 self.Num_Hei = self.spc.shape[2]
250 250 VelRange = dataOut.spc_range[2][:-1]
251 251 dv = VelRange[1]-VelRange[0]
252 252
253 253 # Find the velocities that corresponds to zero
254 254 gc_values = numpy.squeeze(numpy.where(numpy.abs(VelRange) <= ClutterWidth))
255 255
256 256 # Removing novalid data from the spectra
257 257 for ich in range(self.Num_Chn) :
258 258 for ir in range(self.Num_Hei) :
259 259 # Estimate the noise at each range
260 260 HSn = hildebrand_sekhon(self.spc[ich,:,ir],dataOut.nIncohInt)
261 261
262 262 # Removing the noise floor at each range
263 263 novalid = numpy.where(self.spc[ich,:,ir] < HSn)
264 264 self.spc[ich,novalid,ir] = HSn
265 265
266 266 junk = numpy.append(numpy.insert(numpy.squeeze(self.spc[ich,gc_values,ir]),0,HSn),HSn)
267 267 j1index = numpy.squeeze(numpy.where(numpy.diff(junk)>0))
268 268 j2index = numpy.squeeze(numpy.where(numpy.diff(junk)<0))
269 269 if ((numpy.size(j1index)<=1) | (numpy.size(j2index)<=1)) :
270 270 continue
271 271 junk3 = numpy.squeeze(numpy.diff(j1index))
272 272 junk4 = numpy.squeeze(numpy.diff(j2index))
273 273
274 274 valleyindex = j2index[numpy.where(junk4>1)]
275 275 peakindex = j1index[numpy.where(junk3>1)]
276 276
277 277 isvalid = numpy.squeeze(numpy.where(numpy.abs(VelRange[gc_values[peakindex]]) <= 2.5*dv))
278 278 if numpy.size(isvalid) == 0 :
279 279 continue
280 280 if numpy.size(isvalid) >1 :
281 281 vindex = numpy.argmax(self.spc[ich,gc_values[peakindex[isvalid]],ir])
282 282 isvalid = isvalid[vindex]
283 283
284 284 # clutter peak
285 285 gcpeak = peakindex[isvalid]
286 286 vl = numpy.where(valleyindex < gcpeak)
287 287 if numpy.size(vl) == 0:
288 288 continue
289 289 gcvl = valleyindex[vl[0][-1]]
290 290 vr = numpy.where(valleyindex > gcpeak)
291 291 if numpy.size(vr) == 0:
292 292 continue
293 293 gcvr = valleyindex[vr[0][0]]
294 294
295 295 # Removing the clutter
296 296 interpindex = numpy.array([gc_values[gcvl], gc_values[gcvr]])
297 297 gcindex = gc_values[gcvl+1:gcvr-1]
298 298 self.spc_out[ich,gcindex,ir] = numpy.interp(VelRange[gcindex],VelRange[interpindex],self.spc[ich,interpindex,ir])
299 299
300 300 dataOut.data_pre[0] = self.spc_out
301 301 #print ('Leaving RemoveWideGC ... ')
302 302 return dataOut
303 303
304 304 class SpectralFilters(Operation):
305 305 ''' This class allows to replace the novalid values with noise for each channel
306 306 This applies to CLAIRE RADAR
307 307
308 308 PositiveLimit : RightLimit of novalid data
309 309 NegativeLimit : LeftLimit of novalid data
310 310
311 311 Input:
312 312
313 313 self.dataOut.data_pre : SPC and CSPC
314 314 self.dataOut.spc_range : To select wind and rainfall velocities
315 315
316 316 Affected:
317 317
318 318 self.dataOut.data_pre : It is used for the new SPC and CSPC ranges of wind
319 319
320 320 Written by D. ScipiΓ³n 29.01.2021
321 321 '''
322 322 def __init__(self):
323 323 Operation.__init__(self)
324 324 self.i = 0
325 325
326 326 def run(self, dataOut, ):
327 327
328 328 self.spc = dataOut.data_pre[0].copy()
329 329 self.Num_Chn = self.spc.shape[0]
330 330 VelRange = dataOut.spc_range[2]
331 331
332 332 # novalid corresponds to data within the Negative and PositiveLimit
333 333
334 334
335 335 # Removing novalid data from the spectra
336 336 for i in range(self.Num_Chn):
337 337 self.spc[i,novalid,:] = dataOut.noise[i]
338 338 dataOut.data_pre[0] = self.spc
339 339 return dataOut
340 340
341 341 class GaussianFit(Operation):
342 342
343 343 '''
344 344 Function that fit of one and two generalized gaussians (gg) based
345 345 on the PSD shape across an "power band" identified from a cumsum of
346 346 the measured spectrum - noise.
347 347
348 348 Input:
349 349 self.dataOut.data_pre : SelfSpectra
350 350
351 351 Output:
352 352 self.dataOut.SPCparam : SPC_ch1, SPC_ch2
353 353
354 354 '''
355 355 def __init__(self):
356 356 Operation.__init__(self)
357 357 self.i=0
358 358
359 359
360 360 # def run(self, dataOut, num_intg=7, pnoise=1., SNRlimit=-9): #num_intg: Incoherent integrations, pnoise: Noise, vel_arr: range of velocities, similar to the ftt points
361 361 def run(self, dataOut, SNRdBlimit=-9, method='generalized'):
362 362 """This routine will find a couple of generalized Gaussians to a power spectrum
363 363 methods: generalized, squared
364 364 input: spc
365 365 output:
366 366 noise, amplitude0,shift0,width0,p0,Amplitude1,shift1,width1,p1
367 367 """
368 368 print ('Entering ',method,' double Gaussian fit')
369 369 self.spc = dataOut.data_pre[0].copy()
370 370 self.Num_Hei = self.spc.shape[2]
371 371 self.Num_Bin = self.spc.shape[1]
372 372 self.Num_Chn = self.spc.shape[0]
373 373
374 374 start_time = time.time()
375 375
376 376 pool = Pool(processes=self.Num_Chn)
377 377 args = [(dataOut.spc_range[2], ich, dataOut.spc_noise[ich], dataOut.nIncohInt, SNRdBlimit) for ich in range(self.Num_Chn)]
378 378 objs = [self for __ in range(self.Num_Chn)]
379 379 attrs = list(zip(objs, args))
380 380 DGauFitParam = pool.map(target, attrs)
381 381 # Parameters:
382 382 # 0. Noise, 1. Amplitude, 2. Shift, 3. Width 4. Power
383 383 dataOut.DGauFitParams = numpy.asarray(DGauFitParam)
384 384
385 385 # Double Gaussian Curves
386 386 gau0 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
387 387 gau0[:] = numpy.NaN
388 388 gau1 = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
389 389 gau1[:] = numpy.NaN
390 390 x_mtr = numpy.transpose(numpy.tile(dataOut.getVelRange(1)[:-1], (self.Num_Hei,1)))
391 391 for iCh in range(self.Num_Chn):
392 392 N0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,0]] * self.Num_Bin))
393 393 N1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][0,:,1]] * self.Num_Bin))
394 394 A0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,0]] * self.Num_Bin))
395 395 A1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][1,:,1]] * self.Num_Bin))
396 396 v0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,0]] * self.Num_Bin))
397 397 v1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][2,:,1]] * self.Num_Bin))
398 398 s0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,0]] * self.Num_Bin))
399 399 s1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][3,:,1]] * self.Num_Bin))
400 400 if method == 'genealized':
401 401 p0 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,0]] * self.Num_Bin))
402 402 p1 = numpy.transpose(numpy.transpose([dataOut.DGauFitParams[iCh][4,:,1]] * self.Num_Bin))
403 403 elif method == 'squared':
404 404 p0 = 2.
405 405 p1 = 2.
406 406 gau0[iCh] = A0*numpy.exp(-0.5*numpy.abs((x_mtr-v0)/s0)**p0)+N0
407 407 gau1[iCh] = A1*numpy.exp(-0.5*numpy.abs((x_mtr-v1)/s1)**p1)+N1
408 408 dataOut.GaussFit0 = gau0
409 409 dataOut.GaussFit1 = gau1
410 410
411 411 print('Leaving ',method ,' double Gaussian fit')
412 412 return dataOut
413 413
414 414 def FitGau(self, X):
415 415 # print('Entering FitGau')
416 416 # Assigning the variables
417 417 Vrange, ch, wnoise, num_intg, SNRlimit = X
418 418 # Noise Limits
419 419 noisebl = wnoise * 0.9
420 420 noisebh = wnoise * 1.1
421 421 # Radar Velocity
422 422 Va = max(Vrange)
423 423 deltav = Vrange[1] - Vrange[0]
424 424 x = numpy.arange(self.Num_Bin)
425 425
426 426 # print ('stop 0')
427 427
428 428 # 5 parameters, 2 Gaussians
429 429 DGauFitParam = numpy.zeros([5, self.Num_Hei,2])
430 430 DGauFitParam[:] = numpy.NaN
431 431
432 432 # SPCparam = []
433 433 # SPC_ch1 = numpy.zeros([self.Num_Bin,self.Num_Hei])
434 434 # SPC_ch2 = numpy.zeros([self.Num_Bin,self.Num_Hei])
435 435 # SPC_ch1[:] = 0 #numpy.NaN
436 436 # SPC_ch2[:] = 0 #numpy.NaN
437 437 # print ('stop 1')
438 438 for ht in range(self.Num_Hei):
439 439 # print (ht)
440 440 # print ('stop 2')
441 441 # Spectra at each range
442 442 spc = numpy.asarray(self.spc)[ch,:,ht]
443 443 snr = ( spc.mean() - wnoise ) / wnoise
444 444 snrdB = 10.*numpy.log10(snr)
445 445
446 446 #print ('stop 3')
447 447 if snrdB < SNRlimit :
448 448 # snr = numpy.NaN
449 449 # SPC_ch1[:,ht] = 0#numpy.NaN
450 450 # SPC_ch1[:,ht] = 0#numpy.NaN
451 451 # SPCparam = (SPC_ch1,SPC_ch2)
452 452 # print ('SNR less than SNRth')
453 453 continue
454 454 # wnoise = hildebrand_sekhon(spc,num_intg)
455 455 # print ('stop 2.01')
456 456 #############################################
457 457 # normalizing spc and noise
458 458 # This part differs from gg1
459 459 # spc_norm_max = max(spc) #commented by D. ScipiΓ³n 19.03.2021
460 460 #spc = spc / spc_norm_max
461 461 # pnoise = pnoise #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
462 462 #############################################
463 463
464 464 # print ('stop 2.1')
465 465 fatspectra=1.0
466 466 # noise per channel.... we might want to use the noise at each range
467 467
468 468 # wnoise = noise_ #/ spc_norm_max #commented by D. ScipiΓ³n 19.03.2021
469 469 #wnoise,stdv,i_max,index =enoise(spc,num_intg) #noise estimate using Hildebrand Sekhon, only wnoise is used
470 470 #if wnoise>1.1*pnoise: # to be tested later
471 471 # wnoise=pnoise
472 472 # noisebl = wnoise*0.9
473 473 # noisebh = wnoise*1.1
474 474 spc = spc - wnoise # signal
475 475
476 476 # print ('stop 2.2')
477 477 minx = numpy.argmin(spc)
478 478 #spcs=spc.copy()
479 479 spcs = numpy.roll(spc,-minx)
480 480 cum = numpy.cumsum(spcs)
481 481 # tot_noise = wnoise * self.Num_Bin #64;
482 482
483 483 # print ('stop 2.3')
484 484 # snr = sum(spcs) / tot_noise
485 485 # snrdB = 10.*numpy.log10(snr)
486 486 #print ('stop 3')
487 487 # if snrdB < SNRlimit :
488 488 # snr = numpy.NaN
489 489 # SPC_ch1[:,ht] = 0#numpy.NaN
490 490 # SPC_ch1[:,ht] = 0#numpy.NaN
491 491 # SPCparam = (SPC_ch1,SPC_ch2)
492 492 # print ('SNR less than SNRth')
493 493 # continue
494 494
495 495
496 496 #if snrdB<-18 or numpy.isnan(snrdB) or num_intg<4:
497 497 # return [None,]*4,[None,]*4,None,snrdB,None,None,[None,]*5,[None,]*9,None
498 498 # print ('stop 4')
499 499 cummax = max(cum)
500 500 epsi = 0.08 * fatspectra # cumsum to narrow down the energy region
501 501 cumlo = cummax * epsi
502 502 cumhi = cummax * (1-epsi)
503 503 powerindex = numpy.array(numpy.where(numpy.logical_and(cum>cumlo, cum<cumhi))[0])
504 504
505 505 # print ('stop 5')
506 506 if len(powerindex) < 1:# case for powerindex 0
507 507 # print ('powerindex < 1')
508 508 continue
509 509 powerlo = powerindex[0]
510 510 powerhi = powerindex[-1]
511 511 powerwidth = powerhi-powerlo
512 512 if powerwidth <= 1:
513 513 # print('powerwidth <= 1')
514 514 continue
515 515
516 516 # print ('stop 6')
517 517 firstpeak = powerlo + powerwidth/10.# first gaussian energy location
518 518 secondpeak = powerhi - powerwidth/10. #second gaussian energy location
519 519 midpeak = (firstpeak + secondpeak)/2.
520 520 firstamp = spcs[int(firstpeak)]
521 521 secondamp = spcs[int(secondpeak)]
522 522 midamp = spcs[int(midpeak)]
523 523
524 524 y_data = spc + wnoise
525 525
526 526 ''' single Gaussian '''
527 527 shift0 = numpy.mod(midpeak+minx, self.Num_Bin )
528 528 width0 = powerwidth/4.#Initialization entire power of spectrum divided by 4
529 529 power0 = 2.
530 530 amplitude0 = midamp
531 531 state0 = [shift0,width0,amplitude0,power0,wnoise]
532 532 bnds = ((0,self.Num_Bin-1),(1,powerwidth),(0,None),(0.5,3.),(noisebl,noisebh))
533 533 lsq1 = fmin_l_bfgs_b(self.misfit1, state0, args=(y_data,x,num_intg), bounds=bnds, approx_grad=True)
534 534 # print ('stop 7.1')
535 535 # print (bnds)
536 536
537 537 chiSq1=lsq1[1]
538 538
539 539 # print ('stop 8')
540 540 if fatspectra<1.0 and powerwidth<4:
541 541 choice=0
542 542 Amplitude0=lsq1[0][2]
543 543 shift0=lsq1[0][0]
544 544 width0=lsq1[0][1]
545 545 p0=lsq1[0][3]
546 546 Amplitude1=0.
547 547 shift1=0.
548 548 width1=0.
549 549 p1=0.
550 550 noise=lsq1[0][4]
551 551 #return (numpy.array([shift0,width0,Amplitude0,p0]),
552 552 # numpy.array([shift1,width1,Amplitude1,p1]),noise,snrdB,chiSq1,6.,sigmas1,[None,]*9,choice)
553 553
554 554 # print ('stop 9')
555 555 ''' two Gaussians '''
556 556 #shift0=numpy.mod(firstpeak+minx,64); shift1=numpy.mod(secondpeak+minx,64)
557 557 shift0 = numpy.mod(firstpeak+minx, self.Num_Bin )
558 558 shift1 = numpy.mod(secondpeak+minx, self.Num_Bin )
559 559 width0 = powerwidth/6.
560 560 width1 = width0
561 561 power0 = 2.
562 562 power1 = power0
563 563 amplitude0 = firstamp
564 564 amplitude1 = secondamp
565 565 state0 = [shift0,width0,amplitude0,power0,shift1,width1,amplitude1,power1,wnoise]
566 566 #bnds=((0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(0,63),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
567 567 bnds=((0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(0,self.Num_Bin-1),(1,powerwidth/2.),(0,None),(0.5,3.),(noisebl,noisebh))
568 568 #bnds=(( 0,(self.Num_Bin-1) ),(1,powerwidth/2.),(0,None),(0.5,3.),( 0,(self.Num_Bin-1)),(1,powerwidth/2.),(0,None),(0.5,3.),(0.1,0.5))
569 569
570 570 # print ('stop 10')
571 571 lsq2 = fmin_l_bfgs_b( self.misfit2 , state0 , args=(y_data,x,num_intg) , bounds=bnds , approx_grad=True )
572 572
573 573 # print ('stop 11')
574 574 chiSq2 = lsq2[1]
575 575
576 576 # print ('stop 12')
577 577
578 578 oneG = (chiSq1<5 and chiSq1/chiSq2<2.0) and (abs(lsq2[0][0]-lsq2[0][4])<(lsq2[0][1]+lsq2[0][5])/3. or abs(lsq2[0][0]-lsq2[0][4])<10)
579 579
580 580 # print ('stop 13')
581 581 if snrdB>-12: # when SNR is strong pick the peak with least shift (LOS velocity) error
582 582 if oneG:
583 583 choice = 0
584 584 else:
585 585 w1 = lsq2[0][1]; w2 = lsq2[0][5]
586 586 a1 = lsq2[0][2]; a2 = lsq2[0][6]
587 587 p1 = lsq2[0][3]; p2 = lsq2[0][7]
588 588 s1 = (2**(1+1./p1))*scipy.special.gamma(1./p1)/p1
589 589 s2 = (2**(1+1./p2))*scipy.special.gamma(1./p2)/p2
590 590 gp1 = a1*w1*s1; gp2 = a2*w2*s2 # power content of each ggaussian with proper p scaling
591 591
592 592 if gp1>gp2:
593 593 if a1>0.7*a2:
594 594 choice = 1
595 595 else:
596 596 choice = 2
597 597 elif gp2>gp1:
598 598 if a2>0.7*a1:
599 599 choice = 2
600 600 else:
601 601 choice = 1
602 602 else:
603 603 choice = numpy.argmax([a1,a2])+1
604 604 #else:
605 605 #choice=argmin([std2a,std2b])+1
606 606
607 607 else: # with low SNR go to the most energetic peak
608 608 choice = numpy.argmax([lsq1[0][2]*lsq1[0][1],lsq2[0][2]*lsq2[0][1],lsq2[0][6]*lsq2[0][5]])
609 609
610 610 # print ('stop 14')
611 611 shift0 = lsq2[0][0]
612 612 vel0 = Vrange[0] + shift0 * deltav
613 613 shift1 = lsq2[0][4]
614 614 # vel1=Vrange[0] + shift1 * deltav
615 615
616 616 # max_vel = 1.0
617 617 # Va = max(Vrange)
618 618 # deltav = Vrange[1]-Vrange[0]
619 619 # print ('stop 15')
620 620 #first peak will be 0, second peak will be 1
621 621 # if vel0 > -1.0 and vel0 < max_vel : #first peak is in the correct range # Commented by D.ScipiΓ³n 19.03.2021
622 622 if vel0 > -Va and vel0 < Va : #first peak is in the correct range
623 623 shift0 = lsq2[0][0]
624 624 width0 = lsq2[0][1]
625 625 Amplitude0 = lsq2[0][2]
626 626 p0 = lsq2[0][3]
627 627
628 628 shift1 = lsq2[0][4]
629 629 width1 = lsq2[0][5]
630 630 Amplitude1 = lsq2[0][6]
631 631 p1 = lsq2[0][7]
632 632 noise = lsq2[0][8]
633 633 else:
634 634 shift1 = lsq2[0][0]
635 635 width1 = lsq2[0][1]
636 636 Amplitude1 = lsq2[0][2]
637 637 p1 = lsq2[0][3]
638 638
639 639 shift0 = lsq2[0][4]
640 640 width0 = lsq2[0][5]
641 641 Amplitude0 = lsq2[0][6]
642 642 p0 = lsq2[0][7]
643 643 noise = lsq2[0][8]
644 644
645 645 if Amplitude0<0.05: # in case the peak is noise
646 646 shift0,width0,Amplitude0,p0 = 4*[numpy.NaN]
647 647 if Amplitude1<0.05:
648 648 shift1,width1,Amplitude1,p1 = 4*[numpy.NaN]
649 649
650 650 # print ('stop 16 ')
651 651 # SPC_ch1[:,ht] = noise + Amplitude0*numpy.exp(-0.5*(abs(x-shift0)/width0)**p0)
652 652 # SPC_ch2[:,ht] = noise + Amplitude1*numpy.exp(-0.5*(abs(x-shift1)/width1)**p1)
653 653 # SPCparam = (SPC_ch1,SPC_ch2)
654 654
655 655 DGauFitParam[0,ht,0] = noise
656 656 DGauFitParam[0,ht,1] = noise
657 657 DGauFitParam[1,ht,0] = Amplitude0
658 658 DGauFitParam[1,ht,1] = Amplitude1
659 659 DGauFitParam[2,ht,0] = Vrange[0] + shift0 * deltav
660 660 DGauFitParam[2,ht,1] = Vrange[0] + shift1 * deltav
661 661 DGauFitParam[3,ht,0] = width0 * deltav
662 662 DGauFitParam[3,ht,1] = width1 * deltav
663 663 DGauFitParam[4,ht,0] = p0
664 664 DGauFitParam[4,ht,1] = p1
665 665
666 666 # print (DGauFitParam.shape)
667 667 # print ('Leaving FitGau')
668 668 return DGauFitParam
669 669 # return SPCparam
670 670 # return GauSPC
671 671
672 672 def y_model1(self,x,state):
673 673 shift0, width0, amplitude0, power0, noise = state
674 674 model0 = amplitude0*numpy.exp(-0.5*abs((x - shift0)/width0)**power0)
675 675 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
676 676 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
677 677 return model0 + model0u + model0d + noise
678 678
679 679 def y_model2(self,x,state): #Equation for two generalized Gaussians with Nyquist
680 680 shift0, width0, amplitude0, power0, shift1, width1, amplitude1, power1, noise = state
681 681 model0 = amplitude0*numpy.exp(-0.5*abs((x-shift0)/width0)**power0)
682 682 model0u = amplitude0*numpy.exp(-0.5*abs((x - shift0 - self.Num_Bin)/width0)**power0)
683 683 model0d = amplitude0*numpy.exp(-0.5*abs((x - shift0 + self.Num_Bin)/width0)**power0)
684 684
685 685 model1 = amplitude1*numpy.exp(-0.5*abs((x - shift1)/width1)**power1)
686 686 model1u = amplitude1*numpy.exp(-0.5*abs((x - shift1 - self.Num_Bin)/width1)**power1)
687 687 model1d = amplitude1*numpy.exp(-0.5*abs((x - shift1 + self.Num_Bin)/width1)**power1)
688 688 return model0 + model0u + model0d + model1 + model1u + model1d + noise
689 689
690 690 def misfit1(self,state,y_data,x,num_intg): # This function compares how close real data is with the model data, the close it is, the better it is.
691 691
692 692 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model1(x,state)))**2)#/(64-5.) # /(64-5.) can be commented
693 693
694 694 def misfit2(self,state,y_data,x,num_intg):
695 695 return num_intg*sum((numpy.log(y_data)-numpy.log(self.y_model2(x,state)))**2)#/(64-9.)
696 696
697 697
698 698
699 699 class PrecipitationProc(Operation):
700 700
701 701 '''
702 702 Operator that estimates Reflectivity factor (Z), and estimates rainfall Rate (R)
703 703
704 704 Input:
705 705 self.dataOut.data_pre : SelfSpectra
706 706
707 707 Output:
708 708
709 709 self.dataOut.data_output : Reflectivity factor, rainfall Rate
710 710
711 711
712 712 Parameters affected:
713 713 '''
714 714
715 715 def __init__(self):
716 716 Operation.__init__(self)
717 717 self.i=0
718 718
719 719 def run(self, dataOut, radar=None, Pt=5000, Gt=295.1209, Gr=70.7945, Lambda=0.6741, aL=2.5118,
720 720 tauW=4e-06, ThetaT=0.1656317, ThetaR=0.36774087, Km2 = 0.93, Altitude=3350,SNRdBlimit=-30):
721 721
722 722 # print ('Entering PrecepitationProc ... ')
723 723
724 724 if radar == "MIRA35C" :
725 725
726 726 self.spc = dataOut.data_pre[0].copy()
727 727 self.Num_Hei = self.spc.shape[2]
728 728 self.Num_Bin = self.spc.shape[1]
729 729 self.Num_Chn = self.spc.shape[0]
730 730 Ze = self.dBZeMODE2(dataOut)
731 731
732 732 else:
733 733
734 734 self.spc = dataOut.data_pre[0].copy()
735 735
736 736 #NOTA SE DEBE REMOVER EL RANGO DEL PULSO TX
737 737 self.spc[:,:,0:7]= numpy.NaN
738 738
739 739 self.Num_Hei = self.spc.shape[2]
740 740 self.Num_Bin = self.spc.shape[1]
741 741 self.Num_Chn = self.spc.shape[0]
742 742
743 743 VelRange = dataOut.spc_range[2]
744 744
745 745 ''' Se obtiene la constante del RADAR '''
746 746
747 747 self.Pt = Pt
748 748 self.Gt = Gt
749 749 self.Gr = Gr
750 750 self.Lambda = Lambda
751 751 self.aL = aL
752 752 self.tauW = tauW
753 753 self.ThetaT = ThetaT
754 754 self.ThetaR = ThetaR
755 755 self.GSys = 10**(36.63/10) # Ganancia de los LNA 36.63 dB
756 756 self.lt = 10**(1.67/10) # Perdida en cables Tx 1.67 dB
757 757 self.lr = 10**(5.73/10) # Perdida en cables Rx 5.73 dB
758 758
759 759 Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
760 760 Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * tauW * numpy.pi * ThetaT * ThetaR)
761 761 RadarConstant = 10e-26 * Numerator / Denominator #
762 762 ExpConstant = 10**(40/10) #Constante Experimental
763 763
764 764 SignalPower = numpy.zeros([self.Num_Chn,self.Num_Bin,self.Num_Hei])
765 765 for i in range(self.Num_Chn):
766 766 SignalPower[i,:,:] = self.spc[i,:,:] - dataOut.noise[i]
767 767 SignalPower[numpy.where(SignalPower < 0)] = 1e-20
768 768
769 769 SPCmean = numpy.mean(SignalPower, 0)
770 770 Pr = SPCmean[:,:]/dataOut.normFactor
771 771
772 772 # Declaring auxiliary variables
773 773 Range = dataOut.heightList*1000. #Range in m
774 774 # replicate the heightlist to obtain a matrix [Num_Bin,Num_Hei]
775 775 rMtrx = numpy.transpose(numpy.transpose([dataOut.heightList*1000.] * self.Num_Bin))
776 776 zMtrx = rMtrx+Altitude
777 777 # replicate the VelRange to obtain a matrix [Num_Bin,Num_Hei]
778 778 VelMtrx = numpy.transpose(numpy.tile(VelRange[:-1], (self.Num_Hei,1)))
779 779
780 780 # height dependence to air density Foote and Du Toit (1969)
781 781 delv_z = 1 + 3.68e-5 * zMtrx + 1.71e-9 * zMtrx**2
782 782 VMtrx = VelMtrx / delv_z #Normalized velocity
783 783 VMtrx[numpy.where(VMtrx> 9.6)] = numpy.NaN
784 784 # Diameter is related to the fall speed of falling drops
785 785 D_Vz = -1.667 * numpy.log( 0.9369 - 0.097087 * VMtrx ) # D in [mm]
786 786 # Only valid for D>= 0.16 mm
787 787 D_Vz[numpy.where(D_Vz < 0.16)] = numpy.NaN
788 788
789 789 #Calculate Radar Reflectivity ETAn
790 790 ETAn = (RadarConstant *ExpConstant) * Pr * rMtrx**2 #Reflectivity (ETA)
791 791 ETAd = ETAn * 6.18 * exp( -0.6 * D_Vz ) * delv_z
792 792 # Radar Cross Section
793 793 sigmaD = Km2 * (D_Vz * 1e-3 )**6 * numpy.pi**5 / Lambda**4
794 794 # Drop Size Distribution
795 795 DSD = ETAn / sigmaD
796 796 # Equivalente Reflectivy
797 797 Ze_eqn = numpy.nansum( DSD * D_Vz**6 ,axis=0)
798 798 Ze_org = numpy.nansum(ETAn * Lambda**4, axis=0) / (1e-18*numpy.pi**5 * Km2) # [mm^6 /m^3]
799 799 # RainFall Rate
800 800 RR = 0.0006*numpy.pi * numpy.nansum( D_Vz**3 * DSD * VelMtrx ,0) #mm/hr
801 801
802 802 # Censoring the data
803 803 # Removing data with SNRth < 0dB se debe considerar el SNR por canal
804 804 SNRth = 10**(SNRdBlimit/10) #-30dB
805 805 novalid = numpy.where((dataOut.data_snr[0,:] <SNRth) | (dataOut.data_snr[1,:] <SNRth) | (dataOut.data_snr[2,:] <SNRth)) # AND condition. Maybe OR condition better
806 806 W = numpy.nanmean(dataOut.data_dop,0)
807 807 W[novalid] = numpy.NaN
808 808 Ze_org[novalid] = numpy.NaN
809 809 RR[novalid] = numpy.NaN
810 810
811 811 dataOut.data_output = RR[8]
812 812 dataOut.data_param = numpy.ones([3,self.Num_Hei])
813 813 dataOut.channelList = [0,1,2]
814 814
815 815 dataOut.data_param[0]=10*numpy.log10(Ze_org)
816 816 dataOut.data_param[1]=-W
817 817 dataOut.data_param[2]=RR
818 818
819 819 # print ('Leaving PrecepitationProc ... ')
820 820 return dataOut
821 821
822 822 def dBZeMODE2(self, dataOut): # Processing for MIRA35C
823 823
824 824 NPW = dataOut.NPW
825 825 COFA = dataOut.COFA
826 826
827 827 SNR = numpy.array([self.spc[0,:,:] / NPW[0]]) #, self.spc[1,:,:] / NPW[1]])
828 828 RadarConst = dataOut.RadarConst
829 829 #frequency = 34.85*10**9
830 830
831 831 ETA = numpy.zeros(([self.Num_Chn ,self.Num_Hei]))
832 832 data_output = numpy.ones([self.Num_Chn , self.Num_Hei])*numpy.NaN
833 833
834 834 ETA = numpy.sum(SNR,1)
835 835
836 836 ETA = numpy.where(ETA != 0. , ETA, numpy.NaN)
837 837
838 838 Ze = numpy.ones([self.Num_Chn, self.Num_Hei] )
839 839
840 840 for r in range(self.Num_Hei):
841 841
842 842 Ze[0,r] = ( ETA[0,r] ) * COFA[0,r][0] * RadarConst * ((r/5000.)**2)
843 843 #Ze[1,r] = ( ETA[1,r] ) * COFA[1,r][0] * RadarConst * ((r/5000.)**2)
844 844
845 845 return Ze
846 846
847 847 # def GetRadarConstant(self):
848 848 #
849 849 # """
850 850 # Constants:
851 851 #
852 852 # Pt: Transmission Power dB 5kW 5000
853 853 # Gt: Transmission Gain dB 24.7 dB 295.1209
854 854 # Gr: Reception Gain dB 18.5 dB 70.7945
855 855 # Lambda: Wavelenght m 0.6741 m 0.6741
856 856 # aL: Attenuation loses dB 4dB 2.5118
857 857 # tauW: Width of transmission pulse s 4us 4e-6
858 858 # ThetaT: Transmission antenna bean angle rad 0.1656317 rad 0.1656317
859 859 # ThetaR: Reception antenna beam angle rad 0.36774087 rad 0.36774087
860 860 #
861 861 # """
862 862 #
863 863 # Numerator = ( (4*numpy.pi)**3 * aL**2 * 16 * numpy.log(2) )
864 864 # Denominator = ( Pt * Gt * Gr * Lambda**2 * SPEED_OF_LIGHT * TauW * numpy.pi * ThetaT * TheraR)
865 865 # RadarConstant = Numerator / Denominator
866 866 #
867 867 # return RadarConstant
868 868
869 869
870 870
871 871 class FullSpectralAnalysis(Operation):
872 872
873 873 """
874 874 Function that implements Full Spectral Analysis technique.
875 875
876 876 Input:
877 877 self.dataOut.data_pre : SelfSpectra and CrossSpectra data
878 878 self.dataOut.groupList : Pairlist of channels
879 879 self.dataOut.ChanDist : Physical distance between receivers
880 880
881 881
882 882 Output:
883 883
884 884 self.dataOut.data_output : Zonal wind, Meridional wind, and Vertical wind
885 885
886 886
887 887 Parameters affected: Winds, height range, SNR
888 888
889 889 """
890 890 def run(self, dataOut, Xi01=None, Xi02=None, Xi12=None, Eta01=None, Eta02=None, Eta12=None, SNRdBlimit=-30,
891 891 minheight=None, maxheight=None, NegativeLimit=None, PositiveLimit=None):
892 892
893 893 spc = dataOut.data_pre[0].copy()
894 894 cspc = dataOut.data_pre[1]
895 895 nHeights = spc.shape[2]
896 896
897 897 # first_height = 0.75 #km (ref: data header 20170822)
898 898 # resolution_height = 0.075 #km
899 899 '''
900 900 finding height range. check this when radar parameters are changed!
901 901 '''
902 902 if maxheight is not None:
903 903 # range_max = math.ceil((maxheight - first_height) / resolution_height) # theoretical
904 904 range_max = math.ceil(13.26 * maxheight - 3) # empirical, works better
905 905 else:
906 906 range_max = nHeights
907 907 if minheight is not None:
908 908 # range_min = int((minheight - first_height) / resolution_height) # theoretical
909 909 range_min = int(13.26 * minheight - 5) # empirical, works better
910 910 if range_min < 0:
911 911 range_min = 0
912 912 else:
913 913 range_min = 0
914 914
915 915 pairsList = dataOut.groupList
916 916 if dataOut.ChanDist is not None :
917 917 ChanDist = dataOut.ChanDist
918 918 else:
919 919 ChanDist = numpy.array([[Xi01, Eta01],[Xi02,Eta02],[Xi12,Eta12]])
920 920
921 921 # 4 variables: zonal, meridional, vertical, and average SNR
922 922 data_param = numpy.zeros([4,nHeights]) * numpy.NaN
923 923 velocityX = numpy.zeros([nHeights]) * numpy.NaN
924 924 velocityY = numpy.zeros([nHeights]) * numpy.NaN
925 925 velocityZ = numpy.zeros([nHeights]) * numpy.NaN
926 926
927 927 dbSNR = 10*numpy.log10(numpy.average(dataOut.data_snr,0))
928 928
929 929 '''***********************************************WIND ESTIMATION**************************************'''
930 930 for Height in range(nHeights):
931 931
932 932 if Height >= range_min and Height < range_max:
933 933 # error_code will be useful in future analysis
934 934 [Vzon,Vmer,Vver, error_code] = self.WindEstimation(spc[:,:,Height], cspc[:,:,Height], pairsList,
935 935 ChanDist, Height, dataOut.noise, dataOut.spc_range, dbSNR[Height], SNRdBlimit, NegativeLimit, PositiveLimit,dataOut.frequency)
936 936
937 937 if abs(Vzon) < 100. and abs(Vmer) < 100.:
938 938 velocityX[Height] = Vzon
939 939 velocityY[Height] = -Vmer
940 940 velocityZ[Height] = Vver
941 941
942 942 # Censoring data with SNR threshold
943 943 dbSNR [dbSNR < SNRdBlimit] = numpy.NaN
944 944
945 945 data_param[0] = velocityX
946 946 data_param[1] = velocityY
947 947 data_param[2] = velocityZ
948 948 data_param[3] = dbSNR
949 949 dataOut.data_param = data_param
950 950 return dataOut
951 951
952 952 def moving_average(self,x, N=2):
953 953 """ convolution for smoothenig data. note that last N-1 values are convolution with zeroes """
954 954 return numpy.convolve(x, numpy.ones((N,))/N)[(N-1):]
955 955
956 956 def gaus(self,xSamples,Amp,Mu,Sigma):
957 957 return Amp * numpy.exp(-0.5*((xSamples - Mu)/Sigma)**2)
958 958
959 959 def Moments(self, ySamples, xSamples):
960 960 Power = numpy.nanmean(ySamples) # Power, 0th Moment
961 961 yNorm = ySamples / numpy.nansum(ySamples)
962 962 RadVel = numpy.nansum(xSamples * yNorm) # Radial Velocity, 1st Moment
963 963 Sigma2 = numpy.nansum(yNorm * (xSamples - RadVel)**2) # Spectral Width, 2nd Moment
964 964 StdDev = numpy.sqrt(numpy.abs(Sigma2)) # Desv. Estandar, Ancho espectral
965 965 return numpy.array([Power,RadVel,StdDev])
966 966
967 967 def StopWindEstimation(self, error_code):
968 968 Vzon = numpy.NaN
969 969 Vmer = numpy.NaN
970 970 Vver = numpy.NaN
971 971 return Vzon, Vmer, Vver, error_code
972 972
973 973 def AntiAliasing(self, interval, maxstep):
974 974 """
975 975 function to prevent errors from aliased values when computing phaseslope
976 976 """
977 977 antialiased = numpy.zeros(len(interval))
978 978 copyinterval = interval.copy()
979 979
980 980 antialiased[0] = copyinterval[0]
981 981
982 982 for i in range(1,len(antialiased)):
983 983 step = interval[i] - interval[i-1]
984 984 if step > maxstep:
985 985 copyinterval -= 2*numpy.pi
986 986 antialiased[i] = copyinterval[i]
987 987 elif step < maxstep*(-1):
988 988 copyinterval += 2*numpy.pi
989 989 antialiased[i] = copyinterval[i]
990 990 else:
991 991 antialiased[i] = copyinterval[i].copy()
992 992
993 993 return antialiased
994 994
995 995 def WindEstimation(self, spc, cspc, pairsList, ChanDist, Height, noise, AbbsisaRange, dbSNR, SNRlimit, NegativeLimit, PositiveLimit, radfreq):
996 996 """
997 997 Function that Calculates Zonal, Meridional and Vertical wind velocities.
998 998 Initial Version by E. Bocanegra updated by J. Zibell until Nov. 2019.
999 999
1000 1000 Input:
1001 1001 spc, cspc : self spectra and cross spectra data. In Briggs notation something like S_i*(S_i)_conj, (S_j)_conj respectively.
1002 1002 pairsList : Pairlist of channels
1003 1003 ChanDist : array of xi_ij and eta_ij
1004 1004 Height : height at which data is processed
1005 1005 noise : noise in [channels] format for specific height
1006 1006 Abbsisarange : range of the frequencies or velocities
1007 1007 dbSNR, SNRlimit : signal to noise ratio in db, lower limit
1008 1008
1009 1009 Output:
1010 1010 Vzon, Vmer, Vver : wind velocities
1011 1011 error_code : int that states where code is terminated
1012 1012
1013 1013 0 : no error detected
1014 1014 1 : Gaussian of mean spc exceeds widthlimit
1015 1015 2 : no Gaussian of mean spc found
1016 1016 3 : SNR to low or velocity to high -> prec. e.g.
1017 1017 4 : at least one Gaussian of cspc exceeds widthlimit
1018 1018 5 : zero out of three cspc Gaussian fits converged
1019 1019 6 : phase slope fit could not be found
1020 1020 7 : arrays used to fit phase have different length
1021 1021 8 : frequency range is either too short (len <= 5) or very long (> 30% of cspc)
1022 1022
1023 1023 """
1024 1024
1025 1025 error_code = 0
1026 1026
1027 1027 nChan = spc.shape[0]
1028 1028 nProf = spc.shape[1]
1029 1029 nPair = cspc.shape[0]
1030 1030
1031 1031 SPC_Samples = numpy.zeros([nChan, nProf]) # for normalized spc values for one height
1032 1032 CSPC_Samples = numpy.zeros([nPair, nProf], dtype=numpy.complex_) # for normalized cspc values
1033 1033 phase = numpy.zeros([nPair, nProf]) # phase between channels
1034 1034 PhaseSlope = numpy.zeros(nPair) # slope of the phases, channelwise
1035 1035 PhaseInter = numpy.zeros(nPair) # intercept to the slope of the phases, channelwise
1036 1036 xFrec = AbbsisaRange[0][:-1] # frequency range
1037 1037 xVel = AbbsisaRange[2][:-1] # velocity range
1038 1038 xSamples = xFrec # the frequency range is taken
1039 1039 delta_x = xSamples[1] - xSamples[0] # delta_f or delta_x
1040 1040
1041 1041 # only consider velocities with in NegativeLimit and PositiveLimit
1042 1042 if (NegativeLimit is None):
1043 1043 NegativeLimit = numpy.min(xVel)
1044 1044 if (PositiveLimit is None):
1045 1045 PositiveLimit = numpy.max(xVel)
1046 1046 xvalid = numpy.where((xVel > NegativeLimit) & (xVel < PositiveLimit))
1047 1047 xSamples_zoom = xSamples[xvalid]
1048 1048
1049 1049 '''Getting Eij and Nij'''
1050 1050 Xi01, Xi02, Xi12 = ChanDist[:,0]
1051 1051 Eta01, Eta02, Eta12 = ChanDist[:,1]
1052 1052
1053 1053 # spwd limit - updated by D. ScipiΓ³n 30.03.2021
1054 1054 widthlimit = 10
1055 1055 '''************************* SPC is normalized ********************************'''
1056 1056 spc_norm = spc.copy()
1057 1057 # For each channel
1058 1058 for i in range(nChan):
1059 1059 spc_sub = spc_norm[i,:] - noise[i] # only the signal power
1060 1060 SPC_Samples[i] = spc_sub / (numpy.nansum(spc_sub) * delta_x)
1061 1061
1062 1062 '''********************** FITTING MEAN SPC GAUSSIAN **********************'''
1063 1063
1064 1064 """ the gaussian of the mean: first subtract noise, then normalize. this is legal because
1065 1065 you only fit the curve and don't need the absolute value of height for calculation,
1066 1066 only for estimation of width. for normalization of cross spectra, you need initial,
1067 1067 unnormalized self-spectra With noise.
1068 1068
1069 1069 Technically, you don't even need to normalize the self-spectra, as you only need the
1070 1070 width of the peak. However, it was left this way. Note that the normalization has a flaw:
1071 1071 due to subtraction of the noise, some values are below zero. Raw "spc" values should be
1072 1072 >= 0, as it is the modulus squared of the signals (complex * it's conjugate)
1073 1073 """
1074 1074 # initial conditions
1075 1075 popt = [1e-10,0,1e-10]
1076 1076 # Spectra average
1077 1077 SPCMean = numpy.average(SPC_Samples,0)
1078 1078 # Moments in frequency
1079 1079 SPCMoments = self.Moments(SPCMean[xvalid], xSamples_zoom)
1080 1080
1081 1081 # Gauss Fit SPC in frequency domain
1082 1082 if dbSNR > SNRlimit: # only if SNR > SNRth
1083 1083 try:
1084 1084 popt,pcov = curve_fit(self.gaus,xSamples_zoom,SPCMean[xvalid],p0=SPCMoments)
1085 1085 if popt[2] <= 0 or popt[2] > widthlimit: # CONDITION
1086 1086 return self.StopWindEstimation(error_code = 1)
1087 1087 FitGauss = self.gaus(xSamples_zoom,*popt)
1088 1088 except :#RuntimeError:
1089 1089 return self.StopWindEstimation(error_code = 2)
1090 1090 else:
1091 1091 return self.StopWindEstimation(error_code = 3)
1092 1092
1093 1093 '''***************************** CSPC Normalization *************************
1094 1094 The Spc spectra are used to normalize the crossspectra. Peaks from precipitation
1095 1095 influence the norm which is not desired. First, a range is identified where the
1096 1096 wind peak is estimated -> sum_wind is sum of those frequencies. Next, the area
1097 1097 around it gets cut off and values replaced by mean determined by the boundary
1098 1098 data -> sum_noise (spc is not normalized here, thats why the noise is important)
1099 1099
1100 1100 The sums are then added and multiplied by range/datapoints, because you need
1101 1101 an integral and not a sum for normalization.
1102 1102
1103 1103 A norm is found according to Briggs 92.
1104 1104 '''
1105 1105 # for each pair
1106 1106 for i in range(nPair):
1107 1107 cspc_norm = cspc[i,:].copy()
1108 1108 chan_index0 = pairsList[i][0]
1109 1109 chan_index1 = pairsList[i][1]
1110 1110 CSPC_Samples[i] = cspc_norm / (numpy.sqrt(numpy.nansum(spc_norm[chan_index0])*numpy.nansum(spc_norm[chan_index1])) * delta_x)
1111 1111 phase[i] = numpy.arctan2(CSPC_Samples[i].imag, CSPC_Samples[i].real)
1112 1112
1113 1113 CSPCmoments = numpy.vstack([self.Moments(numpy.abs(CSPC_Samples[0,xvalid]), xSamples_zoom),
1114 1114 self.Moments(numpy.abs(CSPC_Samples[1,xvalid]), xSamples_zoom),
1115 1115 self.Moments(numpy.abs(CSPC_Samples[2,xvalid]), xSamples_zoom)])
1116 1116
1117 1117 popt01, popt02, popt12 = [1e-10,0,1e-10], [1e-10,0,1e-10] ,[1e-10,0,1e-10]
1118 1118 FitGauss01, FitGauss02, FitGauss12 = numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples)), numpy.zeros(len(xSamples))
1119 1119
1120 1120 '''*******************************FIT GAUSS CSPC************************************'''
1121 1121 try:
1122 1122 popt01,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[0][xvalid]),p0=CSPCmoments[0])
1123 1123 if popt01[2] > widthlimit: # CONDITION
1124 1124 return self.StopWindEstimation(error_code = 4)
1125 1125 popt02,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[1][xvalid]),p0=CSPCmoments[1])
1126 1126 if popt02[2] > widthlimit: # CONDITION
1127 1127 return self.StopWindEstimation(error_code = 4)
1128 1128 popt12,pcov = curve_fit(self.gaus,xSamples_zoom,numpy.abs(CSPC_Samples[2][xvalid]),p0=CSPCmoments[2])
1129 1129 if popt12[2] > widthlimit: # CONDITION
1130 1130 return self.StopWindEstimation(error_code = 4)
1131 1131
1132 1132 FitGauss01 = self.gaus(xSamples_zoom, *popt01)
1133 1133 FitGauss02 = self.gaus(xSamples_zoom, *popt02)
1134 1134 FitGauss12 = self.gaus(xSamples_zoom, *popt12)
1135 1135 except:
1136 1136 return self.StopWindEstimation(error_code = 5)
1137 1137
1138 1138
1139 1139 '''************* Getting Fij ***************'''
1140 1140 # x-axis point of the gaussian where the center is located from GaussFit of spectra
1141 1141 GaussCenter = popt[1]
1142 1142 ClosestCenter = xSamples_zoom[numpy.abs(xSamples_zoom-GaussCenter).argmin()]
1143 1143 PointGauCenter = numpy.where(xSamples_zoom==ClosestCenter)[0][0]
1144 1144
1145 1145 # Point where e^-1 is located in the gaussian
1146 1146 PeMinus1 = numpy.max(FitGauss) * numpy.exp(-1)
1147 1147 FijClosest = FitGauss[numpy.abs(FitGauss-PeMinus1).argmin()] # The closest point to"Peminus1" in "FitGauss"
1148 1148 PointFij = numpy.where(FitGauss==FijClosest)[0][0]
1149 1149 Fij = numpy.abs(xSamples_zoom[PointFij] - xSamples_zoom[PointGauCenter])
1150 1150
1151 1151 '''********** Taking frequency ranges from mean SPCs **********'''
1152 1152 GauWidth = popt[2] * 3/2 # Bandwidth of Gau01
1153 1153 Range = numpy.empty(2)
1154 1154 Range[0] = GaussCenter - GauWidth
1155 1155 Range[1] = GaussCenter + GauWidth
1156 1156 # Point in x-axis where the bandwidth is located (min:max)
1157 1157 ClosRangeMin = xSamples_zoom[numpy.abs(xSamples_zoom-Range[0]).argmin()]
1158 1158 ClosRangeMax = xSamples_zoom[numpy.abs(xSamples_zoom-Range[1]).argmin()]
1159 1159 PointRangeMin = numpy.where(xSamples_zoom==ClosRangeMin)[0][0]
1160 1160 PointRangeMax = numpy.where(xSamples_zoom==ClosRangeMax)[0][0]
1161 1161 Range = numpy.array([ PointRangeMin, PointRangeMax ])
1162 1162 FrecRange = xSamples_zoom[ Range[0] : Range[1] ]
1163 1163
1164 1164 '''************************** Getting Phase Slope ***************************'''
1165 1165 for i in range(nPair):
1166 1166 if len(FrecRange) > 5:
1167 1167 PhaseRange = phase[i, xvalid[0][Range[0]:Range[1]]].copy()
1168 1168 mask = ~numpy.isnan(FrecRange) & ~numpy.isnan(PhaseRange)
1169 1169 if len(FrecRange) == len(PhaseRange):
1170 1170 try:
1171 1171 slope, intercept, _, _, _ = stats.linregress(FrecRange[mask], self.AntiAliasing(PhaseRange[mask], 4.5))
1172 1172 PhaseSlope[i] = slope
1173 1173 PhaseInter[i] = intercept
1174 1174 except:
1175 1175 return self.StopWindEstimation(error_code = 6)
1176 1176 else:
1177 1177 return self.StopWindEstimation(error_code = 7)
1178 1178 else:
1179 1179 return self.StopWindEstimation(error_code = 8)
1180 1180
1181 1181 '''*** Constants A-H correspond to the convention as in Briggs and Vincent 1992 ***'''
1182 1182
1183 1183 '''Getting constant C'''
1184 1184 cC=(Fij*numpy.pi)**2
1185 1185
1186 1186 '''****** Getting constants F and G ******'''
1187 1187 MijEijNij = numpy.array([[Xi02,Eta02], [Xi12,Eta12]])
1188 1188 # MijEijNij = numpy.array([[Xi01,Eta01], [Xi02,Eta02], [Xi12,Eta12]])
1189 1189 # MijResult0 = (-PhaseSlope[0] * cC) / (2*numpy.pi)
1190 1190 MijResult1 = (-PhaseSlope[1] * cC) / (2*numpy.pi)
1191 1191 MijResult2 = (-PhaseSlope[2] * cC) / (2*numpy.pi)
1192 1192 # MijResults = numpy.array([MijResult0, MijResult1, MijResult2])
1193 1193 MijResults = numpy.array([MijResult1, MijResult2])
1194 1194 (cF,cG) = numpy.linalg.solve(MijEijNij, MijResults)
1195 1195
1196 1196 '''****** Getting constants A, B and H ******'''
1197 1197 W01 = numpy.nanmax( FitGauss01 )
1198 1198 W02 = numpy.nanmax( FitGauss02 )
1199 1199 W12 = numpy.nanmax( FitGauss12 )
1200 1200
1201 1201 WijResult01 = ((cF * Xi01 + cG * Eta01)**2)/cC - numpy.log(W01 / numpy.sqrt(numpy.pi / cC))
1202 1202 WijResult02 = ((cF * Xi02 + cG * Eta02)**2)/cC - numpy.log(W02 / numpy.sqrt(numpy.pi / cC))
1203 1203 WijResult12 = ((cF * Xi12 + cG * Eta12)**2)/cC - numpy.log(W12 / numpy.sqrt(numpy.pi / cC))
1204 1204 WijResults = numpy.array([WijResult01, WijResult02, WijResult12])
1205 1205
1206 1206 WijEijNij = numpy.array([ [Xi01**2, Eta01**2, 2*Xi01*Eta01] , [Xi02**2, Eta02**2, 2*Xi02*Eta02] , [Xi12**2, Eta12**2, 2*Xi12*Eta12] ])
1207 1207 (cA,cB,cH) = numpy.linalg.solve(WijEijNij, WijResults)
1208 1208
1209 1209 VxVy = numpy.array([[cA,cH],[cH,cB]])
1210 1210 VxVyResults = numpy.array([-cF,-cG])
1211 1211 (Vmer,Vzon) = numpy.linalg.solve(VxVy, VxVyResults)
1212 1212 Vver = -SPCMoments[1]*SPEED_OF_LIGHT/(2*radfreq)
1213 1213 error_code = 0
1214 1214
1215 1215 return Vzon, Vmer, Vver, error_code
1216 1216
1217 1217 class SpectralMoments(Operation):
1218 1218
1219 1219 '''
1220 1220 Function SpectralMoments()
1221 1221
1222 1222 Calculates moments (power, mean, standard deviation) and SNR of the signal
1223 1223
1224 1224 Type of dataIn: Spectra
1225 1225
1226 1226 Configuration Parameters:
1227 1227
1228 1228 dirCosx : Cosine director in X axis
1229 1229 dirCosy : Cosine director in Y axis
1230 1230
1231 1231 elevation :
1232 1232 azimuth :
1233 1233
1234 1234 Input:
1235 1235 channelList : simple channel list to select e.g. [2,3,7]
1236 1236 self.dataOut.data_pre : Spectral data
1237 1237 self.dataOut.abscissaList : List of frequencies
1238 1238 self.dataOut.noise : Noise level per channel
1239 1239
1240 1240 Affected:
1241 1241 self.dataOut.moments : Parameters per channel
1242 1242 self.dataOut.data_snr : SNR per channel
1243 1243
1244 1244 '''
1245 1245
1246 1246 def run(self, dataOut):
1247 1247
1248 1248 data = dataOut.data_pre[0]
1249 1249 absc = dataOut.abscissaList[:-1]
1250 1250 noise = dataOut.noise
1251 1251 nChannel = data.shape[0]
1252 1252 data_param = numpy.zeros((nChannel, 4, data.shape[2]))
1253 1253
1254 1254 for ind in range(nChannel):
1255 1255 data_param[ind,:,:] = self.__calculateMoments( data[ind,:,:] , absc , noise[ind] )
1256 1256
1257 1257 dataOut.moments = data_param[:,1:,:]
1258 1258 dataOut.data_snr = data_param[:,0]
1259 1259 dataOut.data_pow = data_param[:,1]
1260 1260 dataOut.data_dop = data_param[:,2]
1261 1261 dataOut.data_width = data_param[:,3]
1262
1263 1262 return dataOut
1264 1263
1265 1264 def __calculateMoments(self, oldspec, oldfreq, n0,
1266 1265 nicoh = None, graph = None, smooth = None, type1 = None, fwindow = None, snrth = None, dc = None, aliasing = None, oldfd = None, wwauto = None):
1267 1266
1268 1267 if (nicoh is None): nicoh = 1
1269 1268 if (graph is None): graph = 0
1270 1269 if (smooth is None): smooth = 0
1271 1270 elif (self.smooth < 3): smooth = 0
1272 1271
1273 1272 if (type1 is None): type1 = 0
1274 1273 if (fwindow is None): fwindow = numpy.zeros(oldfreq.size) + 1
1275 1274 if (snrth is None): snrth = -3
1276 1275 if (dc is None): dc = 0
1277 1276 if (aliasing is None): aliasing = 0
1278 1277 if (oldfd is None): oldfd = 0
1279 1278 if (wwauto is None): wwauto = 0
1280 1279
1281 1280 if (n0 < 1.e-20): n0 = 1.e-20
1282 1281
1283 1282 freq = oldfreq
1284 1283 vec_power = numpy.zeros(oldspec.shape[1])
1285 1284 vec_fd = numpy.zeros(oldspec.shape[1])
1286 1285 vec_w = numpy.zeros(oldspec.shape[1])
1287 1286 vec_snr = numpy.zeros(oldspec.shape[1])
1288 1287
1289 1288 # oldspec = numpy.ma.masked_invalid(oldspec)
1290 1289
1291 1290 for ind in range(oldspec.shape[1]):
1292 1291
1293 1292 spec = oldspec[:,ind]
1294 1293 aux = spec*fwindow
1295 1294 max_spec = aux.max()
1296 1295 m = aux.tolist().index(max_spec)
1297 1296
1298 1297 # Smooth
1299 1298 if (smooth == 0):
1300 1299 spec2 = spec
1301 1300 else:
1302 1301 spec2 = scipy.ndimage.filters.uniform_filter1d(spec,size=smooth)
1303 1302
1304 1303 # Moments Estimation
1305 1304 bb = spec2[numpy.arange(m,spec2.size)]
1306 1305 bb = (bb<n0).nonzero()
1307 1306 bb = bb[0]
1308 1307
1309 1308 ss = spec2[numpy.arange(0,m + 1)]
1310 1309 ss = (ss<n0).nonzero()
1311 1310 ss = ss[0]
1312 1311
1313 1312 if (bb.size == 0):
1314 1313 bb0 = spec.size - 1 - m
1315 1314 else:
1316 1315 bb0 = bb[0] - 1
1317 1316 if (bb0 < 0):
1318 1317 bb0 = 0
1319 1318
1320 1319 if (ss.size == 0):
1321 1320 ss1 = 1
1322 1321 else:
1323 1322 ss1 = max(ss) + 1
1324 1323
1325 1324 if (ss1 > m):
1326 1325 ss1 = m
1327 1326
1328 1327 valid = numpy.arange(int(m + bb0 - ss1 + 1)) + ss1
1329 1328
1330 1329 signal_power = ((spec2[valid] - n0) * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
1331 1330 total_power = (spec2[valid] * fwindow[valid]).mean() # D. ScipiΓ³n added with correct definition
1332 1331 power = ((spec2[valid] - n0) * fwindow[valid]).sum()
1333 1332 fd = ((spec2[valid]- n0)*freq[valid] * fwindow[valid]).sum() / power
1334 1333 w = numpy.sqrt(((spec2[valid] - n0)*fwindow[valid]*(freq[valid]- fd)**2).sum() / power)
1335 1334 snr = (spec2.mean()-n0)/n0
1336 1335 if (snr < 1.e-20) :
1337 1336 snr = 1.e-20
1338 1337
1339 1338 # vec_power[ind] = power #D. ScipiΓ³n replaced with the line below
1340 1339 vec_power[ind] = total_power
1341 1340 vec_fd[ind] = fd
1342 1341 vec_w[ind] = w
1343 1342 vec_snr[ind] = snr
1344 1343
1345 1344 return numpy.vstack((vec_snr, vec_power, vec_fd, vec_w))
1346 1345
1347 1346 #------------------ Get SA Parameters --------------------------
1348 1347
1349 1348 def GetSAParameters(self):
1350 1349 #SA en frecuencia
1351 1350 pairslist = self.dataOut.groupList
1352 1351 num_pairs = len(pairslist)
1353 1352
1354 1353 vel = self.dataOut.abscissaList
1355 1354 spectra = self.dataOut.data_pre
1356 1355 cspectra = self.dataIn.data_cspc
1357 1356 delta_v = vel[1] - vel[0]
1358 1357
1359 1358 #Calculating the power spectrum
1360 1359 spc_pow = numpy.sum(spectra, 3)*delta_v
1361 1360 #Normalizing Spectra
1362 1361 norm_spectra = spectra/spc_pow
1363 1362 #Calculating the norm_spectra at peak
1364 1363 max_spectra = numpy.max(norm_spectra, 3)
1365 1364
1366 1365 #Normalizing Cross Spectra
1367 1366 norm_cspectra = numpy.zeros(cspectra.shape)
1368 1367
1369 1368 for i in range(num_chan):
1370 1369 norm_cspectra[i,:,:] = cspectra[i,:,:]/numpy.sqrt(spc_pow[pairslist[i][0],:]*spc_pow[pairslist[i][1],:])
1371 1370
1372 1371 max_cspectra = numpy.max(norm_cspectra,2)
1373 1372 max_cspectra_index = numpy.argmax(norm_cspectra, 2)
1374 1373
1375 1374 for i in range(num_pairs):
1376 1375 cspc_par[i,:,:] = __calculateMoments(norm_cspectra)
1377 1376 #------------------- Get Lags ----------------------------------
1378 1377
1379 1378 class SALags(Operation):
1380 1379 '''
1381 1380 Function GetMoments()
1382 1381
1383 1382 Input:
1384 1383 self.dataOut.data_pre
1385 1384 self.dataOut.abscissaList
1386 1385 self.dataOut.noise
1387 1386 self.dataOut.normFactor
1388 1387 self.dataOut.data_snr
1389 1388 self.dataOut.groupList
1390 1389 self.dataOut.nChannels
1391 1390
1392 1391 Affected:
1393 1392 self.dataOut.data_param
1394 1393
1395 1394 '''
1396 1395 def run(self, dataOut):
1397 1396 data_acf = dataOut.data_pre[0]
1398 1397 data_ccf = dataOut.data_pre[1]
1399 1398 normFactor_acf = dataOut.normFactor[0]
1400 1399 normFactor_ccf = dataOut.normFactor[1]
1401 1400 pairs_acf = dataOut.groupList[0]
1402 1401 pairs_ccf = dataOut.groupList[1]
1403 1402
1404 1403 nHeights = dataOut.nHeights
1405 1404 absc = dataOut.abscissaList
1406 1405 noise = dataOut.noise
1407 1406 SNR = dataOut.data_snr
1408 1407 nChannels = dataOut.nChannels
1409 1408 # pairsList = dataOut.groupList
1410 1409 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairsList, nChannels)
1411 1410
1412 1411 for l in range(len(pairs_acf)):
1413 1412 data_acf[l,:,:] = data_acf[l,:,:]/normFactor_acf[l,:]
1414 1413
1415 1414 for l in range(len(pairs_ccf)):
1416 1415 data_ccf[l,:,:] = data_ccf[l,:,:]/normFactor_ccf[l,:]
1417 1416
1418 1417 dataOut.data_param = numpy.zeros((len(pairs_ccf)*2 + 1, nHeights))
1419 1418 dataOut.data_param[:-1,:] = self.__calculateTaus(data_acf, data_ccf, absc)
1420 1419 dataOut.data_param[-1,:] = self.__calculateLag1Phase(data_acf, absc)
1421 1420 return
1422 1421
1423 1422 # def __getPairsAutoCorr(self, pairsList, nChannels):
1424 1423 #
1425 1424 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1426 1425 #
1427 1426 # for l in range(len(pairsList)):
1428 1427 # firstChannel = pairsList[l][0]
1429 1428 # secondChannel = pairsList[l][1]
1430 1429 #
1431 1430 # #Obteniendo pares de Autocorrelacion
1432 1431 # if firstChannel == secondChannel:
1433 1432 # pairsAutoCorr[firstChannel] = int(l)
1434 1433 #
1435 1434 # pairsAutoCorr = pairsAutoCorr.astype(int)
1436 1435 #
1437 1436 # pairsCrossCorr = range(len(pairsList))
1438 1437 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1439 1438 #
1440 1439 # return pairsAutoCorr, pairsCrossCorr
1441 1440
1442 1441 def __calculateTaus(self, data_acf, data_ccf, lagRange):
1443 1442
1444 1443 lag0 = data_acf.shape[1]/2
1445 1444 #Funcion de Autocorrelacion
1446 1445 mean_acf = stats.nanmean(data_acf, axis = 0)
1447 1446
1448 1447 #Obtencion Indice de TauCross
1449 1448 ind_ccf = data_ccf.argmax(axis = 1)
1450 1449 #Obtencion Indice de TauAuto
1451 1450 ind_acf = numpy.zeros(ind_ccf.shape,dtype = 'int')
1452 1451 ccf_lag0 = data_ccf[:,lag0,:]
1453 1452
1454 1453 for i in range(ccf_lag0.shape[0]):
1455 1454 ind_acf[i,:] = numpy.abs(mean_acf - ccf_lag0[i,:]).argmin(axis = 0)
1456 1455
1457 1456 #Obtencion de TauCross y TauAuto
1458 1457 tau_ccf = lagRange[ind_ccf]
1459 1458 tau_acf = lagRange[ind_acf]
1460 1459
1461 1460 Nan1, Nan2 = numpy.where(tau_ccf == lagRange[0])
1462 1461
1463 1462 tau_ccf[Nan1,Nan2] = numpy.nan
1464 1463 tau_acf[Nan1,Nan2] = numpy.nan
1465 1464 tau = numpy.vstack((tau_ccf,tau_acf))
1466 1465
1467 1466 return tau
1468 1467
1469 1468 def __calculateLag1Phase(self, data, lagTRange):
1470 1469 data1 = stats.nanmean(data, axis = 0)
1471 1470 lag1 = numpy.where(lagTRange == 0)[0][0] + 1
1472 1471
1473 1472 phase = numpy.angle(data1[lag1,:])
1474 1473
1475 1474 return phase
1476 1475
1477 1476 class SpectralFitting(Operation):
1478 1477 '''
1479 1478 Function GetMoments()
1480 1479
1481 1480 Input:
1482 1481 Output:
1483 1482 Variables modified:
1484 1483 '''
1485 1484
1486 1485 def run(self, dataOut, getSNR = True, path=None, file=None, groupList=None):
1487 1486
1488 1487
1489 1488 if path != None:
1490 1489 sys.path.append(path)
1491 1490 self.dataOut.library = importlib.import_module(file)
1492 1491
1493 1492 #To be inserted as a parameter
1494 1493 groupArray = numpy.array(groupList)
1495 1494 # groupArray = numpy.array([[0,1],[2,3]])
1496 1495 self.dataOut.groupList = groupArray
1497 1496
1498 1497 nGroups = groupArray.shape[0]
1499 1498 nChannels = self.dataIn.nChannels
1500 1499 nHeights=self.dataIn.heightList.size
1501 1500
1502 1501 #Parameters Array
1503 1502 self.dataOut.data_param = None
1504 1503
1505 1504 #Set constants
1506 1505 constants = self.dataOut.library.setConstants(self.dataIn)
1507 1506 self.dataOut.constants = constants
1508 1507 M = self.dataIn.normFactor
1509 1508 N = self.dataIn.nFFTPoints
1510 1509 ippSeconds = self.dataIn.ippSeconds
1511 1510 K = self.dataIn.nIncohInt
1512 1511 pairsArray = numpy.array(self.dataIn.pairsList)
1513 1512
1514 1513 #List of possible combinations
1515 1514 listComb = itertools.combinations(numpy.arange(groupArray.shape[1]),2)
1516 1515 indCross = numpy.zeros(len(list(listComb)), dtype = 'int')
1517 1516
1518 1517 if getSNR:
1519 1518 listChannels = groupArray.reshape((groupArray.size))
1520 1519 listChannels.sort()
1521 1520 noise = self.dataIn.getNoise()
1522 1521 self.dataOut.data_snr = self.__getSNR(self.dataIn.data_spc[listChannels,:,:], noise[listChannels])
1523 1522
1524 1523 for i in range(nGroups):
1525 1524 coord = groupArray[i,:]
1526 1525
1527 1526 #Input data array
1528 1527 data = self.dataIn.data_spc[coord,:,:]/(M*N)
1529 1528 data = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
1530 1529
1531 1530 #Cross Spectra data array for Covariance Matrixes
1532 1531 ind = 0
1533 1532 for pairs in listComb:
1534 1533 pairsSel = numpy.array([coord[x],coord[y]])
1535 1534 indCross[ind] = int(numpy.where(numpy.all(pairsArray == pairsSel, axis = 1))[0][0])
1536 1535 ind += 1
1537 1536 dataCross = self.dataIn.data_cspc[indCross,:,:]/(M*N)
1538 1537 dataCross = dataCross**2/K
1539 1538
1540 1539 for h in range(nHeights):
1541 1540
1542 1541 #Input
1543 1542 d = data[:,h]
1544 1543
1545 1544 #Covariance Matrix
1546 1545 D = numpy.diag(d**2/K)
1547 1546 ind = 0
1548 1547 for pairs in listComb:
1549 1548 #Coordinates in Covariance Matrix
1550 1549 x = pairs[0]
1551 1550 y = pairs[1]
1552 1551 #Channel Index
1553 1552 S12 = dataCross[ind,:,h]
1554 1553 D12 = numpy.diag(S12)
1555 1554 #Completing Covariance Matrix with Cross Spectras
1556 1555 D[x*N:(x+1)*N,y*N:(y+1)*N] = D12
1557 1556 D[y*N:(y+1)*N,x*N:(x+1)*N] = D12
1558 1557 ind += 1
1559 1558 Dinv=numpy.linalg.inv(D)
1560 1559 L=numpy.linalg.cholesky(Dinv)
1561 1560 LT=L.T
1562 1561
1563 1562 dp = numpy.dot(LT,d)
1564 1563
1565 1564 #Initial values
1566 1565 data_spc = self.dataIn.data_spc[coord,:,h]
1567 1566
1568 1567 if (h>0)and(error1[3]<5):
1569 1568 p0 = self.dataOut.data_param[i,:,h-1]
1570 1569 else:
1571 1570 p0 = numpy.array(self.dataOut.library.initialValuesFunction(data_spc, constants, i))
1572 1571
1573 1572 try:
1574 1573 #Least Squares
1575 1574 minp,covp,infodict,mesg,ier = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants),full_output=True)
1576 1575 # minp,covp = optimize.leastsq(self.__residFunction,p0,args=(dp,LT,constants))
1577 1576 #Chi square error
1578 1577 error0 = numpy.sum(infodict['fvec']**2)/(2*N)
1579 1578 #Error with Jacobian
1580 1579 error1 = self.dataOut.library.errorFunction(minp,constants,LT)
1581 1580 except:
1582 1581 minp = p0*numpy.nan
1583 1582 error0 = numpy.nan
1584 1583 error1 = p0*numpy.nan
1585 1584
1586 1585 #Save
1587 1586 if self.dataOut.data_param is None:
1588 1587 self.dataOut.data_param = numpy.zeros((nGroups, p0.size, nHeights))*numpy.nan
1589 1588 self.dataOut.data_error = numpy.zeros((nGroups, p0.size + 1, nHeights))*numpy.nan
1590 1589
1591 1590 self.dataOut.data_error[i,:,h] = numpy.hstack((error0,error1))
1592 1591 self.dataOut.data_param[i,:,h] = minp
1593 1592 return
1594 1593
1595 1594 def __residFunction(self, p, dp, LT, constants):
1596 1595
1597 1596 fm = self.dataOut.library.modelFunction(p, constants)
1598 1597 fmp=numpy.dot(LT,fm)
1599 1598
1600 1599 return dp-fmp
1601 1600
1602 1601 def __getSNR(self, z, noise):
1603 1602
1604 1603 avg = numpy.average(z, axis=1)
1605 1604 SNR = (avg.T-noise)/noise
1606 1605 SNR = SNR.T
1607 1606 return SNR
1608 1607
1609 1608 def __chisq(p,chindex,hindex):
1610 1609 #similar to Resid but calculates CHI**2
1611 1610 [LT,d,fm]=setupLTdfm(p,chindex,hindex)
1612 1611 dp=numpy.dot(LT,d)
1613 1612 fmp=numpy.dot(LT,fm)
1614 1613 chisq=numpy.dot((dp-fmp).T,(dp-fmp))
1615 1614 return chisq
1616 1615
1617 1616 class WindProfiler(Operation):
1618 1617
1619 1618 __isConfig = False
1620 1619
1621 1620 __initime = None
1622 1621 __lastdatatime = None
1623 1622 __integrationtime = None
1624 1623
1625 1624 __buffer = None
1626 1625
1627 1626 __dataReady = False
1628 1627
1629 1628 __firstdata = None
1630 1629
1631 1630 n = None
1632 1631
1633 1632 def __init__(self):
1634 1633 Operation.__init__(self)
1635 1634
1636 1635 def __calculateCosDir(self, elev, azim):
1637 1636 zen = (90 - elev)*numpy.pi/180
1638 1637 azim = azim*numpy.pi/180
1639 1638 cosDirX = numpy.sqrt((1-numpy.cos(zen)**2)/((1+numpy.tan(azim)**2)))
1640 1639 cosDirY = numpy.sqrt(1-numpy.cos(zen)**2-cosDirX**2)
1641 1640
1642 1641 signX = numpy.sign(numpy.cos(azim))
1643 1642 signY = numpy.sign(numpy.sin(azim))
1644 1643
1645 1644 cosDirX = numpy.copysign(cosDirX, signX)
1646 1645 cosDirY = numpy.copysign(cosDirY, signY)
1647 1646 return cosDirX, cosDirY
1648 1647
1649 1648 def __calculateAngles(self, theta_x, theta_y, azimuth):
1650 1649
1651 1650 dir_cosw = numpy.sqrt(1-theta_x**2-theta_y**2)
1652 1651 zenith_arr = numpy.arccos(dir_cosw)
1653 1652 azimuth_arr = numpy.arctan2(theta_x,theta_y) + azimuth*math.pi/180
1654 1653
1655 1654 dir_cosu = numpy.sin(azimuth_arr)*numpy.sin(zenith_arr)
1656 1655 dir_cosv = numpy.cos(azimuth_arr)*numpy.sin(zenith_arr)
1657 1656
1658 1657 return azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw
1659 1658
1660 1659 def __calculateMatA(self, dir_cosu, dir_cosv, dir_cosw, horOnly):
1661 1660
1662 1661 #
1663 1662 if horOnly:
1664 1663 A = numpy.c_[dir_cosu,dir_cosv]
1665 1664 else:
1666 1665 A = numpy.c_[dir_cosu,dir_cosv,dir_cosw]
1667 1666 A = numpy.asmatrix(A)
1668 1667 A1 = numpy.linalg.inv(A.transpose()*A)*A.transpose()
1669 1668
1670 1669 return A1
1671 1670
1672 1671 def __correctValues(self, heiRang, phi, velRadial, SNR):
1673 1672 listPhi = phi.tolist()
1674 1673 maxid = listPhi.index(max(listPhi))
1675 1674 minid = listPhi.index(min(listPhi))
1676 1675
1677 1676 rango = list(range(len(phi)))
1678 1677 # rango = numpy.delete(rango,maxid)
1679 1678
1680 1679 heiRang1 = heiRang*math.cos(phi[maxid])
1681 1680 heiRangAux = heiRang*math.cos(phi[minid])
1682 1681 indOut = (heiRang1 < heiRangAux[0]).nonzero()
1683 1682 heiRang1 = numpy.delete(heiRang1,indOut)
1684 1683
1685 1684 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
1686 1685 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
1687 1686
1688 1687 for i in rango:
1689 1688 x = heiRang*math.cos(phi[i])
1690 1689 y1 = velRadial[i,:]
1691 1690 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
1692 1691
1693 1692 x1 = heiRang1
1694 1693 y11 = f1(x1)
1695 1694
1696 1695 y2 = SNR[i,:]
1697 1696 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
1698 1697 y21 = f2(x1)
1699 1698
1700 1699 velRadial1[i,:] = y11
1701 1700 SNR1[i,:] = y21
1702 1701
1703 1702 return heiRang1, velRadial1, SNR1
1704 1703
1705 1704 def __calculateVelUVW(self, A, velRadial):
1706 1705
1707 1706 #Operacion Matricial
1708 1707 # velUVW = numpy.zeros((velRadial.shape[1],3))
1709 1708 # for ind in range(velRadial.shape[1]):
1710 1709 # velUVW[ind,:] = numpy.dot(A,velRadial[:,ind])
1711 1710 # velUVW = velUVW.transpose()
1712 1711 velUVW = numpy.zeros((A.shape[0],velRadial.shape[1]))
1713 1712 velUVW[:,:] = numpy.dot(A,velRadial)
1714 1713
1715 1714
1716 1715 return velUVW
1717 1716
1718 1717 # def techniqueDBS(self, velRadial0, dirCosx, disrCosy, azimuth, correct, horizontalOnly, heiRang, SNR0):
1719 1718
1720 1719 def techniqueDBS(self, kwargs):
1721 1720 """
1722 1721 Function that implements Doppler Beam Swinging (DBS) technique.
1723 1722
1724 1723 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1725 1724 Direction correction (if necessary), Ranges and SNR
1726 1725
1727 1726 Output: Winds estimation (Zonal, Meridional and Vertical)
1728 1727
1729 1728 Parameters affected: Winds, height range, SNR
1730 1729 """
1731 1730 velRadial0 = kwargs['velRadial']
1732 1731 heiRang = kwargs['heightList']
1733 1732 SNR0 = kwargs['SNR']
1734 1733
1735 1734 if 'dirCosx' in kwargs and 'dirCosy' in kwargs:
1736 1735 theta_x = numpy.array(kwargs['dirCosx'])
1737 1736 theta_y = numpy.array(kwargs['dirCosy'])
1738 1737 else:
1739 1738 elev = numpy.array(kwargs['elevation'])
1740 1739 azim = numpy.array(kwargs['azimuth'])
1741 1740 theta_x, theta_y = self.__calculateCosDir(elev, azim)
1742 1741 azimuth = kwargs['correctAzimuth']
1743 1742 if 'horizontalOnly' in kwargs:
1744 1743 horizontalOnly = kwargs['horizontalOnly']
1745 1744 else: horizontalOnly = False
1746 1745 if 'correctFactor' in kwargs:
1747 1746 correctFactor = kwargs['correctFactor']
1748 1747 else: correctFactor = 1
1749 1748 if 'channelList' in kwargs:
1750 1749 channelList = kwargs['channelList']
1751 1750 if len(channelList) == 2:
1752 1751 horizontalOnly = True
1753 1752 arrayChannel = numpy.array(channelList)
1754 1753 param = param[arrayChannel,:,:]
1755 1754 theta_x = theta_x[arrayChannel]
1756 1755 theta_y = theta_y[arrayChannel]
1757 1756
1758 1757 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
1759 1758 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, zenith_arr, correctFactor*velRadial0, SNR0)
1760 1759 A = self.__calculateMatA(dir_cosu, dir_cosv, dir_cosw, horizontalOnly)
1761 1760
1762 1761 #Calculo de Componentes de la velocidad con DBS
1763 1762 winds = self.__calculateVelUVW(A,velRadial1)
1764 1763
1765 1764 return winds, heiRang1, SNR1
1766 1765
1767 1766 def __calculateDistance(self, posx, posy, pairs_ccf, azimuth = None):
1768 1767
1769 1768 nPairs = len(pairs_ccf)
1770 1769 posx = numpy.asarray(posx)
1771 1770 posy = numpy.asarray(posy)
1772 1771
1773 1772 #Rotacion Inversa para alinear con el azimuth
1774 1773 if azimuth!= None:
1775 1774 azimuth = azimuth*math.pi/180
1776 1775 posx1 = posx*math.cos(azimuth) + posy*math.sin(azimuth)
1777 1776 posy1 = -posx*math.sin(azimuth) + posy*math.cos(azimuth)
1778 1777 else:
1779 1778 posx1 = posx
1780 1779 posy1 = posy
1781 1780
1782 1781 #Calculo de Distancias
1783 1782 distx = numpy.zeros(nPairs)
1784 1783 disty = numpy.zeros(nPairs)
1785 1784 dist = numpy.zeros(nPairs)
1786 1785 ang = numpy.zeros(nPairs)
1787 1786
1788 1787 for i in range(nPairs):
1789 1788 distx[i] = posx1[pairs_ccf[i][1]] - posx1[pairs_ccf[i][0]]
1790 1789 disty[i] = posy1[pairs_ccf[i][1]] - posy1[pairs_ccf[i][0]]
1791 1790 dist[i] = numpy.sqrt(distx[i]**2 + disty[i]**2)
1792 1791 ang[i] = numpy.arctan2(disty[i],distx[i])
1793 1792
1794 1793 return distx, disty, dist, ang
1795 1794 #Calculo de Matrices
1796 1795 # nPairs = len(pairs)
1797 1796 # ang1 = numpy.zeros((nPairs, 2, 1))
1798 1797 # dist1 = numpy.zeros((nPairs, 2, 1))
1799 1798 #
1800 1799 # for j in range(nPairs):
1801 1800 # dist1[j,0,0] = dist[pairs[j][0]]
1802 1801 # dist1[j,1,0] = dist[pairs[j][1]]
1803 1802 # ang1[j,0,0] = ang[pairs[j][0]]
1804 1803 # ang1[j,1,0] = ang[pairs[j][1]]
1805 1804 #
1806 1805 # return distx,disty, dist1,ang1
1807 1806
1808 1807
1809 1808 def __calculateVelVer(self, phase, lagTRange, _lambda):
1810 1809
1811 1810 Ts = lagTRange[1] - lagTRange[0]
1812 1811 velW = -_lambda*phase/(4*math.pi*Ts)
1813 1812
1814 1813 return velW
1815 1814
1816 1815 def __calculateVelHorDir(self, dist, tau1, tau2, ang):
1817 1816 nPairs = tau1.shape[0]
1818 1817 nHeights = tau1.shape[1]
1819 1818 vel = numpy.zeros((nPairs,3,nHeights))
1820 1819 dist1 = numpy.reshape(dist, (dist.size,1))
1821 1820
1822 1821 angCos = numpy.cos(ang)
1823 1822 angSin = numpy.sin(ang)
1824 1823
1825 1824 vel0 = dist1*tau1/(2*tau2**2)
1826 1825 vel[:,0,:] = (vel0*angCos).sum(axis = 1)
1827 1826 vel[:,1,:] = (vel0*angSin).sum(axis = 1)
1828 1827
1829 1828 ind = numpy.where(numpy.isinf(vel))
1830 1829 vel[ind] = numpy.nan
1831 1830
1832 1831 return vel
1833 1832
1834 1833 # def __getPairsAutoCorr(self, pairsList, nChannels):
1835 1834 #
1836 1835 # pairsAutoCorr = numpy.zeros(nChannels, dtype = 'int')*numpy.nan
1837 1836 #
1838 1837 # for l in range(len(pairsList)):
1839 1838 # firstChannel = pairsList[l][0]
1840 1839 # secondChannel = pairsList[l][1]
1841 1840 #
1842 1841 # #Obteniendo pares de Autocorrelacion
1843 1842 # if firstChannel == secondChannel:
1844 1843 # pairsAutoCorr[firstChannel] = int(l)
1845 1844 #
1846 1845 # pairsAutoCorr = pairsAutoCorr.astype(int)
1847 1846 #
1848 1847 # pairsCrossCorr = range(len(pairsList))
1849 1848 # pairsCrossCorr = numpy.delete(pairsCrossCorr,pairsAutoCorr)
1850 1849 #
1851 1850 # return pairsAutoCorr, pairsCrossCorr
1852 1851
1853 1852 # def techniqueSA(self, pairsSelected, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, lagTRange, correctFactor):
1854 1853 def techniqueSA(self, kwargs):
1855 1854
1856 1855 """
1857 1856 Function that implements Spaced Antenna (SA) technique.
1858 1857
1859 1858 Input: Radial velocities, Direction cosines (x and y) of the Beam, Antenna azimuth,
1860 1859 Direction correction (if necessary), Ranges and SNR
1861 1860
1862 1861 Output: Winds estimation (Zonal, Meridional and Vertical)
1863 1862
1864 1863 Parameters affected: Winds
1865 1864 """
1866 1865 position_x = kwargs['positionX']
1867 1866 position_y = kwargs['positionY']
1868 1867 azimuth = kwargs['azimuth']
1869 1868
1870 1869 if 'correctFactor' in kwargs:
1871 1870 correctFactor = kwargs['correctFactor']
1872 1871 else:
1873 1872 correctFactor = 1
1874 1873
1875 1874 groupList = kwargs['groupList']
1876 1875 pairs_ccf = groupList[1]
1877 1876 tau = kwargs['tau']
1878 1877 _lambda = kwargs['_lambda']
1879 1878
1880 1879 #Cross Correlation pairs obtained
1881 1880 # pairsAutoCorr, pairsCrossCorr = self.__getPairsAutoCorr(pairssList, nChannels)
1882 1881 # pairsArray = numpy.array(pairsList)[pairsCrossCorr]
1883 1882 # pairsSelArray = numpy.array(pairsSelected)
1884 1883 # pairs = []
1885 1884 #
1886 1885 # #Wind estimation pairs obtained
1887 1886 # for i in range(pairsSelArray.shape[0]/2):
1888 1887 # ind1 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i], axis = 1))[0][0]
1889 1888 # ind2 = numpy.where(numpy.all(pairsArray == pairsSelArray[2*i + 1], axis = 1))[0][0]
1890 1889 # pairs.append((ind1,ind2))
1891 1890
1892 1891 indtau = tau.shape[0]/2
1893 1892 tau1 = tau[:indtau,:]
1894 1893 tau2 = tau[indtau:-1,:]
1895 1894 # tau1 = tau1[pairs,:]
1896 1895 # tau2 = tau2[pairs,:]
1897 1896 phase1 = tau[-1,:]
1898 1897
1899 1898 #---------------------------------------------------------------------
1900 1899 #Metodo Directo
1901 1900 distx, disty, dist, ang = self.__calculateDistance(position_x, position_y, pairs_ccf,azimuth)
1902 1901 winds = self.__calculateVelHorDir(dist, tau1, tau2, ang)
1903 1902 winds = stats.nanmean(winds, axis=0)
1904 1903 #---------------------------------------------------------------------
1905 1904 #Metodo General
1906 1905 # distx, disty, dist = self.calculateDistance(position_x,position_y,pairsCrossCorr, pairsList, azimuth)
1907 1906 # #Calculo Coeficientes de Funcion de Correlacion
1908 1907 # F,G,A,B,H = self.calculateCoef(tau1,tau2,distx,disty,n)
1909 1908 # #Calculo de Velocidades
1910 1909 # winds = self.calculateVelUV(F,G,A,B,H)
1911 1910
1912 1911 #---------------------------------------------------------------------
1913 1912 winds[2,:] = self.__calculateVelVer(phase1, lagTRange, _lambda)
1914 1913 winds = correctFactor*winds
1915 1914 return winds
1916 1915
1917 1916 def __checkTime(self, currentTime, paramInterval, outputInterval):
1918 1917
1919 1918 dataTime = currentTime + paramInterval
1920 1919 deltaTime = dataTime - self.__initime
1921 1920
1922 1921 if deltaTime >= outputInterval or deltaTime < 0:
1923 1922 self.__dataReady = True
1924 1923 return
1925 1924
1926 1925 def techniqueMeteors(self, arrayMeteor, meteorThresh, heightMin, heightMax):
1927 1926 '''
1928 1927 Function that implements winds estimation technique with detected meteors.
1929 1928
1930 1929 Input: Detected meteors, Minimum meteor quantity to wind estimation
1931 1930
1932 1931 Output: Winds estimation (Zonal and Meridional)
1933 1932
1934 1933 Parameters affected: Winds
1935 1934 '''
1936 1935 #Settings
1937 1936 nInt = (heightMax - heightMin)/2
1938 1937 nInt = int(nInt)
1939 1938 winds = numpy.zeros((2,nInt))*numpy.nan
1940 1939
1941 1940 #Filter errors
1942 1941 error = numpy.where(arrayMeteor[:,-1] == 0)[0]
1943 1942 finalMeteor = arrayMeteor[error,:]
1944 1943
1945 1944 #Meteor Histogram
1946 1945 finalHeights = finalMeteor[:,2]
1947 1946 hist = numpy.histogram(finalHeights, bins = nInt, range = (heightMin,heightMax))
1948 1947 nMeteorsPerI = hist[0]
1949 1948 heightPerI = hist[1]
1950 1949
1951 1950 #Sort of meteors
1952 1951 indSort = finalHeights.argsort()
1953 1952 finalMeteor2 = finalMeteor[indSort,:]
1954 1953
1955 1954 # Calculating winds
1956 1955 ind1 = 0
1957 1956 ind2 = 0
1958 1957
1959 1958 for i in range(nInt):
1960 1959 nMet = nMeteorsPerI[i]
1961 1960 ind1 = ind2
1962 1961 ind2 = ind1 + nMet
1963 1962
1964 1963 meteorAux = finalMeteor2[ind1:ind2,:]
1965 1964
1966 1965 if meteorAux.shape[0] >= meteorThresh:
1967 1966 vel = meteorAux[:, 6]
1968 1967 zen = meteorAux[:, 4]*numpy.pi/180
1969 1968 azim = meteorAux[:, 3]*numpy.pi/180
1970 1969
1971 1970 n = numpy.cos(zen)
1972 1971 # m = (1 - n**2)/(1 - numpy.tan(azim)**2)
1973 1972 # l = m*numpy.tan(azim)
1974 1973 l = numpy.sin(zen)*numpy.sin(azim)
1975 1974 m = numpy.sin(zen)*numpy.cos(azim)
1976 1975
1977 1976 A = numpy.vstack((l, m)).transpose()
1978 1977 A1 = numpy.dot(numpy.linalg.inv( numpy.dot(A.transpose(),A) ),A.transpose())
1979 1978 windsAux = numpy.dot(A1, vel)
1980 1979
1981 1980 winds[0,i] = windsAux[0]
1982 1981 winds[1,i] = windsAux[1]
1983 1982
1984 1983 return winds, heightPerI[:-1]
1985 1984
1986 1985 def techniqueNSM_SA(self, **kwargs):
1987 1986 metArray = kwargs['metArray']
1988 1987 heightList = kwargs['heightList']
1989 1988 timeList = kwargs['timeList']
1990 1989
1991 1990 rx_location = kwargs['rx_location']
1992 1991 groupList = kwargs['groupList']
1993 1992 azimuth = kwargs['azimuth']
1994 1993 dfactor = kwargs['dfactor']
1995 1994 k = kwargs['k']
1996 1995
1997 1996 azimuth1, dist = self.__calculateAzimuth1(rx_location, groupList, azimuth)
1998 1997 d = dist*dfactor
1999 1998 #Phase calculation
2000 1999 metArray1 = self.__getPhaseSlope(metArray, heightList, timeList)
2001 2000
2002 2001 metArray1[:,-2] = metArray1[:,-2]*metArray1[:,2]*1000/(k*d[metArray1[:,1].astype(int)]) #angles into velocities
2003 2002
2004 2003 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2005 2004 azimuth1 = azimuth1*numpy.pi/180
2006 2005
2007 2006 for i in range(heightList.size):
2008 2007 h = heightList[i]
2009 2008 indH = numpy.where((metArray1[:,2] == h)&(numpy.abs(metArray1[:,-2]) < 100))[0]
2010 2009 metHeight = metArray1[indH,:]
2011 2010 if metHeight.shape[0] >= 2:
2012 2011 velAux = numpy.asmatrix(metHeight[:,-2]).T #Radial Velocities
2013 2012 iazim = metHeight[:,1].astype(int)
2014 2013 azimAux = numpy.asmatrix(azimuth1[iazim]).T #Azimuths
2015 2014 A = numpy.hstack((numpy.cos(azimAux),numpy.sin(azimAux)))
2016 2015 A = numpy.asmatrix(A)
2017 2016 A1 = numpy.linalg.pinv(A.transpose()*A)*A.transpose()
2018 2017 velHor = numpy.dot(A1,velAux)
2019 2018
2020 2019 velEst[i,:] = numpy.squeeze(velHor)
2021 2020 return velEst
2022 2021
2023 2022 def __getPhaseSlope(self, metArray, heightList, timeList):
2024 2023 meteorList = []
2025 2024 #utctime sec1 height SNR velRad ph0 ph1 ph2 coh0 coh1 coh2
2026 2025 #Putting back together the meteor matrix
2027 2026 utctime = metArray[:,0]
2028 2027 uniqueTime = numpy.unique(utctime)
2029 2028
2030 2029 phaseDerThresh = 0.5
2031 2030 ippSeconds = timeList[1] - timeList[0]
2032 2031 sec = numpy.where(timeList>1)[0][0]
2033 2032 nPairs = metArray.shape[1] - 6
2034 2033 nHeights = len(heightList)
2035 2034
2036 2035 for t in uniqueTime:
2037 2036 metArray1 = metArray[utctime==t,:]
2038 2037 # phaseDerThresh = numpy.pi/4 #reducir Phase thresh
2039 2038 tmet = metArray1[:,1].astype(int)
2040 2039 hmet = metArray1[:,2].astype(int)
2041 2040
2042 2041 metPhase = numpy.zeros((nPairs, heightList.size, timeList.size - 1))
2043 2042 metPhase[:,:] = numpy.nan
2044 2043 metPhase[:,hmet,tmet] = metArray1[:,6:].T
2045 2044
2046 2045 #Delete short trails
2047 2046 metBool = ~numpy.isnan(metPhase[0,:,:])
2048 2047 heightVect = numpy.sum(metBool, axis = 1)
2049 2048 metBool[heightVect<sec,:] = False
2050 2049 metPhase[:,heightVect<sec,:] = numpy.nan
2051 2050
2052 2051 #Derivative
2053 2052 metDer = numpy.abs(metPhase[:,:,1:] - metPhase[:,:,:-1])
2054 2053 phDerAux = numpy.dstack((numpy.full((nPairs,nHeights,1), False, dtype=bool),metDer > phaseDerThresh))
2055 2054 metPhase[phDerAux] = numpy.nan
2056 2055
2057 2056 #--------------------------METEOR DETECTION -----------------------------------------
2058 2057 indMet = numpy.where(numpy.any(metBool,axis=1))[0]
2059 2058
2060 2059 for p in numpy.arange(nPairs):
2061 2060 phase = metPhase[p,:,:]
2062 2061 phDer = metDer[p,:,:]
2063 2062
2064 2063 for h in indMet:
2065 2064 height = heightList[h]
2066 2065 phase1 = phase[h,:] #82
2067 2066 phDer1 = phDer[h,:]
2068 2067
2069 2068 phase1[~numpy.isnan(phase1)] = numpy.unwrap(phase1[~numpy.isnan(phase1)]) #Unwrap
2070 2069
2071 2070 indValid = numpy.where(~numpy.isnan(phase1))[0]
2072 2071 initMet = indValid[0]
2073 2072 endMet = 0
2074 2073
2075 2074 for i in range(len(indValid)-1):
2076 2075
2077 2076 #Time difference
2078 2077 inow = indValid[i]
2079 2078 inext = indValid[i+1]
2080 2079 idiff = inext - inow
2081 2080 #Phase difference
2082 2081 phDiff = numpy.abs(phase1[inext] - phase1[inow])
2083 2082
2084 2083 if idiff>sec or phDiff>numpy.pi/4 or inext==indValid[-1]: #End of Meteor
2085 2084 sizeTrail = inow - initMet + 1
2086 2085 if sizeTrail>3*sec: #Too short meteors
2087 2086 x = numpy.arange(initMet,inow+1)*ippSeconds
2088 2087 y = phase1[initMet:inow+1]
2089 2088 ynnan = ~numpy.isnan(y)
2090 2089 x = x[ynnan]
2091 2090 y = y[ynnan]
2092 2091 slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
2093 2092 ylin = x*slope + intercept
2094 2093 rsq = r_value**2
2095 2094 if rsq > 0.5:
2096 2095 vel = slope#*height*1000/(k*d)
2097 2096 estAux = numpy.array([utctime,p,height, vel, rsq])
2098 2097 meteorList.append(estAux)
2099 2098 initMet = inext
2100 2099 metArray2 = numpy.array(meteorList)
2101 2100
2102 2101 return metArray2
2103 2102
2104 2103 def __calculateAzimuth1(self, rx_location, pairslist, azimuth0):
2105 2104
2106 2105 azimuth1 = numpy.zeros(len(pairslist))
2107 2106 dist = numpy.zeros(len(pairslist))
2108 2107
2109 2108 for i in range(len(rx_location)):
2110 2109 ch0 = pairslist[i][0]
2111 2110 ch1 = pairslist[i][1]
2112 2111
2113 2112 diffX = rx_location[ch0][0] - rx_location[ch1][0]
2114 2113 diffY = rx_location[ch0][1] - rx_location[ch1][1]
2115 2114 azimuth1[i] = numpy.arctan2(diffY,diffX)*180/numpy.pi
2116 2115 dist[i] = numpy.sqrt(diffX**2 + diffY**2)
2117 2116
2118 2117 azimuth1 -= azimuth0
2119 2118 return azimuth1, dist
2120 2119
2121 2120 def techniqueNSM_DBS(self, **kwargs):
2122 2121 metArray = kwargs['metArray']
2123 2122 heightList = kwargs['heightList']
2124 2123 timeList = kwargs['timeList']
2125 2124 azimuth = kwargs['azimuth']
2126 2125 theta_x = numpy.array(kwargs['theta_x'])
2127 2126 theta_y = numpy.array(kwargs['theta_y'])
2128 2127
2129 2128 utctime = metArray[:,0]
2130 2129 cmet = metArray[:,1].astype(int)
2131 2130 hmet = metArray[:,3].astype(int)
2132 2131 SNRmet = metArray[:,4]
2133 2132 vmet = metArray[:,5]
2134 2133 spcmet = metArray[:,6]
2135 2134
2136 2135 nChan = numpy.max(cmet) + 1
2137 2136 nHeights = len(heightList)
2138 2137
2139 2138 azimuth_arr, zenith_arr, dir_cosu, dir_cosv, dir_cosw = self.__calculateAngles(theta_x, theta_y, azimuth)
2140 2139 hmet = heightList[hmet]
2141 2140 h1met = hmet*numpy.cos(zenith_arr[cmet]) #Corrected heights
2142 2141
2143 2142 velEst = numpy.zeros((heightList.size,2))*numpy.nan
2144 2143
2145 2144 for i in range(nHeights - 1):
2146 2145 hmin = heightList[i]
2147 2146 hmax = heightList[i + 1]
2148 2147
2149 2148 thisH = (h1met>=hmin) & (h1met<hmax) & (cmet!=2) & (SNRmet>8) & (vmet<50) & (spcmet<10)
2150 2149 indthisH = numpy.where(thisH)
2151 2150
2152 2151 if numpy.size(indthisH) > 3:
2153 2152
2154 2153 vel_aux = vmet[thisH]
2155 2154 chan_aux = cmet[thisH]
2156 2155 cosu_aux = dir_cosu[chan_aux]
2157 2156 cosv_aux = dir_cosv[chan_aux]
2158 2157 cosw_aux = dir_cosw[chan_aux]
2159 2158
2160 2159 nch = numpy.size(numpy.unique(chan_aux))
2161 2160 if nch > 1:
2162 2161 A = self.__calculateMatA(cosu_aux, cosv_aux, cosw_aux, True)
2163 2162 velEst[i,:] = numpy.dot(A,vel_aux)
2164 2163
2165 2164 return velEst
2166 2165
2167 2166 def run(self, dataOut, technique, nHours=1, hmin=70, hmax=110, **kwargs):
2168 2167
2169 2168 param = dataOut.data_param
2170 2169 if dataOut.abscissaList != None:
2171 2170 absc = dataOut.abscissaList[:-1]
2172 2171 # noise = dataOut.noise
2173 2172 heightList = dataOut.heightList
2174 2173 SNR = dataOut.data_snr
2175 2174
2176 2175 if technique == 'DBS':
2177 2176
2178 2177 kwargs['velRadial'] = param[:,1,:] #Radial velocity
2179 2178 kwargs['heightList'] = heightList
2180 2179 kwargs['SNR'] = SNR
2181 2180
2182 2181 dataOut.data_output, dataOut.heightList, dataOut.data_snr = self.techniqueDBS(kwargs) #DBS Function
2183 2182 dataOut.utctimeInit = dataOut.utctime
2184 2183 dataOut.outputInterval = dataOut.paramInterval
2185 2184
2186 2185 elif technique == 'SA':
2187 2186
2188 2187 #Parameters
2189 2188 # position_x = kwargs['positionX']
2190 2189 # position_y = kwargs['positionY']
2191 2190 # azimuth = kwargs['azimuth']
2192 2191 #
2193 2192 # if kwargs.has_key('crosspairsList'):
2194 2193 # pairs = kwargs['crosspairsList']
2195 2194 # else:
2196 2195 # pairs = None
2197 2196 #
2198 2197 # if kwargs.has_key('correctFactor'):
2199 2198 # correctFactor = kwargs['correctFactor']
2200 2199 # else:
2201 2200 # correctFactor = 1
2202 2201
2203 2202 # tau = dataOut.data_param
2204 2203 # _lambda = dataOut.C/dataOut.frequency
2205 2204 # pairsList = dataOut.groupList
2206 2205 # nChannels = dataOut.nChannels
2207 2206
2208 2207 kwargs['groupList'] = dataOut.groupList
2209 2208 kwargs['tau'] = dataOut.data_param
2210 2209 kwargs['_lambda'] = dataOut.C/dataOut.frequency
2211 2210 # dataOut.data_output = self.techniqueSA(pairs, pairsList, nChannels, tau, azimuth, _lambda, position_x, position_y, absc, correctFactor)
2212 2211 dataOut.data_output = self.techniqueSA(kwargs)
2213 2212 dataOut.utctimeInit = dataOut.utctime
2214 2213 dataOut.outputInterval = dataOut.timeInterval
2215 2214
2216 2215 elif technique == 'Meteors':
2217 2216 dataOut.flagNoData = True
2218 2217 self.__dataReady = False
2219 2218
2220 2219 if 'nHours' in kwargs:
2221 2220 nHours = kwargs['nHours']
2222 2221 else:
2223 2222 nHours = 1
2224 2223
2225 2224 if 'meteorsPerBin' in kwargs:
2226 2225 meteorThresh = kwargs['meteorsPerBin']
2227 2226 else:
2228 2227 meteorThresh = 6
2229 2228
2230 2229 if 'hmin' in kwargs:
2231 2230 hmin = kwargs['hmin']
2232 2231 else: hmin = 70
2233 2232 if 'hmax' in kwargs:
2234 2233 hmax = kwargs['hmax']
2235 2234 else: hmax = 110
2236 2235
2237 2236 dataOut.outputInterval = nHours*3600
2238 2237
2239 2238 if self.__isConfig == False:
2240 2239 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2241 2240 #Get Initial LTC time
2242 2241 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2243 2242 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2244 2243
2245 2244 self.__isConfig = True
2246 2245
2247 2246 if self.__buffer is None:
2248 2247 self.__buffer = dataOut.data_param
2249 2248 self.__firstdata = copy.copy(dataOut)
2250 2249
2251 2250 else:
2252 2251 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2253 2252
2254 2253 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2255 2254
2256 2255 if self.__dataReady:
2257 2256 dataOut.utctimeInit = self.__initime
2258 2257
2259 2258 self.__initime += dataOut.outputInterval #to erase time offset
2260 2259
2261 2260 dataOut.data_output, dataOut.heightList = self.techniqueMeteors(self.__buffer, meteorThresh, hmin, hmax)
2262 2261 dataOut.flagNoData = False
2263 2262 self.__buffer = None
2264 2263
2265 2264 elif technique == 'Meteors1':
2266 2265 dataOut.flagNoData = True
2267 2266 self.__dataReady = False
2268 2267
2269 2268 if 'nMins' in kwargs:
2270 2269 nMins = kwargs['nMins']
2271 2270 else: nMins = 20
2272 2271 if 'rx_location' in kwargs:
2273 2272 rx_location = kwargs['rx_location']
2274 2273 else: rx_location = [(0,1),(1,1),(1,0)]
2275 2274 if 'azimuth' in kwargs:
2276 2275 azimuth = kwargs['azimuth']
2277 2276 else: azimuth = 51.06
2278 2277 if 'dfactor' in kwargs:
2279 2278 dfactor = kwargs['dfactor']
2280 2279 if 'mode' in kwargs:
2281 2280 mode = kwargs['mode']
2282 2281 if 'theta_x' in kwargs:
2283 2282 theta_x = kwargs['theta_x']
2284 2283 if 'theta_y' in kwargs:
2285 2284 theta_y = kwargs['theta_y']
2286 2285 else: mode = 'SA'
2287 2286
2288 2287 #Borrar luego esto
2289 2288 if dataOut.groupList is None:
2290 2289 dataOut.groupList = [(0,1),(0,2),(1,2)]
2291 2290 groupList = dataOut.groupList
2292 2291 C = 3e8
2293 2292 freq = 50e6
2294 2293 lamb = C/freq
2295 2294 k = 2*numpy.pi/lamb
2296 2295
2297 2296 timeList = dataOut.abscissaList
2298 2297 heightList = dataOut.heightList
2299 2298
2300 2299 if self.__isConfig == False:
2301 2300 dataOut.outputInterval = nMins*60
2302 2301 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
2303 2302 #Get Initial LTC time
2304 2303 initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
2305 2304 minuteAux = initime.minute
2306 2305 minuteNew = int(numpy.floor(minuteAux/nMins)*nMins)
2307 2306 self.__initime = (initime.replace(minute = minuteNew, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
2308 2307
2309 2308 self.__isConfig = True
2310 2309
2311 2310 if self.__buffer is None:
2312 2311 self.__buffer = dataOut.data_param
2313 2312 self.__firstdata = copy.copy(dataOut)
2314 2313
2315 2314 else:
2316 2315 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
2317 2316
2318 2317 self.__checkTime(dataOut.utctime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
2319 2318
2320 2319 if self.__dataReady:
2321 2320 dataOut.utctimeInit = self.__initime
2322 2321 self.__initime += dataOut.outputInterval #to erase time offset
2323 2322
2324 2323 metArray = self.__buffer
2325 2324 if mode == 'SA':
2326 2325 dataOut.data_output = self.techniqueNSM_SA(rx_location=rx_location, groupList=groupList, azimuth=azimuth, dfactor=dfactor, k=k,metArray=metArray, heightList=heightList,timeList=timeList)
2327 2326 elif mode == 'DBS':
2328 2327 dataOut.data_output = self.techniqueNSM_DBS(metArray=metArray,heightList=heightList,timeList=timeList, azimuth=azimuth, theta_x=theta_x, theta_y=theta_y)
2329 2328 dataOut.data_output = dataOut.data_output.T
2330 2329 dataOut.flagNoData = False
2331 2330 self.__buffer = None
2332 2331
2333 2332 return
2334 2333
2335 2334 class EWDriftsEstimation(Operation):
2336 2335
2337 2336 def __init__(self):
2338 2337 Operation.__init__(self)
2339 2338
2340 2339 def __correctValues(self, heiRang, phi, velRadial, SNR):
2341 2340 listPhi = phi.tolist()
2342 2341 maxid = listPhi.index(max(listPhi))
2343 2342 minid = listPhi.index(min(listPhi))
2344 2343
2345 2344 rango = list(range(len(phi)))
2346 2345 # rango = numpy.delete(rango,maxid)
2347 2346
2348 2347 heiRang1 = heiRang*math.cos(phi[maxid])
2349 2348 heiRangAux = heiRang*math.cos(phi[minid])
2350 2349 indOut = (heiRang1 < heiRangAux[0]).nonzero()
2351 2350 heiRang1 = numpy.delete(heiRang1,indOut)
2352 2351
2353 2352 velRadial1 = numpy.zeros([len(phi),len(heiRang1)])
2354 2353 SNR1 = numpy.zeros([len(phi),len(heiRang1)])
2355 2354
2356 2355 for i in rango:
2357 2356 x = heiRang*math.cos(phi[i])
2358 2357 y1 = velRadial[i,:]
2359 2358 f1 = interpolate.interp1d(x,y1,kind = 'cubic')
2360 2359
2361 2360 x1 = heiRang1
2362 2361 y11 = f1(x1)
2363 2362
2364 2363 y2 = SNR[i,:]
2365 2364 f2 = interpolate.interp1d(x,y2,kind = 'cubic')
2366 2365 y21 = f2(x1)
2367 2366
2368 2367 velRadial1[i,:] = y11
2369 2368 SNR1[i,:] = y21
2370 2369
2371 2370 return heiRang1, velRadial1, SNR1
2372 2371
2373 2372 def run(self, dataOut, zenith, zenithCorrection):
2374 2373 heiRang = dataOut.heightList
2375 2374 velRadial = dataOut.data_param[:,3,:]
2376 2375 SNR = dataOut.data_snr
2377 2376
2378 2377 zenith = numpy.array(zenith)
2379 2378 zenith -= zenithCorrection
2380 2379 zenith *= numpy.pi/180
2381 2380
2382 2381 heiRang1, velRadial1, SNR1 = self.__correctValues(heiRang, numpy.abs(zenith), velRadial, SNR)
2383 2382
2384 2383 alp = zenith[0]
2385 2384 bet = zenith[1]
2386 2385
2387 2386 w_w = velRadial1[0,:]
2388 2387 w_e = velRadial1[1,:]
2389 2388
2390 2389 w = (w_w*numpy.sin(bet) - w_e*numpy.sin(alp))/(numpy.cos(alp)*numpy.sin(bet) - numpy.cos(bet)*numpy.sin(alp))
2391 2390 u = (w_w*numpy.cos(bet) - w_e*numpy.cos(alp))/(numpy.sin(alp)*numpy.cos(bet) - numpy.sin(bet)*numpy.cos(alp))
2392 2391
2393 2392 winds = numpy.vstack((u,w))
2394 2393
2395 2394 dataOut.heightList = heiRang1
2396 2395 dataOut.data_output = winds
2397 2396 dataOut.data_snr = SNR1
2398 2397
2399 2398 dataOut.utctimeInit = dataOut.utctime
2400 2399 dataOut.outputInterval = dataOut.timeInterval
2401 2400 return
2402 2401
2403 2402 #--------------- Non Specular Meteor ----------------
2404 2403
2405 2404 class NonSpecularMeteorDetection(Operation):
2406 2405
2407 2406 def run(self, dataOut, mode, SNRthresh=8, phaseDerThresh=0.5, cohThresh=0.8, allData = False):
2408 2407 data_acf = dataOut.data_pre[0]
2409 2408 data_ccf = dataOut.data_pre[1]
2410 2409 pairsList = dataOut.groupList[1]
2411 2410
2412 2411 lamb = dataOut.C/dataOut.frequency
2413 2412 tSamp = dataOut.ippSeconds*dataOut.nCohInt
2414 2413 paramInterval = dataOut.paramInterval
2415 2414
2416 2415 nChannels = data_acf.shape[0]
2417 2416 nLags = data_acf.shape[1]
2418 2417 nProfiles = data_acf.shape[2]
2419 2418 nHeights = dataOut.nHeights
2420 2419 nCohInt = dataOut.nCohInt
2421 2420 sec = numpy.round(nProfiles/dataOut.paramInterval)
2422 2421 heightList = dataOut.heightList
2423 2422 ippSeconds = dataOut.ippSeconds*dataOut.nCohInt*dataOut.nAvg
2424 2423 utctime = dataOut.utctime
2425 2424
2426 2425 dataOut.abscissaList = numpy.arange(0,paramInterval+ippSeconds,ippSeconds)
2427 2426
2428 2427 #------------------------ SNR --------------------------------------
2429 2428 power = data_acf[:,0,:,:].real
2430 2429 noise = numpy.zeros(nChannels)
2431 2430 SNR = numpy.zeros(power.shape)
2432 2431 for i in range(nChannels):
2433 2432 noise[i] = hildebrand_sekhon(power[i,:], nCohInt)
2434 2433 SNR[i] = (power[i]-noise[i])/noise[i]
2435 2434 SNRm = numpy.nanmean(SNR, axis = 0)
2436 2435 SNRdB = 10*numpy.log10(SNR)
2437 2436
2438 2437 if mode == 'SA':
2439 2438 dataOut.groupList = dataOut.groupList[1]
2440 2439 nPairs = data_ccf.shape[0]
2441 2440 #---------------------- Coherence and Phase --------------------------
2442 2441 phase = numpy.zeros(data_ccf[:,0,:,:].shape)
2443 2442 # phase1 = numpy.copy(phase)
2444 2443 coh1 = numpy.zeros(data_ccf[:,0,:,:].shape)
2445 2444
2446 2445 for p in range(nPairs):
2447 2446 ch0 = pairsList[p][0]
2448 2447 ch1 = pairsList[p][1]
2449 2448 ccf = data_ccf[p,0,:,:]/numpy.sqrt(data_acf[ch0,0,:,:]*data_acf[ch1,0,:,:])
2450 2449 phase[p,:,:] = ndimage.median_filter(numpy.angle(ccf), size = (5,1)) #median filter
2451 2450 # phase1[p,:,:] = numpy.angle(ccf) #median filter
2452 2451 coh1[p,:,:] = ndimage.median_filter(numpy.abs(ccf), 5) #median filter
2453 2452 # coh1[p,:,:] = numpy.abs(ccf) #median filter
2454 2453 coh = numpy.nanmax(coh1, axis = 0)
2455 2454 # struc = numpy.ones((5,1))
2456 2455 # coh = ndimage.morphology.grey_dilation(coh, size=(10,1))
2457 2456 #---------------------- Radial Velocity ----------------------------
2458 2457 phaseAux = numpy.mean(numpy.angle(data_acf[:,1,:,:]), axis = 0)
2459 2458 velRad = phaseAux*lamb/(4*numpy.pi*tSamp)
2460 2459
2461 2460 if allData:
2462 2461 boolMetFin = ~numpy.isnan(SNRm)
2463 2462 # coh[:-1,:] = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2464 2463 else:
2465 2464 #------------------------ Meteor mask ---------------------------------
2466 2465 # #SNR mask
2467 2466 # boolMet = (SNRdB>SNRthresh)#|(~numpy.isnan(SNRdB))
2468 2467 #
2469 2468 # #Erase small objects
2470 2469 # boolMet1 = self.__erase_small(boolMet, 2*sec, 5)
2471 2470 #
2472 2471 # auxEEJ = numpy.sum(boolMet1,axis=0)
2473 2472 # indOver = auxEEJ>nProfiles*0.8 #Use this later
2474 2473 # indEEJ = numpy.where(indOver)[0]
2475 2474 # indNEEJ = numpy.where(~indOver)[0]
2476 2475 #
2477 2476 # boolMetFin = boolMet1
2478 2477 #
2479 2478 # if indEEJ.size > 0:
2480 2479 # boolMet1[:,indEEJ] = False #Erase heights with EEJ
2481 2480 #
2482 2481 # boolMet2 = coh > cohThresh
2483 2482 # boolMet2 = self.__erase_small(boolMet2, 2*sec,5)
2484 2483 #
2485 2484 # #Final Meteor mask
2486 2485 # boolMetFin = boolMet1|boolMet2
2487 2486
2488 2487 #Coherence mask
2489 2488 boolMet1 = coh > 0.75
2490 2489 struc = numpy.ones((30,1))
2491 2490 boolMet1 = ndimage.morphology.binary_dilation(boolMet1, structure=struc)
2492 2491
2493 2492 #Derivative mask
2494 2493 derPhase = numpy.nanmean(numpy.abs(phase[:,1:,:] - phase[:,:-1,:]),axis=0)
2495 2494 boolMet2 = derPhase < 0.2
2496 2495 # boolMet2 = ndimage.morphology.binary_opening(boolMet2)
2497 2496 # boolMet2 = ndimage.morphology.binary_closing(boolMet2, structure = numpy.ones((10,1)))
2498 2497 boolMet2 = ndimage.median_filter(boolMet2,size=5)
2499 2498 boolMet2 = numpy.vstack((boolMet2,numpy.full((1,nHeights), True, dtype=bool)))
2500 2499 # #Final mask
2501 2500 # boolMetFin = boolMet2
2502 2501 boolMetFin = boolMet1&boolMet2
2503 2502 # boolMetFin = ndimage.morphology.binary_dilation(boolMetFin)
2504 2503 #Creating data_param
2505 2504 coordMet = numpy.where(boolMetFin)
2506 2505
2507 2506 tmet = coordMet[0]
2508 2507 hmet = coordMet[1]
2509 2508
2510 2509 data_param = numpy.zeros((tmet.size, 6 + nPairs))
2511 2510 data_param[:,0] = utctime
2512 2511 data_param[:,1] = tmet
2513 2512 data_param[:,2] = hmet
2514 2513 data_param[:,3] = SNRm[tmet,hmet]
2515 2514 data_param[:,4] = velRad[tmet,hmet]
2516 2515 data_param[:,5] = coh[tmet,hmet]
2517 2516 data_param[:,6:] = phase[:,tmet,hmet].T
2518 2517
2519 2518 elif mode == 'DBS':
2520 2519 dataOut.groupList = numpy.arange(nChannels)
2521 2520
2522 2521 #Radial Velocities
2523 2522 phase = numpy.angle(data_acf[:,1,:,:])
2524 2523 # phase = ndimage.median_filter(numpy.angle(data_acf[:,1,:,:]), size = (1,5,1))
2525 2524 velRad = phase*lamb/(4*numpy.pi*tSamp)
2526 2525
2527 2526 #Spectral width
2528 2527 # acf1 = ndimage.median_filter(numpy.abs(data_acf[:,1,:,:]), size = (1,5,1))
2529 2528 # acf2 = ndimage.median_filter(numpy.abs(data_acf[:,2,:,:]), size = (1,5,1))
2530 2529 acf1 = data_acf[:,1,:,:]
2531 2530 acf2 = data_acf[:,2,:,:]
2532 2531
2533 2532 spcWidth = (lamb/(2*numpy.sqrt(6)*numpy.pi*tSamp))*numpy.sqrt(numpy.log(acf1/acf2))
2534 2533 # velRad = ndimage.median_filter(velRad, size = (1,5,1))
2535 2534 if allData:
2536 2535 boolMetFin = ~numpy.isnan(SNRdB)
2537 2536 else:
2538 2537 #SNR
2539 2538 boolMet1 = (SNRdB>SNRthresh) #SNR mask
2540 2539 boolMet1 = ndimage.median_filter(boolMet1, size=(1,5,5))
2541 2540
2542 2541 #Radial velocity
2543 2542 boolMet2 = numpy.abs(velRad) < 20
2544 2543 boolMet2 = ndimage.median_filter(boolMet2, (1,5,5))
2545 2544
2546 2545 #Spectral Width
2547 2546 boolMet3 = spcWidth < 30
2548 2547 boolMet3 = ndimage.median_filter(boolMet3, (1,5,5))
2549 2548 # boolMetFin = self.__erase_small(boolMet1, 10,5)
2550 2549 boolMetFin = boolMet1&boolMet2&boolMet3
2551 2550
2552 2551 #Creating data_param
2553 2552 coordMet = numpy.where(boolMetFin)
2554 2553
2555 2554 cmet = coordMet[0]
2556 2555 tmet = coordMet[1]
2557 2556 hmet = coordMet[2]
2558 2557
2559 2558 data_param = numpy.zeros((tmet.size, 7))
2560 2559 data_param[:,0] = utctime
2561 2560 data_param[:,1] = cmet
2562 2561 data_param[:,2] = tmet
2563 2562 data_param[:,3] = hmet
2564 2563 data_param[:,4] = SNR[cmet,tmet,hmet].T
2565 2564 data_param[:,5] = velRad[cmet,tmet,hmet].T
2566 2565 data_param[:,6] = spcWidth[cmet,tmet,hmet].T
2567 2566
2568 2567 # self.dataOut.data_param = data_int
2569 2568 if len(data_param) == 0:
2570 2569 dataOut.flagNoData = True
2571 2570 else:
2572 2571 dataOut.data_param = data_param
2573 2572
2574 2573 def __erase_small(self, binArray, threshX, threshY):
2575 2574 labarray, numfeat = ndimage.measurements.label(binArray)
2576 2575 binArray1 = numpy.copy(binArray)
2577 2576
2578 2577 for i in range(1,numfeat + 1):
2579 2578 auxBin = (labarray==i)
2580 2579 auxSize = auxBin.sum()
2581 2580
2582 2581 x,y = numpy.where(auxBin)
2583 2582 widthX = x.max() - x.min()
2584 2583 widthY = y.max() - y.min()
2585 2584
2586 2585 #width X: 3 seg -> 12.5*3
2587 2586 #width Y:
2588 2587
2589 2588 if (auxSize < 50) or (widthX < threshX) or (widthY < threshY):
2590 2589 binArray1[auxBin] = False
2591 2590
2592 2591 return binArray1
2593 2592
2594 2593 #--------------- Specular Meteor ----------------
2595 2594
2596 2595 class SMDetection(Operation):
2597 2596 '''
2598 2597 Function DetectMeteors()
2599 2598 Project developed with paper:
2600 2599 HOLDSWORTH ET AL. 2004
2601 2600
2602 2601 Input:
2603 2602 self.dataOut.data_pre
2604 2603
2605 2604 centerReceiverIndex: From the channels, which is the center receiver
2606 2605
2607 2606 hei_ref: Height reference for the Beacon signal extraction
2608 2607 tauindex:
2609 2608 predefinedPhaseShifts: Predefined phase offset for the voltge signals
2610 2609
2611 2610 cohDetection: Whether to user Coherent detection or not
2612 2611 cohDet_timeStep: Coherent Detection calculation time step
2613 2612 cohDet_thresh: Coherent Detection phase threshold to correct phases
2614 2613
2615 2614 noise_timeStep: Noise calculation time step
2616 2615 noise_multiple: Noise multiple to define signal threshold
2617 2616
2618 2617 multDet_timeLimit: Multiple Detection Removal time limit in seconds
2619 2618 multDet_rangeLimit: Multiple Detection Removal range limit in km
2620 2619
2621 2620 phaseThresh: Maximum phase difference between receiver to be consider a meteor
2622 2621 SNRThresh: Minimum SNR threshold of the meteor signal to be consider a meteor
2623 2622
2624 2623 hmin: Minimum Height of the meteor to use it in the further wind estimations
2625 2624 hmax: Maximum Height of the meteor to use it in the further wind estimations
2626 2625 azimuth: Azimuth angle correction
2627 2626
2628 2627 Affected:
2629 2628 self.dataOut.data_param
2630 2629
2631 2630 Rejection Criteria (Errors):
2632 2631 0: No error; analysis OK
2633 2632 1: SNR < SNR threshold
2634 2633 2: angle of arrival (AOA) ambiguously determined
2635 2634 3: AOA estimate not feasible
2636 2635 4: Large difference in AOAs obtained from different antenna baselines
2637 2636 5: echo at start or end of time series
2638 2637 6: echo less than 5 examples long; too short for analysis
2639 2638 7: echo rise exceeds 0.3s
2640 2639 8: echo decay time less than twice rise time
2641 2640 9: large power level before echo
2642 2641 10: large power level after echo
2643 2642 11: poor fit to amplitude for estimation of decay time
2644 2643 12: poor fit to CCF phase variation for estimation of radial drift velocity
2645 2644 13: height unresolvable echo: not valid height within 70 to 110 km
2646 2645 14: height ambiguous echo: more then one possible height within 70 to 110 km
2647 2646 15: radial drift velocity or projected horizontal velocity exceeds 200 m/s
2648 2647 16: oscilatory echo, indicating event most likely not an underdense echo
2649 2648
2650 2649 17: phase difference in meteor Reestimation
2651 2650
2652 2651 Data Storage:
2653 2652 Meteors for Wind Estimation (8):
2654 2653 Utc Time | Range Height
2655 2654 Azimuth Zenith errorCosDir
2656 2655 VelRad errorVelRad
2657 2656 Phase0 Phase1 Phase2 Phase3
2658 2657 TypeError
2659 2658
2660 2659 '''
2661 2660
2662 2661 def run(self, dataOut, hei_ref = None, tauindex = 0,
2663 2662 phaseOffsets = None,
2664 2663 cohDetection = False, cohDet_timeStep = 1, cohDet_thresh = 25,
2665 2664 noise_timeStep = 4, noise_multiple = 4,
2666 2665 multDet_timeLimit = 1, multDet_rangeLimit = 3,
2667 2666 phaseThresh = 20, SNRThresh = 5,
2668 2667 hmin = 50, hmax=150, azimuth = 0,
2669 2668 channelPositions = None) :
2670 2669
2671 2670
2672 2671 #Getting Pairslist
2673 2672 if channelPositions is None:
2674 2673 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
2675 2674 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
2676 2675 meteorOps = SMOperations()
2677 2676 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
2678 2677 heiRang = dataOut.heightList
2679 2678 #Get Beacon signal - No Beacon signal anymore
2680 2679 # newheis = numpy.where(self.dataOut.heightList>self.dataOut.radarControllerHeaderObj.Taus[tauindex])
2681 2680 #
2682 2681 # if hei_ref != None:
2683 2682 # newheis = numpy.where(self.dataOut.heightList>hei_ref)
2684 2683 #
2685 2684
2686 2685
2687 2686 #****************REMOVING HARDWARE PHASE DIFFERENCES***************
2688 2687 # see if the user put in pre defined phase shifts
2689 2688 voltsPShift = dataOut.data_pre.copy()
2690 2689
2691 2690 # if predefinedPhaseShifts != None:
2692 2691 # hardwarePhaseShifts = numpy.array(predefinedPhaseShifts)*numpy.pi/180
2693 2692 #
2694 2693 # # elif beaconPhaseShifts:
2695 2694 # # #get hardware phase shifts using beacon signal
2696 2695 # # hardwarePhaseShifts = self.__getHardwarePhaseDiff(self.dataOut.data_pre, pairslist, newheis, 10)
2697 2696 # # hardwarePhaseShifts = numpy.insert(hardwarePhaseShifts,centerReceiverIndex,0)
2698 2697 #
2699 2698 # else:
2700 2699 # hardwarePhaseShifts = numpy.zeros(5)
2701 2700 #
2702 2701 # voltsPShift = numpy.zeros((self.dataOut.data_pre.shape[0],self.dataOut.data_pre.shape[1],self.dataOut.data_pre.shape[2]), dtype = 'complex')
2703 2702 # for i in range(self.dataOut.data_pre.shape[0]):
2704 2703 # voltsPShift[i,:,:] = self.__shiftPhase(self.dataOut.data_pre[i,:,:], hardwarePhaseShifts[i])
2705 2704
2706 2705 #******************END OF REMOVING HARDWARE PHASE DIFFERENCES*********
2707 2706
2708 2707 #Remove DC
2709 2708 voltsDC = numpy.mean(voltsPShift,1)
2710 2709 voltsDC = numpy.mean(voltsDC,1)
2711 2710 for i in range(voltsDC.shape[0]):
2712 2711 voltsPShift[i] = voltsPShift[i] - voltsDC[i]
2713 2712
2714 2713 #Don't considerate last heights, theyre used to calculate Hardware Phase Shift
2715 2714 # voltsPShift = voltsPShift[:,:,:newheis[0][0]]
2716 2715
2717 2716 #************ FIND POWER OF DATA W/COH OR NON COH DETECTION (3.4) **********
2718 2717 #Coherent Detection
2719 2718 if cohDetection:
2720 2719 #use coherent detection to get the net power
2721 2720 cohDet_thresh = cohDet_thresh*numpy.pi/180
2722 2721 voltsPShift = self.__coherentDetection(voltsPShift, cohDet_timeStep, dataOut.timeInterval, pairslist0, cohDet_thresh)
2723 2722
2724 2723 #Non-coherent detection!
2725 2724 powerNet = numpy.nansum(numpy.abs(voltsPShift[:,:,:])**2,0)
2726 2725 #********** END OF COH/NON-COH POWER CALCULATION**********************
2727 2726
2728 2727 #********** FIND THE NOISE LEVEL AND POSSIBLE METEORS ****************
2729 2728 #Get noise
2730 2729 noise, noise1 = self.__getNoise(powerNet, noise_timeStep, dataOut.timeInterval)
2731 2730 # noise = self.getNoise1(powerNet, noise_timeStep, self.dataOut.timeInterval)
2732 2731 #Get signal threshold
2733 2732 signalThresh = noise_multiple*noise
2734 2733 #Meteor echoes detection
2735 2734 listMeteors = self.__findMeteors(powerNet, signalThresh)
2736 2735 #******* END OF NOISE LEVEL AND POSSIBLE METEORS CACULATION **********
2737 2736
2738 2737 #************** REMOVE MULTIPLE DETECTIONS (3.5) ***************************
2739 2738 #Parameters
2740 2739 heiRange = dataOut.heightList
2741 2740 rangeInterval = heiRange[1] - heiRange[0]
2742 2741 rangeLimit = multDet_rangeLimit/rangeInterval
2743 2742 timeLimit = multDet_timeLimit/dataOut.timeInterval
2744 2743 #Multiple detection removals
2745 2744 listMeteors1 = self.__removeMultipleDetections(listMeteors, rangeLimit, timeLimit)
2746 2745 #************ END OF REMOVE MULTIPLE DETECTIONS **********************
2747 2746
2748 2747 #********************* METEOR REESTIMATION (3.7, 3.8, 3.9, 3.10) ********************
2749 2748 #Parameters
2750 2749 phaseThresh = phaseThresh*numpy.pi/180
2751 2750 thresh = [phaseThresh, noise_multiple, SNRThresh]
2752 2751 #Meteor reestimation (Errors N 1, 6, 12, 17)
2753 2752 listMeteors2, listMeteorsPower, listMeteorsVolts = self.__meteorReestimation(listMeteors1, voltsPShift, pairslist0, thresh, noise, dataOut.timeInterval, dataOut.frequency)
2754 2753 # listMeteors2, listMeteorsPower, listMeteorsVolts = self.meteorReestimation3(listMeteors2, listMeteorsPower, listMeteorsVolts, voltsPShift, pairslist, thresh, noise)
2755 2754 #Estimation of decay times (Errors N 7, 8, 11)
2756 2755 listMeteors3 = self.__estimateDecayTime(listMeteors2, listMeteorsPower, dataOut.timeInterval, dataOut.frequency)
2757 2756 #******************* END OF METEOR REESTIMATION *******************
2758 2757
2759 2758 #********************* METEOR PARAMETERS CALCULATION (3.11, 3.12, 3.13) **************************
2760 2759 #Calculating Radial Velocity (Error N 15)
2761 2760 radialStdThresh = 10
2762 2761 listMeteors4 = self.__getRadialVelocity(listMeteors3, listMeteorsVolts, radialStdThresh, pairslist0, dataOut.timeInterval)
2763 2762
2764 2763 if len(listMeteors4) > 0:
2765 2764 #Setting New Array
2766 2765 date = dataOut.utctime
2767 2766 arrayParameters = self.__setNewArrays(listMeteors4, date, heiRang)
2768 2767
2769 2768 #Correcting phase offset
2770 2769 if phaseOffsets != None:
2771 2770 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
2772 2771 arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
2773 2772
2774 2773 #Second Pairslist
2775 2774 pairsList = []
2776 2775 pairx = (0,1)
2777 2776 pairy = (2,3)
2778 2777 pairsList.append(pairx)
2779 2778 pairsList.append(pairy)
2780 2779
2781 2780 jph = numpy.array([0,0,0,0])
2782 2781 h = (hmin,hmax)
2783 2782 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
2784 2783
2785 2784 # #Calculate AOA (Error N 3, 4)
2786 2785 # #JONES ET AL. 1998
2787 2786 # error = arrayParameters[:,-1]
2788 2787 # AOAthresh = numpy.pi/8
2789 2788 # phases = -arrayParameters[:,9:13]
2790 2789 # arrayParameters[:,4:7], arrayParameters[:,-1] = meteorOps.getAOA(phases, pairsList, error, AOAthresh, azimuth)
2791 2790 #
2792 2791 # #Calculate Heights (Error N 13 and 14)
2793 2792 # error = arrayParameters[:,-1]
2794 2793 # Ranges = arrayParameters[:,2]
2795 2794 # zenith = arrayParameters[:,5]
2796 2795 # arrayParameters[:,3], arrayParameters[:,-1] = meteorOps.getHeights(Ranges, zenith, error, hmin, hmax)
2797 2796 # error = arrayParameters[:,-1]
2798 2797 #********************* END OF PARAMETERS CALCULATION **************************
2799 2798
2800 2799 #***************************+ PASS DATA TO NEXT STEP **********************
2801 2800 # arrayFinal = arrayParameters.reshape((1,arrayParameters.shape[0],arrayParameters.shape[1]))
2802 2801 dataOut.data_param = arrayParameters
2803 2802
2804 2803 if arrayParameters is None:
2805 2804 dataOut.flagNoData = True
2806 2805 else:
2807 2806 dataOut.flagNoData = True
2808 2807
2809 2808 return
2810 2809
2811 2810 def __getHardwarePhaseDiff(self, voltage0, pairslist, newheis, n):
2812 2811
2813 2812 minIndex = min(newheis[0])
2814 2813 maxIndex = max(newheis[0])
2815 2814
2816 2815 voltage = voltage0[:,:,minIndex:maxIndex+1]
2817 2816 nLength = voltage.shape[1]/n
2818 2817 nMin = 0
2819 2818 nMax = 0
2820 2819 phaseOffset = numpy.zeros((len(pairslist),n))
2821 2820
2822 2821 for i in range(n):
2823 2822 nMax += nLength
2824 2823 phaseCCF = -numpy.angle(self.__calculateCCF(voltage[:,nMin:nMax,:], pairslist, [0]))
2825 2824 phaseCCF = numpy.mean(phaseCCF, axis = 2)
2826 2825 phaseOffset[:,i] = phaseCCF.transpose()
2827 2826 nMin = nMax
2828 2827 # phaseDiff, phaseArrival = self.estimatePhaseDifference(voltage, pairslist)
2829 2828
2830 2829 #Remove Outliers
2831 2830 factor = 2
2832 2831 wt = phaseOffset - signal.medfilt(phaseOffset,(1,5))
2833 2832 dw = numpy.std(wt,axis = 1)
2834 2833 dw = dw.reshape((dw.size,1))
2835 2834 ind = numpy.where(numpy.logical_or(wt>dw*factor,wt<-dw*factor))
2836 2835 phaseOffset[ind] = numpy.nan
2837 2836 phaseOffset = stats.nanmean(phaseOffset, axis=1)
2838 2837
2839 2838 return phaseOffset
2840 2839
2841 2840 def __shiftPhase(self, data, phaseShift):
2842 2841 #this will shift the phase of a complex number
2843 2842 dataShifted = numpy.abs(data) * numpy.exp((numpy.angle(data)+phaseShift)*1j)
2844 2843 return dataShifted
2845 2844
2846 2845 def __estimatePhaseDifference(self, array, pairslist):
2847 2846 nChannel = array.shape[0]
2848 2847 nHeights = array.shape[2]
2849 2848 numPairs = len(pairslist)
2850 2849 # phaseCCF = numpy.zeros((nChannel, 5, nHeights))
2851 2850 phaseCCF = numpy.angle(self.__calculateCCF(array, pairslist, [-2,-1,0,1,2]))
2852 2851
2853 2852 #Correct phases
2854 2853 derPhaseCCF = phaseCCF[:,1:,:] - phaseCCF[:,0:-1,:]
2855 2854 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
2856 2855
2857 2856 if indDer[0].shape[0] > 0:
2858 2857 for i in range(indDer[0].shape[0]):
2859 2858 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i],indDer[2][i]])
2860 2859 phaseCCF[indDer[0][i],indDer[1][i]+1:,:] += signo*2*numpy.pi
2861 2860
2862 2861 # for j in range(numSides):
2863 2862 # phaseCCFAux = self.calculateCCF(arrayCenter, arraySides[j,:,:], [-2,1,0,1,2])
2864 2863 # phaseCCF[j,:,:] = numpy.angle(phaseCCFAux)
2865 2864 #
2866 2865 #Linear
2867 2866 phaseInt = numpy.zeros((numPairs,1))
2868 2867 angAllCCF = phaseCCF[:,[0,1,3,4],0]
2869 2868 for j in range(numPairs):
2870 2869 fit = stats.linregress([-2,-1,1,2],angAllCCF[j,:])
2871 2870 phaseInt[j] = fit[1]
2872 2871 #Phase Differences
2873 2872 phaseDiff = phaseInt - phaseCCF[:,2,:]
2874 2873 phaseArrival = phaseInt.reshape(phaseInt.size)
2875 2874
2876 2875 #Dealias
2877 2876 phaseArrival = numpy.angle(numpy.exp(1j*phaseArrival))
2878 2877 # indAlias = numpy.where(phaseArrival > numpy.pi)
2879 2878 # phaseArrival[indAlias] -= 2*numpy.pi
2880 2879 # indAlias = numpy.where(phaseArrival < -numpy.pi)
2881 2880 # phaseArrival[indAlias] += 2*numpy.pi
2882 2881
2883 2882 return phaseDiff, phaseArrival
2884 2883
2885 2884 def __coherentDetection(self, volts, timeSegment, timeInterval, pairslist, thresh):
2886 2885 #this function will run the coherent detection used in Holdworth et al. 2004 and return the net power
2887 2886 #find the phase shifts of each channel over 1 second intervals
2888 2887 #only look at ranges below the beacon signal
2889 2888 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
2890 2889 numBlocks = int(volts.shape[1]/numProfPerBlock)
2891 2890 numHeights = volts.shape[2]
2892 2891 nChannel = volts.shape[0]
2893 2892 voltsCohDet = volts.copy()
2894 2893
2895 2894 pairsarray = numpy.array(pairslist)
2896 2895 indSides = pairsarray[:,1]
2897 2896 # indSides = numpy.array(range(nChannel))
2898 2897 # indSides = numpy.delete(indSides, indCenter)
2899 2898 #
2900 2899 # listCenter = numpy.array_split(volts[indCenter,:,:], numBlocks, 0)
2901 2900 listBlocks = numpy.array_split(volts, numBlocks, 1)
2902 2901
2903 2902 startInd = 0
2904 2903 endInd = 0
2905 2904
2906 2905 for i in range(numBlocks):
2907 2906 startInd = endInd
2908 2907 endInd = endInd + listBlocks[i].shape[1]
2909 2908
2910 2909 arrayBlock = listBlocks[i]
2911 2910 # arrayBlockCenter = listCenter[i]
2912 2911
2913 2912 #Estimate the Phase Difference
2914 2913 phaseDiff, aux = self.__estimatePhaseDifference(arrayBlock, pairslist)
2915 2914 #Phase Difference RMS
2916 2915 arrayPhaseRMS = numpy.abs(phaseDiff)
2917 2916 phaseRMSaux = numpy.sum(arrayPhaseRMS < thresh,0)
2918 2917 indPhase = numpy.where(phaseRMSaux==4)
2919 2918 #Shifting
2920 2919 if indPhase[0].shape[0] > 0:
2921 2920 for j in range(indSides.size):
2922 2921 arrayBlock[indSides[j],:,indPhase] = self.__shiftPhase(arrayBlock[indSides[j],:,indPhase], phaseDiff[j,indPhase].transpose())
2923 2922 voltsCohDet[:,startInd:endInd,:] = arrayBlock
2924 2923
2925 2924 return voltsCohDet
2926 2925
2927 2926 def __calculateCCF(self, volts, pairslist ,laglist):
2928 2927
2929 2928 nHeights = volts.shape[2]
2930 2929 nPoints = volts.shape[1]
2931 2930 voltsCCF = numpy.zeros((len(pairslist), len(laglist), nHeights),dtype = 'complex')
2932 2931
2933 2932 for i in range(len(pairslist)):
2934 2933 volts1 = volts[pairslist[i][0]]
2935 2934 volts2 = volts[pairslist[i][1]]
2936 2935
2937 2936 for t in range(len(laglist)):
2938 2937 idxT = laglist[t]
2939 2938 if idxT >= 0:
2940 2939 vStacked = numpy.vstack((volts2[idxT:,:],
2941 2940 numpy.zeros((idxT, nHeights),dtype='complex')))
2942 2941 else:
2943 2942 vStacked = numpy.vstack((numpy.zeros((-idxT, nHeights),dtype='complex'),
2944 2943 volts2[:(nPoints + idxT),:]))
2945 2944 voltsCCF[i,t,:] = numpy.sum((numpy.conjugate(volts1)*vStacked),axis=0)
2946 2945
2947 2946 vStacked = None
2948 2947 return voltsCCF
2949 2948
2950 2949 def __getNoise(self, power, timeSegment, timeInterval):
2951 2950 numProfPerBlock = numpy.ceil(timeSegment/timeInterval)
2952 2951 numBlocks = int(power.shape[0]/numProfPerBlock)
2953 2952 numHeights = power.shape[1]
2954 2953
2955 2954 listPower = numpy.array_split(power, numBlocks, 0)
2956 2955 noise = numpy.zeros((power.shape[0], power.shape[1]))
2957 2956 noise1 = numpy.zeros((power.shape[0], power.shape[1]))
2958 2957
2959 2958 startInd = 0
2960 2959 endInd = 0
2961 2960
2962 2961 for i in range(numBlocks): #split por canal
2963 2962 startInd = endInd
2964 2963 endInd = endInd + listPower[i].shape[0]
2965 2964
2966 2965 arrayBlock = listPower[i]
2967 2966 noiseAux = numpy.mean(arrayBlock, 0)
2968 2967 # noiseAux = numpy.median(noiseAux)
2969 2968 # noiseAux = numpy.mean(arrayBlock)
2970 2969 noise[startInd:endInd,:] = noise[startInd:endInd,:] + noiseAux
2971 2970
2972 2971 noiseAux1 = numpy.mean(arrayBlock)
2973 2972 noise1[startInd:endInd,:] = noise1[startInd:endInd,:] + noiseAux1
2974 2973
2975 2974 return noise, noise1
2976 2975
2977 2976 def __findMeteors(self, power, thresh):
2978 2977 nProf = power.shape[0]
2979 2978 nHeights = power.shape[1]
2980 2979 listMeteors = []
2981 2980
2982 2981 for i in range(nHeights):
2983 2982 powerAux = power[:,i]
2984 2983 threshAux = thresh[:,i]
2985 2984
2986 2985 indUPthresh = numpy.where(powerAux > threshAux)[0]
2987 2986 indDNthresh = numpy.where(powerAux <= threshAux)[0]
2988 2987
2989 2988 j = 0
2990 2989
2991 2990 while (j < indUPthresh.size - 2):
2992 2991 if (indUPthresh[j + 2] == indUPthresh[j] + 2):
2993 2992 indDNAux = numpy.where(indDNthresh > indUPthresh[j])
2994 2993 indDNthresh = indDNthresh[indDNAux]
2995 2994
2996 2995 if (indDNthresh.size > 0):
2997 2996 indEnd = indDNthresh[0] - 1
2998 2997 indInit = indUPthresh[j]
2999 2998
3000 2999 meteor = powerAux[indInit:indEnd + 1]
3001 3000 indPeak = meteor.argmax() + indInit
3002 3001 FLA = sum(numpy.conj(meteor)*numpy.hstack((meteor[1:],0)))
3003 3002
3004 3003 listMeteors.append(numpy.array([i,indInit,indPeak,indEnd,FLA])) #CHEQUEAR!!!!!
3005 3004 j = numpy.where(indUPthresh == indEnd)[0] + 1
3006 3005 else: j+=1
3007 3006 else: j+=1
3008 3007
3009 3008 return listMeteors
3010 3009
3011 3010 def __removeMultipleDetections(self,listMeteors, rangeLimit, timeLimit):
3012 3011
3013 3012 arrayMeteors = numpy.asarray(listMeteors)
3014 3013 listMeteors1 = []
3015 3014
3016 3015 while arrayMeteors.shape[0] > 0:
3017 3016 FLAs = arrayMeteors[:,4]
3018 3017 maxFLA = FLAs.argmax()
3019 3018 listMeteors1.append(arrayMeteors[maxFLA,:])
3020 3019
3021 3020 MeteorInitTime = arrayMeteors[maxFLA,1]
3022 3021 MeteorEndTime = arrayMeteors[maxFLA,3]
3023 3022 MeteorHeight = arrayMeteors[maxFLA,0]
3024 3023
3025 3024 #Check neighborhood
3026 3025 maxHeightIndex = MeteorHeight + rangeLimit
3027 3026 minHeightIndex = MeteorHeight - rangeLimit
3028 3027 minTimeIndex = MeteorInitTime - timeLimit
3029 3028 maxTimeIndex = MeteorEndTime + timeLimit
3030 3029
3031 3030 #Check Heights
3032 3031 indHeight = numpy.logical_and(arrayMeteors[:,0] >= minHeightIndex, arrayMeteors[:,0] <= maxHeightIndex)
3033 3032 indTime = numpy.logical_and(arrayMeteors[:,3] >= minTimeIndex, arrayMeteors[:,1] <= maxTimeIndex)
3034 3033 indBoth = numpy.where(numpy.logical_and(indTime,indHeight))
3035 3034
3036 3035 arrayMeteors = numpy.delete(arrayMeteors, indBoth, axis = 0)
3037 3036
3038 3037 return listMeteors1
3039 3038
3040 3039 def __meteorReestimation(self, listMeteors, volts, pairslist, thresh, noise, timeInterval,frequency):
3041 3040 numHeights = volts.shape[2]
3042 3041 nChannel = volts.shape[0]
3043 3042
3044 3043 thresholdPhase = thresh[0]
3045 3044 thresholdNoise = thresh[1]
3046 3045 thresholdDB = float(thresh[2])
3047 3046
3048 3047 thresholdDB1 = 10**(thresholdDB/10)
3049 3048 pairsarray = numpy.array(pairslist)
3050 3049 indSides = pairsarray[:,1]
3051 3050
3052 3051 pairslist1 = list(pairslist)
3053 3052 pairslist1.append((0,1))
3054 3053 pairslist1.append((3,4))
3055 3054
3056 3055 listMeteors1 = []
3057 3056 listPowerSeries = []
3058 3057 listVoltageSeries = []
3059 3058 #volts has the war data
3060 3059
3061 3060 if frequency == 30e6:
3062 3061 timeLag = 45*10**-3
3063 3062 else:
3064 3063 timeLag = 15*10**-3
3065 3064 lag = numpy.ceil(timeLag/timeInterval)
3066 3065
3067 3066 for i in range(len(listMeteors)):
3068 3067
3069 3068 ###################### 3.6 - 3.7 PARAMETERS REESTIMATION #########################
3070 3069 meteorAux = numpy.zeros(16)
3071 3070
3072 3071 #Loading meteor Data (mHeight, mStart, mPeak, mEnd)
3073 3072 mHeight = listMeteors[i][0]
3074 3073 mStart = listMeteors[i][1]
3075 3074 mPeak = listMeteors[i][2]
3076 3075 mEnd = listMeteors[i][3]
3077 3076
3078 3077 #get the volt data between the start and end times of the meteor
3079 3078 meteorVolts = volts[:,mStart:mEnd+1,mHeight]
3080 3079 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3081 3080
3082 3081 #3.6. Phase Difference estimation
3083 3082 phaseDiff, aux = self.__estimatePhaseDifference(meteorVolts, pairslist)
3084 3083
3085 3084 #3.7. Phase difference removal & meteor start, peak and end times reestimated
3086 3085 #meteorVolts0.- all Channels, all Profiles
3087 3086 meteorVolts0 = volts[:,:,mHeight]
3088 3087 meteorThresh = noise[:,mHeight]*thresholdNoise
3089 3088 meteorNoise = noise[:,mHeight]
3090 3089 meteorVolts0[indSides,:] = self.__shiftPhase(meteorVolts0[indSides,:], phaseDiff) #Phase Shifting
3091 3090 powerNet0 = numpy.nansum(numpy.abs(meteorVolts0)**2, axis = 0) #Power
3092 3091
3093 3092 #Times reestimation
3094 3093 mStart1 = numpy.where(powerNet0[:mPeak] < meteorThresh[:mPeak])[0]
3095 3094 if mStart1.size > 0:
3096 3095 mStart1 = mStart1[-1] + 1
3097 3096
3098 3097 else:
3099 3098 mStart1 = mPeak
3100 3099
3101 3100 mEnd1 = numpy.where(powerNet0[mPeak:] < meteorThresh[mPeak:])[0][0] + mPeak - 1
3102 3101 mEndDecayTime1 = numpy.where(powerNet0[mPeak:] < meteorNoise[mPeak:])[0]
3103 3102 if mEndDecayTime1.size == 0:
3104 3103 mEndDecayTime1 = powerNet0.size
3105 3104 else:
3106 3105 mEndDecayTime1 = mEndDecayTime1[0] + mPeak - 1
3107 3106 # mPeak1 = meteorVolts0[mStart1:mEnd1 + 1].argmax()
3108 3107
3109 3108 #meteorVolts1.- all Channels, from start to end
3110 3109 meteorVolts1 = meteorVolts0[:,mStart1:mEnd1 + 1]
3111 3110 meteorVolts2 = meteorVolts0[:,mPeak + lag:mEnd1 + 1]
3112 3111 if meteorVolts2.shape[1] == 0:
3113 3112 meteorVolts2 = meteorVolts0[:,mPeak:mEnd1 + 1]
3114 3113 meteorVolts1 = meteorVolts1.reshape(meteorVolts1.shape[0], meteorVolts1.shape[1], 1)
3115 3114 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1], 1)
3116 3115 ##################### END PARAMETERS REESTIMATION #########################
3117 3116
3118 3117 ##################### 3.8 PHASE DIFFERENCE REESTIMATION ########################
3119 3118 # if mEnd1 - mStart1 > 4: #Error Number 6: echo less than 5 samples long; too short for analysis
3120 3119 if meteorVolts2.shape[1] > 0:
3121 3120 #Phase Difference re-estimation
3122 3121 phaseDiff1, phaseDiffint = self.__estimatePhaseDifference(meteorVolts2, pairslist1) #Phase Difference Estimation
3123 3122 # phaseDiff1, phaseDiffint = self.estimatePhaseDifference(meteorVolts2, pairslist)
3124 3123 meteorVolts2 = meteorVolts2.reshape(meteorVolts2.shape[0], meteorVolts2.shape[1])
3125 3124 phaseDiff11 = numpy.reshape(phaseDiff1, (phaseDiff1.shape[0],1))
3126 3125 meteorVolts2[indSides,:] = self.__shiftPhase(meteorVolts2[indSides,:], phaseDiff11[0:4]) #Phase Shifting
3127 3126
3128 3127 #Phase Difference RMS
3129 3128 phaseRMS1 = numpy.sqrt(numpy.mean(numpy.square(phaseDiff1)))
3130 3129 powerNet1 = numpy.nansum(numpy.abs(meteorVolts1[:,:])**2,0)
3131 3130 #Data from Meteor
3132 3131 mPeak1 = powerNet1.argmax() + mStart1
3133 3132 mPeakPower1 = powerNet1.max()
3134 3133 noiseAux = sum(noise[mStart1:mEnd1 + 1,mHeight])
3135 3134 mSNR1 = (sum(powerNet1)-noiseAux)/noiseAux
3136 3135 Meteor1 = numpy.array([mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1])
3137 3136 Meteor1 = numpy.hstack((Meteor1,phaseDiffint))
3138 3137 PowerSeries = powerNet0[mStart1:mEndDecayTime1 + 1]
3139 3138 #Vectorize
3140 3139 meteorAux[0:7] = [mHeight, mStart1, mPeak1, mEnd1, mPeakPower1, mSNR1, phaseRMS1]
3141 3140 meteorAux[7:11] = phaseDiffint[0:4]
3142 3141
3143 3142 #Rejection Criterions
3144 3143 if phaseRMS1 > thresholdPhase: #Error Number 17: Phase variation
3145 3144 meteorAux[-1] = 17
3146 3145 elif mSNR1 < thresholdDB1: #Error Number 1: SNR < threshold dB
3147 3146 meteorAux[-1] = 1
3148 3147
3149 3148
3150 3149 else:
3151 3150 meteorAux[0:4] = [mHeight, mStart, mPeak, mEnd]
3152 3151 meteorAux[-1] = 6 #Error Number 6: echo less than 5 samples long; too short for analysis
3153 3152 PowerSeries = 0
3154 3153
3155 3154 listMeteors1.append(meteorAux)
3156 3155 listPowerSeries.append(PowerSeries)
3157 3156 listVoltageSeries.append(meteorVolts1)
3158 3157
3159 3158 return listMeteors1, listPowerSeries, listVoltageSeries
3160 3159
3161 3160 def __estimateDecayTime(self, listMeteors, listPower, timeInterval, frequency):
3162 3161
3163 3162 threshError = 10
3164 3163 #Depending if it is 30 or 50 MHz
3165 3164 if frequency == 30e6:
3166 3165 timeLag = 45*10**-3
3167 3166 else:
3168 3167 timeLag = 15*10**-3
3169 3168 lag = numpy.ceil(timeLag/timeInterval)
3170 3169
3171 3170 listMeteors1 = []
3172 3171
3173 3172 for i in range(len(listMeteors)):
3174 3173 meteorPower = listPower[i]
3175 3174 meteorAux = listMeteors[i]
3176 3175
3177 3176 if meteorAux[-1] == 0:
3178 3177
3179 3178 try:
3180 3179 indmax = meteorPower.argmax()
3181 3180 indlag = indmax + lag
3182 3181
3183 3182 y = meteorPower[indlag:]
3184 3183 x = numpy.arange(0, y.size)*timeLag
3185 3184
3186 3185 #first guess
3187 3186 a = y[0]
3188 3187 tau = timeLag
3189 3188 #exponential fit
3190 3189 popt, pcov = optimize.curve_fit(self.__exponential_function, x, y, p0 = [a, tau])
3191 3190 y1 = self.__exponential_function(x, *popt)
3192 3191 #error estimation
3193 3192 error = sum((y - y1)**2)/(numpy.var(y)*(y.size - popt.size))
3194 3193
3195 3194 decayTime = popt[1]
3196 3195 riseTime = indmax*timeInterval
3197 3196 meteorAux[11:13] = [decayTime, error]
3198 3197
3199 3198 #Table items 7, 8 and 11
3200 3199 if (riseTime > 0.3): #Number 7: Echo rise exceeds 0.3s
3201 3200 meteorAux[-1] = 7
3202 3201 elif (decayTime < 2*riseTime) : #Number 8: Echo decay time less than than twice rise time
3203 3202 meteorAux[-1] = 8
3204 3203 if (error > threshError): #Number 11: Poor fit to amplitude for estimation of decay time
3205 3204 meteorAux[-1] = 11
3206 3205
3207 3206
3208 3207 except:
3209 3208 meteorAux[-1] = 11
3210 3209
3211 3210
3212 3211 listMeteors1.append(meteorAux)
3213 3212
3214 3213 return listMeteors1
3215 3214
3216 3215 #Exponential Function
3217 3216
3218 3217 def __exponential_function(self, x, a, tau):
3219 3218 y = a*numpy.exp(-x/tau)
3220 3219 return y
3221 3220
3222 3221 def __getRadialVelocity(self, listMeteors, listVolts, radialStdThresh, pairslist, timeInterval):
3223 3222
3224 3223 pairslist1 = list(pairslist)
3225 3224 pairslist1.append((0,1))
3226 3225 pairslist1.append((3,4))
3227 3226 numPairs = len(pairslist1)
3228 3227 #Time Lag
3229 3228 timeLag = 45*10**-3
3230 3229 c = 3e8
3231 3230 lag = numpy.ceil(timeLag/timeInterval)
3232 3231 freq = 30e6
3233 3232
3234 3233 listMeteors1 = []
3235 3234
3236 3235 for i in range(len(listMeteors)):
3237 3236 meteorAux = listMeteors[i]
3238 3237 if meteorAux[-1] == 0:
3239 3238 mStart = listMeteors[i][1]
3240 3239 mPeak = listMeteors[i][2]
3241 3240 mLag = mPeak - mStart + lag
3242 3241
3243 3242 #get the volt data between the start and end times of the meteor
3244 3243 meteorVolts = listVolts[i]
3245 3244 meteorVolts = meteorVolts.reshape(meteorVolts.shape[0], meteorVolts.shape[1], 1)
3246 3245
3247 3246 #Get CCF
3248 3247 allCCFs = self.__calculateCCF(meteorVolts, pairslist1, [-2,-1,0,1,2])
3249 3248
3250 3249 #Method 2
3251 3250 slopes = numpy.zeros(numPairs)
3252 3251 time = numpy.array([-2,-1,1,2])*timeInterval
3253 3252 angAllCCF = numpy.angle(allCCFs[:,[0,1,3,4],0])
3254 3253
3255 3254 #Correct phases
3256 3255 derPhaseCCF = angAllCCF[:,1:] - angAllCCF[:,0:-1]
3257 3256 indDer = numpy.where(numpy.abs(derPhaseCCF) > numpy.pi)
3258 3257
3259 3258 if indDer[0].shape[0] > 0:
3260 3259 for i in range(indDer[0].shape[0]):
3261 3260 signo = -numpy.sign(derPhaseCCF[indDer[0][i],indDer[1][i]])
3262 3261 angAllCCF[indDer[0][i],indDer[1][i]+1:] += signo*2*numpy.pi
3263 3262
3264 3263 # fit = scipy.stats.linregress(numpy.array([-2,-1,1,2])*timeInterval, numpy.array([phaseLagN2s[i],phaseLagN1s[i],phaseLag1s[i],phaseLag2s[i]]))
3265 3264 for j in range(numPairs):
3266 3265 fit = stats.linregress(time, angAllCCF[j,:])
3267 3266 slopes[j] = fit[0]
3268 3267
3269 3268 #Remove Outlier
3270 3269 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3271 3270 # slopes = numpy.delete(slopes,indOut)
3272 3271 # indOut = numpy.argmax(numpy.abs(slopes - numpy.mean(slopes)))
3273 3272 # slopes = numpy.delete(slopes,indOut)
3274 3273
3275 3274 radialVelocity = -numpy.mean(slopes)*(0.25/numpy.pi)*(c/freq)
3276 3275 radialError = numpy.std(slopes)*(0.25/numpy.pi)*(c/freq)
3277 3276 meteorAux[-2] = radialError
3278 3277 meteorAux[-3] = radialVelocity
3279 3278
3280 3279 #Setting Error
3281 3280 #Number 15: Radial Drift velocity or projected horizontal velocity exceeds 200 m/s
3282 3281 if numpy.abs(radialVelocity) > 200:
3283 3282 meteorAux[-1] = 15
3284 3283 #Number 12: Poor fit to CCF variation for estimation of radial drift velocity
3285 3284 elif radialError > radialStdThresh:
3286 3285 meteorAux[-1] = 12
3287 3286
3288 3287 listMeteors1.append(meteorAux)
3289 3288 return listMeteors1
3290 3289
3291 3290 def __setNewArrays(self, listMeteors, date, heiRang):
3292 3291
3293 3292 #New arrays
3294 3293 arrayMeteors = numpy.array(listMeteors)
3295 3294 arrayParameters = numpy.zeros((len(listMeteors), 13))
3296 3295
3297 3296 #Date inclusion
3298 3297 # date = re.findall(r'\((.*?)\)', date)
3299 3298 # date = date[0].split(',')
3300 3299 # date = map(int, date)
3301 3300 #
3302 3301 # if len(date)<6:
3303 3302 # date.append(0)
3304 3303 #
3305 3304 # date = [date[0]*10000 + date[1]*100 + date[2], date[3]*10000 + date[4]*100 + date[5]]
3306 3305 # arrayDate = numpy.tile(date, (len(listMeteors), 1))
3307 3306 arrayDate = numpy.tile(date, (len(listMeteors)))
3308 3307
3309 3308 #Meteor array
3310 3309 # arrayMeteors[:,0] = heiRang[arrayMeteors[:,0].astype(int)]
3311 3310 # arrayMeteors = numpy.hstack((arrayDate, arrayMeteors))
3312 3311
3313 3312 #Parameters Array
3314 3313 arrayParameters[:,0] = arrayDate #Date
3315 3314 arrayParameters[:,1] = heiRang[arrayMeteors[:,0].astype(int)] #Range
3316 3315 arrayParameters[:,6:8] = arrayMeteors[:,-3:-1] #Radial velocity and its error
3317 3316 arrayParameters[:,8:12] = arrayMeteors[:,7:11] #Phases
3318 3317 arrayParameters[:,-1] = arrayMeteors[:,-1] #Error
3319 3318
3320 3319
3321 3320 return arrayParameters
3322 3321
3323 3322 class CorrectSMPhases(Operation):
3324 3323
3325 3324 def run(self, dataOut, phaseOffsets, hmin = 50, hmax = 150, azimuth = 45, channelPositions = None):
3326 3325
3327 3326 arrayParameters = dataOut.data_param
3328 3327 pairsList = []
3329 3328 pairx = (0,1)
3330 3329 pairy = (2,3)
3331 3330 pairsList.append(pairx)
3332 3331 pairsList.append(pairy)
3333 3332 jph = numpy.zeros(4)
3334 3333
3335 3334 phaseOffsets = numpy.array(phaseOffsets)*numpy.pi/180
3336 3335 # arrayParameters[:,8:12] = numpy.unwrap(arrayParameters[:,8:12] + phaseOffsets)
3337 3336 arrayParameters[:,8:12] = numpy.angle(numpy.exp(1j*(arrayParameters[:,8:12] + phaseOffsets)))
3338 3337
3339 3338 meteorOps = SMOperations()
3340 3339 if channelPositions is None:
3341 3340 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3342 3341 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3343 3342
3344 3343 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3345 3344 h = (hmin,hmax)
3346 3345
3347 3346 arrayParameters = meteorOps.getMeteorParams(arrayParameters, azimuth, h, pairsList, distances, jph)
3348 3347
3349 3348 dataOut.data_param = arrayParameters
3350 3349 return
3351 3350
3352 3351 class SMPhaseCalibration(Operation):
3353 3352
3354 3353 __buffer = None
3355 3354
3356 3355 __initime = None
3357 3356
3358 3357 __dataReady = False
3359 3358
3360 3359 __isConfig = False
3361 3360
3362 3361 def __checkTime(self, currentTime, initTime, paramInterval, outputInterval):
3363 3362
3364 3363 dataTime = currentTime + paramInterval
3365 3364 deltaTime = dataTime - initTime
3366 3365
3367 3366 if deltaTime >= outputInterval or deltaTime < 0:
3368 3367 return True
3369 3368
3370 3369 return False
3371 3370
3372 3371 def __getGammas(self, pairs, d, phases):
3373 3372 gammas = numpy.zeros(2)
3374 3373
3375 3374 for i in range(len(pairs)):
3376 3375
3377 3376 pairi = pairs[i]
3378 3377
3379 3378 phip3 = phases[:,pairi[0]]
3380 3379 d3 = d[pairi[0]]
3381 3380 phip2 = phases[:,pairi[1]]
3382 3381 d2 = d[pairi[1]]
3383 3382 #Calculating gamma
3384 3383 # jdcos = alp1/(k*d1)
3385 3384 # jgamma = numpy.angle(numpy.exp(1j*(d0*alp1/d1 - alp0)))
3386 3385 jgamma = -phip2*d3/d2 - phip3
3387 3386 jgamma = numpy.angle(numpy.exp(1j*jgamma))
3388 3387 # jgamma[jgamma>numpy.pi] -= 2*numpy.pi
3389 3388 # jgamma[jgamma<-numpy.pi] += 2*numpy.pi
3390 3389
3391 3390 #Revised distribution
3392 3391 jgammaArray = numpy.hstack((jgamma,jgamma+0.5*numpy.pi,jgamma-0.5*numpy.pi))
3393 3392
3394 3393 #Histogram
3395 3394 nBins = 64
3396 3395 rmin = -0.5*numpy.pi
3397 3396 rmax = 0.5*numpy.pi
3398 3397 phaseHisto = numpy.histogram(jgammaArray, bins=nBins, range=(rmin,rmax))
3399 3398
3400 3399 meteorsY = phaseHisto[0]
3401 3400 phasesX = phaseHisto[1][:-1]
3402 3401 width = phasesX[1] - phasesX[0]
3403 3402 phasesX += width/2
3404 3403
3405 3404 #Gaussian aproximation
3406 3405 bpeak = meteorsY.argmax()
3407 3406 peak = meteorsY.max()
3408 3407 jmin = bpeak - 5
3409 3408 jmax = bpeak + 5 + 1
3410 3409
3411 3410 if jmin<0:
3412 3411 jmin = 0
3413 3412 jmax = 6
3414 3413 elif jmax > meteorsY.size:
3415 3414 jmin = meteorsY.size - 6
3416 3415 jmax = meteorsY.size
3417 3416
3418 3417 x0 = numpy.array([peak,bpeak,50])
3419 3418 coeff = optimize.leastsq(self.__residualFunction, x0, args=(meteorsY[jmin:jmax], phasesX[jmin:jmax]))
3420 3419
3421 3420 #Gammas
3422 3421 gammas[i] = coeff[0][1]
3423 3422
3424 3423 return gammas
3425 3424
3426 3425 def __residualFunction(self, coeffs, y, t):
3427 3426
3428 3427 return y - self.__gauss_function(t, coeffs)
3429 3428
3430 3429 def __gauss_function(self, t, coeffs):
3431 3430
3432 3431 return coeffs[0]*numpy.exp(-0.5*((t - coeffs[1]) / coeffs[2])**2)
3433 3432
3434 3433 def __getPhases(self, azimuth, h, pairsList, d, gammas, meteorsArray):
3435 3434 meteorOps = SMOperations()
3436 3435 nchan = 4
3437 3436 pairx = pairsList[0] #x es 0
3438 3437 pairy = pairsList[1] #y es 1
3439 3438 center_xangle = 0
3440 3439 center_yangle = 0
3441 3440 range_angle = numpy.array([10*numpy.pi,numpy.pi,numpy.pi/2,numpy.pi/4])
3442 3441 ntimes = len(range_angle)
3443 3442
3444 3443 nstepsx = 20
3445 3444 nstepsy = 20
3446 3445
3447 3446 for iz in range(ntimes):
3448 3447 min_xangle = -range_angle[iz]/2 + center_xangle
3449 3448 max_xangle = range_angle[iz]/2 + center_xangle
3450 3449 min_yangle = -range_angle[iz]/2 + center_yangle
3451 3450 max_yangle = range_angle[iz]/2 + center_yangle
3452 3451
3453 3452 inc_x = (max_xangle-min_xangle)/nstepsx
3454 3453 inc_y = (max_yangle-min_yangle)/nstepsy
3455 3454
3456 3455 alpha_y = numpy.arange(nstepsy)*inc_y + min_yangle
3457 3456 alpha_x = numpy.arange(nstepsx)*inc_x + min_xangle
3458 3457 penalty = numpy.zeros((nstepsx,nstepsy))
3459 3458 jph_array = numpy.zeros((nchan,nstepsx,nstepsy))
3460 3459 jph = numpy.zeros(nchan)
3461 3460
3462 3461 # Iterations looking for the offset
3463 3462 for iy in range(int(nstepsy)):
3464 3463 for ix in range(int(nstepsx)):
3465 3464 d3 = d[pairsList[1][0]]
3466 3465 d2 = d[pairsList[1][1]]
3467 3466 d5 = d[pairsList[0][0]]
3468 3467 d4 = d[pairsList[0][1]]
3469 3468
3470 3469 alp2 = alpha_y[iy] #gamma 1
3471 3470 alp4 = alpha_x[ix] #gamma 0
3472 3471
3473 3472 alp3 = -alp2*d3/d2 - gammas[1]
3474 3473 alp5 = -alp4*d5/d4 - gammas[0]
3475 3474 # jph[pairy[1]] = alpha_y[iy]
3476 3475 # jph[pairy[0]] = -gammas[1] - alpha_y[iy]*d[pairy[1]]/d[pairy[0]]
3477 3476
3478 3477 # jph[pairx[1]] = alpha_x[ix]
3479 3478 # jph[pairx[0]] = -gammas[0] - alpha_x[ix]*d[pairx[1]]/d[pairx[0]]
3480 3479 jph[pairsList[0][1]] = alp4
3481 3480 jph[pairsList[0][0]] = alp5
3482 3481 jph[pairsList[1][0]] = alp3
3483 3482 jph[pairsList[1][1]] = alp2
3484 3483 jph_array[:,ix,iy] = jph
3485 3484 # d = [2.0,2.5,2.5,2.0]
3486 3485 #falta chequear si va a leer bien los meteoros
3487 3486 meteorsArray1 = meteorOps.getMeteorParams(meteorsArray, azimuth, h, pairsList, d, jph)
3488 3487 error = meteorsArray1[:,-1]
3489 3488 ind1 = numpy.where(error==0)[0]
3490 3489 penalty[ix,iy] = ind1.size
3491 3490
3492 3491 i,j = numpy.unravel_index(penalty.argmax(), penalty.shape)
3493 3492 phOffset = jph_array[:,i,j]
3494 3493
3495 3494 center_xangle = phOffset[pairx[1]]
3496 3495 center_yangle = phOffset[pairy[1]]
3497 3496
3498 3497 phOffset = numpy.angle(numpy.exp(1j*jph_array[:,i,j]))
3499 3498 phOffset = phOffset*180/numpy.pi
3500 3499 return phOffset
3501 3500
3502 3501
3503 3502 def run(self, dataOut, hmin, hmax, channelPositions=None, nHours = 1):
3504 3503
3505 3504 dataOut.flagNoData = True
3506 3505 self.__dataReady = False
3507 3506 dataOut.outputInterval = nHours*3600
3508 3507
3509 3508 if self.__isConfig == False:
3510 3509 # self.__initime = dataOut.datatime.replace(minute = 0, second = 0, microsecond = 03)
3511 3510 #Get Initial LTC time
3512 3511 self.__initime = datetime.datetime.utcfromtimestamp(dataOut.utctime)
3513 3512 self.__initime = (self.__initime.replace(minute = 0, second = 0, microsecond = 0) - datetime.datetime(1970, 1, 1)).total_seconds()
3514 3513
3515 3514 self.__isConfig = True
3516 3515
3517 3516 if self.__buffer is None:
3518 3517 self.__buffer = dataOut.data_param.copy()
3519 3518
3520 3519 else:
3521 3520 self.__buffer = numpy.vstack((self.__buffer, dataOut.data_param))
3522 3521
3523 3522 self.__dataReady = self.__checkTime(dataOut.utctime, self.__initime, dataOut.paramInterval, dataOut.outputInterval) #Check if the buffer is ready
3524 3523
3525 3524 if self.__dataReady:
3526 3525 dataOut.utctimeInit = self.__initime
3527 3526 self.__initime += dataOut.outputInterval #to erase time offset
3528 3527
3529 3528 freq = dataOut.frequency
3530 3529 c = dataOut.C #m/s
3531 3530 lamb = c/freq
3532 3531 k = 2*numpy.pi/lamb
3533 3532 azimuth = 0
3534 3533 h = (hmin, hmax)
3535 3534 # pairs = ((0,1),(2,3)) #Estrella
3536 3535 # pairs = ((1,0),(2,3)) #T
3537 3536
3538 3537 if channelPositions is None:
3539 3538 # channelPositions = [(2.5,0), (0,2.5), (0,0), (0,4.5), (-2,0)] #T
3540 3539 channelPositions = [(4.5,2), (2,4.5), (2,2), (2,0), (0,2)] #Estrella
3541 3540 meteorOps = SMOperations()
3542 3541 pairslist0, distances = meteorOps.getPhasePairs(channelPositions)
3543 3542
3544 3543 #Checking correct order of pairs
3545 3544 pairs = []
3546 3545 if distances[1] > distances[0]:
3547 3546 pairs.append((1,0))
3548 3547 else:
3549 3548 pairs.append((0,1))
3550 3549
3551 3550 if distances[3] > distances[2]:
3552 3551 pairs.append((3,2))
3553 3552 else:
3554 3553 pairs.append((2,3))
3555 3554 # distances1 = [-distances[0]*lamb, distances[1]*lamb, -distances[2]*lamb, distances[3]*lamb]
3556 3555
3557 3556 meteorsArray = self.__buffer
3558 3557 error = meteorsArray[:,-1]
3559 3558 boolError = (error==0)|(error==3)|(error==4)|(error==13)|(error==14)
3560 3559 ind1 = numpy.where(boolError)[0]
3561 3560 meteorsArray = meteorsArray[ind1,:]
3562 3561 meteorsArray[:,-1] = 0
3563 3562 phases = meteorsArray[:,8:12]
3564 3563
3565 3564 #Calculate Gammas
3566 3565 gammas = self.__getGammas(pairs, distances, phases)
3567 3566 # gammas = numpy.array([-21.70409463,45.76935864])*numpy.pi/180
3568 3567 #Calculate Phases
3569 3568 phasesOff = self.__getPhases(azimuth, h, pairs, distances, gammas, meteorsArray)
3570 3569 phasesOff = phasesOff.reshape((1,phasesOff.size))
3571 3570 dataOut.data_output = -phasesOff
3572 3571 dataOut.flagNoData = False
3573 3572 self.__buffer = None
3574 3573
3575 3574
3576 3575 return
3577 3576
3578 3577 class SMOperations():
3579 3578
3580 3579 def __init__(self):
3581 3580
3582 3581 return
3583 3582
3584 3583 def getMeteorParams(self, arrayParameters0, azimuth, h, pairsList, distances, jph):
3585 3584
3586 3585 arrayParameters = arrayParameters0.copy()
3587 3586 hmin = h[0]
3588 3587 hmax = h[1]
3589 3588
3590 3589 #Calculate AOA (Error N 3, 4)
3591 3590 #JONES ET AL. 1998
3592 3591 AOAthresh = numpy.pi/8
3593 3592 error = arrayParameters[:,-1]
3594 3593 phases = -arrayParameters[:,8:12] + jph
3595 3594 # phases = numpy.unwrap(phases)
3596 3595 arrayParameters[:,3:6], arrayParameters[:,-1] = self.__getAOA(phases, pairsList, distances, error, AOAthresh, azimuth)
3597 3596
3598 3597 #Calculate Heights (Error N 13 and 14)
3599 3598 error = arrayParameters[:,-1]
3600 3599 Ranges = arrayParameters[:,1]
3601 3600 zenith = arrayParameters[:,4]
3602 3601 arrayParameters[:,2], arrayParameters[:,-1] = self.__getHeights(Ranges, zenith, error, hmin, hmax)
3603 3602
3604 3603 #----------------------- Get Final data ------------------------------------
3605 3604 # error = arrayParameters[:,-1]
3606 3605 # ind1 = numpy.where(error==0)[0]
3607 3606 # arrayParameters = arrayParameters[ind1,:]
3608 3607
3609 3608 return arrayParameters
3610 3609
3611 3610 def __getAOA(self, phases, pairsList, directions, error, AOAthresh, azimuth):
3612 3611
3613 3612 arrayAOA = numpy.zeros((phases.shape[0],3))
3614 3613 cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList,directions)
3615 3614
3616 3615 arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3617 3616 cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3618 3617 arrayAOA[:,2] = cosDirError
3619 3618
3620 3619 azimuthAngle = arrayAOA[:,0]
3621 3620 zenithAngle = arrayAOA[:,1]
3622 3621
3623 3622 #Setting Error
3624 3623 indError = numpy.where(numpy.logical_or(error == 3, error == 4))[0]
3625 3624 error[indError] = 0
3626 3625 #Number 3: AOA not fesible
3627 3626 indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3628 3627 error[indInvalid] = 3
3629 3628 #Number 4: Large difference in AOAs obtained from different antenna baselines
3630 3629 indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3631 3630 error[indInvalid] = 4
3632 3631 return arrayAOA, error
3633 3632
3634 3633 def __getDirectionCosines(self, arrayPhase, pairsList, distances):
3635 3634
3636 3635 #Initializing some variables
3637 3636 ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3638 3637 ang_aux = ang_aux.reshape(1,ang_aux.size)
3639 3638
3640 3639 cosdir = numpy.zeros((arrayPhase.shape[0],2))
3641 3640 cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3642 3641
3643 3642
3644 3643 for i in range(2):
3645 3644 ph0 = arrayPhase[:,pairsList[i][0]]
3646 3645 ph1 = arrayPhase[:,pairsList[i][1]]
3647 3646 d0 = distances[pairsList[i][0]]
3648 3647 d1 = distances[pairsList[i][1]]
3649 3648
3650 3649 ph0_aux = ph0 + ph1
3651 3650 ph0_aux = numpy.angle(numpy.exp(1j*ph0_aux))
3652 3651 # ph0_aux[ph0_aux > numpy.pi] -= 2*numpy.pi
3653 3652 # ph0_aux[ph0_aux < -numpy.pi] += 2*numpy.pi
3654 3653 #First Estimation
3655 3654 cosdir0[:,i] = (ph0_aux)/(2*numpy.pi*(d0 - d1))
3656 3655
3657 3656 #Most-Accurate Second Estimation
3658 3657 phi1_aux = ph0 - ph1
3659 3658 phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3660 3659 #Direction Cosine 1
3661 3660 cosdir1 = (phi1_aux + ang_aux)/(2*numpy.pi*(d0 + d1))
3662 3661
3663 3662 #Searching the correct Direction Cosine
3664 3663 cosdir0_aux = cosdir0[:,i]
3665 3664 cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3666 3665 #Minimum Distance
3667 3666 cosDiff = (cosdir1 - cosdir0_aux)**2
3668 3667 indcos = cosDiff.argmin(axis = 1)
3669 3668 #Saving Value obtained
3670 3669 cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3671 3670
3672 3671 return cosdir0, cosdir
3673 3672
3674 3673 def __calculateAOA(self, cosdir, azimuth):
3675 3674 cosdirX = cosdir[:,0]
3676 3675 cosdirY = cosdir[:,1]
3677 3676
3678 3677 zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3679 3678 azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth#0 deg north, 90 deg east
3680 3679 angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3681 3680
3682 3681 return angles
3683 3682
3684 3683 def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3685 3684
3686 3685 Ramb = 375 #Ramb = c/(2*PRF)
3687 3686 Re = 6371 #Earth Radius
3688 3687 heights = numpy.zeros(Ranges.shape)
3689 3688
3690 3689 R_aux = numpy.array([0,1,2])*Ramb
3691 3690 R_aux = R_aux.reshape(1,R_aux.size)
3692 3691
3693 3692 Ranges = Ranges.reshape(Ranges.size,1)
3694 3693
3695 3694 Ri = Ranges + R_aux
3696 3695 hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3697 3696
3698 3697 #Check if there is a height between 70 and 110 km
3699 3698 h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3700 3699 ind_h = numpy.where(h_bool == 1)[0]
3701 3700
3702 3701 hCorr = hi[ind_h, :]
3703 3702 ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3704 3703
3705 3704 hCorr = hi[ind_hCorr][:len(ind_h)]
3706 3705 heights[ind_h] = hCorr
3707 3706
3708 3707 #Setting Error
3709 3708 #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3710 3709 #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3711 3710 indError = numpy.where(numpy.logical_or(error == 13, error == 14))[0]
3712 3711 error[indError] = 0
3713 3712 indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3714 3713 error[indInvalid2] = 14
3715 3714 indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3716 3715 error[indInvalid1] = 13
3717 3716
3718 3717 return heights, error
3719 3718
3720 3719 def getPhasePairs(self, channelPositions):
3721 3720 chanPos = numpy.array(channelPositions)
3722 3721 listOper = list(itertools.combinations(list(range(5)),2))
3723 3722
3724 3723 distances = numpy.zeros(4)
3725 3724 axisX = []
3726 3725 axisY = []
3727 3726 distX = numpy.zeros(3)
3728 3727 distY = numpy.zeros(3)
3729 3728 ix = 0
3730 3729 iy = 0
3731 3730
3732 3731 pairX = numpy.zeros((2,2))
3733 3732 pairY = numpy.zeros((2,2))
3734 3733
3735 3734 for i in range(len(listOper)):
3736 3735 pairi = listOper[i]
3737 3736
3738 3737 posDif = numpy.abs(chanPos[pairi[0],:] - chanPos[pairi[1],:])
3739 3738
3740 3739 if posDif[0] == 0:
3741 3740 axisY.append(pairi)
3742 3741 distY[iy] = posDif[1]
3743 3742 iy += 1
3744 3743 elif posDif[1] == 0:
3745 3744 axisX.append(pairi)
3746 3745 distX[ix] = posDif[0]
3747 3746 ix += 1
3748 3747
3749 3748 for i in range(2):
3750 3749 if i==0:
3751 3750 dist0 = distX
3752 3751 axis0 = axisX
3753 3752 else:
3754 3753 dist0 = distY
3755 3754 axis0 = axisY
3756 3755
3757 3756 side = numpy.argsort(dist0)[:-1]
3758 3757 axis0 = numpy.array(axis0)[side,:]
3759 3758 chanC = int(numpy.intersect1d(axis0[0,:], axis0[1,:])[0])
3760 3759 axis1 = numpy.unique(numpy.reshape(axis0,4))
3761 3760 side = axis1[axis1 != chanC]
3762 3761 diff1 = chanPos[chanC,i] - chanPos[side[0],i]
3763 3762 diff2 = chanPos[chanC,i] - chanPos[side[1],i]
3764 3763 if diff1<0:
3765 3764 chan2 = side[0]
3766 3765 d2 = numpy.abs(diff1)
3767 3766 chan1 = side[1]
3768 3767 d1 = numpy.abs(diff2)
3769 3768 else:
3770 3769 chan2 = side[1]
3771 3770 d2 = numpy.abs(diff2)
3772 3771 chan1 = side[0]
3773 3772 d1 = numpy.abs(diff1)
3774 3773
3775 3774 if i==0:
3776 3775 chanCX = chanC
3777 3776 chan1X = chan1
3778 3777 chan2X = chan2
3779 3778 distances[0:2] = numpy.array([d1,d2])
3780 3779 else:
3781 3780 chanCY = chanC
3782 3781 chan1Y = chan1
3783 3782 chan2Y = chan2
3784 3783 distances[2:4] = numpy.array([d1,d2])
3785 3784 # axisXsides = numpy.reshape(axisX[ix,:],4)
3786 3785 #
3787 3786 # channelCentX = int(numpy.intersect1d(pairX[0,:], pairX[1,:])[0])
3788 3787 # channelCentY = int(numpy.intersect1d(pairY[0,:], pairY[1,:])[0])
3789 3788 #
3790 3789 # ind25X = numpy.where(pairX[0,:] != channelCentX)[0][0]
3791 3790 # ind20X = numpy.where(pairX[1,:] != channelCentX)[0][0]
3792 3791 # channel25X = int(pairX[0,ind25X])
3793 3792 # channel20X = int(pairX[1,ind20X])
3794 3793 # ind25Y = numpy.where(pairY[0,:] != channelCentY)[0][0]
3795 3794 # ind20Y = numpy.where(pairY[1,:] != channelCentY)[0][0]
3796 3795 # channel25Y = int(pairY[0,ind25Y])
3797 3796 # channel20Y = int(pairY[1,ind20Y])
3798 3797
3799 3798 # pairslist = [(channelCentX, channel25X),(channelCentX, channel20X),(channelCentY,channel25Y),(channelCentY, channel20Y)]
3800 3799 pairslist = [(chanCX, chan1X),(chanCX, chan2X),(chanCY,chan1Y),(chanCY, chan2Y)]
3801 3800
3802 3801 return pairslist, distances
3803 3802 # def __getAOA(self, phases, pairsList, error, AOAthresh, azimuth):
3804 3803 #
3805 3804 # arrayAOA = numpy.zeros((phases.shape[0],3))
3806 3805 # cosdir0, cosdir = self.__getDirectionCosines(phases, pairsList)
3807 3806 #
3808 3807 # arrayAOA[:,:2] = self.__calculateAOA(cosdir, azimuth)
3809 3808 # cosDirError = numpy.sum(numpy.abs(cosdir0 - cosdir), axis = 1)
3810 3809 # arrayAOA[:,2] = cosDirError
3811 3810 #
3812 3811 # azimuthAngle = arrayAOA[:,0]
3813 3812 # zenithAngle = arrayAOA[:,1]
3814 3813 #
3815 3814 # #Setting Error
3816 3815 # #Number 3: AOA not fesible
3817 3816 # indInvalid = numpy.where(numpy.logical_and((numpy.logical_or(numpy.isnan(zenithAngle), numpy.isnan(azimuthAngle))),error == 0))[0]
3818 3817 # error[indInvalid] = 3
3819 3818 # #Number 4: Large difference in AOAs obtained from different antenna baselines
3820 3819 # indInvalid = numpy.where(numpy.logical_and(cosDirError > AOAthresh,error == 0))[0]
3821 3820 # error[indInvalid] = 4
3822 3821 # return arrayAOA, error
3823 3822 #
3824 3823 # def __getDirectionCosines(self, arrayPhase, pairsList):
3825 3824 #
3826 3825 # #Initializing some variables
3827 3826 # ang_aux = numpy.array([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8])*2*numpy.pi
3828 3827 # ang_aux = ang_aux.reshape(1,ang_aux.size)
3829 3828 #
3830 3829 # cosdir = numpy.zeros((arrayPhase.shape[0],2))
3831 3830 # cosdir0 = numpy.zeros((arrayPhase.shape[0],2))
3832 3831 #
3833 3832 #
3834 3833 # for i in range(2):
3835 3834 # #First Estimation
3836 3835 # phi0_aux = arrayPhase[:,pairsList[i][0]] + arrayPhase[:,pairsList[i][1]]
3837 3836 # #Dealias
3838 3837 # indcsi = numpy.where(phi0_aux > numpy.pi)
3839 3838 # phi0_aux[indcsi] -= 2*numpy.pi
3840 3839 # indcsi = numpy.where(phi0_aux < -numpy.pi)
3841 3840 # phi0_aux[indcsi] += 2*numpy.pi
3842 3841 # #Direction Cosine 0
3843 3842 # cosdir0[:,i] = -(phi0_aux)/(2*numpy.pi*0.5)
3844 3843 #
3845 3844 # #Most-Accurate Second Estimation
3846 3845 # phi1_aux = arrayPhase[:,pairsList[i][0]] - arrayPhase[:,pairsList[i][1]]
3847 3846 # phi1_aux = phi1_aux.reshape(phi1_aux.size,1)
3848 3847 # #Direction Cosine 1
3849 3848 # cosdir1 = -(phi1_aux + ang_aux)/(2*numpy.pi*4.5)
3850 3849 #
3851 3850 # #Searching the correct Direction Cosine
3852 3851 # cosdir0_aux = cosdir0[:,i]
3853 3852 # cosdir0_aux = cosdir0_aux.reshape(cosdir0_aux.size,1)
3854 3853 # #Minimum Distance
3855 3854 # cosDiff = (cosdir1 - cosdir0_aux)**2
3856 3855 # indcos = cosDiff.argmin(axis = 1)
3857 3856 # #Saving Value obtained
3858 3857 # cosdir[:,i] = cosdir1[numpy.arange(len(indcos)),indcos]
3859 3858 #
3860 3859 # return cosdir0, cosdir
3861 3860 #
3862 3861 # def __calculateAOA(self, cosdir, azimuth):
3863 3862 # cosdirX = cosdir[:,0]
3864 3863 # cosdirY = cosdir[:,1]
3865 3864 #
3866 3865 # zenithAngle = numpy.arccos(numpy.sqrt(1 - cosdirX**2 - cosdirY**2))*180/numpy.pi
3867 3866 # azimuthAngle = numpy.arctan2(cosdirX,cosdirY)*180/numpy.pi + azimuth #0 deg north, 90 deg east
3868 3867 # angles = numpy.vstack((azimuthAngle, zenithAngle)).transpose()
3869 3868 #
3870 3869 # return angles
3871 3870 #
3872 3871 # def __getHeights(self, Ranges, zenith, error, minHeight, maxHeight):
3873 3872 #
3874 3873 # Ramb = 375 #Ramb = c/(2*PRF)
3875 3874 # Re = 6371 #Earth Radius
3876 3875 # heights = numpy.zeros(Ranges.shape)
3877 3876 #
3878 3877 # R_aux = numpy.array([0,1,2])*Ramb
3879 3878 # R_aux = R_aux.reshape(1,R_aux.size)
3880 3879 #
3881 3880 # Ranges = Ranges.reshape(Ranges.size,1)
3882 3881 #
3883 3882 # Ri = Ranges + R_aux
3884 3883 # hi = numpy.sqrt(Re**2 + Ri**2 + (2*Re*numpy.cos(zenith*numpy.pi/180)*Ri.transpose()).transpose()) - Re
3885 3884 #
3886 3885 # #Check if there is a height between 70 and 110 km
3887 3886 # h_bool = numpy.sum(numpy.logical_and(hi > minHeight, hi < maxHeight), axis = 1)
3888 3887 # ind_h = numpy.where(h_bool == 1)[0]
3889 3888 #
3890 3889 # hCorr = hi[ind_h, :]
3891 3890 # ind_hCorr = numpy.where(numpy.logical_and(hi > minHeight, hi < maxHeight))
3892 3891 #
3893 3892 # hCorr = hi[ind_hCorr]
3894 3893 # heights[ind_h] = hCorr
3895 3894 #
3896 3895 # #Setting Error
3897 3896 # #Number 13: Height unresolvable echo: not valid height within 70 to 110 km
3898 3897 # #Number 14: Height ambiguous echo: more than one possible height within 70 to 110 km
3899 3898 #
3900 3899 # indInvalid2 = numpy.where(numpy.logical_and(h_bool > 1, error == 0))[0]
3901 3900 # error[indInvalid2] = 14
3902 3901 # indInvalid1 = numpy.where(numpy.logical_and(h_bool == 0, error == 0))[0]
3903 3902 # error[indInvalid1] = 13
3904 3903 #
3905 3904 # return heights, error
3906 3905
3907 3906
3908 3907 class WeatherRadar(Operation):
3909 3908 '''
3910 3909 Function tat implements Weather Radar operations-
3911 3910 Input:
3912 3911 Output:
3913 3912 Parameters affected:
3914 3913 '''
3915 3914 isConfig = False
3916 3915
3917 3916 def __init__(self):
3918 3917 Operation.__init__(self)
3919 3918
3920 3919 def setup(self,dataOut,Pt=0,Gt=0,Gr=0,lambda_=0, aL=0,
3921 3920 tauW= 0,thetaT=0,thetaR=0,Km =0):
3922 3921 self.nCh = dataOut.nChannels
3923 3922 self.nHeis = dataOut.nHeights
3924 3923 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
3925 3924 self.Range = numpy.arange(dataOut.nHeights)*deltaHeight + dataOut.heightList[0]
3926 3925 self.Range = self.Range.reshape(1,self.nHeis)
3927 3926 self.Range = numpy.tile(self.Range,[self.nCh,1])
3928 3927 '''-----------1 Constante del Radar----------'''
3929 3928 self.Pt = Pt
3930 3929 self.Gt = Gt
3931 3930 self.Gr = Gr
3932 3931 self.lambda_ = lambda_
3933 3932 self.aL = aL
3934 3933 self.tauW = tauW
3935 3934 self.thetaT = thetaT
3936 3935 self.thetaR = thetaR
3937 3936 self.Km = Km
3938 3937 Numerator = ((4*numpy.pi)**3 * aL**2 * 16 *numpy.log(2))
3939 3938 Denominator = (Pt * Gt * Gr * lambda_**2 * SPEED_OF_LIGHT * tauW * numpy.pi*thetaT*thetaR)
3940 3939 self.RadarConstant = Numerator/Denominator
3941 3940 '''-----------2 Reflectividad del Radar y Factor de Reflectividad------'''
3942 3941 self.n_radar = numpy.zeros((self.nCh,self.nHeis))
3943 3942 self.Z_radar = numpy.zeros((self.nCh,self.nHeis))
3944 3943
3945 3944 def setMoments(self,dataOut,i):
3946 3945
3947 3946 type = dataOut.inputUnit
3948 3947 nCh = dataOut.nChannels
3949 3948 nHeis= dataOut.nHeights
3950 3949 data_param = numpy.zeros((nCh,4,nHeis))
3951 3950 if type == "Voltage":
3952 3951 data_param[:,0,:] = dataOut.dataPP_POW/(dataOut.nCohInt**2)
3953 3952 data_param[:,1,:] = dataOut.dataPP_DOP
3954 3953 data_param[:,2,:] = dataOut.dataPP_WIDTH
3955 3954 data_param[:,3,:] = dataOut.dataPP_SNR
3956 3955 if type == "Spectra":
3957 3956 data_param[:,0,:] = dataOut.data_POW
3958 3957 data_param[:,1,:] = dataOut.data_DOP
3959 3958 data_param[:,2,:] = dataOut.data_WIDTH
3960 3959 def setMoments(self,dataOut,i):
3961 3960 data_param[:,3,:] = dataOut.data_SNR
3962 3961
3963 3962 return data_param[:,i,:]
3964 3963
3965 3964
3966 3965 def run(self,dataOut,Pt=25,Gt=200.0,Gr=50.0,lambda_=0.32, aL=2.5118,
3967 3966 tauW= 4.0e-6,thetaT=0.165,thetaR=0.367,Km =0.93):
3968 3967
3969 3968 if not self.isConfig:
3970 3969 self.setup(dataOut= dataOut,Pt=25,Gt=200.0,Gr=50.0,lambda_=0.32, aL=2.5118,
3971 3970 tauW= 4.0e-6,thetaT=0.165,thetaR=0.367,Km =0.93)
3972 3971 self.isConfig = True
3973 3972 '''-----------------------------Potencia de Radar -Signal S-----------------------------'''
3974 3973 Pr = self.setMoments(dataOut,0)
3975 3974
3976 3975 for R in range(self.nHeis):
3977 3976 self.n_radar[:,R] = self.RadarConstant*Pr[:,R]* (self.Range[:,R])**2
3978 3977
3979 3978 self.Z_radar[:,R] = self.n_radar[:,R]* self.lambda_**4/( numpy.pi**5 * self.Km**2)
3980 3979
3981 3980 '''----------- Factor de Reflectividad Equivalente lamda_ < 10 cm , lamda_= 3.2cm-------'''
3982 3981 Zeh = self.Z_radar
3983 3982 dBZeh = 10*numpy.log10(Zeh)
3984 3983 dataOut.factor_Zeh= dBZeh
3985 3984 self.n_radar = numpy.zeros((self.nCh,self.nHeis))
3986 3985 self.Z_radar = numpy.zeros((self.nCh,self.nHeis))
3987 3986
3988 3987 return dataOut
3989 3988
3990 3989 class PedestalInformation(Operation):
3991 3990 path_ped = None
3992 3991 path_adq = None
3993 3992 t_Interval_p = None
3994 3993 n_Muestras_p = None
3995 3994 isConfig = False
3996 3995 blocksPerfile= None
3997 3996 f_a_p = None
3998 3997 online = None
3999 3998 angulo_adq = None
4000 3999 nro_file = None
4001 4000 nro_key_p = None
4002 4001 tmp = None
4003 4002
4004 4003
4005 4004 def __init__(self):
4006 4005 Operation.__init__(self)
4007 4006
4008 4007 def getfirstFilefromPath(self,path,meta,ext):
4009 4008 validFilelist = []
4010 4009 #print("SEARH",path)
4011 4010 try:
4012 4011 fileList = os.listdir(path)
4013 4012 except:
4014 4013 print("check path - fileList")
4015 4014 if len(fileList)<1:
4016 4015 return None
4017 4016 # meta 1234 567 8-18 BCDE
4018 4017 # H,D,PE YYYY DDD EPOC .ext
4019 4018
4020 4019 for thisFile in fileList:
4021 4020 #print("HI",thisFile)
4022 4021 if meta =="PE":
4023 4022 try:
4024 4023 number= int(thisFile[len(meta)+7:len(meta)+17])
4025 4024 except:
4026 4025 print("There is a file or folder with different format")
4027 4026 if meta == "D":
4028 4027 try:
4029 4028 number= int(thisFile[8:11])
4030 4029 except:
4031 4030 print("There is a file or folder with different format")
4032 4031
4033 4032 if not isNumber(str=number):
4034 4033 continue
4035 4034 if (os.path.splitext(thisFile)[-1].lower() != ext.lower()):
4036 4035 continue
4037 4036 validFilelist.sort()
4038 4037 validFilelist.append(thisFile)
4039 4038 if len(validFilelist)>0:
4040 4039 validFilelist = sorted(validFilelist,key=str.lower)
4041 4040 return validFilelist
4042 4041 return None
4043 4042
4044 4043 def gettimeutcfromDirFilename(self,path,file):
4045 4044 dir_file= path+"/"+file
4046 4045 fp = h5py.File(dir_file,'r')
4047 4046 #epoc = fp['Metadata'].get('utctimeInit')[()]
4048 4047 epoc = fp['Data'].get('utc')[()]
4049 4048 fp.close()
4050 4049 return epoc
4051 4050
4052 4051 def gettimeutcadqfromDirFilename(self,path,file):
4053 4052 dir_file= path+"/"+file
4054 4053 fp = h5py.File(dir_file,'r')
4055 4054 epoc = fp['Metadata'].get('utctimeInit')[()]
4056 4055 #epoc = fp['Data'].get('utc')[()]
4057 4056 fp.close()
4058 4057 return epoc
4059 4058
4060 4059 def getDatavaluefromDirFilename(self,path,file,value):
4061 4060 dir_file= path+"/"+file
4062 4061 fp = h5py.File(dir_file,'r')
4063 4062 array = fp['Data'].get(value)[()]
4064 4063 fp.close()
4065 4064 return array
4066 4065
4067 4066 def getFile_KeyP(self,list_pedestal,list_adq):
4068 4067 print(list_pedestal)
4069 4068 print(list_adq)
4070 4069
4071 4070 def getNROFile(self,utc_adq,utc_ped_list):
4072 4071 c=0
4073 4072 print("insidegetNROFile")
4074 4073 print(utc_adq)
4075 4074 print(len(utc_ped_list))
4076 4075 for i in range(len(utc_ped_list)):
4077 4076 if utc_adq>utc_ped_list[i]:
4078 4077 #print("mayor")
4079 4078 #print("utc_ped_list",utc_ped_list[i])
4080 4079 c +=1
4081 4080
4082 4081 return c-1,utc_ped_list[c-1],utc_ped_list[c]
4083 4082
4084 4083 def verificarNROFILE(self,dataOut,utc_ped,f_a_p,n_Muestras_p):
4085 4084 var =int(f_a_p/n_Muestras_p)
4086 4085 flag=0
4087 4086 for i in range(var):
4088 4087 if dataOut.utctime+i==utc_ped:
4089 4088 flag==1
4090 4089 break
4091 4090 return flag
4092 4091
4093 4092 #def setup_offline(self,dataOut,list_pedestal,list_adq):
4094 4093 def setup_offline(self,dataOut,list_pedestal):
4095 4094
4096 4095 print("SETUP OFFLINE")
4097 4096 print(self.path_ped)
4098 4097 #print(self.path_adq)
4099 4098 print(len(self.list_pedestal))
4100 4099 #print(len(self.list_adq))
4101 4100 utc_ped_list=[]
4102 4101 for i in range(len(self.list_pedestal)):
4103 4102 print(i)
4104 4103 utc_ped_list.append(self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[i]))
4105 4104
4106 4105 #utc_ped_list= utc_ped_list
4107 4106 ###utc_adq = self.gettimeutcadqfromDirFilename(path=self.path_adq,file=self.list_adq[0])
4108 4107 print("dios existe donde esta")
4109 4108
4110 4109 #print("utc_ped_list",utc_ped_list)
4111 4110 ###print("utc_adq",utc_adq)
4112 4111 # utc_adq_dataOut
4113 4112 utc_adq_dataOut =dataOut.utctime
4114 4113 print("Offline-utc_adq_dataout",utc_adq_dataOut)
4115 4114
4116 4115 nro_file,utc_ped,utc_ped_1 = self.getNROFile(utc_adq=utc_adq_dataOut, utc_ped_list= utc_ped_list)
4117 4116
4118 4117 print("nro_file",nro_file,"utc_ped",utc_ped)
4119 4118 print("nro_file",i)
4120 4119 nro_key_p = int((utc_adq_dataOut-utc_ped)/self.t_Interval_p)-1 # ojito al -1 estimado alex
4121 4120 print("nro_key_p",nro_key_p)
4122 4121
4123 4122 ff_pedestal = self.list_pedestal[nro_file]
4124 4123 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4125 4124 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4126 4125
4127 4126 print("utc_pedestal_init :",utc_ped+nro_key_p*self.t_Interval_p)
4128 4127 print("angulo_array :",angulo[nro_key_p])
4129 4128 self.nro_file = nro_file
4130 4129 self.nro_key_p = nro_key_p
4131 4130
4132 4131 def setup_online(self,dataOut):
4133 4132 utc_adq =dataOut.utctime
4134 4133 print("Online-utc_adq",utc_adq)
4135 4134 print(len(self.list_pedestal))
4136 4135 utc_ped_list=[]
4137 4136 for i in range(len(self.list_pedestal)):
4138 4137 utc_ped_list.append(self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[i]))
4139 4138 print(utc_ped_list[:20])
4140 4139 #print(utc_ped_list[488:498])
4141 4140 print("ultimo UTC-PEDESTAL",utc_ped_list[-1])
4142 4141 nro_file,utc_ped,utc_ped_1 = self.getNROFile(utc_adq=utc_adq, utc_ped_list= utc_ped_list)
4143 4142 print("nro_file",nro_file,"utc_ped",utc_ped,"utc_ped_1",utc_ped_1)
4144 4143 print("name_PEDESTAL",self.list_pedestal[nro_file])
4145 4144 nro_key_p = int((utc_adq-utc_ped)/self.t_Interval_p)-1
4146 4145 print("nro_key_p",nro_key_p)
4147 4146 ff_pedestal = self.list_pedestal[nro_file]
4148 4147 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4149 4148 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4150 4149
4151 4150 print("utc_pedestal_init :",utc_ped+nro_key_p*self.t_Interval_p)
4152 4151 print("angulo_array :",angulo[nro_key_p])
4153 4152 self.nro_file = nro_file
4154 4153 self.nro_key_p = nro_key_p
4155 4154
4156 4155 #def setup(self,dataOut,path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4157 4156 def setup(self,dataOut,path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4158 4157 print("SETUP PEDESTAL")
4159 4158 self.__dataReady = False
4160 4159 self.path_ped = path_ped
4161 4160 #self.path_adq = path_adq
4162 4161 self.t_Interval_p = t_Interval_p
4163 4162 self.n_Muestras_p = n_Muestras_p
4164 4163 self.blocksPerfile= blocksPerfile
4165 4164 self.f_a_p = f_a_p
4166 4165 self.online = online
4167 4166 self.angulo_adq = numpy.zeros(self.blocksPerfile)
4168 4167 self.__profIndex = 0
4169 4168 self.tmp = 0
4170 4169 self.c_ped = 0
4171 4170 print(self.path_ped)
4172 4171 #print(self.path_adq)
4173 4172 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4174 4173 print("LIST NEW", self.list_pedestal[:20])
4175 4174 #self.list_adq = self.getfirstFilefromPath(path=self.path_adq,meta="D",ext=".hdf5")
4176 4175 print("*************Longitud list pedestal****************",len(self.list_pedestal))
4177 4176
4178 4177 if self.online:
4179 4178 print("Enable Online")
4180 4179 self.setup_online(dataOut)
4181 4180 else:
4182 4181 #self.setup_offline(dataOut,list_pedestal=self.list_pedestal,list_adq=self.list_adq)
4183 4182 self.setup_offline(dataOut,list_pedestal=self.list_pedestal)
4184 4183
4185 4184
4186 4185 def setNextFileP(self,dataOut):
4187 4186 if self.online:
4188 4187 data_pedestal = self.setNextFileonline()
4189 4188 else:
4190 4189 data_pedestal = self.setNextFileoffline(dataOut)
4191 4190
4192 4191 return data_pedestal
4193 4192
4194 4193
4195 4194 def setNextFileoffline(self,dataOut):
4196 4195 ##tmp=0
4197 4196 for j in range(self.blocksPerfile):
4198 4197 ###print("NUMERO DEL BLOQUE---->",j)
4199 4198 ###print("nro_key_p",self.nro_key_p)
4200 4199
4201 4200 #iterador = self.nro_key_p +self.f_a_p*(j-tmp)
4202 4201 iterador = self.nro_key_p +self.f_a_p*self.c_ped
4203 4202 self.c_ped = self.c_ped +1
4204 4203
4205 4204 print("iterador------------->",iterador)
4206 4205 if iterador < self.n_Muestras_p:
4207 4206 self.nro_file = self.nro_file
4208 4207 else:
4209 4208 self.nro_file = self.nro_file+1
4210 4209 print("PRUEBA-------------")
4211 4210 utc_ped_setnext=self.gettimeutcfromDirFilename(path=self.path_ped,file=self.list_pedestal[self.nro_file])
4212 4211 utc_adq_setnext=dataOut.utctime
4213 4212 print("utc_pedestal",utc_ped_setnext)
4214 4213 print("utc_adq",utc_adq_setnext)
4215 4214
4216 4215 print("self.c_ped",self.c_ped)
4217 4216 #dif = self.blocksPerfile-(self.nro_key_p+self.f_a_p*(self.c_ped-2))
4218 4217 dif = self.n_Muestras_p-(self.nro_key_p+self.f_a_p*(self.c_ped-2))
4219 4218
4220 4219 self.c_ped = 1
4221 4220 ##tmp = j
4222 4221 ##print("tmp else",tmp)
4223 4222 self.nro_key_p= self.f_a_p-dif
4224 4223 iterador = self.nro_key_p
4225 4224 print("iterador else",iterador)
4226 4225 #self.c_ped = self.c_ped +1
4227 4226
4228 4227 print("nro_file",self.nro_file)
4229 4228 #print("tmp",tmp)
4230 4229 try:
4231 4230 ff_pedestal = self.list_pedestal[self.nro_file]
4232 4231 print("ff_pedestal",ff_pedestal)
4233 4232 except:
4234 4233 print("############# EXCEPCION ######################")
4235 4234 return numpy.ones(self.blocksPerfile)*numpy.nan
4236 4235
4237 4236 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4238 4237 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4239 4238
4240 4239 self.angulo_adq[j]= angulo[iterador]
4241 4240
4242 4241 return self.angulo_adq
4243 4242
4244 4243 def setNextFileonline(self):
4245 4244 tmp = 0
4246 4245 self.nTries_p = 3
4247 4246 self.delay = 3
4248 4247 ready = 1
4249 4248 for j in range(self.blocksPerfile):
4250 4249 iterador = self.nro_key_p +self.f_a_p*(j-tmp)
4251 4250 if iterador < self.n_Muestras_p:
4252 4251 self.nro_file = self.nro_file
4253 4252 else:
4254 4253 self.nro_file = self.nro_file+1
4255 4254 dif = self.blocksPerfile-(self.nro_key_p+self.f_a_p*(j-tmp-1))
4256 4255 tmp = j
4257 4256 self.nro_key_p= self.f_a_p-dif
4258 4257 iterador = self.nro_key_p
4259 4258 #print("nro_file---------------- :",self.nro_file)
4260 4259 try:
4261 4260 # update list_pedestal
4262 4261 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4263 4262 ff_pedestal = self.list_pedestal[self.nro_file]
4264 4263 except:
4265 4264 ff_pedestal = None
4266 4265 ready = 0
4267 4266 for nTries_p in range(self.nTries_p):
4268 4267 try:
4269 4268 # update list_pedestal
4270 4269 self.list_pedestal = self.getfirstFilefromPath(path=self.path_ped,meta="PE",ext=".hdf5")
4271 4270 ff_pedestal = self.list_pedestal[self.nro_file]
4272 4271 except:
4273 4272 ff_pedestal = None
4274 4273 if ff_pedestal is not None:
4275 4274 ready=1
4276 4275 break
4277 4276 log.warning("Waiting %0.2f sec for the next file: \"%s\" , try %02d ..." % (self.delay, self.nro_file, nTries_p + 1))
4278 4277 time.sleep(self.delay)
4279 4278 continue
4280 4279 #return numpy.ones(self.blocksPerfile)*numpy.nan
4281 4280
4282 4281 if ready == 1:
4283 4282 #angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azimuth")
4284 4283 angulo = self.getDatavaluefromDirFilename(path=self.path_ped,file=ff_pedestal,value="azi_pos")
4285 4284
4286 4285 else:
4287 4286 print("there is no pedestal file")
4288 4287 angulo = numpy.ones(self.n_Muestras_p)*numpy.nan
4289 4288 self.angulo_adq[j]= angulo[iterador]
4290 4289 ####print("Angulo",self.angulo_adq)
4291 4290 ####print("Angulo",len(self.angulo_adq))
4292 4291 #self.nro_key_p=iterador + self.f_a_p
4293 4292 #if self.nro_key_p< self.n_Muestras_p:
4294 4293 # self.nro_file = self.nro_file
4295 4294 #else:
4296 4295 # self.nro_file = self.nro_file+1
4297 4296 # self.nro_key_p= self.nro_key_p
4298 4297 return self.angulo_adq
4299 4298
4300 4299
4301 4300 #def run(self, dataOut,path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4302 4301 def run(self, dataOut,path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online):
4303 4302
4304 4303 if not self.isConfig:
4305 4304 print("######################SETUP#########################################")
4306 4305 #self.setup( dataOut, path_ped,path_adq,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online)
4307 4306 self.setup( dataOut, path_ped,t_Interval_p,n_Muestras_p,blocksPerfile,f_a_p,online)
4308 4307 self.isConfig = True
4309 4308
4310 4309 dataOut.flagNoData = True
4311 4310 print("profIndex",self.__profIndex)
4312 4311
4313 4312 if self.__profIndex==0:
4314 4313 angulo_adq = self.setNextFileP(dataOut)
4315 4314 dataOut.azimuth = angulo_adq
4316 4315 print("TIEMPO:",dataOut.utctime)
4317 4316 ##print("####################################################################")
4318 4317 print("angulos",dataOut.azimuth,len(dataOut.azimuth))
4319 4318 self.__dataReady = True
4320 4319 self.__profIndex += 1
4321 4320 print("TIEMPO_bucle:",dataOut.utctime)
4322 4321 print("profIndex",self.__profIndex)
4323 4322 if self.__profIndex== blocksPerfile:
4324 4323 self.__profIndex = 0
4325 4324 if self.__dataReady:
4326 4325 #print(self.__profIndex,dataOut.azimuth[:10])
4327 4326 dataOut.flagNoData = False
4328 4327 return dataOut
4329 4328
4330 4329
4331 4330 class Block360(Operation):
4332 4331 '''
4333 4332 '''
4334 4333 isConfig = False
4335 4334 __profIndex = 0
4336 4335 __initime = None
4337 4336 __lastdatatime = None
4338 4337 __buffer = None
4339 4338 __dataReady = False
4340 4339 n = None
4341 4340 __nch = 0
4342 4341 __nHeis = 0
4343 4342 index = 0
4344 4343 mode = 0
4345 4344
4346 4345 def __init__(self,**kwargs):
4347 4346 Operation.__init__(self,**kwargs)
4348 4347
4349 4348 def setup(self, dataOut, n = None, mode = None):
4350 4349 '''
4351 4350 n= Numero de PRF's de entrada
4352 4351 '''
4353 4352 self.__initime = None
4354 4353 self.__lastdatatime = 0
4355 4354 self.__dataReady = False
4356 4355 self.__buffer = 0
4357 4356 self.__buffer_1D = 0
4358 4357 self.__profIndex = 0
4359 4358 self.index = 0
4360 4359 self.__nch = dataOut.nChannels
4361 4360 self.__nHeis = dataOut.nHeights
4362 4361 ##print("ELVALOR DE n es:", n)
4363 4362 if n == None:
4364 4363 raise ValueError("n should be specified.")
4365 4364
4366 4365 if mode == None:
4367 4366 raise ValueError("mode should be specified.")
4368 4367
4369 4368 if n != None:
4370 4369 if n<1:
4371 4370 print("n should be greater than 2")
4372 4371 raise ValueError("n should be greater than 2")
4373 4372
4374 4373 self.n = n
4375 4374 self.mode = mode
4376 4375 print("self.mode",self.mode)
4377 4376 #print("nHeights")
4378 4377 self.__buffer = numpy.zeros(( dataOut.nChannels,n, dataOut.nHeights))
4379 4378 self.__buffer2= numpy.zeros(n)
4380 4379
4381 4380 def putData(self,data,mode):
4382 4381 '''
4383 4382 Add a profile to he __buffer and increase in one the __profiel Index
4384 4383 '''
4385 4384 #print("line 4049",data.dataPP_POW.shape,data.dataPP_POW[:10])
4386 4385 #print("line 4049",data.azimuth.shape,data.azimuth)
4387 4386 if self.mode==0:
4388 4387 self.__buffer[:,self.__profIndex,:]= data.dataPP_POW
4389 4388 if self.mode==1:
4390 4389 self.__buffer[:,self.__profIndex,:]= data.data_pow
4391 4390 #print("me casi",self.index,data.azimuth[self.index])
4392 4391 #print(self.__profIndex, self.index , data.azimuth[self.index] )
4393 4392 #print("magic",data.profileIndex)
4394 4393 #print(data.azimuth[self.index])
4395 4394 #print("index",self.index)
4396 4395
4397 4396 self.__buffer2[self.__profIndex] = data.azimuth[self.index]
4398 4397 #print("q pasa")
4399 4398 self.index+=1
4400 4399 #print("index",self.index,data.azimuth[:10])
4401 4400 self.__profIndex += 1
4402 4401 return #Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β· Remove DCΒ·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·Β·
4403 4402
4404 4403 def pushData(self,data):
4405 4404 '''
4406 4405 Return the PULSEPAIR and the profiles used in the operation
4407 4406 Affected : self.__profileIndex
4408 4407 '''
4409 4408 #print("pushData")
4410 4409
4411 4410 data_360 = self.__buffer
4412 4411 data_p = self.__buffer2
4413 4412 n = self.__profIndex
4414 4413
4415 4414 self.__buffer = numpy.zeros((self.__nch, self.n,self.__nHeis))
4416 4415 self.__buffer2 = numpy.zeros(self.n)
4417 4416 self.__profIndex = 0
4418 4417 #print("pushData")
4419 4418 return data_360,n,data_p
4420 4419
4421 4420
4422 4421 def byProfiles(self,dataOut):
4423 4422
4424 4423 self.__dataReady = False
4425 4424 data_360 = None
4426 4425 data_p = None
4427 4426 #print("dataOu",dataOut.dataPP_POW)
4428 4427 self.putData(data=dataOut,mode = self.mode)
4429 4428 #print("profIndex",self.__profIndex)
4430 4429 if self.__profIndex == self.n:
4431 4430 data_360,n,data_p = self.pushData(data=dataOut)
4432 4431 self.__dataReady = True
4433 4432
4434 4433 return data_360,data_p
4435 4434
4436 4435
4437 4436 def blockOp(self, dataOut, datatime= None):
4438 4437 if self.__initime == None:
4439 4438 self.__initime = datatime
4440 4439 data_360,data_p = self.byProfiles(dataOut)
4441 4440 self.__lastdatatime = datatime
4442 4441
4443 4442 if data_360 is None:
4444 4443 return None, None,None
4445 4444
4446 4445 avgdatatime = self.__initime
4447 4446 deltatime = datatime - self.__lastdatatime
4448 4447 self.__initime = datatime
4449 4448 #print(data_360.shape,avgdatatime,data_p.shape)
4450 4449 return data_360,avgdatatime,data_p
4451 4450
4452 4451 def run(self, dataOut,n = None,mode=None,**kwargs):
4453 4452 print("BLOCK 360 HERE WE GO MOMENTOS")
4454 4453 if not self.isConfig:
4455 4454 self.setup(dataOut = dataOut, n = n ,mode= mode ,**kwargs)
4456 4455 self.index = 0
4457 4456 #print("comova",self.isConfig)
4458 4457 self.isConfig = True
4459 4458 if self.index==dataOut.azimuth.shape[0]:
4460 4459 self.index=0
4461 4460 data_360, avgdatatime,data_p = self.blockOp(dataOut, dataOut.utctime)
4462 4461 dataOut.flagNoData = True
4463 4462
4464 4463 if self.__dataReady:
4465 4464 dataOut.data_360 = data_360 # S
4466 4465 ##print("---------------------------------------------------------------------------------")
4467 4466 ##print("---------------------------DATAREADY---------------------------------------------")
4468 4467 ##print("---------------------------------------------------------------------------------")
4469 4468 ##print("data_360",dataOut.data_360.shape)
4470 4469 dataOut.data_azi = data_p
4471 4470 ##print("azi: ",dataOut.data_azi)
4472 4471 #print("jroproc_parameters",data_p[0],data_p[-1])#,data_360.shape,avgdatatime)
4473 4472 dataOut.utctime = avgdatatime
4474 4473 dataOut.flagNoData = False
4475 4474 return dataOut
@@ -1,1627 +1,1628
1 1 import sys
2 2 import numpy,math
3 3 from scipy import interpolate
4 4 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
5 5 from schainpy.model.data.jrodata import Voltage,hildebrand_sekhon
6 6 from schainpy.utils import log
7 7 from time import time
8 8
9 9
10 10
11 11 class VoltageProc(ProcessingUnit):
12 12
13 13 def __init__(self):
14 14
15 15 ProcessingUnit.__init__(self)
16 16
17 17 self.dataOut = Voltage()
18 18 self.flip = 1
19 19 self.setupReq = False
20 20
21 21 def run(self):
22 22
23 23 if self.dataIn.type == 'AMISR':
24 24 self.__updateObjFromAmisrInput()
25 25
26 26 if self.dataIn.type == 'Voltage':
27 27 self.dataOut.copy(self.dataIn)
28 28
29 29 def __updateObjFromAmisrInput(self):
30 30
31 31 self.dataOut.timeZone = self.dataIn.timeZone
32 32 self.dataOut.dstFlag = self.dataIn.dstFlag
33 33 self.dataOut.errorCount = self.dataIn.errorCount
34 34 self.dataOut.useLocalTime = self.dataIn.useLocalTime
35 35
36 36 self.dataOut.flagNoData = self.dataIn.flagNoData
37 37 self.dataOut.data = self.dataIn.data
38 38 self.dataOut.utctime = self.dataIn.utctime
39 39 self.dataOut.channelList = self.dataIn.channelList
40 40 #self.dataOut.timeInterval = self.dataIn.timeInterval
41 41 self.dataOut.heightList = self.dataIn.heightList
42 42 self.dataOut.nProfiles = self.dataIn.nProfiles
43 43
44 44 self.dataOut.nCohInt = self.dataIn.nCohInt
45 45 self.dataOut.ippSeconds = self.dataIn.ippSeconds
46 46 self.dataOut.frequency = self.dataIn.frequency
47 47
48 48 self.dataOut.azimuth = self.dataIn.azimuth
49 49 self.dataOut.zenith = self.dataIn.zenith
50 50
51 51 self.dataOut.beam.codeList = self.dataIn.beam.codeList
52 52 self.dataOut.beam.azimuthList = self.dataIn.beam.azimuthList
53 53 self.dataOut.beam.zenithList = self.dataIn.beam.zenithList
54 54
55 55
56 56 class selectChannels(Operation):
57 57
58 58 def run(self, dataOut, channelList):
59 59
60 60 channelIndexList = []
61 61 self.dataOut = dataOut
62 62 for channel in channelList:
63 63 if channel not in self.dataOut.channelList:
64 64 raise ValueError("Channel %d is not in %s" %(channel, str(self.dataOut.channelList)))
65 65
66 66 index = self.dataOut.channelList.index(channel)
67 67 channelIndexList.append(index)
68 68 self.selectChannelsByIndex(channelIndexList)
69 69 return self.dataOut
70 70
71 71 def selectChannelsByIndex(self, channelIndexList):
72 72 """
73 73 Selecciona un bloque de datos en base a canales segun el channelIndexList
74 74
75 75 Input:
76 76 channelIndexList : lista sencilla de canales a seleccionar por ej. [2,3,7]
77 77
78 78 Affected:
79 79 self.dataOut.data
80 80 self.dataOut.channelIndexList
81 81 self.dataOut.nChannels
82 82 self.dataOut.m_ProcessingHeader.totalSpectra
83 83 self.dataOut.systemHeaderObj.numChannels
84 84 self.dataOut.m_ProcessingHeader.blockSize
85 85
86 86 Return:
87 87 None
88 88 """
89 89
90 90 for channelIndex in channelIndexList:
91 91 if channelIndex not in self.dataOut.channelIndexList:
92 92 raise ValueError("The value %d in channelIndexList is not valid" %channelIndex)
93 93
94 94 if self.dataOut.type == 'Voltage':
95 95 if self.dataOut.flagDataAsBlock:
96 96 """
97 97 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
98 98 """
99 99 data = self.dataOut.data[channelIndexList,:,:]
100 100 else:
101 101 data = self.dataOut.data[channelIndexList,:]
102 102
103 103 self.dataOut.data = data
104 104 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
105 105 self.dataOut.channelList = range(len(channelIndexList))
106 106
107 107 elif self.dataOut.type == 'Spectra':
108 108 data_spc = self.dataOut.data_spc[channelIndexList, :]
109 109 data_dc = self.dataOut.data_dc[channelIndexList, :]
110 110
111 111 self.dataOut.data_spc = data_spc
112 112 self.dataOut.data_dc = data_dc
113 113
114 114 # self.dataOut.channelList = [self.dataOut.channelList[i] for i in channelIndexList]
115 115 self.dataOut.channelList = range(len(channelIndexList))
116 116 self.__selectPairsByChannel(channelIndexList)
117 117
118 118 return 1
119 119
120 120 def __selectPairsByChannel(self, channelList=None):
121 121
122 122 if channelList == None:
123 123 return
124 124
125 125 pairsIndexListSelected = []
126 126 for pairIndex in self.dataOut.pairsIndexList:
127 127 # First pair
128 128 if self.dataOut.pairsList[pairIndex][0] not in channelList:
129 129 continue
130 130 # Second pair
131 131 if self.dataOut.pairsList[pairIndex][1] not in channelList:
132 132 continue
133 133
134 134 pairsIndexListSelected.append(pairIndex)
135 135
136 136 if not pairsIndexListSelected:
137 137 self.dataOut.data_cspc = None
138 138 self.dataOut.pairsList = []
139 139 return
140 140
141 141 self.dataOut.data_cspc = self.dataOut.data_cspc[pairsIndexListSelected]
142 142 self.dataOut.pairsList = [self.dataOut.pairsList[i]
143 143 for i in pairsIndexListSelected]
144 144
145 145 return
146 146
147 147 class selectHeights(Operation):
148 148
149 149 def run(self, dataOut, minHei=None, maxHei=None, minIndex=None, maxIndex=None):
150 150 """
151 151 Selecciona un bloque de datos en base a un grupo de valores de alturas segun el rango
152 152 minHei <= height <= maxHei
153 153
154 154 Input:
155 155 minHei : valor minimo de altura a considerar
156 156 maxHei : valor maximo de altura a considerar
157 157
158 158 Affected:
159 159 Indirectamente son cambiados varios valores a travez del metodo selectHeightsByIndex
160 160
161 161 Return:
162 162 1 si el metodo se ejecuto con exito caso contrario devuelve 0
163 163 """
164 164
165 165 self.dataOut = dataOut
166 166
167 167 if minHei and maxHei:
168 168
169 169 if (minHei < self.dataOut.heightList[0]):
170 170 minHei = self.dataOut.heightList[0]
171 171
172 172 if (maxHei > self.dataOut.heightList[-1]):
173 173 maxHei = self.dataOut.heightList[-1]
174 174
175 175 minIndex = 0
176 176 maxIndex = 0
177 177 heights = self.dataOut.heightList
178 178
179 179 inda = numpy.where(heights >= minHei)
180 180 indb = numpy.where(heights <= maxHei)
181 181
182 182 try:
183 183 minIndex = inda[0][0]
184 184 except:
185 185 minIndex = 0
186 186
187 187 try:
188 188 maxIndex = indb[0][-1]
189 189 except:
190 190 maxIndex = len(heights)
191 191
192 192 self.selectHeightsByIndex(minIndex, maxIndex)
193 193
194 194 return self.dataOut
195 195
196 196 def selectHeightsByIndex(self, minIndex, maxIndex):
197 197 """
198 198 Selecciona un bloque de datos en base a un grupo indices de alturas segun el rango
199 199 minIndex <= index <= maxIndex
200 200
201 201 Input:
202 202 minIndex : valor de indice minimo de altura a considerar
203 203 maxIndex : valor de indice maximo de altura a considerar
204 204
205 205 Affected:
206 206 self.dataOut.data
207 207 self.dataOut.heightList
208 208
209 209 Return:
210 210 1 si el metodo se ejecuto con exito caso contrario devuelve 0
211 211 """
212 212
213 213 if self.dataOut.type == 'Voltage':
214 214 if (minIndex < 0) or (minIndex > maxIndex):
215 215 raise ValueError("Height index range (%d,%d) is not valid" % (minIndex, maxIndex))
216 216
217 217 if (maxIndex >= self.dataOut.nHeights):
218 218 maxIndex = self.dataOut.nHeights
219 219
220 220 #voltage
221 221 if self.dataOut.flagDataAsBlock:
222 222 """
223 223 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
224 224 """
225 225 data = self.dataOut.data[:,:, minIndex:maxIndex]
226 226 else:
227 227 data = self.dataOut.data[:, minIndex:maxIndex]
228 228
229 229 # firstHeight = self.dataOut.heightList[minIndex]
230 230
231 231 self.dataOut.data = data
232 232 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex]
233 233
234 234 if self.dataOut.nHeights <= 1:
235 235 raise ValueError("selectHeights: Too few heights. Current number of heights is %d" %(self.dataOut.nHeights))
236 236 elif self.dataOut.type == 'Spectra':
237 237 if (minIndex < 0) or (minIndex > maxIndex):
238 238 raise ValueError("Error selecting heights: Index range (%d,%d) is not valid" % (
239 239 minIndex, maxIndex))
240 240
241 241 if (maxIndex >= self.dataOut.nHeights):
242 242 maxIndex = self.dataOut.nHeights - 1
243 243
244 244 # Spectra
245 245 data_spc = self.dataOut.data_spc[:, :, minIndex:maxIndex + 1]
246 246
247 247 data_cspc = None
248 248 if self.dataOut.data_cspc is not None:
249 249 data_cspc = self.dataOut.data_cspc[:, :, minIndex:maxIndex + 1]
250 250
251 251 data_dc = None
252 252 if self.dataOut.data_dc is not None:
253 253 data_dc = self.dataOut.data_dc[:, minIndex:maxIndex + 1]
254 254
255 255 self.dataOut.data_spc = data_spc
256 256 self.dataOut.data_cspc = data_cspc
257 257 self.dataOut.data_dc = data_dc
258 258
259 259 self.dataOut.heightList = self.dataOut.heightList[minIndex:maxIndex + 1]
260 260
261 261 return 1
262 262
263 263
264 264 class filterByHeights(Operation):
265 265
266 266 def run(self, dataOut, window):
267 267
268 268 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
269 269
270 270 if window == None:
271 271 window = (dataOut.radarControllerHeaderObj.txA/dataOut.radarControllerHeaderObj.nBaud) / deltaHeight
272 272
273 273 newdelta = deltaHeight * window
274 274 r = dataOut.nHeights % window
275 275 newheights = (dataOut.nHeights-r)/window
276 276
277 277 if newheights <= 1:
278 278 raise ValueError("filterByHeights: Too few heights. Current number of heights is %d and window is %d" %(dataOut.nHeights, window))
279 279
280 280 if dataOut.flagDataAsBlock:
281 281 """
282 282 Si la data es obtenida por bloques, dimension = [nChannels, nProfiles, nHeis]
283 283 """
284 284 buffer = dataOut.data[:, :, 0:int(dataOut.nHeights-r)]
285 285 buffer = buffer.reshape(dataOut.nChannels, dataOut.nProfiles, int(dataOut.nHeights/window), window)
286 286 buffer = numpy.sum(buffer,3)
287 287
288 288 else:
289 289 buffer = dataOut.data[:,0:int(dataOut.nHeights-r)]
290 290 buffer = buffer.reshape(dataOut.nChannels,int(dataOut.nHeights/window),int(window))
291 291 buffer = numpy.sum(buffer,2)
292 292
293 293 dataOut.data = buffer
294 294 dataOut.heightList = dataOut.heightList[0] + numpy.arange( newheights )*newdelta
295 295 dataOut.windowOfFilter = window
296 296
297 297 return dataOut
298 298
299 299
300 300 class setH0(Operation):
301 301
302 302 def run(self, dataOut, h0, deltaHeight = None):
303 303
304 304 if not deltaHeight:
305 305 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
306 306
307 307 nHeights = dataOut.nHeights
308 308
309 309 newHeiRange = h0 + numpy.arange(nHeights)*deltaHeight
310 310
311 311 dataOut.heightList = newHeiRange
312 312
313 313 return dataOut
314 314
315 315
316 316 class deFlip(Operation):
317 317
318 318 def run(self, dataOut, channelList = []):
319 319
320 320 data = dataOut.data.copy()
321 321
322 322 if dataOut.flagDataAsBlock:
323 323 flip = self.flip
324 324 profileList = list(range(dataOut.nProfiles))
325 325
326 326 if not channelList:
327 327 for thisProfile in profileList:
328 328 data[:,thisProfile,:] = data[:,thisProfile,:]*flip
329 329 flip *= -1.0
330 330 else:
331 331 for thisChannel in channelList:
332 332 if thisChannel not in dataOut.channelList:
333 333 continue
334 334
335 335 for thisProfile in profileList:
336 336 data[thisChannel,thisProfile,:] = data[thisChannel,thisProfile,:]*flip
337 337 flip *= -1.0
338 338
339 339 self.flip = flip
340 340
341 341 else:
342 342 if not channelList:
343 343 data[:,:] = data[:,:]*self.flip
344 344 else:
345 345 for thisChannel in channelList:
346 346 if thisChannel not in dataOut.channelList:
347 347 continue
348 348
349 349 data[thisChannel,:] = data[thisChannel,:]*self.flip
350 350
351 351 self.flip *= -1.
352 352
353 353 dataOut.data = data
354 354
355 355 return dataOut
356 356
357 357
358 358 class setAttribute(Operation):
359 359 '''
360 360 Set an arbitrary attribute(s) to dataOut
361 361 '''
362 362
363 363 def __init__(self):
364 364
365 365 Operation.__init__(self)
366 366 self._ready = False
367 367
368 368 def run(self, dataOut, **kwargs):
369 369
370 370 for key, value in kwargs.items():
371 371 setattr(dataOut, key, value)
372 372
373 373 return dataOut
374 374
375 375
376 376 @MPDecorator
377 377 class printAttribute(Operation):
378 378 '''
379 379 Print an arbitrary attribute of dataOut
380 380 '''
381 381
382 382 def __init__(self):
383 383
384 384 Operation.__init__(self)
385 385
386 386 def run(self, dataOut, attributes):
387 387
388 388 if isinstance(attributes, str):
389 389 attributes = [attributes]
390 390 for attr in attributes:
391 391 if hasattr(dataOut, attr):
392 392 log.log(getattr(dataOut, attr), attr)
393 393
394 394
395 395 class interpolateHeights(Operation):
396 396
397 397 def run(self, dataOut, topLim, botLim):
398 398 #69 al 72 para julia
399 399 #82-84 para meteoros
400 400 if len(numpy.shape(dataOut.data))==2:
401 401 sampInterp = (dataOut.data[:,botLim-1] + dataOut.data[:,topLim+1])/2
402 402 sampInterp = numpy.transpose(numpy.tile(sampInterp,(topLim-botLim + 1,1)))
403 403 #dataOut.data[:,botLim:limSup+1] = sampInterp
404 404 dataOut.data[:,botLim:topLim+1] = sampInterp
405 405 else:
406 406 nHeights = dataOut.data.shape[2]
407 407 x = numpy.hstack((numpy.arange(botLim),numpy.arange(topLim+1,nHeights)))
408 408 y = dataOut.data[:,:,list(range(botLim))+list(range(topLim+1,nHeights))]
409 409 f = interpolate.interp1d(x, y, axis = 2)
410 410 xnew = numpy.arange(botLim,topLim+1)
411 411 ynew = f(xnew)
412 412 dataOut.data[:,:,botLim:topLim+1] = ynew
413 413
414 414 return dataOut
415 415
416 416
417 417 class CohInt(Operation):
418 418
419 419 isConfig = False
420 420 __profIndex = 0
421 421 __byTime = False
422 422 __initime = None
423 423 __lastdatatime = None
424 424 __integrationtime = None
425 425 __buffer = None
426 426 __bufferStride = []
427 427 __dataReady = False
428 428 __profIndexStride = 0
429 429 __dataToPutStride = False
430 430 n = None
431 431
432 432 def __init__(self, **kwargs):
433 433
434 434 Operation.__init__(self, **kwargs)
435 435
436 436 def setup(self, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False):
437 437 """
438 438 Set the parameters of the integration class.
439 439
440 440 Inputs:
441 441
442 442 n : Number of coherent integrations
443 443 timeInterval : Time of integration. If the parameter "n" is selected this one does not work
444 444 overlapping :
445 445 """
446 446
447 447 self.__initime = None
448 448 self.__lastdatatime = 0
449 449 self.__buffer = None
450 450 self.__dataReady = False
451 451 self.byblock = byblock
452 452 self.stride = stride
453 453
454 454 if n == None and timeInterval == None:
455 455 raise ValueError("n or timeInterval should be specified ...")
456 456
457 457 if n != None:
458 458 self.n = n
459 459 self.__byTime = False
460 460 else:
461 461 self.__integrationtime = timeInterval #* 60. #if (type(timeInterval)!=integer) -> change this line
462 462 self.n = 9999
463 463 self.__byTime = True
464 464
465 465 if overlapping:
466 466 self.__withOverlapping = True
467 467 self.__buffer = None
468 468 else:
469 469 self.__withOverlapping = False
470 470 self.__buffer = 0
471 471
472 472 self.__profIndex = 0
473 473
474 474 def putData(self, data):
475 475
476 476 """
477 477 Add a profile to the __buffer and increase in one the __profileIndex
478 478
479 479 """
480 480
481 481 if not self.__withOverlapping:
482 482 self.__buffer += data.copy()
483 483 self.__profIndex += 1
484 484 return
485 485
486 486 #Overlapping data
487 487 nChannels, nHeis = data.shape
488 488 data = numpy.reshape(data, (1, nChannels, nHeis))
489 489
490 490 #If the buffer is empty then it takes the data value
491 491 if self.__buffer is None:
492 492 self.__buffer = data
493 493 self.__profIndex += 1
494 494 return
495 495
496 496 #If the buffer length is lower than n then stakcing the data value
497 497 if self.__profIndex < self.n:
498 498 self.__buffer = numpy.vstack((self.__buffer, data))
499 499 self.__profIndex += 1
500 500 return
501 501
502 502 #If the buffer length is equal to n then replacing the last buffer value with the data value
503 503 self.__buffer = numpy.roll(self.__buffer, -1, axis=0)
504 504 self.__buffer[self.n-1] = data
505 505 self.__profIndex = self.n
506 506 return
507 507
508 508
509 509 def pushData(self):
510 510 """
511 511 Return the sum of the last profiles and the profiles used in the sum.
512 512
513 513 Affected:
514 514
515 515 self.__profileIndex
516 516
517 517 """
518 518
519 519 if not self.__withOverlapping:
520 520 data = self.__buffer
521 521 n = self.__profIndex
522 522
523 523 self.__buffer = 0
524 524 self.__profIndex = 0
525 525
526 526 return data, n
527 527
528 528 #Integration with Overlapping
529 529 data = numpy.sum(self.__buffer, axis=0)
530 530 # print data
531 531 # raise
532 532 n = self.__profIndex
533 533
534 534 return data, n
535 535
536 536 def byProfiles(self, data):
537 537
538 538 self.__dataReady = False
539 539 avgdata = None
540 540 # n = None
541 541 # print data
542 542 # raise
543 543 self.putData(data)
544 544
545 545 if self.__profIndex == self.n:
546 546 avgdata, n = self.pushData()
547 547 self.__dataReady = True
548 548
549 549 return avgdata
550 550
551 551 def byTime(self, data, datatime):
552 552
553 553 self.__dataReady = False
554 554 avgdata = None
555 555 n = None
556 556
557 557 self.putData(data)
558 558
559 559 if (datatime - self.__initime) >= self.__integrationtime:
560 560 avgdata, n = self.pushData()
561 561 self.n = n
562 562 self.__dataReady = True
563 563
564 564 return avgdata
565 565
566 566 def integrateByStride(self, data, datatime):
567 567 # print data
568 568 if self.__profIndex == 0:
569 569 self.__buffer = [[data.copy(), datatime]]
570 570 else:
571 571 self.__buffer.append([data.copy(),datatime])
572 572 self.__profIndex += 1
573 573 self.__dataReady = False
574 574
575 575 if self.__profIndex == self.n * self.stride :
576 576 self.__dataToPutStride = True
577 577 self.__profIndexStride = 0
578 578 self.__profIndex = 0
579 579 self.__bufferStride = []
580 580 for i in range(self.stride):
581 581 current = self.__buffer[i::self.stride]
582 582 data = numpy.sum([t[0] for t in current], axis=0)
583 583 avgdatatime = numpy.average([t[1] for t in current])
584 584 # print data
585 585 self.__bufferStride.append((data, avgdatatime))
586 586
587 587 if self.__dataToPutStride:
588 588 self.__dataReady = True
589 589 self.__profIndexStride += 1
590 590 if self.__profIndexStride == self.stride:
591 591 self.__dataToPutStride = False
592 592 # print self.__bufferStride[self.__profIndexStride - 1]
593 593 # raise
594 594 return self.__bufferStride[self.__profIndexStride - 1]
595 595
596 596
597 597 return None, None
598 598
599 599 def integrate(self, data, datatime=None):
600 600
601 601 if self.__initime == None:
602 602 self.__initime = datatime
603 603
604 604 if self.__byTime:
605 605 avgdata = self.byTime(data, datatime)
606 606 else:
607 607 avgdata = self.byProfiles(data)
608 608
609 609
610 610 self.__lastdatatime = datatime
611 611
612 612 if avgdata is None:
613 613 return None, None
614 614
615 615 avgdatatime = self.__initime
616 616
617 617 deltatime = datatime - self.__lastdatatime
618 618
619 619 if not self.__withOverlapping:
620 620 self.__initime = datatime
621 621 else:
622 622 self.__initime += deltatime
623 623
624 624 return avgdata, avgdatatime
625 625
626 626 def integrateByBlock(self, dataOut):
627 627
628 628 times = int(dataOut.data.shape[1]/self.n)
629 629 avgdata = numpy.zeros((dataOut.nChannels, times, dataOut.nHeights), dtype=numpy.complex)
630 630
631 631 id_min = 0
632 632 id_max = self.n
633 633
634 634 for i in range(times):
635 635 junk = dataOut.data[:,id_min:id_max,:]
636 636 avgdata[:,i,:] = junk.sum(axis=1)
637 637 id_min += self.n
638 638 id_max += self.n
639 639
640 640 timeInterval = dataOut.ippSeconds*self.n
641 641 avgdatatime = (times - 1) * timeInterval + dataOut.utctime
642 642 self.__dataReady = True
643 643 return avgdata, avgdatatime
644 644
645 645 def run(self, dataOut, n=None, timeInterval=None, stride=None, overlapping=False, byblock=False, **kwargs):
646 646
647 647 if not self.isConfig:
648 648 self.setup(n=n, stride=stride, timeInterval=timeInterval, overlapping=overlapping, byblock=byblock, **kwargs)
649 649 self.isConfig = True
650 650
651 651 if dataOut.flagDataAsBlock:
652 652 """
653 653 Si la data es leida por bloques, dimension = [nChannels, nProfiles, nHeis]
654 654 """
655 655 avgdata, avgdatatime = self.integrateByBlock(dataOut)
656 656 dataOut.nProfiles /= self.n
657 657 else:
658 658 if stride is None:
659 659 avgdata, avgdatatime = self.integrate(dataOut.data, dataOut.utctime)
660 660 else:
661 661 avgdata, avgdatatime = self.integrateByStride(dataOut.data, dataOut.utctime)
662 662
663 663
664 664 # dataOut.timeInterval *= n
665 665 dataOut.flagNoData = True
666 666
667 667 if self.__dataReady:
668 668 dataOut.data = avgdata
669 669 if not dataOut.flagCohInt:
670 670 dataOut.nCohInt *= self.n
671 671 dataOut.flagCohInt = True
672 672 dataOut.utctime = avgdatatime
673 673 # print avgdata, avgdatatime
674 674 # raise
675 675 # dataOut.timeInterval = dataOut.ippSeconds * dataOut.nCohInt
676 676 dataOut.flagNoData = False
677 677 return dataOut
678 678
679 679 class Decoder(Operation):
680 680
681 681 isConfig = False
682 682 __profIndex = 0
683 683
684 684 code = None
685 685
686 686 nCode = None
687 687 nBaud = None
688 688
689 689 def __init__(self, **kwargs):
690 690
691 691 Operation.__init__(self, **kwargs)
692 692
693 693 self.times = None
694 694 self.osamp = None
695 695 # self.__setValues = False
696 696 self.isConfig = False
697 697 self.setupReq = False
698 698 def setup(self, code, osamp, dataOut):
699 699
700 700 self.__profIndex = 0
701 701
702 702 self.code = code
703 703
704 704 self.nCode = len(code)
705 705 self.nBaud = len(code[0])
706 706
707 707 if (osamp != None) and (osamp >1):
708 708 self.osamp = osamp
709 709 self.code = numpy.repeat(code, repeats=self.osamp, axis=1)
710 710 self.nBaud = self.nBaud*self.osamp
711 711
712 712 self.__nChannels = dataOut.nChannels
713 713 self.__nProfiles = dataOut.nProfiles
714 714 self.__nHeis = dataOut.nHeights
715 715
716 716 if self.__nHeis < self.nBaud:
717 717 raise ValueError('Number of heights (%d) should be greater than number of bauds (%d)' %(self.__nHeis, self.nBaud))
718 718
719 719 #Frequency
720 720 __codeBuffer = numpy.zeros((self.nCode, self.__nHeis), dtype=numpy.complex)
721 721
722 722 __codeBuffer[:,0:self.nBaud] = self.code
723 723
724 724 self.fft_code = numpy.conj(numpy.fft.fft(__codeBuffer, axis=1))
725 725
726 726 if dataOut.flagDataAsBlock:
727 727
728 728 self.ndatadec = self.__nHeis #- self.nBaud + 1
729 729
730 730 self.datadecTime = numpy.zeros((self.__nChannels, self.__nProfiles, self.ndatadec), dtype=numpy.complex)
731 731
732 732 else:
733 733
734 734 #Time
735 735 self.ndatadec = self.__nHeis #- self.nBaud + 1
736 736
737 737 self.datadecTime = numpy.zeros((self.__nChannels, self.ndatadec), dtype=numpy.complex)
738 738
739 739 def __convolutionInFreq(self, data):
740 740
741 741 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
742 742
743 743 fft_data = numpy.fft.fft(data, axis=1)
744 744
745 745 conv = fft_data*fft_code
746 746
747 747 data = numpy.fft.ifft(conv,axis=1)
748 748
749 749 return data
750 750
751 751 def __convolutionInFreqOpt(self, data):
752 752
753 753 raise NotImplementedError
754 754
755 755 def __convolutionInTime(self, data):
756 756
757 757 code = self.code[self.__profIndex]
758 758 for i in range(self.__nChannels):
759 759 self.datadecTime[i,:] = numpy.correlate(data[i,:], code, mode='full')[self.nBaud-1:]
760 760
761 761 return self.datadecTime
762 762
763 763 def __convolutionByBlockInTime(self, data):
764 764
765 765 repetitions = int(self.__nProfiles / self.nCode)
766 766 junk = numpy.lib.stride_tricks.as_strided(self.code, (repetitions, self.code.size), (0, self.code.itemsize))
767 767 junk = junk.flatten()
768 768 code_block = numpy.reshape(junk, (self.nCode*repetitions, self.nBaud))
769 769 profilesList = range(self.__nProfiles)
770 770
771 771 for i in range(self.__nChannels):
772 772 for j in profilesList:
773 773 self.datadecTime[i,j,:] = numpy.correlate(data[i,j,:], code_block[j,:], mode='full')[self.nBaud-1:]
774 774 return self.datadecTime
775 775
776 776 def __convolutionByBlockInFreq(self, data):
777 777
778 778 raise NotImplementedError("Decoder by frequency fro Blocks not implemented")
779 779
780 780
781 781 fft_code = self.fft_code[self.__profIndex].reshape(1,-1)
782 782
783 783 fft_data = numpy.fft.fft(data, axis=2)
784 784
785 785 conv = fft_data*fft_code
786 786
787 787 data = numpy.fft.ifft(conv,axis=2)
788 788
789 789 return data
790 790
791 791
792 792 def run(self, dataOut, code=None, nCode=None, nBaud=None, mode = 0, osamp=None, times=None):
793 793
794 794 if dataOut.flagDecodeData:
795 795 print("This data is already decoded, recoding again ...")
796 796
797 797 if not self.isConfig:
798 798
799 799 if code is None:
800 800 if dataOut.code is None:
801 801 raise ValueError("Code could not be read from %s instance. Enter a value in Code parameter" %dataOut.type)
802 802
803 803 code = dataOut.code
804 804 else:
805 805 code = numpy.array(code).reshape(nCode,nBaud)
806 806 self.setup(code, osamp, dataOut)
807 807
808 808 self.isConfig = True
809 809
810 810 if mode == 3:
811 811 sys.stderr.write("Decoder Warning: mode=%d is not valid, using mode=0\n" %mode)
812 812
813 813 if times != None:
814 814 sys.stderr.write("Decoder Warning: Argument 'times' in not used anymore\n")
815 815
816 816 if self.code is None:
817 817 print("Fail decoding: Code is not defined.")
818 818 return
819 819
820 820 self.__nProfiles = dataOut.nProfiles
821 821 datadec = None
822 822
823 823 if mode == 3:
824 824 mode = 0
825 825
826 826 if dataOut.flagDataAsBlock:
827 827 """
828 828 Decoding when data have been read as block,
829 829 """
830 830
831 831 if mode == 0:
832 832 datadec = self.__convolutionByBlockInTime(dataOut.data)
833 833 if mode == 1:
834 834 datadec = self.__convolutionByBlockInFreq(dataOut.data)
835 835 else:
836 836 """
837 837 Decoding when data have been read profile by profile
838 838 """
839 839 if mode == 0:
840 840 datadec = self.__convolutionInTime(dataOut.data)
841 841
842 842 if mode == 1:
843 843 datadec = self.__convolutionInFreq(dataOut.data)
844 844
845 845 if mode == 2:
846 846 datadec = self.__convolutionInFreqOpt(dataOut.data)
847 847
848 848 if datadec is None:
849 849 raise ValueError("Codification mode selected is not valid: mode=%d. Try selecting 0 or 1" %mode)
850 850
851 851 dataOut.code = self.code
852 852 dataOut.nCode = self.nCode
853 853 dataOut.nBaud = self.nBaud
854 854
855 855 dataOut.data = datadec
856 856
857 857 dataOut.heightList = dataOut.heightList[0:datadec.shape[-1]]
858 858
859 859 dataOut.flagDecodeData = True #asumo q la data esta decodificada
860 860
861 861 if self.__profIndex == self.nCode-1:
862 862 self.__profIndex = 0
863 863 return dataOut
864 864
865 865 self.__profIndex += 1
866 866
867 867 return dataOut
868 868 # dataOut.flagDeflipData = True #asumo q la data no esta sin flip
869 869
870 870
871 871 class ProfileConcat(Operation):
872 872
873 873 isConfig = False
874 874 buffer = None
875 875
876 876 def __init__(self, **kwargs):
877 877
878 878 Operation.__init__(self, **kwargs)
879 879 self.profileIndex = 0
880 880
881 881 def reset(self):
882 882 self.buffer = numpy.zeros_like(self.buffer)
883 883 self.start_index = 0
884 884 self.times = 1
885 885
886 886 def setup(self, data, m, n=1):
887 887 self.buffer = numpy.zeros((data.shape[0],data.shape[1]*m),dtype=type(data[0,0]))
888 888 self.nHeights = data.shape[1]#.nHeights
889 889 self.start_index = 0
890 890 self.times = 1
891 891
892 892 def concat(self, data):
893 893
894 894 self.buffer[:,self.start_index:self.nHeights*self.times] = data.copy()
895 895 self.start_index = self.start_index + self.nHeights
896 896
897 897 def run(self, dataOut, m):
898 898 dataOut.flagNoData = True
899 899
900 900 if not self.isConfig:
901 901 self.setup(dataOut.data, m, 1)
902 902 self.isConfig = True
903 903
904 904 if dataOut.flagDataAsBlock:
905 905 raise ValueError("ProfileConcat can only be used when voltage have been read profile by profile, getBlock = False")
906 906
907 907 else:
908 908 self.concat(dataOut.data)
909 909 self.times += 1
910 910 if self.times > m:
911 911 dataOut.data = self.buffer
912 912 self.reset()
913 913 dataOut.flagNoData = False
914 914 # se deben actualizar mas propiedades del header y del objeto dataOut, por ejemplo, las alturas
915 915 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
916 916 xf = dataOut.heightList[0] + dataOut.nHeights * deltaHeight * m
917 917 dataOut.heightList = numpy.arange(dataOut.heightList[0], xf, deltaHeight)
918 918 dataOut.ippSeconds *= m
919 919 return dataOut
920 920
921 921 class ProfileSelector(Operation):
922 922
923 923 profileIndex = None
924 924 # Tamanho total de los perfiles
925 925 nProfiles = None
926 926
927 927 def __init__(self, **kwargs):
928 928
929 929 Operation.__init__(self, **kwargs)
930 930 self.profileIndex = 0
931 931
932 932 def incProfileIndex(self):
933 933
934 934 self.profileIndex += 1
935 935
936 936 if self.profileIndex >= self.nProfiles:
937 937 self.profileIndex = 0
938 938
939 939 def isThisProfileInRange(self, profileIndex, minIndex, maxIndex):
940 940
941 941 if profileIndex < minIndex:
942 942 return False
943 943
944 944 if profileIndex > maxIndex:
945 945 return False
946 946
947 947 return True
948 948
949 949 def isThisProfileInList(self, profileIndex, profileList):
950 950
951 951 if profileIndex not in profileList:
952 952 return False
953 953
954 954 return True
955 955
956 956 def run(self, dataOut, profileList=None, profileRangeList=None, beam=None, byblock=False, rangeList = None, nProfiles=None):
957 957
958 958 """
959 959 ProfileSelector:
960 960
961 961 Inputs:
962 962 profileList : Index of profiles selected. Example: profileList = (0,1,2,7,8)
963 963
964 964 profileRangeList : Minimum and maximum profile indexes. Example: profileRangeList = (4, 30)
965 965
966 966 rangeList : List of profile ranges. Example: rangeList = ((4, 30), (32, 64), (128, 256))
967 967
968 968 """
969 969
970 970 if rangeList is not None:
971 971 if type(rangeList[0]) not in (tuple, list):
972 972 rangeList = [rangeList]
973 973
974 974 dataOut.flagNoData = True
975 975
976 976 if dataOut.flagDataAsBlock:
977 977 """
978 978 data dimension = [nChannels, nProfiles, nHeis]
979 979 """
980 980 if profileList != None:
981 981 dataOut.data = dataOut.data[:,profileList,:]
982 982
983 983 if profileRangeList != None:
984 984 minIndex = profileRangeList[0]
985 985 maxIndex = profileRangeList[1]
986 986 profileList = list(range(minIndex, maxIndex+1))
987 987
988 988 dataOut.data = dataOut.data[:,minIndex:maxIndex+1,:]
989 989
990 990 if rangeList != None:
991 991
992 992 profileList = []
993 993
994 994 for thisRange in rangeList:
995 995 minIndex = thisRange[0]
996 996 maxIndex = thisRange[1]
997 997
998 998 profileList.extend(list(range(minIndex, maxIndex+1)))
999 999
1000 1000 dataOut.data = dataOut.data[:,profileList,:]
1001 1001
1002 1002 dataOut.nProfiles = len(profileList)
1003 1003 dataOut.profileIndex = dataOut.nProfiles - 1
1004 1004 dataOut.flagNoData = False
1005 1005
1006 1006 return dataOut
1007 1007
1008 1008 """
1009 1009 data dimension = [nChannels, nHeis]
1010 1010 """
1011 1011
1012 1012 if profileList != None:
1013 1013
1014 1014 if self.isThisProfileInList(dataOut.profileIndex, profileList):
1015 1015
1016 1016 self.nProfiles = len(profileList)
1017 1017 dataOut.nProfiles = self.nProfiles
1018 1018 dataOut.profileIndex = self.profileIndex
1019 1019 dataOut.flagNoData = False
1020 1020
1021 1021 self.incProfileIndex()
1022 1022 return dataOut
1023 1023
1024 1024 if profileRangeList != None:
1025 1025
1026 1026 minIndex = profileRangeList[0]
1027 1027 maxIndex = profileRangeList[1]
1028 1028
1029 1029 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1030 1030
1031 1031 self.nProfiles = maxIndex - minIndex + 1
1032 1032 dataOut.nProfiles = self.nProfiles
1033 1033 dataOut.profileIndex = self.profileIndex
1034 1034 dataOut.flagNoData = False
1035 1035
1036 1036 self.incProfileIndex()
1037 1037 return dataOut
1038 1038
1039 1039 if rangeList != None:
1040 1040
1041 1041 nProfiles = 0
1042 1042
1043 1043 for thisRange in rangeList:
1044 1044 minIndex = thisRange[0]
1045 1045 maxIndex = thisRange[1]
1046 1046
1047 1047 nProfiles += maxIndex - minIndex + 1
1048 1048
1049 1049 for thisRange in rangeList:
1050 1050
1051 1051 minIndex = thisRange[0]
1052 1052 maxIndex = thisRange[1]
1053 1053
1054 1054 if self.isThisProfileInRange(dataOut.profileIndex, minIndex, maxIndex):
1055 1055
1056 1056 self.nProfiles = nProfiles
1057 1057 dataOut.nProfiles = self.nProfiles
1058 1058 dataOut.profileIndex = self.profileIndex
1059 1059 dataOut.flagNoData = False
1060 1060
1061 1061 self.incProfileIndex()
1062 1062
1063 1063 break
1064 1064
1065 1065 return dataOut
1066 1066
1067 1067
1068 1068 if beam != None: #beam is only for AMISR data
1069 1069 if self.isThisProfileInList(dataOut.profileIndex, dataOut.beamRangeDict[beam]):
1070 1070 dataOut.flagNoData = False
1071 1071 dataOut.profileIndex = self.profileIndex
1072 1072
1073 1073 self.incProfileIndex()
1074 1074
1075 1075 return dataOut
1076 1076
1077 1077 raise ValueError("ProfileSelector needs profileList, profileRangeList or rangeList parameter")
1078 1078
1079 1079
1080 1080 class Reshaper(Operation):
1081 1081
1082 1082 def __init__(self, **kwargs):
1083 1083
1084 1084 Operation.__init__(self, **kwargs)
1085 1085
1086 1086 self.__buffer = None
1087 1087 self.__nitems = 0
1088 1088
1089 1089 def __appendProfile(self, dataOut, nTxs):
1090 1090
1091 1091 if self.__buffer is None:
1092 1092 shape = (dataOut.nChannels, int(dataOut.nHeights/nTxs) )
1093 1093 self.__buffer = numpy.empty(shape, dtype = dataOut.data.dtype)
1094 1094
1095 1095 ini = dataOut.nHeights * self.__nitems
1096 1096 end = ini + dataOut.nHeights
1097 1097
1098 1098 self.__buffer[:, ini:end] = dataOut.data
1099 1099
1100 1100 self.__nitems += 1
1101 1101
1102 1102 return int(self.__nitems*nTxs)
1103 1103
1104 1104 def __getBuffer(self):
1105 1105
1106 1106 if self.__nitems == int(1./self.__nTxs):
1107 1107
1108 1108 self.__nitems = 0
1109 1109
1110 1110 return self.__buffer.copy()
1111 1111
1112 1112 return None
1113 1113
1114 1114 def __checkInputs(self, dataOut, shape, nTxs):
1115 1115
1116 1116 if shape is None and nTxs is None:
1117 1117 raise ValueError("Reshaper: shape of factor should be defined")
1118 1118
1119 1119 if nTxs:
1120 1120 if nTxs < 0:
1121 1121 raise ValueError("nTxs should be greater than 0")
1122 1122
1123 1123 if nTxs < 1 and dataOut.nProfiles % (1./nTxs) != 0:
1124 1124 raise ValueError("nProfiles= %d is not divisibled by (1./nTxs) = %f" %(dataOut.nProfiles, (1./nTxs)))
1125 1125
1126 1126 shape = [dataOut.nChannels, dataOut.nProfiles*nTxs, dataOut.nHeights/nTxs]
1127 1127
1128 1128 return shape, nTxs
1129 1129
1130 1130 if len(shape) != 2 and len(shape) != 3:
1131 1131 raise ValueError("shape dimension should be equal to 2 or 3. shape = (nProfiles, nHeis) or (nChannels, nProfiles, nHeis). Actually shape = (%d, %d, %d)" %(dataOut.nChannels, dataOut.nProfiles, dataOut.nHeights))
1132 1132
1133 1133 if len(shape) == 2:
1134 1134 shape_tuple = [dataOut.nChannels]
1135 1135 shape_tuple.extend(shape)
1136 1136 else:
1137 1137 shape_tuple = list(shape)
1138 1138
1139 1139 nTxs = 1.0*shape_tuple[1]/dataOut.nProfiles
1140 1140
1141 1141 return shape_tuple, nTxs
1142 1142
1143 1143 def run(self, dataOut, shape=None, nTxs=None):
1144 1144
1145 1145 shape_tuple, self.__nTxs = self.__checkInputs(dataOut, shape, nTxs)
1146 1146
1147 1147 dataOut.flagNoData = True
1148 1148 profileIndex = None
1149 1149
1150 1150 if dataOut.flagDataAsBlock:
1151 1151
1152 1152 dataOut.data = numpy.reshape(dataOut.data, shape_tuple)
1153 1153 dataOut.flagNoData = False
1154 1154
1155 1155 profileIndex = int(dataOut.nProfiles*self.__nTxs) - 1
1156 1156
1157 1157 else:
1158 1158
1159 1159 if self.__nTxs < 1:
1160 1160
1161 1161 self.__appendProfile(dataOut, self.__nTxs)
1162 1162 new_data = self.__getBuffer()
1163 1163
1164 1164 if new_data is not None:
1165 1165 dataOut.data = new_data
1166 1166 dataOut.flagNoData = False
1167 1167
1168 1168 profileIndex = dataOut.profileIndex*nTxs
1169 1169
1170 1170 else:
1171 1171 raise ValueError("nTxs should be greater than 0 and lower than 1, or use VoltageReader(..., getblock=True)")
1172 1172
1173 1173 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1174 1174
1175 1175 dataOut.heightList = numpy.arange(dataOut.nHeights/self.__nTxs) * deltaHeight + dataOut.heightList[0]
1176 1176
1177 1177 dataOut.nProfiles = int(dataOut.nProfiles*self.__nTxs)
1178 1178
1179 1179 dataOut.profileIndex = profileIndex
1180 1180
1181 1181 dataOut.ippSeconds /= self.__nTxs
1182 1182
1183 1183 return dataOut
1184 1184
1185 1185 class SplitProfiles(Operation):
1186 1186
1187 1187 def __init__(self, **kwargs):
1188 1188
1189 1189 Operation.__init__(self, **kwargs)
1190 1190
1191 1191 def run(self, dataOut, n):
1192 1192
1193 1193 dataOut.flagNoData = True
1194 1194 profileIndex = None
1195 1195
1196 1196 if dataOut.flagDataAsBlock:
1197 1197
1198 1198 #nchannels, nprofiles, nsamples
1199 1199 shape = dataOut.data.shape
1200 1200
1201 1201 if shape[2] % n != 0:
1202 1202 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[2]))
1203 1203
1204 1204 new_shape = shape[0], shape[1]*n, int(shape[2]/n)
1205 1205
1206 1206 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1207 1207 dataOut.flagNoData = False
1208 1208
1209 1209 profileIndex = int(dataOut.nProfiles/n) - 1
1210 1210
1211 1211 else:
1212 1212
1213 1213 raise ValueError("Could not split the data when is read Profile by Profile. Use VoltageReader(..., getblock=True)")
1214 1214
1215 1215 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1216 1216
1217 1217 dataOut.heightList = numpy.arange(dataOut.nHeights/n) * deltaHeight + dataOut.heightList[0]
1218 1218
1219 1219 dataOut.nProfiles = int(dataOut.nProfiles*n)
1220 1220
1221 1221 dataOut.profileIndex = profileIndex
1222 1222
1223 1223 dataOut.ippSeconds /= n
1224 1224
1225 1225 return dataOut
1226 1226
1227 1227 class CombineProfiles(Operation):
1228 1228 def __init__(self, **kwargs):
1229 1229
1230 1230 Operation.__init__(self, **kwargs)
1231 1231
1232 1232 self.__remData = None
1233 1233 self.__profileIndex = 0
1234 1234
1235 1235 def run(self, dataOut, n):
1236 1236
1237 1237 dataOut.flagNoData = True
1238 1238 profileIndex = None
1239 1239
1240 1240 if dataOut.flagDataAsBlock:
1241 1241
1242 1242 #nchannels, nprofiles, nsamples
1243 1243 shape = dataOut.data.shape
1244 1244 new_shape = shape[0], shape[1]/n, shape[2]*n
1245 1245
1246 1246 if shape[1] % n != 0:
1247 1247 raise ValueError("Could not split the data, n=%d has to be multiple of %d" %(n, shape[1]))
1248 1248
1249 1249 dataOut.data = numpy.reshape(dataOut.data, new_shape)
1250 1250 dataOut.flagNoData = False
1251 1251
1252 1252 profileIndex = int(dataOut.nProfiles*n) - 1
1253 1253
1254 1254 else:
1255 1255
1256 1256 #nchannels, nsamples
1257 1257 if self.__remData is None:
1258 1258 newData = dataOut.data
1259 1259 else:
1260 1260 newData = numpy.concatenate((self.__remData, dataOut.data), axis=1)
1261 1261
1262 1262 self.__profileIndex += 1
1263 1263
1264 1264 if self.__profileIndex < n:
1265 1265 self.__remData = newData
1266 1266 #continue
1267 1267 return
1268 1268
1269 1269 self.__profileIndex = 0
1270 1270 self.__remData = None
1271 1271
1272 1272 dataOut.data = newData
1273 1273 dataOut.flagNoData = False
1274 1274
1275 1275 profileIndex = dataOut.profileIndex/n
1276 1276
1277 1277
1278 1278 deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1279 1279
1280 1280 dataOut.heightList = numpy.arange(dataOut.nHeights*n) * deltaHeight + dataOut.heightList[0]
1281 1281
1282 1282 dataOut.nProfiles = int(dataOut.nProfiles/n)
1283 1283
1284 1284 dataOut.profileIndex = profileIndex
1285 1285
1286 1286 dataOut.ippSeconds *= n
1287 1287
1288 1288 return dataOut
1289 1289
1290 1290 class PulsePair(Operation):
1291 1291 '''
1292 1292 Function PulsePair(Signal Power, Velocity)
1293 1293 The real component of Lag[0] provides Intensity Information
1294 1294 The imag component of Lag[1] Phase provides Velocity Information
1295 1295
1296 1296 Configuration Parameters:
1297 1297 nPRF = Number of Several PRF
1298 1298 theta = Degree Azimuth angel Boundaries
1299 1299
1300 1300 Input:
1301 1301 self.dataOut
1302 1302 lag[N]
1303 1303 Affected:
1304 1304 self.dataOut.spc
1305 1305 '''
1306 1306 isConfig = False
1307 1307 __profIndex = 0
1308 1308 __initime = None
1309 1309 __lastdatatime = None
1310 1310 __buffer = None
1311 1311 noise = None
1312 1312 __dataReady = False
1313 1313 n = None
1314 1314 __nch = 0
1315 1315 __nHeis = 0
1316 1316 removeDC = False
1317 1317 ipp = None
1318 1318 lambda_ = 0
1319 1319
1320 1320 def __init__(self,**kwargs):
1321 1321 Operation.__init__(self,**kwargs)
1322 1322
1323 1323 def setup(self, dataOut, n = None, removeDC=False):
1324 1324 '''
1325 1325 n= Numero de PRF's de entrada
1326 1326 '''
1327 1327 print("[INICIO]-setup del METODO PULSE PAIR")
1328 1328 self.__initime = None
1329 1329 self.__lastdatatime = 0
1330 1330 self.__dataReady = False
1331 1331 self.__buffer = 0
1332 1332 self.__profIndex = 0
1333 1333 self.noise = None
1334 1334 self.__nch = dataOut.nChannels
1335 1335 self.__nHeis = dataOut.nHeights
1336 1336 self.removeDC = removeDC
1337 1337 self.lambda_ = 3.0e8/(9345.0e6)
1338 1338 self.ippSec = dataOut.ippSeconds
1339 1339 self.nCohInt = dataOut.nCohInt
1340 1340 print("IPPseconds",dataOut.ippSeconds)
1341 1341
1342 1342 print("ELVALOR DE n es:", n)
1343 1343 if n == None:
1344 1344 raise ValueError("n should be specified.")
1345 1345
1346 1346 if n != None:
1347 1347 if n<2:
1348 1348 raise ValueError("n should be greater than 2")
1349 1349
1350 1350 self.n = n
1351 1351 self.__nProf = n
1352 1352
1353 1353 self.__buffer = numpy.zeros((dataOut.nChannels,
1354 1354 n,
1355 1355 dataOut.nHeights),
1356 1356 dtype='complex')
1357 1357
1358 1358 def putData(self,data):
1359 1359 '''
1360 1360 Add a profile to he __buffer and increase in one the __profiel Index
1361 1361 '''
1362 1362 self.__buffer[:,self.__profIndex,:]= data
1363 1363 self.__profIndex += 1
1364 1364 return
1365 1365
1366 1366 def pushData(self,dataOut):
1367 1367 '''
1368 1368 Return the PULSEPAIR and the profiles used in the operation
1369 1369 Affected : self.__profileIndex
1370 1370 '''
1371 1371 #----------------- Remove DC-----------------------------------
1372 1372 if self.removeDC==True:
1373 1373 mean = numpy.mean(self.__buffer,1)
1374 1374 tmp = mean.reshape(self.__nch,1,self.__nHeis)
1375 1375 dc= numpy.tile(tmp,[1,self.__nProf,1])
1376 1376 self.__buffer = self.__buffer - dc
1377 1377 #------------------Calculo de Potencia ------------------------
1378 1378 pair0 = self.__buffer*numpy.conj(self.__buffer)
1379 1379 pair0 = pair0.real
1380 1380 lag_0 = numpy.sum(pair0,1)
1381 1381 #------------------Calculo de Ruido x canal--------------------
1382 1382 self.noise = numpy.zeros(self.__nch)
1383 1383 for i in range(self.__nch):
1384 1384 daux = numpy.sort(pair0[i,:,:],axis= None)
1385 1385 self.noise[i]=hildebrand_sekhon( daux ,self.nCohInt)
1386 1386
1387 1387 self.noise = self.noise.reshape(self.__nch,1)
1388 1388 self.noise = numpy.tile(self.noise,[1,self.__nHeis])
1389 1389 noise_buffer = self.noise.reshape(self.__nch,1,self.__nHeis)
1390 1390 noise_buffer = numpy.tile(noise_buffer,[1,self.__nProf,1])
1391 1391 #------------------ Potencia recibida= P , Potencia senal = S , Ruido= N--
1392 1392 #------------------ P= S+N ,P=lag_0/N ---------------------------------
1393 1393 #-------------------- Power --------------------------------------------------
1394 1394 data_power = lag_0/(self.n*self.nCohInt)
1395 1395 #------------------ Senal ---------------------------------------------------
1396 1396 data_intensity = pair0 - noise_buffer
1397 1397 data_intensity = numpy.sum(data_intensity,axis=1)*(self.n*self.nCohInt)#*self.nCohInt)
1398 1398 #data_intensity = (lag_0-self.noise*self.n)*(self.n*self.nCohInt)
1399 1399 for i in range(self.__nch):
1400 1400 for j in range(self.__nHeis):
1401 1401 if data_intensity[i][j] < 0:
1402 1402 data_intensity[i][j] = numpy.min(numpy.absolute(data_intensity[i][j]))
1403 1403
1404 1404 #----------------- Calculo de Frecuencia y Velocidad doppler--------
1405 1405 pair1 = self.__buffer[:,:-1,:]*numpy.conjugate(self.__buffer[:,1:,:])
1406 1406 lag_1 = numpy.sum(pair1,1)
1407 1407 data_freq = (-1/(2.0*math.pi*self.ippSec*self.nCohInt))*numpy.angle(lag_1)
1408 1408 data_velocity = (self.lambda_/2.0)*data_freq
1409 1409
1410 1410 #---------------- Potencia promedio estimada de la Senal-----------
1411 1411 lag_0 = lag_0/self.n
1412 1412 S = lag_0-self.noise
1413 1413
1414 1414 #---------------- Frecuencia Doppler promedio ---------------------
1415 1415 lag_1 = lag_1/(self.n-1)
1416 1416 R1 = numpy.abs(lag_1)
1417 1417
1418 1418 #---------------- Calculo del SNR----------------------------------
1419 1419 data_snrPP = S/self.noise
1420 1420 for i in range(self.__nch):
1421 1421 for j in range(self.__nHeis):
1422 1422 if data_snrPP[i][j] < 1.e-20:
1423 1423 data_snrPP[i][j] = 1.e-20
1424 1424
1425 1425 #----------------- Calculo del ancho espectral ----------------------
1426 1426 L = S/R1
1427 1427 L = numpy.where(L<0,1,L)
1428 1428 L = numpy.log(L)
1429 1429 tmp = numpy.sqrt(numpy.absolute(L))
1430 1430 data_specwidth = (self.lambda_/(2*math.sqrt(2)*math.pi*self.ippSec*self.nCohInt))*tmp*numpy.sign(L)
1431 1431 n = self.__profIndex
1432 1432
1433 1433 self.__buffer = numpy.zeros((self.__nch, self.__nProf,self.__nHeis), dtype='complex')
1434 1434 self.__profIndex = 0
1435 1435 return data_power,data_intensity,data_velocity,data_snrPP,data_specwidth,n
1436 1436
1437 1437
1438 1438 def pulsePairbyProfiles(self,dataOut):
1439 1439
1440 1440 self.__dataReady = False
1441 1441 data_power = None
1442 1442 data_intensity = None
1443 1443 data_velocity = None
1444 1444 data_specwidth = None
1445 1445 data_snrPP = None
1446 1446 self.putData(data=dataOut.data)
1447 1447 if self.__profIndex == self.n:
1448 1448 data_power,data_intensity, data_velocity,data_snrPP,data_specwidth, n = self.pushData(dataOut=dataOut)
1449 1449 self.__dataReady = True
1450 1450
1451 1451 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth
1452 1452
1453 1453
1454 1454 def pulsePairOp(self, dataOut, datatime= None):
1455 1455
1456 1456 if self.__initime == None:
1457 1457 self.__initime = datatime
1458 1458 data_power, data_intensity, data_velocity, data_snrPP, data_specwidth = self.pulsePairbyProfiles(dataOut)
1459 1459 self.__lastdatatime = datatime
1460 1460
1461 1461 if data_power is None:
1462 1462 return None, None, None,None,None,None
1463 1463
1464 1464 avgdatatime = self.__initime
1465 1465 deltatime = datatime - self.__lastdatatime
1466 1466 self.__initime = datatime
1467 1467
1468 1468 return data_power, data_intensity, data_velocity, data_snrPP, data_specwidth, avgdatatime
1469 1469
1470 1470 def run(self, dataOut,n = None,removeDC= False, overlapping= False,**kwargs):
1471 1471
1472 1472 if not self.isConfig:
1473 1473 self.setup(dataOut = dataOut, n = n , removeDC=removeDC , **kwargs)
1474 1474 self.isConfig = True
1475 1475 data_power, data_intensity, data_velocity,data_snrPP,data_specwidth, avgdatatime = self.pulsePairOp(dataOut, dataOut.utctime)
1476 1476 dataOut.flagNoData = True
1477 1477
1478 1478 if self.__dataReady:
1479 1479 dataOut.nCohInt *= self.n
1480 1480 dataOut.dataPP_POW = data_intensity # S
1481 print("help",data_power)
1481 1482 dataOut.dataPP_POWER = data_power # P
1482 1483 dataOut.dataPP_DOP = data_velocity
1483 1484 dataOut.dataPP_SNR = data_snrPP
1484 1485 dataOut.dataPP_WIDTH = data_specwidth
1485 1486 dataOut.PRFbyAngle = self.n #numero de PRF*cada angulo rotado que equivale a un tiempo.
1486 1487 dataOut.nProfiles = int(dataOut.nProfiles/n)
1487 1488 dataOut.utctime = avgdatatime
1488 1489 dataOut.flagNoData = False
1489 1490 return dataOut
1490 1491
1491 1492
1492 1493
1493 1494 # import collections
1494 1495 # from scipy.stats import mode
1495 1496 #
1496 1497 # class Synchronize(Operation):
1497 1498 #
1498 1499 # isConfig = False
1499 1500 # __profIndex = 0
1500 1501 #
1501 1502 # def __init__(self, **kwargs):
1502 1503 #
1503 1504 # Operation.__init__(self, **kwargs)
1504 1505 # # self.isConfig = False
1505 1506 # self.__powBuffer = None
1506 1507 # self.__startIndex = 0
1507 1508 # self.__pulseFound = False
1508 1509 #
1509 1510 # def __findTxPulse(self, dataOut, channel=0, pulse_with = None):
1510 1511 #
1511 1512 # #Read data
1512 1513 #
1513 1514 # powerdB = dataOut.getPower(channel = channel)
1514 1515 # noisedB = dataOut.getNoise(channel = channel)[0]
1515 1516 #
1516 1517 # self.__powBuffer.extend(powerdB.flatten())
1517 1518 #
1518 1519 # dataArray = numpy.array(self.__powBuffer)
1519 1520 #
1520 1521 # filteredPower = numpy.correlate(dataArray, dataArray[0:self.__nSamples], "same")
1521 1522 #
1522 1523 # maxValue = numpy.nanmax(filteredPower)
1523 1524 #
1524 1525 # if maxValue < noisedB + 10:
1525 1526 # #No se encuentra ningun pulso de transmision
1526 1527 # return None
1527 1528 #
1528 1529 # maxValuesIndex = numpy.where(filteredPower > maxValue - 0.1*abs(maxValue))[0]
1529 1530 #
1530 1531 # if len(maxValuesIndex) < 2:
1531 1532 # #Solo se encontro un solo pulso de transmision de un baudio, esperando por el siguiente TX
1532 1533 # return None
1533 1534 #
1534 1535 # phasedMaxValuesIndex = maxValuesIndex - self.__nSamples
1535 1536 #
1536 1537 # #Seleccionar solo valores con un espaciamiento de nSamples
1537 1538 # pulseIndex = numpy.intersect1d(maxValuesIndex, phasedMaxValuesIndex)
1538 1539 #
1539 1540 # if len(pulseIndex) < 2:
1540 1541 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1541 1542 # return None
1542 1543 #
1543 1544 # spacing = pulseIndex[1:] - pulseIndex[:-1]
1544 1545 #
1545 1546 # #remover senales que se distancien menos de 10 unidades o muestras
1546 1547 # #(No deberian existir IPP menor a 10 unidades)
1547 1548 #
1548 1549 # realIndex = numpy.where(spacing > 10 )[0]
1549 1550 #
1550 1551 # if len(realIndex) < 2:
1551 1552 # #Solo se encontro un pulso de transmision con ancho mayor a 1
1552 1553 # return None
1553 1554 #
1554 1555 # #Eliminar pulsos anchos (deja solo la diferencia entre IPPs)
1555 1556 # realPulseIndex = pulseIndex[realIndex]
1556 1557 #
1557 1558 # period = mode(realPulseIndex[1:] - realPulseIndex[:-1])[0][0]
1558 1559 #
1559 1560 # print "IPP = %d samples" %period
1560 1561 #
1561 1562 # self.__newNSamples = dataOut.nHeights #int(period)
1562 1563 # self.__startIndex = int(realPulseIndex[0])
1563 1564 #
1564 1565 # return 1
1565 1566 #
1566 1567 #
1567 1568 # def setup(self, nSamples, nChannels, buffer_size = 4):
1568 1569 #
1569 1570 # self.__powBuffer = collections.deque(numpy.zeros( buffer_size*nSamples,dtype=numpy.float),
1570 1571 # maxlen = buffer_size*nSamples)
1571 1572 #
1572 1573 # bufferList = []
1573 1574 #
1574 1575 # for i in range(nChannels):
1575 1576 # bufferByChannel = collections.deque(numpy.zeros( buffer_size*nSamples, dtype=numpy.complex) + numpy.NAN,
1576 1577 # maxlen = buffer_size*nSamples)
1577 1578 #
1578 1579 # bufferList.append(bufferByChannel)
1579 1580 #
1580 1581 # self.__nSamples = nSamples
1581 1582 # self.__nChannels = nChannels
1582 1583 # self.__bufferList = bufferList
1583 1584 #
1584 1585 # def run(self, dataOut, channel = 0):
1585 1586 #
1586 1587 # if not self.isConfig:
1587 1588 # nSamples = dataOut.nHeights
1588 1589 # nChannels = dataOut.nChannels
1589 1590 # self.setup(nSamples, nChannels)
1590 1591 # self.isConfig = True
1591 1592 #
1592 1593 # #Append new data to internal buffer
1593 1594 # for thisChannel in range(self.__nChannels):
1594 1595 # bufferByChannel = self.__bufferList[thisChannel]
1595 1596 # bufferByChannel.extend(dataOut.data[thisChannel])
1596 1597 #
1597 1598 # if self.__pulseFound:
1598 1599 # self.__startIndex -= self.__nSamples
1599 1600 #
1600 1601 # #Finding Tx Pulse
1601 1602 # if not self.__pulseFound:
1602 1603 # indexFound = self.__findTxPulse(dataOut, channel)
1603 1604 #
1604 1605 # if indexFound == None:
1605 1606 # dataOut.flagNoData = True
1606 1607 # return
1607 1608 #
1608 1609 # self.__arrayBuffer = numpy.zeros((self.__nChannels, self.__newNSamples), dtype = numpy.complex)
1609 1610 # self.__pulseFound = True
1610 1611 # self.__startIndex = indexFound
1611 1612 #
1612 1613 # #If pulse was found ...
1613 1614 # for thisChannel in range(self.__nChannels):
1614 1615 # bufferByChannel = self.__bufferList[thisChannel]
1615 1616 # #print self.__startIndex
1616 1617 # x = numpy.array(bufferByChannel)
1617 1618 # self.__arrayBuffer[thisChannel] = x[self.__startIndex:self.__startIndex+self.__newNSamples]
1618 1619 #
1619 1620 # deltaHeight = dataOut.heightList[1] - dataOut.heightList[0]
1620 1621 # dataOut.heightList = numpy.arange(self.__newNSamples)*deltaHeight
1621 1622 # # dataOut.ippSeconds = (self.__newNSamples / deltaHeight)/1e6
1622 1623 #
1623 1624 # dataOut.data = self.__arrayBuffer
1624 1625 #
1625 1626 # self.__startIndex += self.__newNSamples
1626 1627 #
1627 1628 # return
@@ -1,157 +1,159
1 1 #!python
2 2 '''
3 3 '''
4 4
5 5 import os, sys
6 6 import datetime
7 7 import time
8 8
9 9 #path = os.path.dirname(os.getcwd())
10 10 #path = os.path.dirname(path)
11 11 #sys.path.insert(0, path)
12 12
13 13 from schainpy.controller import Project
14 14
15 15 desc = "USRP_test"
16 16 filename = "USRP_processing.xml"
17 17 controllerObj = Project()
18 18 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
19 19
20 20 ############## USED TO PLOT IQ VOLTAGE, POWER AND SPECTRA #############
21 21
22 22 #######################################################################
23 23 ######PATH DE LECTURA, ESCRITURA, GRAFICOS Y ENVIO WEB#################
24 24 #######################################################################
25 25 #path = '/media/data/data/vientos/57.2063km/echoes/NCO_Woodman'
26 26 #path = '/DATA_RM/TEST_INTEGRACION'
27 27 #path = '/DATA_RM/TEST_ONLINE'
28 28 #path_pp = '/DATA_RM/TEST_HDF5'
29 29
30 30 #figpath = '/home/soporte/Pictures/TEST_INTEGRACION_IMG'
31 31 ###path = '/DATA_RM/TEST_INTEGRACION/ADQ_OFFLINE/'
32 32 ###path_pp = '/DATA_RM/TEST_HDF5_SPEC'
33 33
34 34 #path = '/DATA_RM/USRP_22'
35 path = '/DATA_RM/23/6v'
35 ###path = '/DATA_RM/23/6v'
36 path = '/DATA_RM/TEST_19OCTUBRE/10MHZ'
36 37 #path_pp = '/DATA_RM/TEST_HDF5'
38 path_pp = '/DATA_RM/TEST_HDF5_19OCT'
37 39 # UTIMO TEST 22 DE SEPTIEMBRE
38 40 #path_pp = '/DATA_RM/TEST_HDF5_SPEC_22'
39 41 #path_pp = '/DATA_RM/TEST_HDF5_SPEC_3v'
40 path_pp = '/DATA_RM/TEST_HDF5_SPEC_23/6v'
42 ###path_pp = '/DATA_RM/TEST_HDF5_SPEC_23/6v'
41 43
42 44
43 45 #remotefolder = "/home/wmaster/graficos"
44 46 #######################################################################
45 47 ################# RANGO DE PLOTEO######################################
46 48 #######################################################################
47 49 dBmin = '-5'
48 50 dBmax = '20'
49 51 xmin = '0'
50 52 xmax ='24'
51 53 ymin = '0'
52 54 ymax = '600'
53 55 #######################################################################
54 56 ########################FECHA##########################################
55 57 #######################################################################
56 58 str = datetime.date.today()
57 59 today = str.strftime("%Y/%m/%d")
58 60 str2 = str - datetime.timedelta(days=1)
59 61 yesterday = str2.strftime("%Y/%m/%d")
60 62 #######################################################################
61 63 ######################## UNIDAD DE LECTURA#############################
62 64 #######################################################################
63 65 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
64 66 path=path,
65 67 startDate="2021/01/01",#today,
66 68 endDate="2021/12/30",#today,
67 69 startTime='00:00:00',
68 70 endTime='23:59:59',
69 71 delay=0,
70 72 #set=0,
71 73 online=0,
72 74 walk=1,
73 75 ippKm = 60)
74 76
75 77 opObj11 = readUnitConfObj.addOperation(name='printInfo')
76 78 #opObj11 = readUnitConfObj.addOperation(name='printNumberOfBlock')
77 79 #######################################################################
78 80 ################ OPERACIONES DOMINIO DEL TIEMPO########################
79 81 #######################################################################
80 82
81 83
82 V=6
84 V=10
83 85 IPP=400*1e-6
84 86 n= int(1/(V*IPP))
85 87 print("n numero de Perfiles a procesar con nFFTPoints ", n)
86 88
87 89 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
88 90
89 91 procUnitConfObjB = controllerObj.addProcUnit(datatype='SpectraProc', inputId=procUnitConfObjA.getId())
90 92 procUnitConfObjB.addParameter(name='nFFTPoints', value=n, format='int')
91 93 procUnitConfObjB.addParameter(name='nProfiles' , value=n, format='int')
92 94
93 95
94 96
95 97 #
96 98 # codigo64='1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,1,1,1,0,0,0,1,0,'+\
97 99 # '1,1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1'
98 100
99 101 #opObj11 = procUnitConfObjA.addOperation(name='setRadarFrequency')
100 102 #opObj11.addParameter(name='frequency', value='70312500')
101 103 #opObj11 = procUnitConfObjA.addOperation(name='PulsePair', optype='other')
102 104 #opObj11.addParameter(name='n', value='625', format='int')#10
103 105 #opObj11.addParameter(name='removeDC', value=1, format='int')
104 106
105 107 # Ploteo TEST
106 108 '''
107 109 opObj11 = procUnitConfObjA.addOperation(name='PulsepairPowerPlot', optype='other')
108 110 opObj11 = procUnitConfObjA.addOperation(name='PulsepairSignalPlot', optype='other')
109 111 opObj11 = procUnitConfObjA.addOperation(name='PulsepairVelocityPlot', optype='other')
110 112 #opObj11.addParameter(name='xmax', value=8)
111 113 opObj11 = procUnitConfObjA.addOperation(name='PulsepairSpecwidthPlot', optype='other')
112 114 '''
113 115 # OJO SCOPE
114 116 #opObj10 = procUnitConfObjA.addOperation(name='ScopePlot', optype='external')
115 117 #opObj10.addParameter(name='buffer_sizeid', value='10', format='int')
116 118 ##opObj10.addParameter(name='xmin', value='0', format='int')
117 119 ##opObj10.addParameter(name='xmax', value='50', format='int')
118 120 #opObj10.addParameter(name='type', value='iq')
119 121 ##opObj10.addParameter(name='ymin', value='-5000', format='int')
120 122 ##opObj10.addParameter(name='ymax', value='8500', format='int')
121 123 #opObj11.addParameter(name='save', value=figpath, format='str')
122 124 #opObj11.addParameter(name='save_period', value=10, format='int')
123 125
124 126 #opObj10 = procUnitConfObjA.addOperation(name='setH0')
125 127 #opObj10.addParameter(name='h0', value='-5000', format='float')
126 128
127 129 #opObj11 = procUnitConfObjA.addOperation(name='filterByHeights')
128 130 #opObj11.addParameter(name='window', value='1', format='int')
129 131
130 132 #codigo='1,1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,-1,1,1,1,1,-1,-1,-1'
131 133 #opObj11 = procUnitConfObjSousy.addOperation(name='Decoder', optype='other')
132 134 #opObj11.addParameter(name='code', value=codigo, formatyesterday='floatlist')
133 135 #opObj11.addParameter(name='nCode', value='1', format='int')
134 136 #opObj11.addParameter(name='nBaud', value='28', format='int')
135 137
136 138 #opObj11 = procUnitConfObjA.addOperation(name='CohInt', optype='other')
137 139 #opObj11.addParameter(name='n', value='100', format='int')
138 140
139 141 #######################################################################
140 142 ########## OPERACIONES ParametersProc########################
141 143 #######################################################################
142 144
143 145 procUnitConfObjC= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjB.getId())
144 146
145 147 procUnitConfObjC.addOperation(name='SpectralMoments')
146 148
147 149
148 150 opObj10 = procUnitConfObjC.addOperation(name='HDFWriter')
149 151 opObj10.addParameter(name='path',value=path_pp)
150 152 #opObj10.addParameter(name='mode',value=0)
151 153 opObj10.addParameter(name='blocksPerFile',value='100',format='int')
152 154 #opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
153 155 opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
154 156
155 157 opObj10.addParameter(name='dataList',value='data_pow,data_dop,utctime',format='list')#,format='list'
156 158
157 159 controllerObj.start()
@@ -1,213 +1,216
1 1 # Ing. AVP
2 2 # 06/10/2021
3 3 # ARCHIVO DE LECTURA
4 4 import os, sys
5 5 import datetime
6 6 import time
7 7 from schainpy.controller import Project
8 8 #### NOTA###########################################
9 9 # INPUT :
10 10 # VELOCIDAD PARAMETRO : V = 2Β°/seg
11 11 # MODO PULSE PAIR O MOMENTOS: 0 : Pulse Pair ,1 : Momentos
12 12 ######################################################
13 13 ##### PROCESAMIENTO ##################################
14 14 ##### OJO TENER EN CUENTA EL n= para el Pulse Pair ##
15 15 ##### O EL n= nFFTPoints ###
16 16 ######################################################
17 17 ######## BUSCAMOS EL numero de IPP equivalente 1Β°#####
18 18 ######## Sea V la velocidad del Pedestal en Β°/seg#####
19 19 ######## 1Β° sera Recorrido en un tiempo de 1/V ######
20 20 ######## IPP del Radar 400 useg --> 60 Km ############
21 21 ######## n = 1/(V(Β°/seg)*IPP(Km)) , NUMERO DE IPP ##
22 22 ######## n = 1/(V*IPP) #############################
23 23 ######## VELOCIDAD DEL PEDESTAL ######################
24 24 print("SETUP- RADAR METEOROLOGICO")
25 25 V = 10
26 26 mode = 1
27 27 #path = '/DATA_RM/23/6v'
28 path = '/DATA_RM/TEST_INTEGRACION_2M'
29 path_ped='/DATA_RM/TEST_PEDESTAL/P20211012-082745'
28 ####path = '/DATA_RM/TEST_INTEGRACION_2M'
29 #path = '/DATA_RM/TEST_19OCTUBRE/10MHZ'
30 path = '/DATA_RM/WR_20_OCT'
31 #### path_ped='/DATA_RM/TEST_PEDESTAL/P20211012-082745'
32 #### path_ped='/DATA_RM/TEST_PEDESTAL/P20211019-192244'
30 33 figpath_pp = "/home/soporte/Pictures/TEST_PP"
31 figpath_mom = "/home/soporte/Pictures/TEST_MOM"
32 plot = 0
33 integration = 1
34 figpath_spec = "/home/soporte/Pictures/TEST_MOM"
35 plot = 1
36 integration = 0
34 37 save = 0
35 38 if save == 1:
36 39 if mode==0:
37 40 path_save = '/DATA_RM/TEST_HDF5_PP_23/6v'
38 41 path_save = '/DATA_RM/TEST_HDF5_PP'
39 42 path_save = '/DATA_RM/TEST_HDF5_PP_100'
40 43 else:
41 44 path_save = '/DATA_RM/TEST_HDF5_SPEC_23_V2/6v'
42 45
43 46 print("* PATH data ADQ :", path)
44 47 print("* Velocidad Pedestal :",V,"Β°/seg")
45 48 ############################ NRO Perfiles PROCESAMIENTO ###################
46 49 V=V
47 50 IPP=400*1e-6
48 51 n= int(1/(V*IPP))
49 52 print("* n - NRO Perfiles Proc:", n )
50 53 ################################## MODE ###################################
51 54 print("* Modo de Operacion :",mode)
52 55 if mode ==0:
53 56 print("* Met. Seleccionado : Pulse Pair")
54 57 else:
55 58 print("* Met. Momentos : Momentos")
56 59
57 60 ################################## MODE ###################################
58 61 print("* Grabado de datos :",save)
59 62 if save ==1:
60 63 if mode==0:
61 64 ope= "Pulse Pair"
62 65 else:
63 66 ope= "Momentos"
64 67 print("* Path-Save Data -", ope , path_save)
65 68
66 69 print("* Integracion de datos :",integration)
67 70
68 71 time.sleep(15)
69 72 #remotefolder = "/home/wmaster/graficos"
70 73 #######################################################################
71 74 ################# RANGO DE PLOTEO######################################
72 75 dBmin = '1'
73 dBmax = '85'
74 xmin = '15'
75 xmax = '15.25'
76 dBmax = '65'
77 xmin = '13.2'
78 xmax = '13.5'
76 79 ymin = '0'
77 ymax = '600'
80 ymax = '60'
78 81 #######################################################################
79 82 ########################FECHA##########################################
80 83 str = datetime.date.today()
81 84 today = str.strftime("%Y/%m/%d")
82 85 str2 = str - datetime.timedelta(days=1)
83 86 yesterday = str2.strftime("%Y/%m/%d")
84 87 #######################################################################
85 88 ########################SIGNAL CHAIN ##################################
86 89 #######################################################################
87 90 desc = "USRP_test"
88 91 filename = "USRP_processing.xml"
89 92 controllerObj = Project()
90 93 controllerObj.setup(id = '191', name='Test_USRP', description=desc)
91 94 #######################################################################
92 95 ######################## UNIDAD DE LECTURA#############################
93 96 #######################################################################
94 97 readUnitConfObj = controllerObj.addReadUnit(datatype='DigitalRFReader',
95 98 path=path,
96 99 startDate="2021/01/01",#today,
97 100 endDate="2021/12/30",#today,
98 101 startTime='00:00:00',
99 102 endTime='23:59:59',
100 103 delay=0,
101 104 #set=0,
102 105 online=0,
103 106 walk=1,
104 107 ippKm = 60)
105 108
106 109 opObj11 = readUnitConfObj.addOperation(name='printInfo')
107 110
108 111 procUnitConfObjA = controllerObj.addProcUnit(datatype='VoltageProc', inputId=readUnitConfObj.getId())
109 112
110 113 if mode ==0:
111 114 ####################### METODO PULSE PAIR ######################################################################
112 115 opObj11 = procUnitConfObjA.addOperation(name='PulsePair', optype='other')
113 116 opObj11.addParameter(name='n', value=int(n), format='int')#10 VOY A USAR 250 DADO QUE LA VELOCIDAD ES 10 GRADOS
114 117 #opObj11.addParameter(name='removeDC', value=1, format='int')
115 118 ####################### METODO Parametros ######################################################################
116 119 procUnitConfObjB= controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjA.getId())
117 120 if plot==1:
118 121 opObj11 = procUnitConfObjB.addOperation(name='GenericRTIPlot',optype='external')
119 opObj11.addParameter(name='attr_data', value='dataPP_POW')
122 opObj11.addParameter(name='attr_data', value='dataPP_POWER')
120 123 opObj11.addParameter(name='colormap', value='jet')
121 124 opObj11.addParameter(name='xmin', value=xmin)
122 125 opObj11.addParameter(name='xmax', value=xmax)
123 126 opObj11.addParameter(name='zmin', value=dBmin)
124 127 opObj11.addParameter(name='zmax', value=dBmax)
125 128 opObj11.addParameter(name='save', value=figpath_pp)
126 129 opObj11.addParameter(name='showprofile', value=0)
127 opObj11.addParameter(name='save_period', value=50)
130 opObj11.addParameter(name='save_period', value=10)
128 131
129 132 ####################### METODO ESCRITURA #######################################################################
130 133 if save==1:
131 134 opObj10 = procUnitConfObjB.addOperation(name='HDFWriter')
132 135 opObj10.addParameter(name='path',value=path_save)
133 136 #opObj10.addParameter(name='mode',value=0)
134 137 opObj10.addParameter(name='blocksPerFile',value='100',format='int')
135 138 opObj10.addParameter(name='metadataList',value='utctimeInit,timeZone,paramInterval,profileIndex,channelList,heightList,flagDataAsBlock',format='list')
136 opObj10.addParameter(name='dataList',value='dataPP_POW,dataPP_DOP,utctime',format='list')#,format='list'
139 opObj10.addParameter(name='dataList',value='dataPP_POWER,dataPP_DOP,utctime',format='list')#,format='list'
137 140 if integration==1:
138 141 V=10
139 142 blocksPerfile=360
140 143 print("* Velocidad del Pedestal:",V)
141 144 tmp_blocksPerfile = 100
142 145 f_a_p= int(tmp_blocksPerfile/V)
143 146
144 147 opObj11 = procUnitConfObjB.addOperation(name='PedestalInformation')
145 148 opObj11.addParameter(name='path_ped', value=path_ped)
146 149 #opObj11.addParameter(name='path_adq', value=path_adq)
147 150 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
148 151 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
149 152 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
150 153 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
151 154 opObj11.addParameter(name='online', value='0', format='int')
152 155
153 156 opObj11 = procUnitConfObjB.addOperation(name='Block360')
154 157 opObj11.addParameter(name='n', value='10', format='int')
155 158 opObj11.addParameter(name='mode', value=mode, format='int')
156 159
157 160 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
158 161
159 162 opObj11= procUnitConfObjB.addOperation(name='WeatherPlot',optype='other')
160 163
161 164
162 165 else:
163 166 ####################### METODO SPECTROS ######################################################################
164 167 procUnitConfObjB = controllerObj.addProcUnit(datatype='SpectraProc', inputId=procUnitConfObjA.getId())
165 168 procUnitConfObjB.addParameter(name='nFFTPoints', value=n, format='int')
166 169 procUnitConfObjB.addParameter(name='nProfiles' , value=n, format='int')
167 170
168 171 procUnitConfObjC = controllerObj.addProcUnit(datatype='ParametersProc',inputId=procUnitConfObjB.getId())
169 172 procUnitConfObjC.addOperation(name='SpectralMoments')
170 173 if plot==1:
171 174 dBmin = '1'
172 175 dBmax = '65'
173 176 opObj11 = procUnitConfObjC.addOperation(name='PowerPlot',optype='external')
174 177 opObj11.addParameter(name='xmin', value=xmin)
175 178 opObj11.addParameter(name='xmax', value=xmax)
176 179 opObj11.addParameter(name='zmin', value=dBmin)
177 180 opObj11.addParameter(name='zmax', value=dBmax)
178 opObj11.addParameter(name='save', value=figpath_mom)
181 opObj11.addParameter(name='save', value=figpath_spec)
179 182 opObj11.addParameter(name='showprofile', value=0)
180 opObj11.addParameter(name='save_period', value=100)
183 opObj11.addParameter(name='save_period', value=10)
181 184
182 185 if save==1:
183 186 opObj10 = procUnitConfObjC.addOperation(name='HDFWriter')
184 187 opObj10.addParameter(name='path',value=path_save)
185 188 #opObj10.addParameter(name='mode',value=0)
186 189 opObj10.addParameter(name='blocksPerFile',value='360',format='int')
187 190 #opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
188 191 opObj10.addParameter(name='metadataList',value='utctimeInit,heightList,nIncohInt,nCohInt,nProfiles,channelList',format='list')#profileIndex
189 192 opObj10.addParameter(name='dataList',value='data_pow,data_dop,utctime',format='list')#,format='list'
190 193
191 194 if integration==1:
192 195 V=10
193 196 blocksPerfile=360
194 197 print("* Velocidad del Pedestal:",V)
195 198 tmp_blocksPerfile = 100
196 199 f_a_p= int(tmp_blocksPerfile/V)
197 200
198 201 opObj11 = procUnitConfObjC.addOperation(name='PedestalInformation')
199 202 opObj11.addParameter(name='path_ped', value=path_ped)
200 203 #opObj11.addParameter(name='path_adq', value=path_adq)
201 204 opObj11.addParameter(name='t_Interval_p', value='0.01', format='float')
202 205 opObj11.addParameter(name='blocksPerfile', value=blocksPerfile, format='int')
203 206 opObj11.addParameter(name='n_Muestras_p', value='100', format='float')
204 207 opObj11.addParameter(name='f_a_p', value=f_a_p, format='int')
205 208 opObj11.addParameter(name='online', value='0', format='int')
206 209
207 210 opObj11 = procUnitConfObjC.addOperation(name='Block360')
208 211 opObj11.addParameter(name='n', value='10', format='int')
209 212 opObj11.addParameter(name='mode', value=mode, format='int')
210 213
211 214 # este bloque funciona bien con divisores de 360 no olvidar 0 10 20 30 40 60 90 120 180
212 215 opObj11= procUnitConfObjC.addOperation(name='WeatherPlot',optype='other')
213 216 controllerObj.start()
@@ -1,112 +1,119
1 1 # Ing-AlexanderValdez
2 2 # Monitoreo de Pedestal
3 3
4 4 ############## IMPORTA LIBRERIAS ###################
5 5 import os,numpy,h5py
6 6 import sys,time
7 7 import matplotlib.pyplot as plt
8 8 ####################################################
9 path_ped = '/DATA_RM/TEST_PEDESTAL/P20211012-082745'
9 #################################################################
10 # LA FECHA 21-10-20 CORRESPONDE A LAS PRUEBAS DEL DIA MIERCOLES
11 # 1:15:51 pm hasta 3:49:32 pm
12 #################################################################
13
14 #path_ped = '/DATA_RM/TEST_PEDESTAL/P20211012-082745'
15 path_ped = '/DATA_RM/TEST_PEDESTAL/P20211020-131248'
10 16 # Metodo para verificar numero
11 17 def isNumber(str):
12 18 try:
13 19 float(str)
14 20 return True
15 21 except:
16 22 return False
17 23 # Metodo para extraer el arreglo
18 24 def getDatavaluefromDirFilename(path,file,value):
19 25 dir_file= path+"/"+file
20 26 fp = h5py.File(dir_file,'r')
21 27 array = fp['Data'].get(value)[()]
22 28 fp.close()
23 29 return array
24 30
25 31 # LISTA COMPLETA DE ARCHIVOS HDF5 Pedestal
26 32 LIST= sorted(os.listdir(path_ped))
27 33 m=len(LIST)
28 34 print("TOTAL DE ARCHIVOS DE PEDESTAL:",m)
29 35 # Contadores temporales
30 36 k= 0
31 37 l= 0
32 38 t= 0
33 39 # Marca de tiempo temporal
34 40 time_ = numpy.zeros([m])
35 41 # creacion de
36 42 for i in range(m):
43 print("order:",i)
37 44 tmp_azi_pos = getDatavaluefromDirFilename(path=path_ped,file=LIST[i],value="azi_pos")
38 45 tmp_ele_pos = getDatavaluefromDirFilename(path=path_ped,file=LIST[i],value="ele_pos")
39 46 tmp_azi_vel = getDatavaluefromDirFilename(path=path_ped,file=LIST[i],value="azi_vel")
40 47 tmp_ele_vel = getDatavaluefromDirFilename(path=path_ped,file=LIST[i],value="azi_vel")# nuevo :D
41 48
42 49 time_[i] = getDatavaluefromDirFilename(path=path_ped,file=LIST[i],value="utc")
43 50
44 51 k=k +tmp_azi_pos.shape[0]
45 52 l=l +tmp_ele_pos.shape[0]
46 53 t=t +tmp_azi_vel.shape[0]
47 54
48 55 print("TOTAL DE MUESTRAS, ARCHIVOS X100:",k)
49 56 time.sleep(5)
50 57 ######CREACION DE ARREGLOS CANTIDAD DE VALORES POR MUESTRA#################
51 58 azi_pos = numpy.zeros([k])
52 59 ele_pos = numpy.zeros([l])
53 60 time_azi_pos= numpy.zeros([k])
54 61 # Contadores temporales
55 62 p=0
56 63 r=0
57 64 z=0
58 65 # VARIABLES TMP para almacenar azimuth, elevacion y tiempo
59 66
60 67 #for filename in sorted(os.listdir(path_ped)):
61 68 # CONDICION POR LEER EN TIEMPO REAL NO OFFLINE
62 69
63 70 for filename in LIST:
64 71 tmp_azi_pos = getDatavaluefromDirFilename(path=path_ped,file=filename,value="azi_pos")
65 72 tmp_ele_pos = getDatavaluefromDirFilename(path=path_ped,file=filename,value="ele_pos")
66 73 # CONDICION POR LEER EN TIEMPO REAL NO OFFLINE
67 74
68 75 if z==(m-1):
69 76 tmp_azi_time=numpy.arange(time_[z],time_[z]+1,1/(tmp_azi_pos.shape[0]))
70 77 else:
71 78 tmp_azi_time=numpy.arange(time_[z],time_[z+1],(time_[z+1]-time_[z])/(tmp_azi_pos.shape[0]))
72 79
73 80 print(filename,time_[z])
74 81 print(z,tmp_azi_pos.shape[0])
75 82
76 83 i=0
77 84 for i in range(tmp_azi_pos.shape[0]):
78 85 index=p+i
79 86 azi_pos[index]=tmp_azi_pos[i]
80 87 time_azi_pos[index]=tmp_azi_time[i]
81 88 p=p+tmp_azi_pos.shape[0]
82 89 i=0
83 90 for i in range(tmp_ele_pos.shape[0]):
84 91 index=r+i
85 92 ele_pos[index]=tmp_ele_pos[i]
86 93 r=r+tmp_ele_pos.shape[0]
87 94
88 95
89 96 z+=1
90 97
91 98
92 99 ######## GRAFIQUEMOS Y VEAMOS LOS DATOS DEL Pedestal
93 100 fig, ax = plt.subplots(figsize=(16,8))
94 101 print(time_azi_pos.shape)
95 102 print(azi_pos.shape)
96 103 t=numpy.arange(time_azi_pos.shape[0])*0.01/(60.0)
97 104 plt.plot(t,azi_pos,label='AZIMUTH_POS',color='blue')
98 105
99 106 # AQUI ESTOY ADICIONANDO LA POSICION EN elevaciont=numpy.arange(len(ele_pos))*0.01/60.0
100 107 t=numpy.arange(len(ele_pos))*0.01/60.0
101 108 plt.plot(t,ele_pos,label='ELEVATION_POS',color='red')#*10
102 109
103 110 #ax.set_xlim(0, 9)
104 111 ax.set_ylim(-5, 400)
105 112 plt.ylabel("Azimuth Position")
106 113 plt.xlabel("Muestra")
107 114 plt.title('Azimuth Position vs Muestra ', fontsize=20)
108 115 axes = plt.gca()
109 116 axes.yaxis.grid()
110 117 plt.xticks(fontsize=16)
111 118 plt.yticks(fontsize=16)
112 119 plt.show()
@@ -1,78 +1,79
1 1 import os,sys,json
2 2 import datetime
3 3 import time
4 4 from schainpy.controller import Project
5 5 '''
6 6 NOTA:
7 7 Este script de prueba.
8 8 - Unidad del lectura 'HDFReader'.
9 9 - Unidad de procesamiento ParametersProc
10 10 - Operacion SpectralMomentsPlot
11 11
12 12 '''
13 13
14 14 #######################################################################
15 15 ################# RANGO DE PLOTEO######################################
16 16 #######################################################################
17 17 dBmin = '1'
18 18 dBmax = '65'
19 19 xmin = '0'
20 20 xmax ='24'
21 21 #tmmin = 16.2
22 22 #tmmax = 16.25
23 23 tmmin =15
24 24 tmmax =15.5
25 25 ymin = '0'
26 26 ymax = '600'
27 27 #######################################################################
28 28 #######################################################################
29 29 #######################################################################
30 30 #path = '/DATA_RM/TEST_HDF5_SPEC'
31 path = '/DATA_RM/TEST_HDF5_SPEC_23/6v/'
31 #path = '/DATA_RM/TEST_HDF5_SPEC_23/6v/'
32 path = '/DATA_RM/TEST_HDF5_19OCT'
32 33 figpath = '/home/soporte/Downloads/23/6v'
33 34 desc = "Simulator Test"
34 35 desc_data = {
35 36 'Data': {
36 37 'data_pow': ['Data/data_pow/channel00','Data/data_pow/channel01'],
37 38 'data_dop': ['Data/data_dop/channel00','Data/data_dop/channel01'],
38 39 'utctime':'Data/utctime'
39 40 },
40 41 'Metadata': {
41 42 'heightList':'Metadata/heightList',
42 43 'nIncohInt' :'Metadata/nIncohInt',
43 44 'nCohInt' :'Metadata/nCohInt',
44 45 'nProfiles' :'Metadata/nProfiles',
45 46 'channelList' :'Metadata/channelList',
46 47 'utctimeInit' :'Metadata/utctimeInit'
47 48
48 49 }
49 50 }
50 51
51 52 controllerObj = Project()
52 53
53 54 controllerObj.setup(id='10',name='Test Simulator',description=desc)
54 55
55 56 readUnitConfObj = controllerObj.addReadUnit(datatype='HDFReader',
56 57 path=path,
57 58 startDate="2021/01/01", #"2020/01/01",#today,
58 59 endDate= "2021/12/01", #"2020/12/30",#today,
59 60 startTime='00:00:00',
60 61 endTime='23:59:59',
61 62 delay=0,
62 63 #set=0,
63 64 online=0,
64 65 walk=1,
65 66 description= json.dumps(desc_data))#1
66 67
67 68 procUnitConfObjA = controllerObj.addProcUnit(datatype='ParametersProc',inputId=readUnitConfObj.getId())
68 69
69 70 opObj11 = procUnitConfObjA.addOperation(name='PowerPlot',optype='external')
70 71 opObj11.addParameter(name='xmin', value=tmmin)
71 72 opObj11.addParameter(name='xmax', value=tmmax)
72 73 opObj11.addParameter(name='zmin', value=dBmin)
73 74 opObj11.addParameter(name='zmax', value=dBmax)
74 75 opObj11.addParameter(name='save', value=figpath)
75 76 opObj11.addParameter(name='showprofile', value=0)
76 77 opObj11.addParameter(name='save_period', value=10)
77 78
78 79 controllerObj.start()
General Comments 0
You need to be logged in to leave comments. Login now