In [3]:

```
import math
#Prior probability of s1 P_s1 = 0.4
P_s1 = 0.4;
#Prior probability of s2 P_s2 = 1 - P_s1
P_s2 = 1 - P_s1;
#Voltage level V1 = 1
V1 = 1;
#Voltage level V2 = -1
V2 = -1;
#Part a
#Noise Variance sigma1 = 10**-3
sigma1 = 10**-3;
#Descision Threshold lambda1
lambda1 = (V1+V2)/2 + (sigma1)*math.log(P_s2/P_s1)/(V1-V2);
#Probability of error Pe
Pe = 0.5*(2*P_s1 - P_s1*math.erfc(((V2-V1)/(2*sigma1*2**0.5)) + (sigma1)*math.log(P_s2/P_s1)/((V1-V2)*2**0.5)));
print 'The decision threshold is %f'%lambda1,' V'
print 'The probability of error is approximately ',Pe#Part b
#Noise Variance sigma2 = 10**-1
sigma2 = 10**-1;
#Descision Threshold lambda2
lambda2 = (V1+V2)/2 + (sigma2)*math.log(P_s2/P_s1)/(V1-V2);
#Probability of error Pe
Pe1 = 0.5*(2*P_s1 - P_s1*math.erfc(((V2-V1)/(2*sigma2*2**0.5)) + (sigma2)*math.log(P_s2/P_s1)/((V1-V2)*2**0.5)));
#In the textbook Pe has been calulated to be 0.0021 because of the use of a very high precision calculator, unfortunately in scilab the function erfc approximates the output value to a larger extent due to which an exact value cannot be obtained.
print 'The decision threshold is %f'%lambda2,' V'
print 'The probability of error is approximately ',Pe1
```

In [4]:

```
import math
#Part b
#Voltage level V1 = 1
V1 = 1;
#Voltage level V2 = -1
V2 = -1;
#Prior probability of s1 P_s1 = 0.4
P_s1 = 0.4;
#Prior probability of s2 P_s2 = 1 - P_s1
P_s2 = 1 - P_s1;
#Cost of selecting s1 when s2 is transmitted C12 = 0.7
C12 = 0.7;
#Cost of selecting s2 when s1 is transmitted C21 = 1 - C12
C21 = 1 - C12;
#Noise Variance sigma = 10**-3
sigma = 10**-3;
#Descision Threshold lambda
lambda1 = (V1+V2)/2 + (sigma)*math.log((C12*P_s2)/(C21*P_s1))/(V1-V2);
print 'The decision threshold is %f'%lambda1,' V'
```

In [5]:

```
import math
#The voltage level of reciever is V = 5 mV
V = 5*10**-3;
#The time required to transfer one bit is T = 1/9600 sec
T = 9600**-1;
#the signal energy of a bit be Es
Es = (V**2)*T;
#The power spectral density is n/2 = 10**-9 Watt/hertz
n = 2*10**-9;
#Probability error for optimal reciever is Pe
Pe = 0.5*math.erfc((Es/n)**0.5);
print 'The probability of error is %.4f'%Pe
#When the data rate is doubled, the new effective energy per bit is Es_new
Es_new = (V**2)*(T/2);
#The new probability of error is Pe_new
Pe_new = 0.5*math.erfc((Es_new/n)**0.5);
#Percentage increase in error rate is P
P = 100*(Pe_new - Pe)/Pe;
print 'Percentage increase in error rate is %.4f'%P
#Voltage required to restore probability levels, V_new
V_new = V*2**0.5;
print 'Voltage required to restore the probability levels is %.4f'%V_new,' Volts'
```

In [6]:

```
import math
#Amplitude of signal is A = 10 mV
A = 10*10**-3;
#Power Spectral Density n = 2 * 10**(-9) W/Hz
n = 2 * 10**(-9);
#Frequency is f = 1 MHz
f = 1.*10**6;
#Data rate is D = 10**4 bps;
D = 10.**4;
#Time taken for a bit to traverse
T = 1/D;
#Energy per signal element is Es
Es = A**2/(2*D);
#Probability of error Pe
Pe = 0.5*math.erfc((Es/n)**0.5);
print 'Probability of error is %.4f'%Pe
#Phase shift phi = math.pi/6
phi = math.pi/6;
#Probability of error Pe_local_oscillator
Pe_local_oscillator = 0.5*math.erfc(((Es/n)**0.5)*math.cos(phi));
print 'Probability of error of local oscillator with phase shift is %.4f'%Pe_local_oscillator
#Timing error t
t = 0.1*T;
#Probability of error when there is a synchronization fault Pe_timing_error
Pe_timing_error = 0.5*math.erfc(((Es/n)*(1 - 2*(t/T))**2)**0.5);
print 'Probability of error with synchronization fault is %.4f'%Pe_timing_error
#Probability of error when both faults occur Pe_both
Pe_both = 0.5*math.erfc(((Es/n)*(math.cos(phi)**2)*(1 - 2*(t/T))**2)**0.5);
print 'Probability of error when both faults occur %.4f'%Pe_both
```

In [7]:

```
import math
#Amplitude of signal is A = 10 mV
A = 10.*10**-3
#Power Spectral Density n = 2 * 10**(-9) W/Hz
n = 2. * 10**(-9);
#Data rate is D = 10**4 bps;
D = 10.**4;
#Time taken for a bit to traverse
T = 1/D;
#Energy per signal element is Es
Es = A**2/(2*D);
#Probability of error Pe_a
Pe_a = 0.5*math.erfc((0.6*Es/n)**0.5);
print 'Probability of error when offset is small is %.4f'%Pe_a
#Probability of error Pe_b
Pe_b = 0.5*math.erfc((Es/(2*n))**0.5);
print 'Probability of error when frequencies used are orthogonal is %.4f'%Pe_b
#Probability of error Pe_c
Pe_c = 0.5*math.exp(-(Es/(2*n)));
print 'Probability of error for non coherent detection is %.4f'%Pe_c
```

In [8]:

```
import math
#Energy aasosciated with each bit Eb = 5 * 10**(-8) J
Eb = 5. * 10**(-8);
#Power Spectral Density n = 2 * 10**(-9) W/Hz
n = 2. * 10**(-9);
#No of symbols M
M = 16.
#No of bits N
N = math.log(M,2);
#Error limit for 16-PSK is P_16_PSK
P_16_PSK = math.erfc(((N*Eb*(math.pi)**2)/(((M)**2)*n))**0.5);
print 'Upper limit of error probability of 16 PSK system is %.4f'%P_16_PSK
#Error limit for 16-QASK is P_16_QASK
P_16_QASK = 2*math.erfc(((0.4*Eb)/(n))**0.5);
print 'Upper limit of error probability of 16 QASK system is %.4e'%P_16_QASK
#Error limit for 16-FSK is P_16_FSK
P_16_FSK = ((2**4 - 1)/2.)*math.erfc(((N*Eb)/(2*n))**0.5);
print 'Upper limit of error probability of 16 FSK system is %.4e'%P_16_FSK,', negligibly small'
```

In [9]:

```
import math
#Energy aasosciated with each bit Eb = 5 * 10**(-8) J
Eb = 5 * 10**(-8);
#Power Spectral Density n = 2 * 10**(-9) W/Hz
n = 2 * 10**(-9);
#Probability of error Pe
Pe = 0.5*math.erfc(((Eb*(math.pi)**2)/(16*n))**0.5);
print 'Probability of error of QPR system is %.3e'%Pe
#Given Bandwidth of channel is BW
BW = 10*10**3;
D = 2*BW;
print 'Data rate is ',D,' bps'
```