Skip to content

Commit 10f41fc

Browse files
committed
acf and news
1 parent 7adb77e commit 10f41fc

File tree

4 files changed

+241
-3
lines changed

4 files changed

+241
-3
lines changed

mitarspysigproc/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .estimators import create_sti
1+
from .estimators import create_sti, make_acf
22
from .detectors import cfar
33
from .filtertools import kaiser_coeffs, kaiser_syn_coeffs, kaiser_pfb_coefs, rref_coef
44
from .pfb import (

mitarspysigproc/estimators.py

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

mitarspysigproc/pfb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ def pfb_rec_simp(data, nchans, coeffs, mask, fillmethod, fillparams=[], realout=
222222
npw = np.nanmedian(data.flatten().real ** 2 + data.flatten().imag ** 2)
223223
npw = npw / np.log(2)
224224
d1r = np.random.randn(*shp, dtype=data.dtype)
225-
d1i = np.random.randn(*shp, dtype=data.dtype)
226-
d1 = d1r + 1j*d1i
225+
d1i = np.random.randn(*shp, dtype=data.dtype)
226+
d1 = d1r + 1j * d1i
227227

228228
d1 = np.sqrt(npw / 2) * d1
229229
rec_input = d1

news/vone.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
**Added:**
2+
3+
* Documentation via sphinx and readthedocs
4+
* ACF estimation for noncoherent processing
5+
* Conda build
6+
* pypi build
7+
8+
9+
**Changed:**
10+
11+
* Chirp and sine test are now just test code for the PFBs.
12+
* Moved scripts with plotting to examples
13+
* Examples are also located in doc/source/notebooks in the form of jupyter notebooks.
14+
15+
**Deprecated:**
16+
17+
* <news item>
18+
19+
**Removed:**
20+
21+
* <news item>
22+
23+
**Fixed:**
24+
25+
* <news item>
26+
27+
**Security:**
28+
29+
* <news item>

0 commit comments

Comments
 (0)