Пример #1
0
def msk_psd(fbin, fmax, bitrate):
    bins = int(round(2*fmax/fbin))
    f = fbin*(np.arange(bins)-int(bins/2))
    f_norm = f/bitrate
    psd = calc_msk(f_norm)
    psd /= np.sum(psd)
    return make_signal(fd=np.sqrt(np.fft.fftshift(psd)), fs=bins*fbin)
Пример #2
0
def gmsk_psd(fbin, fmax, bitrate, bt):
    bins = int(round(2*fmax/fbin))
    f = fbin*(np.arange(bins)-int(bins/2))
    f_norm = f/bitrate
    gauss = np.exp((np.log(2)/-2)*(f_norm/bt)**2)
    psd = gauss*calc_msk(f_norm)
    psd /= np.amax(psd)
    psd *= bins**2
    return make_signal(fd=np.sqrt(np.fft.fftshift(psd)), fs=bins*fbin)
Пример #3
0
def frame_data_bursts(signal,
                      sync_code,
                      payload_len,
                      fs,
                      bitrate,
                      fps,
                      sync_pos="center",
                      autocompute_fd=False,
                      verbose=True,
                      *args,
                      **kwargs):
    """ Takes data and creates with frames with data payload and sync field
        Bursts evenly spaced with specified bitrate, but symbol rate increased to fs
        If sync_pos is "start":
        |<-sync->|<---------------payload----------------->|
        If sync_pos is "center":
        |<------payload----->|<-sync->|<------paylod------>|

        Will zero pad if not enough data passed to fill all frame
    """
    sync_code = np.array(sync_code)
    n_frames = int(np.ceil(len(signal.td) / payload_len))
    f_len = payload_len + len(sync_code) + int((fs - bitrate) / float(fps))
    f_len_error = (fs - bitrate) / float(fps) - int(
        (fs - bitrate) / float(fps))
    s_len = len(sync_code)
    p_len = payload_len
    message = np.zeros(int(n_frames * p_len))
    message[:len(signal.td)] = signal.td
    td = np.zeros(int(n_frames * (f_len + f_len_error)))
    c_offset = int(payload_len / 2.0)
    for n in range(n_frames):
        error = int(n * f_len_error)
        if sync_pos == "center":
            td[error + n * f_len:error + n * f_len +
               c_offset] = message[n * p_len:n * p_len + c_offset]
            td[error + n * f_len + c_offset:error + n * f_len + c_offset +
               s_len] = sync_code
            td[error + n * f_len + c_offset + s_len:error + n * f_len + s_len +
               p_len] = message[n * p_len + c_offset:n * p_len + p_len]
        elif sync_pos == "start":
            td[n * f_len:n * f_len + s_len] = sync_code
            td[n * f_len + s_len:n * f_len +
               f_len] = message[n * p_len:n * p_len + p_len]

    return make_signal(td=td,
                       fs=fs,
                       bitrate=bitrate,
                       name=signal.name + "_%db_frames_%db_sync" %
                       (f_len, s_len),
                       autocompute_fd=autocompute_fd,
                       verbose=False)
Пример #4
0
def frame_data(signal,
               sync_code,
               payload_len,
               fs,
               bitrate,
               sync_pos="center",
               autocompute_fd=False,
               verbose=True,
               *args,
               **kwargs):
    """ Takes data and creates with frames with data payload and sync field
        If sync_pos is "start":
        |<-sync->|<---------------payload----------------->|
        If sync_pos is "center":
        |<------payload----->|<-sync->|<------paylod------>|

        Will zero pad if not enough data passed to fill all frame
    """
    sync_code = np.array(sync_code)
    n_frames = int(np.ceil(len(signal.td) / payload_len))
    f_len = payload_len + len(sync_code)
    s_len = len(sync_code)
    p_len = payload_len
    message = np.zeros(int(n_frames * p_len))
    message[:len(signal.td)] = signal.td
    td = np.zeros(int(n_frames * f_len))
    c_offset = int(payload_len / 2.0)
    for n in range(n_frames):
        if sync_pos == "center":
            td[n * f_len:n * f_len + c_offset] = message[n * p_len:n * p_len +
                                                         c_offset]
            td[n * f_len + c_offset:n * f_len + c_offset + s_len] = sync_code
            td[n * f_len + c_offset + s_len:n * f_len +
               f_len] = message[n * p_len + c_offset:n * p_len + p_len]
        elif sync_pos == "start":
            td[n * f_len:n * f_len + s_len] = sync_code
            td[n * f_len + s_len:n * f_len +
               f_len] = message[n * p_len:n * p_len + p_len]

    return make_signal(td=td,
                       fs=fs,
                       bitrate=bitrate,
                       name=signal.name + "_%db_frames_%db_sync" %
                       (f_len, s_len),
                       autocompute_fd=autocompute_fd,
                       verbose=False)
