Module DigiCommPy.scripts.chapter_1.demo_scripts

Test scripts described in Chapter 1

@author: Mathuranathan Viswanathan Created on Jul 16, 2019

Expand source code
'''
Test scripts described in Chapter 1

@author: Mathuranathan Viswanathan
Created on Jul 16, 2019
'''
def sine_wave_demo():
    """
    Simulate a sinusoidal signal with given sampling rate    
    """
    import numpy as np
    import matplotlib.pyplot as plt # library for plotting
    from signalgen import sine_wave # import the function
    
    f = 10 #frequency = 10 Hz
    overSampRate = 30 #oversammpling rate
    phase = 1/3*np.pi #phase shift in radians
    nCyl = 5 # desired number of cycles of the sine wave
    (t,g) = sine_wave(f,overSampRate,phase,nCyl) #function call 
    
    plt.plot(t,g) # plot using pyplot library from matplotlib package
    plt.title('Sine wave f='+str(f)+' Hz') # plot title 
    plt.xlabel('Time (s)') # x-axis label
    plt.ylabel('Amplitude') # y-axis label
    plt.show() # disply the figure

def scipy_square_wave():
    """
    Generate a square wave with given sampling rate
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import signal
    
    f = 10 # f = 10Hz 
    overSampRate = 30 # oversampling rate
    nCyl = 5 # number of cycles to generate
    
    fs = overSampRate*f # sampling frequency
    t = np.arange(start=0,stop=nCyl*1/f,step=1/fs)# time base
    g = signal.square(2 * np.pi * f * t, duty = 0.2)
    plt.plot(t,g); plt.show()

def chirp_demo():
    """
    Generating and plotting a chirp signal
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import chirp
    
    fs = 500 # sampling frequency in Hz
    t =np.arange(start = 0, stop = 1,step = 1/fs) #total time base from 0 to 1 second
    g = chirp(t, f0=1, t1=0.5, f1=20, phi=0, method='linear')
    plt.plot(t,g); plt.show()

def interpret_fft_demo():
    """
    Demonstrate how to interpret FFT results
    """
    from scipy.fftpack import fft
    import numpy as np
    import matplotlib.pyplot as plt
    np.set_printoptions(formatter={"float_kind": lambda x: "%g" % x})
    
    fc=10 # frequency of the carrier
    fs=32*fc # sampling frequency with oversampling factor=32
    t=np.arange(start = 0,stop = 2,step = 1/fs) # 2 seconds duration
    x=np.cos(2*np.pi*fc*t) # time domain signal (real number)
    
    fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1)
    ax1.plot(t,x) #plot the signal
    ax1.set_title('$x[n]= cos(2 \pi 10 t)$')
    ax1.set_xlabel('$t=nT_s$')
    ax1.set_ylabel('$x[n]$')
    
    N=256 # FFT size
    X = fft(x,N) # N-point complex DFT, output contains DC at index 0
    # Nyquist frequency at N/2 th index positive frequencies from
    # index 2 to N/2-1 and negative frequencies from index N/2 to N-1
    print(X[0]) #output approximately equal to zero
    print(abs(X[7:10])) #display samples 7 to 9
    
    # calculate frequency bins with FFT
    df=fs/N # frequency resolution
    sampleIndex = np.arange(start = 0,stop = N) # raw index for FFT plot
    f=sampleIndex*df # x-axis index converted to frequencies
    
    ax2.stem(sampleIndex,abs(X),use_line_collection=True) # sample values on x-axis
    ax2.set_title('X[k]');ax2.set_xlabel('k');ax2.set_ylabel('|X(k)|');
    ax3.stem(f,abs(X),use_line_collection=True); # x-axis represent frequencies
    ax3.set_title('X[f]');ax3.set_xlabel('frequencies (f)');ax3.set_ylabel('|X(f)|');
    fig.show()
    
    nyquistIndex=N//2 #// is for integer division
    print(X[nyquistIndex-2:nyquistIndex+3, None]) #None argument to print array as column
    
    from scipy.fftpack import fftshift
    #re-order the index for emulating fftshift
    sampleIndex = np.arange(start = -N//2, stop = N//2) # // for integer division
    X1 = X[sampleIndex] #order frequencies without using fftShift
    X2 = fftshift(X) # order frequencies by using fftshift
    df=fs/N # frequency resolution
    f=sampleIndex*df # x-axis index converted to frequencies
    
    #plot ordered spectrum using the two methods
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)#subplots creation
    ax1.stem(sampleIndex,abs(X1), use_line_collection=True)# result without fftshift
    ax1.stem(sampleIndex,abs(X2),'r', use_line_collection=True) # result with fftshift
    ax1.set_xlabel('k');ax1.set_ylabel('|X(k)|')
    
    ax2.stem(f,abs(X1), use_line_collection=True)
    ax2.stem(f,abs(X2),'r' , use_line_collection=True)
    ax2.set_xlabel('frequencies (f)'),ax2.set_ylabel('|X(f)|')
    fig.show()

