@@ -69,3 +69,212 @@ def create_sti(filename, nfft, decimation, secoffset):
6969 Sxxlist .append (Sxx0db )
7070 t_ar = t_ar + secoffset
7171 return freq , t_ar , len_s , Sxxlist
72+
73+
74+ # %% Lag Functions
75+
76+
77+ def lag_product (x_in , nlag , nmean = 10 , numtype = np .complex64 , lagtype = "centered" ):
78+ """This function will create a lag product for each range using the raw IQ given to it. It will form each lag for each pulse and then integrate all of the pulses.
79+
80+ Parameters
81+ ----------
82+ x_in : ndarray
83+ This is a NpxNs complex numpy array where Ns is number of samples per pulse and Np is number of pulses
84+ nmean : int
85+ Number of pulses to be averaged first before median applied.
86+ nlag : int
87+ Length of the lag product formation.
88+ numtype : type
89+ numerical representaiton of the array.
90+
91+ lagtype : str
92+ Can be centered forward or backward.
93+
94+ Returns
95+ -------
96+ acf_cent : ndarray
97+ This is a NrxNl complex numpy array where Nr is number of range gate and Nl is number of lags.
98+ rg_keep : ndarray
99+ Indicies of the samples/range gates that will be kept after the lag formation.
100+ """
101+ # It will be assumed the data will be pulses vs range gates
102+ x_in = x_in .transpose ()
103+ (Nr , Np ) = x_in .shape
104+ med_int = np .arange (0 , Np , nmean )
105+ n_start = med_int [:- 1 ]
106+ n_end = med_int [1 :]
107+ n_sub = len (n_start )
108+ # Make masks for each piece of data
109+ if lagtype == "forward" :
110+ arback = np .zeros (nlag , dtype = int )
111+ arfor = np .arange (nlag , dtype = int )
112+
113+ elif lagtype == "backward" :
114+ arback = - np .arange (nlag , dtype = int )
115+ arfor = np .zeros (nlag , dtype = int )
116+ else :
117+ # arex = np.arange(0,N/2.0,0.5);
118+ arback = - np .floor (np .arange (0 , nlag / 2.0 , 0.5 )).astype (int )
119+ arfor = np .ceil (np .arange (0 , nlag / 2.0 , 0.5 )).astype (int )
120+
121+ # figure out how much range space will be kept
122+ ap = - 1 * np .min (arback )
123+ ep = Nr - np .nanmax (arfor )
124+ rg_keep = np .arange (ap , ep )
125+ # wearr = (1./(N-np.tile((arfor-arback)[:,np.newaxis],(1,Np)))).astype(numtype)
126+ # acf_cent = np.zeros((ep-ap,N))*(1+1j)
127+ acf_cent = np .zeros ((ep - ap , nlag ), dtype = numtype )
128+ for irng , curange in enumerate (rg_keep ):
129+ rng_ar1 = int (curange ) + arback
130+ rng_ar2 = int (curange ) + arfor
131+ # get all of the acfs across pulses # sum along the pulses
132+ acf_tmp = np .conj (x_in [rng_ar1 , :]) * x_in [rng_ar2 , :] # *wearr
133+ acf_sub = np .zeros ((n_sub , * acf_tmp .shape ), dtype = numtype )
134+ for i_ind , (ibeg , iend ) in enumerate (zip (n_start , n_end )):
135+ tmp_acf = acf_tmp [:, slice (ibeg , iend )]
136+ acf_sub [i_ind ] = np .nanmean (tmp_acf , axis = 1 )
137+ acf_ave = np .nanmedian (acf_sub , axis = 0 )
138+
139+ acf_cent [irng , :] = acf_ave # might need to transpose this
140+ return acf_cent , rg_keep
141+
142+
143+ # %% Pulse shapes
144+ def gen_bark (blen ):
145+ """This function will output a Barker code pulse.
146+
147+ Parameters
148+ ----------
149+ blen : int
150+ An integer for number of bauds in barker code.
151+
152+ Returns
153+ -------
154+ outar : ndarray
155+ A blen length numpy array.
156+ """
157+ bdict = {
158+ 1 : [- 1 ],
159+ 2 : [- 1 , 1 ],
160+ 3 : [- 1 , - 1 , 1 ],
161+ 4 : [- 1 , - 1 , 1 , - 1 ],
162+ 5 : [- 1 , - 1 , - 1 , 1 , - 1 ],
163+ 7 : [- 1 , - 1 , - 1 , 1 , 1 , - 1 , 1 ],
164+ 11 : [- 1 , - 1 , - 1 , 1 , 1 , 1 , - 1 , 1 , 1 , - 1 , 1 ],
165+ 13 : [- 1 , - 1 , - 1 , - 1 , - 1 , 1 , 1 , - 1 , - 1 , 1 , - 1 , 1 , - 1 ],
166+ }
167+ outar = np .array (bdict [blen ])
168+ outar .astype (np .float64 )
169+ return outar
170+
171+
172+ def barker_lag (x_in , numtype = None , pulse = gen_bark (13 )):
173+ """This will process barker code data by filtering it with a barker code pulse and then sum up the pulses.
174+
175+ Paramaters
176+ ----------
177+ x_in : ndarray
178+ A complex numpy array size NpxNs where Np is the number of pulses and
179+ numtype : type
180+ The type used for processing the data.
181+ pulse : ndarray
182+ The barkercode pulse.
183+ Returns
184+ -------
185+ outdata : ndarray
186+ A Nrx1 size numpy array that holds the processed data. Nr is the number of range gates
187+ """
188+
189+ if numtype is None :
190+ numtype = x_in .dtype
191+
192+ # It will be assumed the data will be pulses vs rangne
193+ x_in = x_in .transpose ()
194+ (Nr , Np ) = x_in .shape
195+ pulsepow = np .power (np .absolute (pulse ), 2.0 ).sum ()
196+ # Make matched filter
197+ filt = np .fft .fft (pulse [::- 1 ] / np .sqrt (pulsepow ), n = Nr )
198+ filtmat = np .repeat (filt [:, np .newaxis ], Np , axis = 1 )
199+ rawfreq = np .fft .fft (x_in , axis = 0 )
200+ outdata = np .fft .ifft (filtmat * rawfreq , axis = 0 )
201+
202+ outdata = outdata * outdata .conj ()
203+ outdata = np .sum (outdata , axis = - 1 )
204+ # increase the number of axes
205+ return outdata [len (pulse ) - 1 :, np .newaxis ]
206+
207+
208+ def make_sum_rule (nlag , lagtype = "centered" , srule = None ):
209+ """This function will return the sum rule.
210+
211+ Parameter
212+ ---------
213+ nlag : int
214+ Number of lags in the ACF.
215+ lagtype : str
216+ Type of lags, centered, forward or backward.
217+
218+ Returns
219+ -------
220+ sumrule : ndarray
221+ A 2 x nlag numpy array that holds the summation rule.
222+ """
223+ if lagtype == "forward" :
224+ arback = - np .arange (nlag , dtype = int )
225+ arforward = np .zeros (nlag , dtype = int )
226+ elif lagtype == "backward" :
227+ arback = np .zeros (nlag , dtype = int )
228+ arforward = np .arange (nlag , dtype = int )
229+ elif lagtype == "centered" :
230+ arback = - np .ceil (np .arange (0 , nlag / 2.0 , 0.5 )).astype (int )
231+ arforward = np .floor (np .arange (0 , nlag / 2.0 , 0.5 )).astype (int )
232+ elif lagtype == "barker" :
233+ arback = np .zeros (1 , dtype = int )
234+ arforward = np .zeros (1 , dtype = int )
235+ sumrule = np .array ([arback , arforward ])
236+ return sumrule
237+
238+
239+ def make_acf (
240+ x_in , nlag , nmean = 10 , numtype = np .complex64 , lagtype = "centered" , srule = "centered"
241+ ):
242+ """Performs the full ACF estimation including application of the summation rule to equalize the lag statistics.
243+
244+ Parameters
245+ ----------
246+ x_in : ndarray
247+ This is a NpxNs complex numpy array where Ns is number of samples per pulse and Np is number of pulses
248+ nmean : int
249+ Number of pulses to be averaged first before median applied.
250+ nlag : int
251+ Length of the lag product formation.
252+ numtype : type
253+ numerical representaiton of the array.
254+ lagtype : str
255+ Can be centered forward or backward.
256+ srule : str
257+
258+ Returns
259+ -------
260+ acf_est : ndarray
261+ This is a NrxNl complex numpy array where Nr is number of range gate and Nl is number of lags.
262+ rg_keep : ndarray
263+ Indicies of the samples/range gates that will be kept after the lag formation.
264+ """
265+
266+ sumrule = make_sum_rule (nlag , lagtype , srule )
267+ y_out , rng_k1 = lag_product (x_in , nlag , nmean , numtype , lagtype )
268+ n_rg = y_out .shape [0 ]
269+ minrg = - 1 * sumrule [0 ].min ()
270+ maxrg = n_rg - sumrule [1 ].max ()
271+ n_rg_out = maxrg - minrg
272+ rng_k2 = rng_k1 [minrg , maxrg ]
273+ acf_est = np .zeros ((n_rg_out , nlag ), dtype = numtype )
274+ for inum , irg in enumerate (range (minrg , maxrg )):
275+ for ilag in range (nlag ):
276+ cur_sr = sumrule [:, ilag ]
277+ r_sl = slice (irg + cur_sr [0 ], irg + cur_sr [1 ])
278+ # perform a sum on the lags instead of a averaging otherwise you have to weight a window on the output.
279+ acf_est [inum ] = np .nansum (y_out [r_sl , ilag ], axis = 0 )
280+ return acf_est , rng_k2
0 commit comments