Пример #5
0
def gmsk_tx_filter(k,
                   m,
                   bt,
                   fs,
                   dt=0.0,
                   norm=False,
                   autocompute_fd=False,
                   verbose=True,
                   *args,
                   **kwargs):
    """ Design GMSK transmit filter
         k      : samples/symbol
         m      : pulse_span
         bt     : rolloff factor (0 < bt <= 1)
         dt     : fractional sample delay
    """
    if k < 1:
        raise Exception("error: gmsk_tx_filter(): k must be greater than 0\n")
    elif m < 1:
        raise Exception("error: gmsk_tx_filter(): m must be greater than 0\n")
    elif bt < 0.0 or bt > 1.0:
        raise Exception("error: gmsk_tx_filter(): beta must be in [0,1]\n")

    # derived values
    fir_len = k * m + 1

    # compute filter coefficients
    t = np.arange(fir_len) / float(k) - 0.5 * m + dt
    tx_fir = q(2 * pi * bt * (t - 0.5) / SQRTLN2) - q(2 * pi * bt *
                                                      (t + 0.5) / SQRTLN2)

    # normalize filter coefficients such that the filter's
    # integral is pi/2
    if norm:
        tx_fir *= 1.0 / float(sum(tx_fir))
    else:  # pi/2 scale
        tx_fir *= pi / (2.0 * sum(tx_fir))

    return make_signal(td=tx_fir,
                       fs=fs,
                       force_even_samples=False,
                       name="gmsk_tx_fir_bt_%.2f" % bt,
                       autocompute_fd=autocompute_fd,
                       verbose=False)
Пример #6
0
def make_sync_fir(sync_code,
                  pulse_fir,
                  oversampling,
                  autocompute_fd=False,
                  verbose=True,
                  *args,
                  **kwargs):
    """ Takes binary sync code word, oversamples it and convolves it with a pulse
        shape finite impulse response to make a FIR sequence that can be used on
        Rx signal for synchronization.
    """
    _sync_code = np.array(sync_code, dtype=float)
    _sync_code[_sync_code <= 0] = -1.0
    _sync_code[_sync_code > 0] = 1.0
    sync_fir = np.zeros(len(_sync_code) * oversampling)
    sync_fir[np.arange(len(_sync_code)) * oversampling] = _sync_code
    sync_fir = np.convolve(sync_fir, pulse_fir.td, mode="full")
    return make_signal(td=sync_fir,
                       fs=pulse_fir.fs,
                       name="sync_code_" + pulse_fir.name,
                       autocompute_fd=autocompute_fd,
                       verbose=False)