def magnitude_phase_info_from_fft():
    """
    Demonstrate how to extract magnitude and phase using FFT/IFFT
    """
    from scipy.fftpack import fft, ifft, fftshift, ifftshift
    import numpy as np
    import matplotlib.pyplot as plt
    
    A = 0.5 # amplitude of the cosine wave
    fc=10 # frequency of the cosine wave in Hz
    phase=30 # desired phase shift of the cosine in degrees
    fs=32*fc # sampling frequency with oversampling factor 32
    t=np.arange(start = 0,stop = 2,step = 1/fs) # 2 seconds duration
    
    phi = phase*np.pi/180; # convert phase shift in degrees in radians
    x=A*np.cos(2*np.pi*fc*t+phi) # time domain signal with phase shift
    
    fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4, ncols=1)
    ax1.plot(t,x) # plot time domain representation
    ax1.set_title(r'$x(t) = 0.5 cos (2 \pi 10 t + \pi/6)$')
    ax1.set_xlabel('time (t seconds)');ax1.set_ylabel('x(t)')
    
    N=256 # FFT size
    X = 1/N*fftshift(fft(x,N)) # N-point complex DFT
    
    df=fs/N # frequency resolution
    sampleIndex = np.arange(start = -N//2,stop = N//2) # // for integer division
    f=sampleIndex*df # x-axis index converted to ordered frequencies
    ax2.stem(f,abs(X), use_line_collection=True) # magnitudes vs frequencies
    ax2.set_xlim(-30, 30)
    ax2.set_title('Amplitude spectrum')
    ax2.set_xlabel('f (Hz)');ax2.set_ylabel(r'$ \left| X(k) \right|$')
    
    phase=np.arctan2(np.imag(X),np.real(X))*180/np.pi # phase information
    ax3.plot(f,phase) # phase vs frequencies
    ax3.set_title('Phase spectrum')
    ax3.set_ylabel(r"$\angle$ X[k]");ax3.set_xlabel('f(Hz)')
    
    X2=X #store the FFT results in another array
    # detect noise (very small numbers (eps)) and ignore them
    threshold = max(abs(X))/10000; # tolerance threshold
    X2[abs(X)<threshold]=0 # maskout values below the threshold
    phase=np.arctan2(np.imag(X2),np.real(X2))*180/np.pi # phase information
    ax4.stem(f,phase, use_line_collection=True) # phase vs frequencies
    ax4.set_xlim(-30, 30)
    ax4.set_title('Phase spectrum')
    ax4.set_ylabel(r"$\angle$ X[k]");ax4.set_xlabel('f(Hz)')
    fig.show()
    
    x_recon = N*ifft(ifftshift(X),N) # reconstructed signal
    t = np.arange(start = 0,stop = len(x_recon))/fs # recompute time index
    fig2, ax5 = plt.subplots()
    ax5.plot(t,np.real(x_recon)) # reconstructed signal
    ax5.set_title('reconstructed signal')
    ax1.set_xlabel('time (t seconds)');ax1.set_ylabel('x(t)')
    fig2.show()

def sine_wave_psd_demo():
    """
    Computation of power of a signal - simulation and verification
    """
    import numpy as np
    import matplotlib.pyplot as plt
    
    A=1 #Amplitude of sine wave
    fc=100 #Frequency of sine wave
    fs=3000 # Sampling frequency - oversampled by the rate of 30
    nCyl=3 # Number of cycles of the sinewave
    t=np.arange(start = 0,stop = nCyl/fc,step = 1/fs) #Time base
    x=-A*np.sin(2*np.pi*fc*t) # Sinusoidal function
    
    fig, (ax1,ax2) = plt.subplots(nrows=1,ncols = 2)
    ax1.plot(t,x)
    ax1.set_title('Sinusoid of frequency $f_c=100 Hz$')
    ax1.set_xlabel('Time(s)');ax1.set_ylabel('Amplitude')
    fig.show()
    
    from numpy.linalg import norm
    L=len(x)
    P=(norm(x)**2)/L; #norm from numpy linear algo package
    print('Power of the Signal from Time domain {:0.4f}'.format(P))
    
    from scipy.fftpack import fft,fftshift
    NFFT=L
    X=fftshift(fft(x,NFFT))
    Px=X*np.conj(X)/(L**2) #Power of each freq components
    fVals=fs*np.arange(start = -NFFT/2,stop = NFFT/2)/NFFT
    ax2.stem(fVals,Px,'r')
    ax2.set_title('Power Spectral Density')
    ax2.set_xlabel('Frequency (Hz)');ax2.set_ylabel('Power')

def compare_convolutions():
    """
    Comparing different methods for computing convolution
    """
    import numpy as np
    from scipy.fftpack import fft,ifft
    from essentials import my_convolve #import our function from essentials.py
    
    x = np.random.normal(size = 7) + 1j*np.random.normal(size = 7) #normal random complex vectors
    h = np.random.normal(size = 3) + 1j*np.random.normal(size = 3) #normal random complex vectors
    L = len(x) + len(h) - 1 #length of convolution output
       
    y1=my_convolve(h,x) #Convolution Using Toeplitz matrix
    y2=ifft(fft(x,L)*(fft(h,L))).T #Convolution using FFT
    y3=np.convolve(h,x) #Numpy's standard function
    print(f' y1 : {y1} \n y2 : {y2} \n y3 : {y3} \n')

def analytic_signal_demo():
    """
    Investigate components of an analytic signal
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from essentials import analytic_signal #import our function from essentials.py
    
    t=np.arange(start=0,stop=0.5,step=0.001); # time base
    x = np.sin(2*np.pi*10*t) # real-valued f = 10 Hz
    
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(t,x) # plot the original signal
    ax1.set_title('x[n] - real-valued signal')
    ax1.set_xlabel('n');
    ax1.set_ylabel('x[n]')
    
    z = analytic_signal(x) # construct analytic signal
    
    ax2.plot(t, np.real(z), 'k',label='Real(z[n])')
    ax2.plot(t, np.imag(z), 'r',label='Imag(z[n])')
    ax2.set_title('Components of Analytic signal');
    ax2.set_xlabel('n');
    ax2.set_ylabel(r'$z_r[n]$ and $z_i[n]$')
    ax2.legend();fig.show()

def extract_envelope_phase():
    """
    Demonstrate extraction of instantaneous amplitude and phase from 
    the analytic signal constructed from a real-valued modulated signal
    """
    import numpy as np
    from scipy.signal import chirp
    import matplotlib.pyplot as plt
    from essentials import analytic_signal
    
    fs = 600 # sampling frequency in Hz
    t = np.arange(start=0,stop=1, step=1/fs) # time base
    a_t = 1.0 + 0.7 * np.sin(2.0*np.pi*3.0*t) # information signal
    c_t = chirp(t, f0=20, t1=t[-1], f1=80, phi=0, method='linear')
    x = a_t * c_t # modulated signal
    
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(x) # plot the modulated signal
    z = analytic_signal(x) # form the analytical signal
    inst_amplitude = abs(z) # envelope extraction
    inst_phase = np.unwrap(np.angle(z)) # inst phase
    inst_freq = np.diff(inst_phase)/(2*np.pi)*fs # inst frequency
    
    # Regenerate the carrier from the instantaneous phase
    extracted_carrier = np.cos(inst_phase)
    ax1.plot(inst_amplitude,'r') # overlay the extracted envelope
    ax1.set_title('Modulated signal and extracted envelope')
    ax1.set_xlabel('n');ax1.set_ylabel(r'x(t) and $|z(t)|$')
    ax2.plot(extracted_carrier)
    ax2.set_title('Extracted carrier or TFS')
    ax2.set_xlabel('n');ax2.set_ylabel(r'$cos[\omega(t)]$')
    fig.show()

def hilbert_phase_demod():
    """
    Demonstrate simple Phase Demodulation using Hilbert transform
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import hilbert
    
    fc = 210 # carrier frequency
    fm = 10 # frequency of modulating signal
    alpha = 1 # amplitude of modulating signal
    theta = np.pi/4 # phase offset of modulating signal
    beta = np.pi/5 # constant carrier phase offset
    # Set True if receiver knows carrier frequency & phase offset 
    receiverKnowsCarrier= False
        
    fs = 8*fc # sampling frequency
    duration = 0.5 # duration of the signal
    t = np.arange(start = 0, stop = duration, step = 1/fs) # time base
    
    #Phase Modulation
    m_t = alpha*np.sin(2*np.pi*fm*t + theta) # modulating signal
    x = np.cos(2*np.pi*fc*t + beta + m_t ) # modulated signal
    
    fig1, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(t,m_t) # plot modulating signal
    ax1.set_title('Modulating signal')
    ax1.set_xlabel('t');ax1.set_ylabel('m(t)')
    
    ax2.plot(t,x) # plot modulated signal
    ax2.set_title('Modulated signal')
    ax2.set_xlabel('t');ax2.set_ylabel('x(t)');fig1.show()
    
    #Add AWGN noise to the transmitted signal
    mu = 0; sigma = 0.1  # noise mean and sigma
    n = mu + sigma*np.random.normal(len(t)) # awgn noise
    r = x + n # noisy received signal
    
    # Demodulation of the noisy Phase Modulated signal
    z= hilbert(r) # form the analytical signal from the received vector
    inst_phase = np.unwrap(np.angle(z)) # instaneous phase
    
    if receiverKnowsCarrier: # If receiver knows the carrier freq/phase perfectly
        offsetTerm = 2*np.pi*fc*t+beta
    else: # else, estimate the subtraction term
        p = np.polyfit(x =t, y =inst_phase, deg =1)#linear fit instantaneous phase
        #re-evaluate the offset term using the fitted values
        estimated = np.polyval(p,t)
        offsetTerm = estimated
    
    demodulated = inst_phase - offsetTerm
    
    fig2, ax3 = plt.subplots()
    ax3.plot(t,demodulated) # demodulated signal
    ax3.set_title('Demodulated signal')
    ax3.set_xlabel('n')
    ax3.set_ylabel(r'$\hat{m(t)}$');fig2.show()

Functions

def analytic_signal_demo()

Investigate components of an analytic signal

Expand source code
def analytic_signal_demo():
    """
    Investigate components of an analytic signal
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from essentials import analytic_signal #import our function from essentials.py
    
    t=np.arange(start=0,stop=0.5,step=0.001); # time base
    x = np.sin(2*np.pi*10*t) # real-valued f = 10 Hz
    
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(t,x) # plot the original signal
    ax1.set_title('x[n] - real-valued signal')
    ax1.set_xlabel('n');
    ax1.set_ylabel('x[n]')
    
    z = analytic_signal(x) # construct analytic signal
    
    ax2.plot(t, np.real(z), 'k',label='Real(z[n])')
    ax2.plot(t, np.imag(z), 'r',label='Imag(z[n])')
    ax2.set_title('Components of Analytic signal');
    ax2.set_xlabel('n');
    ax2.set_ylabel(r'$z_r[n]$ and $z_i[n]$')
    ax2.legend();fig.show()
def chirp_demo()

Generating and plotting a chirp signal

Expand source code
def chirp_demo():
    """
    Generating and plotting a chirp signal
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import chirp
    
    fs = 500 # sampling frequency in Hz
    t =np.arange(start = 0, stop = 1,step = 1/fs) #total time base from 0 to 1 second
    g = chirp(t, f0=1, t1=0.5, f1=20, phi=0, method='linear')
    plt.plot(t,g); plt.show()
def compare_convolutions()

Comparing different methods for computing convolution

Expand source code
def compare_convolutions():
    """
    Comparing different methods for computing convolution
    """
    import numpy as np
    from scipy.fftpack import fft,ifft
    from essentials import my_convolve #import our function from essentials.py
    
    x = np.random.normal(size = 7) + 1j*np.random.normal(size = 7) #normal random complex vectors
    h = np.random.normal(size = 3) + 1j*np.random.normal(size = 3) #normal random complex vectors
    L = len(x) + len(h) - 1 #length of convolution output
       
    y1=my_convolve(h,x) #Convolution Using Toeplitz matrix
    y2=ifft(fft(x,L)*(fft(h,L))).T #Convolution using FFT
    y3=np.convolve(h,x) #Numpy's standard function
    print(f' y1 : {y1} \n y2 : {y2} \n y3 : {y3} \n')
def extract_envelope_phase()

Demonstrate extraction of instantaneous amplitude and phase from the analytic signal constructed from a real-valued modulated signal

Expand source code
def extract_envelope_phase():
    """
    Demonstrate extraction of instantaneous amplitude and phase from 
    the analytic signal constructed from a real-valued modulated signal
    """
    import numpy as np
    from scipy.signal import chirp
    import matplotlib.pyplot as plt
    from essentials import analytic_signal
    
    fs = 600 # sampling frequency in Hz
    t = np.arange(start=0,stop=1, step=1/fs) # time base
    a_t = 1.0 + 0.7 * np.sin(2.0*np.pi*3.0*t) # information signal
    c_t = chirp(t, f0=20, t1=t[-1], f1=80, phi=0, method='linear')
    x = a_t * c_t # modulated signal
    
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(x) # plot the modulated signal
    z = analytic_signal(x) # form the analytical signal
    inst_amplitude = abs(z) # envelope extraction
    inst_phase = np.unwrap(np.angle(z)) # inst phase
    inst_freq = np.diff(inst_phase)/(2*np.pi)*fs # inst frequency
    
    # Regenerate the carrier from the instantaneous phase
    extracted_carrier = np.cos(inst_phase)
    ax1.plot(inst_amplitude,'r') # overlay the extracted envelope
    ax1.set_title('Modulated signal and extracted envelope')
    ax1.set_xlabel('n');ax1.set_ylabel(r'x(t) and $|z(t)|$')
    ax2.plot(extracted_carrier)
    ax2.set_title('Extracted carrier or TFS')
    ax2.set_xlabel('n');ax2.set_ylabel(r'$cos[\omega(t)]$')
    fig.show()
def hilbert_phase_demod()

Demonstrate simple Phase Demodulation using Hilbert transform

Expand source code
def hilbert_phase_demod():
    """
    Demonstrate simple Phase Demodulation using Hilbert transform
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import hilbert
    
    fc = 210 # carrier frequency
    fm = 10 # frequency of modulating signal
    alpha = 1 # amplitude of modulating signal
    theta = np.pi/4 # phase offset of modulating signal
    beta = np.pi/5 # constant carrier phase offset
    # Set True if receiver knows carrier frequency & phase offset 
    receiverKnowsCarrier= False
        
    fs = 8*fc # sampling frequency
    duration = 0.5 # duration of the signal
    t = np.arange(start = 0, stop = duration, step = 1/fs) # time base
    
    #Phase Modulation
    m_t = alpha*np.sin(2*np.pi*fm*t + theta) # modulating signal
    x = np.cos(2*np.pi*fc*t + beta + m_t ) # modulated signal
    
    fig1, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)
    ax1.plot(t,m_t) # plot modulating signal
    ax1.set_title('Modulating signal')
    ax1.set_xlabel('t');ax1.set_ylabel('m(t)')
    
    ax2.plot(t,x) # plot modulated signal
    ax2.set_title('Modulated signal')
    ax2.set_xlabel('t');ax2.set_ylabel('x(t)');fig1.show()
    
    #Add AWGN noise to the transmitted signal
    mu = 0; sigma = 0.1  # noise mean and sigma
    n = mu + sigma*np.random.normal(len(t)) # awgn noise
    r = x + n # noisy received signal
    
    # Demodulation of the noisy Phase Modulated signal
    z= hilbert(r) # form the analytical signal from the received vector
    inst_phase = np.unwrap(np.angle(z)) # instaneous phase
    
    if receiverKnowsCarrier: # If receiver knows the carrier freq/phase perfectly
        offsetTerm = 2*np.pi*fc*t+beta
    else: # else, estimate the subtraction term
        p = np.polyfit(x =t, y =inst_phase, deg =1)#linear fit instantaneous phase
        #re-evaluate the offset term using the fitted values
        estimated = np.polyval(p,t)
        offsetTerm = estimated
    
    demodulated = inst_phase - offsetTerm
    
    fig2, ax3 = plt.subplots()
    ax3.plot(t,demodulated) # demodulated signal
    ax3.set_title('Demodulated signal')
    ax3.set_xlabel('n')
    ax3.set_ylabel(r'$\hat{m(t)}$');fig2.show()
def interpret_fft_demo()

Demonstrate how to interpret FFT results

Expand source code
def interpret_fft_demo():
    """
    Demonstrate how to interpret FFT results
    """
    from scipy.fftpack import fft
    import numpy as np
    import matplotlib.pyplot as plt
    np.set_printoptions(formatter={"float_kind": lambda x: "%g" % x})
    
    fc=10 # frequency of the carrier
    fs=32*fc # sampling frequency with oversampling factor=32
    t=np.arange(start = 0,stop = 2,step = 1/fs) # 2 seconds duration
    x=np.cos(2*np.pi*fc*t) # time domain signal (real number)
    
    fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1)
    ax1.plot(t,x) #plot the signal
    ax1.set_title('$x[n]= cos(2 \pi 10 t)$')
    ax1.set_xlabel('$t=nT_s$')
    ax1.set_ylabel('$x[n]$')
    
    N=256 # FFT size
    X = fft(x,N) # N-point complex DFT, output contains DC at index 0
    # Nyquist frequency at N/2 th index positive frequencies from
    # index 2 to N/2-1 and negative frequencies from index N/2 to N-1
    print(X[0]) #output approximately equal to zero
    print(abs(X[7:10])) #display samples 7 to 9
    
    # calculate frequency bins with FFT
    df=fs/N # frequency resolution
    sampleIndex = np.arange(start = 0,stop = N) # raw index for FFT plot
    f=sampleIndex*df # x-axis index converted to frequencies
    
    ax2.stem(sampleIndex,abs(X),use_line_collection=True) # sample values on x-axis
    ax2.set_title('X[k]');ax2.set_xlabel('k');ax2.set_ylabel('|X(k)|');
    ax3.stem(f,abs(X),use_line_collection=True); # x-axis represent frequencies
    ax3.set_title('X[f]');ax3.set_xlabel('frequencies (f)');ax3.set_ylabel('|X(f)|');
    fig.show()
    
    nyquistIndex=N//2 #// is for integer division
    print(X[nyquistIndex-2:nyquistIndex+3, None]) #None argument to print array as column
    
    from scipy.fftpack import fftshift
    #re-order the index for emulating fftshift
    sampleIndex = np.arange(start = -N//2, stop = N//2) # // for integer division
    X1 = X[sampleIndex] #order frequencies without using fftShift
    X2 = fftshift(X) # order frequencies by using fftshift
    df=fs/N # frequency resolution
    f=sampleIndex*df # x-axis index converted to frequencies
    
    #plot ordered spectrum using the two methods
    fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)#subplots creation
    ax1.stem(sampleIndex,abs(X1), use_line_collection=True)# result without fftshift
    ax1.stem(sampleIndex,abs(X2),'r', use_line_collection=True) # result with fftshift
    ax1.set_xlabel('k');ax1.set_ylabel('|X(k)|')
    
    ax2.stem(f,abs(X1), use_line_collection=True)
    ax2.stem(f,abs(X2),'r' , use_line_collection=True)
    ax2.set_xlabel('frequencies (f)'),ax2.set_ylabel('|X(f)|')
    fig.show()
def magnitude_phase_info_from_fft()

Demonstrate how to extract magnitude and phase using FFT/IFFT

Expand source code
def magnitude_phase_info_from_fft():
    """
    Demonstrate how to extract magnitude and phase using FFT/IFFT
    """
    from scipy.fftpack import fft, ifft, fftshift, ifftshift
    import numpy as np
    import matplotlib.pyplot as plt
    
    A = 0.5 # amplitude of the cosine wave
    fc=10 # frequency of the cosine wave in Hz
    phase=30 # desired phase shift of the cosine in degrees
    fs=32*fc # sampling frequency with oversampling factor 32
    t=np.arange(start = 0,stop = 2,step = 1/fs) # 2 seconds duration
    
    phi = phase*np.pi/180; # convert phase shift in degrees in radians
    x=A*np.cos(2*np.pi*fc*t+phi) # time domain signal with phase shift
    
    fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4, ncols=1)
    ax1.plot(t,x) # plot time domain representation
    ax1.set_title(r'$x(t) = 0.5 cos (2 \pi 10 t + \pi/6)$')
    ax1.set_xlabel('time (t seconds)');ax1.set_ylabel('x(t)')
    
    N=256 # FFT size
    X = 1/N*fftshift(fft(x,N)) # N-point complex DFT
    
    df=fs/N # frequency resolution
    sampleIndex = np.arange(start = -N//2,stop = N//2) # // for integer division
    f=sampleIndex*df # x-axis index converted to ordered frequencies
    ax2.stem(f,abs(X), use_line_collection=True) # magnitudes vs frequencies
    ax2.set_xlim(-30, 30)
    ax2.set_title('Amplitude spectrum')
    ax2.set_xlabel('f (Hz)');ax2.set_ylabel(r'$ \left| X(k) \right|$')
    
    phase=np.arctan2(np.imag(X),np.real(X))*180/np.pi # phase information
    ax3.plot(f,phase) # phase vs frequencies
    ax3.set_title('Phase spectrum')
    ax3.set_ylabel(r"$\angle$ X[k]");ax3.set_xlabel('f(Hz)')
    
    X2=X #store the FFT results in another array
    # detect noise (very small numbers (eps)) and ignore them
    threshold = max(abs(X))/10000; # tolerance threshold
    X2[abs(X)<threshold]=0 # maskout values below the threshold
    phase=np.arctan2(np.imag(X2),np.real(X2))*180/np.pi # phase information
    ax4.stem(f,phase, use_line_collection=True) # phase vs frequencies
    ax4.set_xlim(-30, 30)
    ax4.set_title('Phase spectrum')
    ax4.set_ylabel(r"$\angle$ X[k]");ax4.set_xlabel('f(Hz)')
    fig.show()
    
    x_recon = N*ifft(ifftshift(X),N) # reconstructed signal
    t = np.arange(start = 0,stop = len(x_recon))/fs # recompute time index
    fig2, ax5 = plt.subplots()
    ax5.plot(t,np.real(x_recon)) # reconstructed signal
    ax5.set_title('reconstructed signal')
    ax1.set_xlabel('time (t seconds)');ax1.set_ylabel('x(t)')
    fig2.show()
def scipy_square_wave()

Generate a square wave with given sampling rate

Expand source code
def scipy_square_wave():
    """
    Generate a square wave with given sampling rate
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import signal
    
    f = 10 # f = 10Hz 
    overSampRate = 30 # oversampling rate
    nCyl = 5 # number of cycles to generate
    
    fs = overSampRate*f # sampling frequency
    t = np.arange(start=0,stop=nCyl*1/f,step=1/fs)# time base
    g = signal.square(2 * np.pi * f * t, duty = 0.2)
    plt.plot(t,g); plt.show()
def sine_wave_demo()

Simulate a sinusoidal signal with given sampling rate

Expand source code
def sine_wave_demo():
    """
    Simulate a sinusoidal signal with given sampling rate    
    """
    import numpy as np
    import matplotlib.pyplot as plt # library for plotting
    from signalgen import sine_wave # import the function
    
    f = 10 #frequency = 10 Hz
    overSampRate = 30 #oversammpling rate
    phase = 1/3*np.pi #phase shift in radians
    nCyl = 5 # desired number of cycles of the sine wave
    (t,g) = sine_wave(f,overSampRate,phase,nCyl) #function call 
    
    plt.plot(t,g) # plot using pyplot library from matplotlib package
    plt.title('Sine wave f='+str(f)+' Hz') # plot title 
    plt.xlabel('Time (s)') # x-axis label
    plt.ylabel('Amplitude') # y-axis label
    plt.show() # disply the figure
def sine_wave_psd_demo()

Computation of power of a signal - simulation and verification

Expand source code
def sine_wave_psd_demo():
    """
    Computation of power of a signal - simulation and verification
    """
    import numpy as np
    import matplotlib.pyplot as plt
    
    A=1 #Amplitude of sine wave
    fc=100 #Frequency of sine wave
    fs=3000 # Sampling frequency - oversampled by the rate of 30
    nCyl=3 # Number of cycles of the sinewave
    t=np.arange(start = 0,stop = nCyl/fc,step = 1/fs) #Time base
    x=-A*np.sin(2*np.pi*fc*t) # Sinusoidal function
    
    fig, (ax1,ax2) = plt.subplots(nrows=1,ncols = 2)
    ax1.plot(t,x)
    ax1.set_title('Sinusoid of frequency $f_c=100 Hz$')
    ax1.set_xlabel('Time(s)');ax1.set_ylabel('Amplitude')
    fig.show()
    
    from numpy.linalg import norm
    L=len(x)
    P=(norm(x)**2)/L; #norm from numpy linear algo package
    print('Power of the Signal from Time domain {:0.4f}'.format(P))
    
    from scipy.fftpack import fft,fftshift
    NFFT=L
    X=fftshift(fft(x,NFFT))
    Px=X*np.conj(X)/(L**2) #Power of each freq components
    fVals=fs*np.arange(start = -NFFT/2,stop = NFFT/2)/NFFT
    ax2.stem(fVals,Px,'r')
    ax2.set_title('Power Spectral Density')
    ax2.set_xlabel('Frequency (Hz)');ax2.set_ylabel('Power')