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