Пример #7
0
def gmsk_matched_kaiser_rx_filter(k,
                                  m,
                                  bt_tx,
                                  bt_composite,
                                  fs,
                                  dt=0.0,
                                  delta=1e-3,
                                  autocompute_fd=False,
                                  verbose=True,
                                  *args,
                                  **kwargs):
    """ Design GMSK receive filter
        k      : samples/symbol
        m      : fir span
        bt     : rolloff factor (0 < beta <= 1)
        dt     : fractional sample delay
    """
    # validate input
    if k < 1:
        raise Exception(
            "error: gmsk_matched_kaiser_rx_filter(): k must be greater than 0\n"
        )
    elif m < 1:
        raise Exception(
            "error: gmsk_matched_kaiser_rx_filter(): m must be greater than 0\n"
        )
    elif bt_tx < 0.0 or bt_tx > 1.0:
        raise exception(
            "error: gmsk_matched_kaiser_rx_filter(): beta must be in [0,1]\n")
    elif bt_composite < 0.0 or bt_composite > 1.0:
        raise exception(
            "error: gmsk_matched_kaiser_rx_filter(): beta must be in [0,1]\n")

    # derived values
    fir_len = k * m + 1  # filter length
    # design transmit filter
    tx_fir = gmsk_tx_filter(k, m, bt_tx, fs).td

    # start of Rx filter design procedure
    # create 'prototype' matched filter
    prototype_fir = kaiser_filter_prototype(k, m, bt_composite, 0.0)
    prototype_fir *= pi / (2.0 * sum(prototype_fir))

    # create 'gain' filter to improve stop-band rejection
    fc = (0.7 + 0.1 * bt_tx) / float(k)
    As = 60.0
    oob_reject_fir = kaiser_filter_design(fir_len, fc, As, 0.0)

    # run ffts
    prototype_fd = np.fft.fft(prototype_fir)
    oob_reject_fd = np.fft.fft(oob_reject_fir)
    tx_fd = np.fft.fft(tx_fir)

    # find minimum of reponses
    tx_fd_min = np.amin(np.abs(tx_fd))
    prototype_fd_min = np.amin(np.abs(prototype_fd))
    oob_reject_fd_min = np.amin(np.abs(oob_reject_fd))

    # compute approximate matched Rx response, removing minima, and add correction factor
    rx_fd = (np.abs(prototype_fd) - prototype_fd_min +
             delta) / (np.abs(tx_fd) - tx_fd_min + delta)
    # Out of band suppression
    rx_fd *= (np.abs(oob_reject_fd) - oob_reject_fd_min) / (np.abs(
        oob_reject_fd[0]))
    rx_fir = np.fft.fftshift(np.fft.ifft(rx_fd))
    rx_fir = np.real(rx_fir) * k

    return make_signal(
        td=rx_fir,
        fs=fs,
        force_even_samples=False,
        name="gmsk_kaiser_matched_rx_fir_bt_tx_%.2f_bt_comp_%.2f" %
        (bt_tx, bt_composite),
        autocompute_fd=autocompute_fd,
        verbose=False)
Пример #8
0
def rcos_composite_tx_rx_filter(k,
                                m,
                                bt_tx,
                                bt_composite,
                                fs,
                                dt=0.0,
                                delta=1e-3,
                                autocompute_fd=False,
                                norm=False,
                                verbose=True,
                                *args,
                                **kwargs):
    """ Raised cosine response including out of band supression
        k      : samples/symbol
        m      : fir span
        bt     : tx rolloff factor (0 < beta <= 1)
        beta   :
        dt     : fractional sample delay
    """
    # validate input
    if k < 1:
        raise Exception(
            "error: rcos_composite_tx_rx_filter(): k must be greater than 0\n")
    elif m < 1:
        raise Exception(
            "error: rcos_composite_tx_rx_filter(): m must be greater than 0\n")
    elif bt_tx < 0.0 or bt_tx > 1.0:
        raise exception(
            "error: rcos_composite_tx_rx_filter(): beta must be in [0,1]\n")
    elif bt_composite < 0.0 or bt_composite > 1.0:
        raise exception(
            "error: rcos_composite_tx_rx_filter(): beta must be in [0,1]\n")

    # derived values
    fir_len = k * m + 1  # filter length

    # create 'prototype' matched filter

    t = np.arange(fir_len) / float(k) - 0.5 * m + dt
    prototype_fir = v_raised_cos(t, 1.0, bt_composite)
    prototype_fir *= pi / (2.0 * sum(prototype_fir))
    # create 'gain' filter to improve stop-band rejection
    fc = (0.7 + 0.1 * bt_tx) / float(k)
    As = 60.0
    oob_reject_fir = kaiser_filter_design(fir_len, fc, As, 0.0)

    # run ffts
    prototype_fd = np.fft.fft(prototype_fir)
    oob_reject_fd = np.fft.fft(oob_reject_fir)

    # find minimum of reponses
    prototype_fd_min = np.amin(np.abs(prototype_fd))
    oob_reject_fd_min = np.amin(np.abs(oob_reject_fd))

    # compute approximate matched Rx response, removing minima, and add correction factor
    comp_fd = (np.abs(prototype_fd) - prototype_fd_min + delta)
    # Out of band suppression
    comp_fd *= (np.abs(oob_reject_fd) - oob_reject_fd_min) / (np.abs(
        oob_reject_fd[0]))
    comp_fir = np.fft.fftshift(np.fft.ifft(comp_fd))
    comp_fir = np.real(comp_fir) * k
    if norm:
        comp_fir *= 1.0 / float(sum(comp_fir))

    return make_signal(td=comp_fir,
                       fs=fs,
                       force_even_samples=False,
                       name="rcos_composite_fir_%.2f_bt_comp_%.2f" %
                       (bt_tx, bt_composite),
                       autocompute_fd=autocompute_fd,
                       verbose=False)