I was trying to write 4QPSK in Python for my self learning based on the book Digital Modulations Using Python.
When I have my sampling frequency set to 4 times the carrier frequency, I get exactly 4 points in the eye diagram using the inphase and quadrature values. Also I get only 4 unique phases with modulated complex value(s_t)
If I change my sample frequency to multiples of any number (say OF) other than 4, my eye diagram gives me OF number of coordinates.
My code is below. Also demodulation is not providing me with correct value even without introducing any noise. For code given below against given input [1 0 1 1 0 0 0 1], got demodulated output as [1 0 1 1 0 1 0 0]
Please help me correct my mistake.
%matplotlib inline
import numpy as np
from scipy.signal import upfirdn #NRZ encoder
import matplotlib.pyplot as plt
baseband_bit_sequence = np.array([1, 0, 1, 1, 0, 0, 0, 1 ])
# Parameters
Fc = 10 # Carrier frequency Hertz
OF = 16 #Over sampling Factor
Fs = OF*Fc # Sampling frequency Hertz (i.e. Number of samples per second)
uL = OF*2 #Up Sampling repeat
I = baseband_bit_sequence[0::2]
Q = baseband_bit_sequence[1::2]
#Given Baseband bit sequence is very small. So let we up sample the same to get better visualization
#Let we upsample the given baseband_bit_sequence by value uL
#The same bit values in baseband_bit_sequence will be repeated uL times
I = np.repeat(I, uL)*2 - 1
Q = np.repeat(Q, uL)*2 - 1
#Now we have len(I) Inphase symbols and len(Q) Quadrature symbols (len (I) = len(Q) )
#For a given Sampling frequency Fs, now we have len(I) samples
#The duration (in seconds) taken for sending Fs symbol is 1 second becuase Fs is samples per second
#The duration (in seconds) taken for sending len(I) symbol is ((len(I)/Fs)*1sec)
duration = (len(I)/Fs)*1
#duration = ((len(I) + len(Q))/Fs)*1
#The time taken for sending one symbol is 1/Fs
one_symbol_duration = 1/Fs
#Time axis for duration D at regular interval of 1/Fs is
t = np.arange(0,duration,one_symbol_duration) #time base
I_t = I*np.cos((2*np.pi*Fc*t));Q_t = Q*np.sin((2*np.pi*Fc*t))
#Let we do frequency mixing to postive frequency
s_t = I_t + Q_t * 1j # QPSK modulated baseband signal
print (np.angle(s_t, deg=True)) # I should get only 4 unique phase angle ???
#For eye diagram do not plot all samples
#Only desired samples to be plot to get perfect 4 quadrant in eye diagram
desired_sample_value_index = int(OF/4)
plt.plot(s_t.real[::desired_sample_value_index], s_t.imag[::desired_sample_value_index], 'ro')
plt.plot(s_t.real, s_t.imag, 'ro')
plt.xlabel('Real Part'), plt.ylabel('Imag part')
#QPSK Demodulation
x=s_t*np.cos(2*np.pi*Fc*t) # I arm
y=s_t*np.sin(2*np.pi*Fc*t) # Q arm
x = np.convolve(x,np.ones(uL)) # integrate for L (Tsym=2*Tb) duration
y = np.convolve(y,np.ones(uL)) #integrate for L (Tsym=2*Tb) duration
x = x[uL-1::uL] # I arm - sample at every symbol instant Tsym
y = y[uL-1::uL] # Q arm - sample at every symbol instant Tsym
a_hat = np.zeros(2*len(x))
a_hat[0::2] = (x>0) # even bits
a_hat[1::2] = (y>0) # odd bits
print(a_hat)
print(baseband_bit_sequence)