コード例 #1
0
def LS_Filter_Toeplitz(ref, srv, nlag, return_filter=False):
    '''Least squares clutter removal for passive radar. Computes filter taps
    by assuming that the autocorrelation matrix of the reference channel signal 
    is Hermitian and Toeplitz. Faster than the direct matrix inversion method,
    but inaccurate if the assumptions are violated (i.e. if the input signal is
    not wide sense stationary.)
    
    
    Parameters:
    ref: reference signal
    srv: surveillance signal
    nlag: filter length in samples
    return_filter: (bool) option to return filter taps as well as cleaned signal
    
    Returns:
    y: surveillance signal with clutter removed
    w: (optional) least squares filter taps

    '''
    rs = np.roll(ref, -10)

    # compute the first column of the autocorelation matrix of ref
    c = xcorr(rs, rs, 0, nlag)

    # compute the cross-correlation of ref and srv
    r = xcorr(srv, rs, 0, nlag)

    # solve the Toeplitz least squares problem
    w = solve_toeplitz(c, r)

    if return_filter:
        return srv - np.convolve(rs, w, mode='same'), w
    else:
        return srv - np.convolve(rs, w, mode='same')
コード例 #2
0
def LS_Filter_Toeplitz(refChannel,
                       srvChannel,
                       filterLen,
                       peek=10,
                       return_filter=False):
    '''Block east squares adaptive filter. Computes filter coefficients using
    scipy's solve_toeplitz function. This assumes the autocorrelation matrix of 
    refChannel is Hermitian and Toeplitz (i.e. wide the reference signal is
    wide sense stationary). Faster than the direct matrix inversion method but
    inaccurate if the assumptions are violated. 
    
    Parameters:
        refChannel:     Array containing the reference channel signal
        srvChannel:     Array containing the surveillance channel signal
        filterLen:   Length of the least squares filter (in samples)
        peek:           Number of noncausal filter taps. Set to zero for a 
                        causal filter. If nonzero, clutter estimates can depend 
                        on future values of the reference signal (this helps 
                        sometimes)
        return_filter:  Boolean indicating whether to return the filter taps

    Returns:
        srvChannelFiltered: Surveillance channel signal with clutter removed
        filterTaps:     (optional) least squares filter taps

    '''

    if refChannel.shape != srvChannel.shape:
        raise ValueError(f'''Input vectors must have the same length - 
        got {refChannel.shape} and {srvChannel.shape}''')

    # shift reference channel because for some reason the filtering works
    # better when you allow the clutter filter to be noncausal
    refChannelShift = np.roll(refChannel, -1 * peek)

    # compute the first column of the autocorelation matrix of ref
    autocorrRef = xcorr(refChannelShift, refChannelShift, 0,
                        filterLen + peek - 1)

    # compute the cross-correlation of ref and srv
    xcorrSrvRef = xcorr(srvChannel, refChannelShift, 0, filterLen + peek - 1)

    # solve the Toeplitz least squares problem
    filterTaps = solve_toeplitz(autocorrRef, xcorrSrvRef)

    # compute clutter signal and remove from surveillance Channel
    clutter = np.convolve(refChannelShift, filterTaps, mode='full')
    clutter = clutter[0:srvChannel.shape[0]]
    srvChannelFiltered = srvChannel - clutter

    if return_filter:
        return srvChannelFiltered, filterTaps
    else:
        return srvChannelFiltered
コード例 #3
0
def direct_xambg(refChannel, srvChannel, rangeBins, freqBins, sampleRate):
    ''' Direct Cross-Ambiguity Fuction (time domain method)
    
    Args:
        refChannel: reference channel data
        srvChannel: surveillance channel data
        rangeBins:  number of range bins to compute
        freqBins:   number of doppler bins to compute
        sampleRate: input sample rate in Hz
    Returns:
        ndarray of dimensions (nf, nlag+1, 1) containing the cross-ambiguity
        surface. third dimension added for easy stacking in dask.
    '''
    if refChannel.shape != srvChannel.shape:
        raise ValueError('Input vectors must have the same length')

    # calculate the coherent processing interval in seconds
    CPI = refChannel.shape[0] / sampleRate

    # pre-allocate space for the result
    xambg = np.zeros((freqBins, rangeBins + 1, 1), dtype=np.complex64)

    # loop over frequency bins
    for i in range(freqBins):
        # get Doppler shift for the current bin
        df = (i - 0.5 * freqBins) / CPI
        # create a frequency shifted copy of the reference signal
        ref_shifted = frequency_shift(refChannel, df, sampleRate)
        # correlate surveillance and shifted reference signals
        xambg[i, :, 0] = xcorr(ref_shifted, srvChannel, rangeBins, 0)

    return xambg
コード例 #4
0
def signal_preview(config):

    inputFile = h5py.File(config['input_file'], 'r')

    if config['interleaved_input_channels']:

        data = inputFile[config['interleaved_data_path']][0:config['input_chunk_length']]
        data_IQ = deinterleave_IQ(data)
        
        ref = data_IQ[0::2]
        srv = data_IQ[1::2]

        offset = find_channel_offset(ref,srv,4,50000)

    else:

        # get the first few seconds of data and use it to estimate the
        # offset between the channels
        ref = inputFile[config['input_ref_path']][0:config['input_chunk_length']]
        srv = inputFile[config['input_srv_path']][0:config['input_chunk_length']]

        ref = deinterleave_IQ(ref)
        srv = deinterleave_IQ(srv)
        
        offset = find_channel_offset(ref,srv,4,50000)

    plt.figure()
    plt.psd(ref, NFFT=8192, Fs=config['input_sample_rate'], 
        Fc=config['input_center_freq'])
    plt.psd(srv, NFFT=8192, Fs=config['input_sample_rate'], 
        Fc=config['input_center_freq'])
    plt.legend(['Reference channel', 'Surveillance channel'])
    plt.title("Spectrum of Input Data")
    plt.show()

    reff = frequency_shift(ref, 
        config['offset_freq'], config['input_sample_rate'])
    srvv = frequency_shift(srv, 
        config['offset_freq'], config['input_sample_rate'])

    reff = resample(reff, config['resamp_up'], config['resamp_dn'])
    srvv = resample(srvv, config['resamp_up'], config['resamp_dn'])

    plt.figure()
    plt.psd(reff, NFFT=2048, Fs=config['channel_bandwidth'], 
        Fc=config['channel_freq'])
    plt.psd(srvv, NFFT=2048, Fs=config['channel_bandwidth'], 
        Fc=config['channel_freq'])
    plt.legend(['Reference channel', 'Surveillance channel'])
    plt.title("Channel Spectrum")
    plt.show()

    fig, ax = plt.subplots()
    xx = np.arange(-2000, 2001)
    xc = np.abs(xcorr(ref, srv, 2000, 2000))
    plt.plot(xx, xc)
    plt.title("Cross-correlation between channels")
    plt.text(0.1, 0.9, f"Offset of {offset} samples between channels", transform=ax.transAxes)
    plt.show()
コード例 #5
0
def direct_xambg(ref, srv, fs, fd, df, nlag):
    '''Create a range-doppler map from two signals
    
    input parameters:
    ref, srv:       input signals
    fs:             input sample rate (samples/sec)
    fd:             number of Doppler bins to compute
    df:             doppler resolution (Hz)
    nlag:           maximum lag between signals (samples)
    '''
    if ref.shape != srv.shape:
        raise ValueError('Input vectors must have the same length')

    omega_d = 2 * np.pi * np.arange(-1 * fd, fd - df, df) / fs
    nf = omega_d.shape[0]
    t = np.arange(ref.shape[0])
    xambg = np.zeros((nf, nlag + 1, 1), dtype=np.complex64)

    for k in range(nf):
        srv_shift = np.exp(1j * omega_d[k] * t) * srv
        xambg[k, :, 0] = xcorr(ref, srv_shift, 0, nlag)

    return xambg