2 minute read

[4X1] QO-STBC QPSK

import numpy as np
import math
from random import randrange
from math import pi as PI


```python
def STBC_4x1(Num_Bit, BER_start, BER_end, Error_limit, mod, demod):


  Nt = 4                # The number of transmit antennas
  Nr = 1                # The number of receive antenna
  Num_Bit = Num_Bit     # It depends on what the modulation is
  BER = []
  BitPerNoiseDB_iter = range(BER_start, BER_end)     # Set the range of BER you wanna see



  for BitPerNoiseDB in BitPerNoiseDB_iter:
    SymbolPerNoiseRATIO = Num_Bit*10**(BitPerNoiseDB/10)    # It contains 'Num_Bit' number of bits per symbol, so we have to product Num_Bit
    AWGN_sigma = math.sqrt(1/(2*SymbolPerNoiseRATIO))       # When the SymbolPerNoiseRATIO increases, the variance of AWGN decreases

    Error_Count = 0
    Total_Error_Count = 0
    Bit_Count = 0



    while Total_Error_Count < Error_limit:            # Set the limit number of error count. if you don't have an enough time to observe the result of the simulation,
                                                      # you can reduce it. But to get more elaborate results, I recommand you to set the number at least more than 100.


      ### ---------------------------------------------------------------- ###
      ### Define some matrixs and arrays what we're gonna use at the below ###
      Information_Generator = np.zeros([Nt, Num_Bit], dtype='int')
      Detected_Array = np.zeros([Nt, Num_Bit], dtype='int')
      Bit = np.zeros([Nt, Num_Bit], dtype='int')
      symbol = []
      AWGN = []
      h = []
      signal = np.zeros([4, 1], dtype='complex')
      STBC_symbol = np.zeros([4, 4], dtype='complex')
      h_matrix = np.zeros([4, 4], dtype='complex')
      ### ---------------------------------------------------------------- ###



      for a in range(0, Nt):
        for generator in range(0, Num_Bit):
          Information_Generator[a][generator] = randrange(2)    # Generate the information bits!! The value of bits has to be 0 or 1
          
      Bit = Information_Generator
      #print('Bit:', Bit)
      #print('------------------')




      for i in range(0, Nt):
        symbol.append(QPSK_mod(Bit[i]))       # Modulate the Bits to symbols
                                              # As you can see, you can change the type of modulation by changing the name of it



      for i in range(0, Nt):
        AWGN_gen = np.random.normal(size = (1,2))
        AWGN.append(complex(AWGN_gen[0][0], AWGN_gen[0][1]) * AWGN_sigma)       # By producting AWGN_sigma with AWGN, we can adjust the size of AWGN 
        h.append(np.random.randn(1)*np.sqrt(0.5) + 1j*np.random.randn(1)*np.sqrt(0.5))  # Rayleigh fading



      h_matrix[0][0] = h[0]                   # For computing the process of demodulation of STBC, we have to have channel gain matrix (h_matrix)
      h_matrix[0][1] = h[1]
      h_matrix[0][2] = h[2]
      h_matrix[0][3] = h[3]

      h_matrix[1][0] = h[1].conjugate()
      h_matrix[1][1] = -h[0].conjugate()
      h_matrix[1][2] = h[3].conjugate()
      h_matrix[1][3] = -h[2].conjugate()

      h_matrix[2][0] = h[2]
      h_matrix[2][1] = h[3]
      h_matrix[2][2] = h[0]
      h_matrix[2][3] = h[1]

      h_matrix[3][0] = h[3].conjugate()
      h_matrix[3][1] = -h[2].conjugate()
      h_matrix[3][2] = h[1].conjugate()
      h_matrix[3][3] = -h[0].conjugate()




      STBC_symbol[0][0] = symbol[0]           # STBC Encoding
      STBC_symbol[0][1] = symbol[1]
      STBC_symbol[0][2] = symbol[2]
      STBC_symbol[0][3] = symbol[3]

      STBC_symbol[1][0] = -symbol[1].conjugate()
      STBC_symbol[1][1] = symbol[0].conjugate()
      STBC_symbol[1][2] = -symbol[3].conjugate()
      STBC_symbol[1][3] = symbol[2].conjugate()

      STBC_symbol[2][0] = symbol[2]        
      STBC_symbol[2][1] = symbol[3]
      STBC_symbol[2][2] = symbol[0]
      STBC_symbol[2][3] = symbol[1]

      STBC_symbol[3][0] = -symbol[3].conjugate()
      STBC_symbol[3][1] = symbol[2].conjugate()
      STBC_symbol[3][2] = -symbol[1].conjugate()
      STBC_symbol[3][3] = symbol[0].conjugate()





      STBC_symbol = STBC_symbol/np.sqrt(Nt)   # To make the energy of symbols one, devide the symbols by sqrt of the number of transmit antennas 
      STBC_symbol = np.matmul(STBC_symbol, h)   # y = X*h


      signal = [STBC_symbol[i][0] + AWGN[i] for i in range(len(AWGN))]                 # y = X*h + n ::: SHOTING!!! :::




      #--------------Demodulation-------------#

      signal[1] = signal[1].conjugate()
      signal[3] = signal[3].conjugate()

      h_hermitian_mul_signal = np.matmul(h_matrix.conj().T, signal)

      Inverse_of_H_matrix = np.linalg.inv(np.matmul(h_matrix, h_matrix.conj().T))

      h_hermitian_mul_signal = np.matmul(Inverse_of_H_matrix, h_hermitian_mul_signal)



      for i in range(4):
        Detected_Array[i][0],Detected_Array[i][1] = demod(h_hermitian_mul_signal[i]) 



      Error_Count = 0
      
      for row in range(0, Nt):
        for col in range(0, Num_Bit):
          if Bit[row][col] != Detected_Array[row][col]:       # Comparing the original bits from the transmitter and the detected bits at the receiver
            Error_Count += 1                                  # If those are different each other, It means error

    

      Total_Error_Count += Error_Count
      Bit_Count += Num_Bit*Nt



    
    BER.append(Total_Error_Count/Bit_Count)

    print("Bit_Count :", Bit_Count)
    print("Eb/N0 :{} [dB]".format(BitPerNoiseDB))
    print("The number of bits with errors :", Total_Error_Count)
    print("BER :", BER[BitPerNoiseDB-BER_start] )
    print("---------------------------------")

  
  return BER
BER = STBC_4x1(2, 0, 21, 200, QPSK_mod, QPSK_demod)

download (2)

Categories:

Updated: