Search code examples
pythonnumpyscipysignal-processing

Easy way to implement a Root Raised Cosine (RRC) filter using Python & Numpy


SciPy/Numpy seems to support many filters, but not the root-raised cosine filter. Is there a trick to easily create one rather than calculating the transfer function? An approximation would be fine as well.


Solution

  • The commpy package has several filters included with it. The order of return variables was switched in an earlier version (as of this edit, current version is 0.8.0). To install, follow instructions here or here.

    Here's an example for 1024 symbols of QAM16:

    import numpy as np
    from commpy.modulation import QAMModem
    from commpy.filters import rrcosfilter
    N = 1024  # Number of symbols. Also, the filter length in samples.
    os = 8    # Over-sampling factor
    # Create modulation. QAM16 makes 4 bits/symbol
    mod1 = QAMModem(16)
    # Generate the bit stream for N symbols
    sB = np.random.randint(0, 2, N*mod1.num_bits_symbol)
    # Generate N complex-integer valued symbols
    sQ = mod1.modulate(sB)
    sQ_upsampled = np.zeros(os*(len(sQ)-1)+1,dtype = np.complex64) 
    sQ_upsampled[::os] = sQ
    # Create a filter with limited bandwidth. Parameters:
    #      N: Filter length in samples
    #    0.8: Roll off factor alpha
    #      1: Symbol period in time-units
    #     os: Sample rate in 1/time-units
    sPSF = rrcosfilter(N, alpha=0.8, Ts=1, Fs=os)[1]
    # Analog signal has N/2 leading and trailing near-zero samples
    qW = np.convolve(sPSF, sQ_upsampled)
    

    Here's some explanation of the parameters. N is the number of baud samples. You need 4 times as many bits (in the case of QAM) as samples. I made the sPSF array return with N elements so we can see the signal with leading and trailing samples. See the Wikipedia Root-raised-cosine filter page for explanation of parameter alpha. Ts is the symbol period in seconds and Fs is the number of filter samples per Ts. I like to pretend Ts=1 to keep things simple (unit symbol rate). Then Fs is the number of complex waveform samples per baud point.

    If you use return element 0 from rrcosfilter to get the sample time indexes, you need to insert the correct symbol period and filter sample rate in Ts and Fs for the index values to be correctly scaled.