Co-operative Ultra Narrowband based simulation for smart meters
diff --git a/MainCode18th_aug.py b/MainCode18th_aug.py
new file mode 100644
index 0000000..d36d936
--- /dev/null
+++ b/MainCode18th_aug.py
@@ -0,0 +1,231 @@
+import numpy
+import math
+import random
+import simpy
+
+from SimLibraryOneBS_aug18 import *
+import scipy.stats as stats
+
+############################################### Arrival Traffic Function Definitions#############################################
+#control variables
+k=1
+j=1
+i=1
+cache=0
+cache1=0
+cache2=0
+cache3=0
+cache4=0
+reportInterval_SM = 60 #60 sec time for keep alive
+reportInterval_SM_Normal = 300 #10 mins
+Mean_Report_Interval = 3600 # 1 hour for Aperiodic packets
+N=300#no of Smart meters
+itrn=1
+itrn2=1
+#LoopbackTime=12
+#for uplink packet from smart meter to BS
+SIMULATION=2000
+def ArrivalTimeSM_keepAlive():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache,k
+ #global reportInterval_SM,reportInterval_SM_Normal
+ reportInterval_SM = 60 #60 sec time for keep alive
+ a = 0
+ b = reportInterval_SM - 1
+ #print "k %s"%k
+ if(k<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ k=k+1
+ #cache=random.randint(a,b)
+ cache=random.uniform(a,b)
+ return cache
+
+ else:#after all the smart meter have an initial offset the 60 sec interval follows
+ k=k+1
+ cache = reportInterval_SM #then the arrival rate of 60 follows
+ return cache
+
+
+#####Defining Arrival Rate for Normal packets#########
+def ArrivalTimeSM_Normal():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache1,j
+ reportInterval_SM_Normal = 300#5 min time for Normal packets
+ a = 0
+ b = reportInterval_SM_Normal - 1
+ #print "k %s"%k
+ if(j<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+
+ j=j+1
+ #cache1=random.randint(a,b)
+ cache1=random.uniform(a,b)
+ return cache1
+
+ else:#the second packet sent to another Base station is the replica of the first one
+ j=j+1
+ cache1 = reportInterval_SM_Normal#then the arrival rate of 14400 follows
+ return cache1
+
+#####Defining Arrival Rate for Alarm packets#########
+def ArrivalTimeSM_Alarm():
+ global Mean_Report_Interval ,i ,cache2
+ i=i+1
+ cache2=math.ceil(random.expovariate(1.0/Mean_Report_Interval)) #exponential arrival rate with a mean of one hour
+ return cache2
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Household meters################################
+def upLinkUser_HouseHoldPkt(str): # Constant packet size distribution 90 percent of users
+ if(str=="keepAlive"):
+ #92 bytes the packet size+ 132 bits * (92/32)
+ #headers :40 bit MAC header, 12 bit Seq Counter, 40 bit node identifier, 16 bit Auth Hash, 8 bits CRC, 16 bits ECC
+ return 141.5 #constant payload of 92 bytes + 3*16.5 bytes(132 bits) as 92 byte/32 bytes= 3
+ elif(str=="Normal" ):
+ #254 bytes the packet size+ 132 bits *(254/32) = 254 + 8*16.5 bytes
+ return 386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 200 as per the discusiion with Proff
+ global itrn,cache3
+ mean=200
+ itrn+=1
+ size=random.expovariate(1.0/mean)
+ cache3= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache3
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Commercial meters################################
+def upLinkUser_CommercialPkt(str):
+ if(str=="keepAlive"):
+ #double of Household
+ return 2*141.5
+ elif(str=="Normal"):
+ #double of household
+ return 2*386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 400 as per the discusiion with Proff
+
+ global itrn2,cache4
+ mean2=400
+
+ itrn2+=1
+ size=random.expovariate(1.0/mean2)
+ cache4= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache4
+
+
+
+##################Start of Simulation###########################################
+start = True
+env = simpy.Environment() # Create the SimPy environment
+#log normal calculation, currently i havent utilized these in the consideration of collision
+d0 = 1 #reference distance = 1 meter
+prd0 = 0 #received signal at reference distance is 0 dBm
+n = 3.5 #path loss coefficient. Assume urban area
+prd_req = -120 #minimum required received power at base station
+sigma = 8 # standard deviation of 8 dB
+upLinkBitRate = 250
+downLinkBitRate= 600
+household=0
+commercial=0
+
+#ContentionWindow = 4 #for BackOff calculation
+BS1_id=1 #Base Station 1 ID
+#BS2_id=2
+
+#Base Station 1 and 2 SINK instantiated
+BS1_PS = PacketSink(env,BS1_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+#BS2_PS = PacketSink(env,BS2_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+
+
+#Smart Meter ID would range from 3 to 102 (I am considering 100 Smart Meters)
+SM_id=3
+#creates a 100 x 2 matrix to store the Id
+#Channel ID would range from 1 to 8
+channel_size=8
+
+#sequence number would be used in further simulations..currently kept inactive
+#max_seq_Num=4095
+#seq_Num=0
+#seq_Num=1
+
+#base station co-ordinate
+BS1_Loc = numpy.array((1154,1000))
+#BS2_Loc = numpy.array((2885,1000))
+
+BS1_List =[]
+#BS2_List=[]
+#carrying out the experiment for 100 smart meters
+while(SM_id<3+N):
+
+ new=[]
+ new.append(SM_id)
+ a = random.normalvariate(5,0.217)
+ #assuming a square cell with a diagonal of 2000m
+ #x_cord = random.randint(0,3750) #x coordinate of the smart meter node
+ x_cord = random.randint(0,2308) #x coordinate of the smart meter node
+ y_cord = random.randint(0,2000) #y coordinate of the smart meter node
+ cord = numpy.array((x_cord,y_cord))#cord holds the coordinate of the smart meter
+ distBS1 = numpy.linalg.norm(cord-BS1_Loc)# Distance between the Smart meter and the Base Station
+ #distBS2 = numpy.linalg.norm(cord-BS2_Loc)
+
+ prd_mean_BS1=prd0 -10*n*math.log10(distBS1/d0)#power received at Base Station from the smart meters
+ #prd_mean_BS2=prd0 -10*n*math.log10(distBS2/d0)
+ #calculation of Q value...probability that the received signal is higher than -120dB
+ prob_rec_BS1=0.5*math.erfc((prd_req-prd_mean_BS1)/sigma*math.sqrt(2))
+ #prob_rec_BS2=0.5*math.erfc((prd_req-prd_mean_BS2)/sigma*math.sqrt(2))
+
+ if a<5.278:#for 0.9 probability for household Smart meters
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ household=household+1
+ #array to hold the SM id and channel used
+ else:
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ commercial=commercial+1
+
+ #SM_PG2.out = BS2_PS
+ SM_PG1.out = BS1_PS
+
+ #SM_PG4.out = BS2_PS
+ SM_PG3.out = BS1_PS
+
+ #SM_PG6.out = BS2_PS
+ SM_PG5.out = BS1_PS
+
+
+ #print"SM_id is %s "%SM_id
+
+ SM_id=SM_id+1
+env.run(until=SIMULATION) #until how much time we run the simulation
+#global CollisionCount,NoOfRetransmission
+#print "Total Packets received by the Base station is %s"%BS1_PS.packets_rec
diff --git a/MainCode18th_aug_TwoBS.py b/MainCode18th_aug_TwoBS.py
new file mode 100644
index 0000000..715d558
--- /dev/null
+++ b/MainCode18th_aug_TwoBS.py
@@ -0,0 +1,244 @@
+import numpy
+import math
+import random
+import simpy
+
+from SimLibraryTwoBS_aug18 import *
+import scipy.stats as stats
+#from SimLibraryTwoBS import CollisionCount
+
+############################################### Arrival Traffic Function Definitions#############################################
+#control variables
+k=1
+j=1
+i=1
+cache=0
+cache1=0
+cache2=0
+cache3=0
+cache4=0
+reportInterval_SM = 60 #60 sec time for keep alive
+reportInterval_SM_Normal = 300 #5 mins
+Mean_Report_Interval = 3600 # 1 hour for Aperiodic packets
+N=300#no of Smart meters
+itrn=1
+itrn2=1
+#LoopbackTime=12
+#for uplink packet from smart meter to BS
+SIMULATION=2000
+def ArrivalTimeSM_keepAlive():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache,k
+ #global reportInterval_SM,reportInterval_SM_Normal
+ reportInterval_SM = 60 #60 sec time for keep alive
+ a = 0
+ b = reportInterval_SM - 1
+ #print "k %s"%k
+ if(k<=2*N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ if k%2==1 :
+ k=k+1
+ #cache=random.randint(a,b)
+ cache=random.uniform(a,b)
+ return cache
+ else:
+ k=k+1
+ return cache
+ else:#after all the smart meter have an initial offset the 60 sec interval follows
+ k=k+1
+ cache = reportInterval_SM #then the arrival rate of 60 follows
+ return cache
+
+
+#####Defining Arrival Rate for Normal packets#########
+def ArrivalTimeSM_Normal():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache1,j
+ reportInterval_SM_Normal = 300#5 min time for Normal packets
+ a = 0
+ b = reportInterval_SM_Normal - 1
+ #print "k %s"%k
+ if(j<=2*N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ if j%2==1:
+ j=j+1
+ #cache1=random.randint(a,b)
+ cache1=random.uniform(a,b)
+ return cache1
+ else:
+ j=j+1
+ return cache1
+
+ else:#the second packet sent to another Base station is the replica of the first one
+ j=j+1
+ cache1 = reportInterval_SM_Normal#then the arrival rate of 14400 follows
+ return cache1
+
+#####Defining Arrival Rate for Alarm packets#########
+def ArrivalTimeSM_Alarm():
+ global Mean_Report_Interval ,i ,cache2
+ if( i%2==1):
+ i=i+1
+ cache2=math.ceil(random.expovariate(1.0/Mean_Report_Interval)) #exponential arrival rate with a mean of one hour
+ return cache2
+ else:
+ i=i+1
+ return cache2
+
+
+#########Defining keepAlive,Normal and Alarm packets for Household meters################################
+def upLinkUser_HouseHoldPkt(str): # Constant packet size distribution 90 percent of users
+ if(str=="keepAlive"):
+ #92 bytes the packet size+ 132 bits * (92/32)
+ #headers :40 bit MAC header, 12 bit Seq Counter, 40 bit node identifier, 16 bit Auth Hash, 8 bits CRC, 16 bits ECC
+ return 141.5 #constant payload of 92 bytes + 3*16.5 bytes(132 bits) as 92 byte/32 bytes= 3
+ elif(str=="Normal" ):
+ #254 bytes the packet size+ 132 bits *(254/32) = 254 + 8*16.5 bytes
+ return 386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 200 as per the discusiion with Proff
+ global itrn,cache3
+ mean=200
+ if(itrn%2==1):
+ itrn+=1
+ size=random.expovariate(1.0/mean)
+ cache3= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache3
+ else:
+ itrn+=1
+ return cache3
+
+#########Defining keepAlive,Normal and Alarm packets for Commercial meters################################
+def upLinkUser_CommercialPkt(str):
+ if(str=="keepAlive"):
+ #double of Household
+ return 2*141.5
+ elif(str=="Normal"):
+ #double of household
+ return 2*386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 400 as per the discusiion with Proff
+
+ global itrn2,cache4
+ mean2=400
+ if(itrn2%2==1):
+ itrn2+=1
+ size=random.expovariate(1.0/mean2)
+ cache4= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache4
+ else:
+ itrn2+=1
+ return cache4
+
+
+##################Start of Simulation###########################################
+start = True
+env = simpy.Environment() # Create the SimPy environment
+#log normal calculation, currently i havent utilized these in the consideration of collision
+d0 = 1 #reference distance = 1 meter
+prd0 = 0 #received signal at reference distance is 0 dBm
+n = 3.5 #path loss coefficient. Assume urban area
+prd_req = -120 #minimum required received power at base station
+sigma = 8 # standard deviation of 8 dB
+upLinkBitRate = 250
+downLinkBitRate= 600
+household=0
+commercial=0
+
+#ContentionWindow = 4 #for BackOff calculation
+BS1_id=1 #Base Station 1 ID
+BS2_id=2
+
+#Base Station 1 and 2 SINK instantiated
+BS1_PS = PacketSink(env,BS1_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+BS2_PS = PacketSink(env,BS2_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+
+
+#Smart Meter ID would range from 3 to 102 (I am considering 100 Smart Meters)
+SM_id=3
+#creates a 100 x 2 matrix to store the Id
+#Channel ID would range from 1 to 8
+channel_size=8
+
+#sequence number would be used in further simulations..currently kept inactive
+#max_seq_Num=4095
+#seq_Num=0
+#seq_Num=1
+
+#base station co-ordinate
+BS1_Loc = numpy.array((1154,1000))
+BS2_Loc = numpy.array((2885,1000))
+
+BS1_List =[]
+BS2_List=[]
+#carrying out the experiment for 100 smart meters
+while(SM_id<3+N):
+
+ new=[]
+ new.append(SM_id)
+ a = random.normalvariate(5,0.217)
+ #assuming a square cell with a diagonal of 2000m
+ x_cord = random.randint(0,3750) #x coordinate of the smart meter node
+ #x_cord = random.randint(0,2000) #x coordinate of the smart meter node
+ y_cord = random.randint(0,2000) #y coordinate of the smart meter node
+ cord = numpy.array((x_cord,y_cord))#cord holds the coordinate of the smart meter
+ distBS1 = numpy.linalg.norm(cord-BS1_Loc)# Distance between the Smart meter and the Base Station
+ distBS2 = numpy.linalg.norm(cord-BS2_Loc)
+
+ prd_mean_BS1=prd0 -10*n*math.log10(distBS1/d0)#power received at Base Station from the smart meters
+ prd_mean_BS2=prd0 -10*n*math.log10(distBS2/d0)
+ #calculation of Q value...probability that the received signal is higher than -120dB
+ prob_rec_BS1=0.5*math.erfc((prd_req-prd_mean_BS1)/sigma*math.sqrt(2))
+ prob_rec_BS2=0.5*math.erfc((prd_req-prd_mean_BS2)/sigma*math.sqrt(2))
+
+ if a<5.278:#for 0.9 probability for household Smart meters
+
+
+ #Keep Alive Packet from the smart meter
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,0,"Normal")
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ household=household+1
+ #array to hold the SM id and channel used
+ else:
+
+
+ #Keep Alive Packet from the smart meter
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,0,"Normal")
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ commercial=commercial+1
+
+ SM_PG2.out = BS2_PS
+ SM_PG1.out = BS1_PS
+
+ SM_PG4.out = BS2_PS
+ SM_PG3.out = BS1_PS
+
+ SM_PG6.out = BS2_PS
+ SM_PG5.out = BS1_PS
+
+
+ #print"SM_id is %s "%SM_id
+
+ SM_id=SM_id+1
+env.run(until=SIMULATION) #until how much time we run the simulation
+#global CollisionCount,NoOfRetransmission
+#print "Total Packets received by the Base station is %s"%BS1_PS.packets_rec
+#print "number of collisions: %d"%SimLibraryTwoBS.CollisionCount
diff --git a/MainCode18th_aug_TwoBS_noretrans.py b/MainCode18th_aug_TwoBS_noretrans.py
new file mode 100644
index 0000000..aebf57b
--- /dev/null
+++ b/MainCode18th_aug_TwoBS_noretrans.py
@@ -0,0 +1,244 @@
+import numpy
+import math
+import random
+import simpy
+
+from SimLibraryTwoBS_aug18_noretrans import *
+import scipy.stats as stats
+#from SimLibraryTwoBS import CollisionCount
+
+############################################### Arrival Traffic Function Definitions#############################################
+#control variables
+k=1
+j=1
+i=1
+cache=0
+cache1=0
+cache2=0
+cache3=0
+cache4=0
+reportInterval_SM = 60 #60 sec time for keep alive
+reportInterval_SM_Normal = 300 #5 mins
+Mean_Report_Interval = 3600 # 1 hour for Aperiodic packets
+N=300#no of Smart meters
+itrn=1
+itrn2=1
+#LoopbackTime=12
+#for uplink packet from smart meter to BS
+SIMULATION=2000
+def ArrivalTimeSM_keepAlive():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache,k
+ #global reportInterval_SM,reportInterval_SM_Normal
+ reportInterval_SM = 60 #60 sec time for keep alive
+ a = 0
+ b = reportInterval_SM - 1
+ #print "k %s"%k
+ if(k<=2*N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ if k%2==1 :
+ k=k+1
+ #cache=random.randint(a,b)
+ cache=random.uniform(a,b)
+ return cache
+ else:
+ k=k+1
+ return cache
+ else:#after all the smart meter have an initial offset the 60 sec interval follows
+ k=k+1
+ cache = reportInterval_SM #then the arrival rate of 60 follows
+ return cache
+
+
+#####Defining Arrival Rate for Normal packets#########
+def ArrivalTimeSM_Normal():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache1,j
+ reportInterval_SM_Normal = 300#5 min time for Normal packets
+ a = 0
+ b = reportInterval_SM_Normal - 1
+ #print "k %s"%k
+ if(j<=2*N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ if j%2==1:
+ j=j+1
+ #cache1=random.randint(a,b)
+ cache1=random.uniform(a,b)
+ return cache1
+ else:
+ j=j+1
+ return cache1
+
+ else:#the second packet sent to another Base station is the replica of the first one
+ j=j+1
+ cache1 = reportInterval_SM_Normal#then the arrival rate of 14400 follows
+ return cache1
+
+#####Defining Arrival Rate for Alarm packets#########
+def ArrivalTimeSM_Alarm():
+ global Mean_Report_Interval ,i ,cache2
+ if( i%2==1):
+ i=i+1
+ cache2=math.ceil(random.expovariate(1.0/Mean_Report_Interval)) #exponential arrival rate with a mean of one hour
+ return cache2
+ else:
+ i=i+1
+ return cache2
+
+
+#########Defining keepAlive,Normal and Alarm packets for Household meters################################
+def upLinkUser_HouseHoldPkt(str): # Constant packet size distribution 90 percent of users
+ if(str=="keepAlive"):
+ #92 bytes the packet size+ 132 bits * (92/32)
+ #headers :40 bit MAC header, 12 bit Seq Counter, 40 bit node identifier, 16 bit Auth Hash, 8 bits CRC, 16 bits ECC
+ return 141.5 #constant payload of 92 bytes + 3*16.5 bytes(132 bits) as 92 byte/32 bytes= 3
+ elif(str=="Normal" ):
+ #254 bytes the packet size+ 132 bits *(254/32) = 254 + 8*16.5 bytes
+ return 386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 200 as per the discusiion with Proff
+ global itrn,cache3
+ mean=200
+ if(itrn%2==1):
+ itrn+=1
+ size=random.expovariate(1.0/mean)
+ cache3= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache3
+ else:
+ itrn+=1
+ return cache3
+
+#########Defining keepAlive,Normal and Alarm packets for Commercial meters################################
+def upLinkUser_CommercialPkt(str):
+ if(str=="keepAlive"):
+ #double of Household
+ return 2*141.5
+ elif(str=="Normal"):
+ #double of household
+ return 2*386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 400 as per the discusiion with Proff
+
+ global itrn2,cache4
+ mean2=400
+ if(itrn2%2==1):
+ itrn2+=1
+ size=random.expovariate(1.0/mean2)
+ cache4= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache4
+ else:
+ itrn2+=1
+ return cache4
+
+
+##################Start of Simulation###########################################
+start = True
+env = simpy.Environment() # Create the SimPy environment
+#log normal calculation, currently i havent utilized these in the consideration of collision
+d0 = 1 #reference distance = 1 meter
+prd0 = 0 #received signal at reference distance is 0 dBm
+n = 3.5 #path loss coefficient. Assume urban area
+prd_req = -120 #minimum required received power at base station
+sigma = 8 # standard deviation of 8 dB
+upLinkBitRate = 250
+downLinkBitRate= 600
+household=0
+commercial=0
+
+#ContentionWindow = 4 #for BackOff calculation
+BS1_id=1 #Base Station 1 ID
+BS2_id=2
+
+#Base Station 1 and 2 SINK instantiated
+BS1_PS = PacketSink(env,BS1_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+BS2_PS = PacketSink(env,BS2_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+
+
+#Smart Meter ID would range from 3 to 102 (I am considering 100 Smart Meters)
+SM_id=3
+#creates a 100 x 2 matrix to store the Id
+#Channel ID would range from 1 to 8
+channel_size=8
+
+#sequence number would be used in further simulations..currently kept inactive
+#max_seq_Num=4095
+#seq_Num=0
+#seq_Num=1
+
+#base station co-ordinate
+BS1_Loc = numpy.array((1154,1000))
+BS2_Loc = numpy.array((2885,1000))
+
+BS1_List =[]
+BS2_List=[]
+#carrying out the experiment for 100 smart meters
+while(SM_id<3+N):
+
+ new=[]
+ new.append(SM_id)
+ a = random.normalvariate(5,0.217)
+ #assuming a square cell with a diagonal of 2000m
+ x_cord = random.randint(0,3750) #x coordinate of the smart meter node
+ #x_cord = random.randint(0,2000) #x coordinate of the smart meter node
+ y_cord = random.randint(0,2000) #y coordinate of the smart meter node
+ cord = numpy.array((x_cord,y_cord))#cord holds the coordinate of the smart meter
+ distBS1 = numpy.linalg.norm(cord-BS1_Loc)# Distance between the Smart meter and the Base Station
+ distBS2 = numpy.linalg.norm(cord-BS2_Loc)
+
+ prd_mean_BS1=prd0 -10*n*math.log10(distBS1/d0)#power received at Base Station from the smart meters
+ prd_mean_BS2=prd0 -10*n*math.log10(distBS2/d0)
+ #calculation of Q value...probability that the received signal is higher than -120dB
+ prob_rec_BS1=0.5*math.erfc((prd_req-prd_mean_BS1)/sigma*math.sqrt(2))
+ prob_rec_BS2=0.5*math.erfc((prd_req-prd_mean_BS2)/sigma*math.sqrt(2))
+
+ if a<5.278:#for 0.9 probability for household Smart meters
+
+
+ #Keep Alive Packet from the smart meter
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,0,"Normal")
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ household=household+1
+ #array to hold the SM id and channel used
+ else:
+
+
+ #Keep Alive Packet from the smart meter
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,0,"Normal")
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ commercial=commercial+1
+
+ SM_PG2.out = BS2_PS
+ SM_PG1.out = BS1_PS
+
+ SM_PG4.out = BS2_PS
+ SM_PG3.out = BS1_PS
+
+ SM_PG6.out = BS2_PS
+ SM_PG5.out = BS1_PS
+
+
+ #print"SM_id is %s "%SM_id
+
+ SM_id=SM_id+1
+env.run(until=SIMULATION) #until how much time we run the simulation
+#global CollisionCount,NoOfRetransmission
+#print "Total Packets received by the Base station is %s"%BS1_PS.packets_rec
+#print "number of collisions: %d"%SimLibraryTwoBS.CollisionCount
diff --git a/MainCode18th_aug_noretrans.py b/MainCode18th_aug_noretrans.py
new file mode 100644
index 0000000..cbc2768
--- /dev/null
+++ b/MainCode18th_aug_noretrans.py
@@ -0,0 +1,231 @@
+import numpy
+import math
+import random
+import simpy
+
+from SimLibraryOneBS_aug18_noretrans import *
+import scipy.stats as stats
+
+############################################### Arrival Traffic Function Definitions#############################################
+#control variables
+k=1
+j=1
+i=1
+cache=0
+cache1=0
+cache2=0
+cache3=0
+cache4=0
+reportInterval_SM = 60 #60 sec time for keep alive
+reportInterval_SM_Normal = 300 #10 mins
+Mean_Report_Interval = 3600 # 1 hour for Aperiodic packets
+N=300#no of Smart meters
+itrn=1
+itrn2=1
+#LoopbackTime=12
+#for uplink packet from smart meter to BS
+SIMULATION=2000
+def ArrivalTimeSM_keepAlive():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache,k
+ #global reportInterval_SM,reportInterval_SM_Normal
+ reportInterval_SM = 60 #60 sec time for keep alive
+ a = 0
+ b = reportInterval_SM - 1
+ #print "k %s"%k
+ if(k<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ k=k+1
+ #cache=random.randint(a,b)
+ cache=random.uniform(a,b)
+ return cache
+
+ else:#after all the smart meter have an initial offset the 60 sec interval follows
+ k=k+1
+ cache = reportInterval_SM #then the arrival rate of 60 follows
+ return cache
+
+
+#####Defining Arrival Rate for Normal packets#########
+def ArrivalTimeSM_Normal():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache1,j
+ reportInterval_SM_Normal = 300#5 min time for Normal packets
+ a = 0
+ b = reportInterval_SM_Normal - 1
+ #print "k %s"%k
+ if(j<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+
+ j=j+1
+ #cache1=random.randint(a,b)
+ cache1=random.uniform(a,b)
+ return cache1
+
+ else:#the second packet sent to another Base station is the replica of the first one
+ j=j+1
+ cache1 = reportInterval_SM_Normal#then the arrival rate of 14400 follows
+ return cache1
+
+#####Defining Arrival Rate for Alarm packets#########
+def ArrivalTimeSM_Alarm():
+ global Mean_Report_Interval ,i ,cache2
+ i=i+1
+ cache2=math.ceil(random.expovariate(1.0/Mean_Report_Interval)) #exponential arrival rate with a mean of one hour
+ return cache2
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Household meters################################
+def upLinkUser_HouseHoldPkt(str): # Constant packet size distribution 90 percent of users
+ if(str=="keepAlive"):
+ #92 bytes the packet size+ 132 bits * (92/32)
+ #headers :40 bit MAC header, 12 bit Seq Counter, 40 bit node identifier, 16 bit Auth Hash, 8 bits CRC, 16 bits ECC
+ return 141.5 #constant payload of 92 bytes + 3*16.5 bytes(132 bits) as 92 byte/32 bytes= 3
+ elif(str=="Normal" ):
+ #254 bytes the packet size+ 132 bits *(254/32) = 254 + 8*16.5 bytes
+ return 386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 200 as per the discusiion with Proff
+ global itrn,cache3
+ mean=200
+ itrn+=1
+ size=random.expovariate(1.0/mean)
+ cache3= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache3
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Commercial meters################################
+def upLinkUser_CommercialPkt(str):
+ if(str=="keepAlive"):
+ #double of Household
+ return 2*141.5
+ elif(str=="Normal"):
+ #double of household
+ return 2*386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 400 as per the discusiion with Proff
+
+ global itrn2,cache4
+ mean2=400
+
+ itrn2+=1
+ size=random.expovariate(1.0/mean2)
+ cache4= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache4
+
+
+
+##################Start of Simulation###########################################
+start = True
+env = simpy.Environment() # Create the SimPy environment
+#log normal calculation, currently i havent utilized these in the consideration of collision
+d0 = 1 #reference distance = 1 meter
+prd0 = 0 #received signal at reference distance is 0 dBm
+n = 3.5 #path loss coefficient. Assume urban area
+prd_req = -120 #minimum required received power at base station
+sigma = 8 # standard deviation of 8 dB
+upLinkBitRate = 250
+downLinkBitRate= 600
+household=0
+commercial=0
+
+#ContentionWindow = 4 #for BackOff calculation
+BS1_id=1 #Base Station 1 ID
+#BS2_id=2
+
+#Base Station 1 and 2 SINK instantiated
+BS1_PS = PacketSink(env,BS1_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+#BS2_PS = PacketSink(env,BS2_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+
+
+#Smart Meter ID would range from 3 to 102 (I am considering 100 Smart Meters)
+SM_id=3
+#creates a 100 x 2 matrix to store the Id
+#Channel ID would range from 1 to 8
+channel_size=8
+
+#sequence number would be used in further simulations..currently kept inactive
+#max_seq_Num=4095
+#seq_Num=0
+#seq_Num=1
+
+#base station co-ordinate
+BS1_Loc = numpy.array((1154,1000))
+#BS2_Loc = numpy.array((2885,1000))
+
+BS1_List =[]
+#BS2_List=[]
+#carrying out the experiment for 100 smart meters
+while(SM_id<3+N):
+
+ new=[]
+ new.append(SM_id)
+ a = random.normalvariate(5,0.217)
+ #assuming a square cell with a diagonal of 2000m
+ #x_cord = random.randint(0,3750) #x coordinate of the smart meter node
+ x_cord = random.randint(0,2308) #x coordinate of the smart meter node
+ y_cord = random.randint(0,2000) #y coordinate of the smart meter node
+ cord = numpy.array((x_cord,y_cord))#cord holds the coordinate of the smart meter
+ distBS1 = numpy.linalg.norm(cord-BS1_Loc)# Distance between the Smart meter and the Base Station
+ #distBS2 = numpy.linalg.norm(cord-BS2_Loc)
+
+ prd_mean_BS1=prd0 -10*n*math.log10(distBS1/d0)#power received at Base Station from the smart meters
+ #prd_mean_BS2=prd0 -10*n*math.log10(distBS2/d0)
+ #calculation of Q value...probability that the received signal is higher than -120dB
+ prob_rec_BS1=0.5*math.erfc((prd_req-prd_mean_BS1)/sigma*math.sqrt(2))
+ #prob_rec_BS2=0.5*math.erfc((prd_req-prd_mean_BS2)/sigma*math.sqrt(2))
+
+ if a<5.278:#for 0.9 probability for household Smart meters
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ household=household+1
+ #array to hold the SM id and channel used
+ else:
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ commercial=commercial+1
+
+ #SM_PG2.out = BS2_PS
+ SM_PG1.out = BS1_PS
+
+ #SM_PG4.out = BS2_PS
+ SM_PG3.out = BS1_PS
+
+ #SM_PG6.out = BS2_PS
+ SM_PG5.out = BS1_PS
+
+
+ #print"SM_id is %s "%SM_id
+
+ SM_id=SM_id+1
+env.run(until=SIMULATION) #until how much time we run the simulation
+#global CollisionCount,NoOfRetransmission
+#print "Total Packets received by the Base station is %s"%BS1_PS.packets_rec
diff --git a/SimLibraryOneBS_aug18.py b/SimLibraryOneBS_aug18.py
new file mode 100644
index 0000000..eba79f9
--- /dev/null
+++ b/SimLibraryOneBS_aug18.py
@@ -0,0 +1,516 @@
+import simpy
+import random
+import numpy
+import math
+
+#########################################control variables used in the code########################################################################################################
+N=300 #the number of smart meters that are communicating to the Base stations
+CollisionCount=0
+NoOfRetransmission=0
+keepAliveCount=0 #keepAlive Packet count
+NormalCount=0 #normal packet count
+AlarmCount=0 #alarm packet Count
+NoOfRetransmissionAlarm=0 #total number of Alarm packet that got retransmitted
+NoOfRetransmissionKeepAlive=0 # total number of keepAlive packet that got retransmitted
+NoOfRetransmissionNormal=0 #total number of Normal packet that got retranmsitted
+#STATUSA =False #this global variable is used for collision detection at Base Station 1
+#STATUSB =False #this global variable is used for collision detection at Base Station 2
+TotalTime=0 #this variable holds the sum of delay time of all the packets that are generated from smart meters, to caluclate the average delay
+#LoopBackPeriod = 5 #ACK response time
+pthres=0.75 #probability of threshold for the Base station to detect the packet....based on the signal receiving capacity of the Base station
+#BS1_ACK_send_STATUS=False #this variable is used to prevent deduplication of ACK. if Base station has succesfully transmitted an ACK den BS2 should not transmit
+ACK_STATUS=numpy.full(N,False,dtype=bool) #this array holds ACK status of each packet that is ACKed by the Base station
+ACK_ID=numpy.zeros(N) #this array will hold the IDs of the Smart mter whose packet got ACKed..it is used in run() of PacketSink and Timer() of PacketGenerator
+SEQUENCE=0 #this variable stores the sequence number of the packet ACKed, so as to verify that at the transmitter
+TYPE = ["" for x in range(N)] #this is an array that stores the type of packet ACKed by the Base station. Goto run() of PacketSink to see its usage
+#ACK_TIME=numpy.zeros(N,dtype=numpy.float)
+ACK_PACKET_ID=0 #this variable holds the ID of the smart meter whose packet got ACKed.
+PKT_ACKED_SUCCESFULLY=0
+k=1 #this variable is used to use same channel for broadcasting at a Smart meter...
+collision_check=0 #goto __init__() of class PacketGenerator to see its implementation
+x=1 #this variable is used to logically prevent duplicate maintenance of packets in the smart meter queue....
+ #goto run() of Class PacketGenerator to see its usage
+cache=0 #this variable is used to use same channel for broadcasting at a Smart meter...
+ #goto __init__() of class PacketGenerator to see its implementation
+print_control=0
+######################################## Packet Class ##############################################################################################################################
+class Packet(object):
+ """ A very simple class that represents a packet.
+ This packet will run through a queue at a switch output port.
+ We use a float to represent the size of the packet in bytes so that
+ we can compare to ideal M/M/1 queues.
+
+ Parameters
+ ----------
+ time : float
+ the time the packet arrives at the output queue.
+ size : float
+ the size of the packet in bytes
+ id : int
+ an identifier for the packet
+ seq_no: int
+ it is the sequence number of the packet used for retransmission
+ src, dst : int
+ identifiers for source and destination
+ flow_id : int
+ small integer that can be used to identify a flow
+ channel : int
+ channel id used by the nodes to transmit that particular packet
+ bitrate : int
+ for uplink we take as 250 bits/sec and downlink we take 600 bits/sec
+ prob_rec_BS1,prob_rec_BS2 : float
+ it is the probabibilty of successful reception at two Base stations respectively
+ type : string
+ defines the type of packet...In our case we are considering the Normal, keepAlive, Alarm and ACK packets
+ retransmitted : boolean
+ defines whether the packet is a retransmitted or a non retransmitted packet
+ retrans_no :int
+ number of times the packet is retransmitted
+ """
+ def __init__(self, time, size, id,seq_no,src="a", dst="z", flow_id=0, channel=10,bitrate=0,prob_rec_BS1=1,type="ACK",retransmitted=False,retrans_no=0):
+ self.time = time
+ self.size = size
+ self.id = id
+ self.src = src
+ self.dst = dst
+ self.flow_id = flow_id
+ #self.channel=channel
+ global k,cache
+ if(self.src==1 or self.src==2):
+ self.channel=channel
+ elif(self.src >2 and (self.size ==283.0 or self.size ==772.0)):
+ self.channel=1
+ elif(self.src >2 and (self.size !=283.0 or self.size !=772.0)): #if household packet
+ k+=1
+ cache=random.randint(2,channel)
+ self.channel=cache
+
+ self.bitrate=bitrate
+ self.prob_rec_BS1=prob_rec_BS1
+ #self.prob_rec_BS2=prob_rec_BS2
+ self.type=type
+ self.retransmitted=retransmitted
+ self.seq_no=seq_no
+ if(self.retransmitted == True):
+ self.retrans_no=retrans_no
+ else:
+ self.retrans_no=0
+ self.ACKed=False
+ def __repr__(self):
+ if(self.src>2):
+ #print"*****************************************************************************************"
+ return "UPLINK {} Packet : id: {}, src: {},seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}, Prob_R at BS1:{}, retransmitted:{} ".\
+ format(self.type,self.id, self.src,self.seq_no, self.time, self.size,self.channel,self.bitrate,self.prob_rec_BS1,self.retransmitted)
+ else:
+ #print"*****************************************************************************************"
+ return "DOWNLINK Packet : id: {}, src: {},seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}".\
+ format(self.id, self.src,self.seq_no ,self.time, self.size,self.channel,self.bitrate)
+
+ #this function increments the retransmission for a packet
+ def noOfRetransmission(self):
+ self.retrans_no=self.retrans_no+1
+ return self.retrans_no
+
+######################################## PacketGenerator Class ##############################################################################################################################
+class PacketGenerator(object):
+ """ Generates packets with given inter-arrival time distribution.
+ Set the "out" member variable to the entity to receive the packet.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ adist : function
+ a no parameter function that returns the successive inter-arrival times of the packets
+ sdist : function
+ a no parameter function that returns the successive sizes of the packets
+
+ initial_delay : number
+ Starts generation after an initial delay. Default = 0
+ finish : number
+ Stops generation at the finish time. Default is infinite
+ pktType:either keepAlive,Alarm or Normal or ACK
+
+ """
+ def __init__(self, env, id, adist, sdist, channel, bitrate,prob_rec_BS1,seq_no,type="ACK",retransmitted=False,initial_delay=0, finish=float("inf"), flow_id=0,packetRecv=False):
+ self.id = id
+ self.env = env
+ self.adist = adist
+ self.sdist = sdist
+ self.initial_delay = initial_delay
+ self.finish = finish
+ self.out = None
+ self.type=type
+ self.retransmitted=retransmitted
+ self.packets_sent = 0
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.action = env.process(self.Timer()) #this is another timer () method that runs concurrently with the run() method...it is used to probe the received ACK at the Smart meters
+ self.flow_id = flow_id
+ self.ContentionWindow=4
+ self.channel=channel
+ #when the id =1, i.e. Base station ID then the same channel with which the packet was received by the Base station
+ #would be used for ACK transmission
+ #In the else part for Smartmeters it is random channel selection
+ #self.packetRecv=packetRecv
+ self.prob_rec_BS1=prob_rec_BS1
+ #self.prob_rec_BS2=prob_rec_BS2
+ self.bitrate=bitrate
+
+ if(self.id==1):
+ self.seq_no=seq_no #the sequence number used by the Base station here are the ACK number thats why they should be same as the seq number of the packet received at Base station
+ else:
+ self.seq_no=0 # A smart meter must initiates his packet generation with a sequence number of zero
+
+ self.Queue=[] #for storing the packets transmitted...so if they are not ACKed in the retransmission timeout period, they can be transmitted again by fetching from queue
+ self.Queue_Size=100#maximum size of a queue for a device would be 10
+
+ def run(self):
+ """The generator function used in simulations.
+ """
+ global x,keepAliveCount,NormalCount,AlarmCount
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish: #till infinite
+ self.packets_sent += 1
+ # wait for next transmission...yielding based on the type of packet generated as the ACK is conditioned we provide a constant rather than function based
+ if (self.id==1 ): #sending the ACKs once for BS1 and BS2...that is why for packet_sent == 1 they just yield once... for packet_sent > 1, yield timeout is infinite.. that means they do not yield
+ if(self.packets_sent==1):
+ yield self.env.timeout(self.adist) #yielding for packet generated as ACK
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,type=self.type)
+ self.out.put(p)
+ else:#to make the Base station transmit one ACK for one reception of Data
+ yield self.env.timeout(float("inf")) #this is to prevent the continous transmission to ACK packets..when packets_sent=2,arrival time made infinite
+ else:#this is the normal,keepalive and alarm packet generation at Smart meters
+ yield self.env.timeout(self.adist()) #yielding for other packet
+ #here we need to implement the retransmission portion
+ self.seq_no+=1
+ if(self.seq_no>=4095):#wraps around at 4095 as 12 bits allocated to sequence counter
+ self.seq_no=0
+ #first packet arrival....so send the packet and enqueue it
+ #we should not yield twice....or the net yield gets added up....
+ #transmit original packet
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,type=self.type)
+ self.out.put(p)
+ if(self.type=="keepAlive"):
+ keepAliveCount+=1
+ #print "keepalive:%d"%keepAliveCount
+ elif(self.type=="Normal"):
+ NormalCount+=1
+ print "Normal:%d"%NormalCount
+ self.enQueue(p)
+ elif(self.type=="Alarm"):
+ AlarmCount+=1
+ print "Alarm:%d"%AlarmCount
+ self.enQueue(p)
+
+ def Timer(self):
+ global ACK_ID,ACK_STATUS,SEQUENCE,TYPE,N,ACK_PACKET_ID,PKT_ACKED_SUCCESFULLY,NoOfRetransmissionAlarm,NoOfRetransmissionKeepAlive,NoOfRetransmissionNormal,TotalTime
+ count_keepAlive=0
+ count_Normal=0
+ count_Alarm=0
+
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish:
+ yield self.env.timeout(0.2)
+ for i in range(len(self.Queue)):
+ f=len(self.Queue)-1-i
+ #print "f for SM%d = %d"%(self.id,f)
+ #if current time - sent pkt time < 2 RTT i.e. packet gets acked before the retranmsission timeout i.e. before 2 RTT
+ if(self.env.now-self.getDeparture(self.Queue[f].seq_no)<=2*((self.Queue[f].size*8/250)+(14*8/600)+5) and self.id>2):
+ #print "current time%d wait time %d for %d wd seq no %d and 2*RTT %d"%(self.env.now,self.env.now-self.getDeparture(self.Queue[i].seq_no),self.id,self.Queue[i].seq_no,2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #self.display()
+ for j in range(0,N):
+ #print "ACK_STATUS%s and ACK_ID %d and Type %s and current type %s and time %0.4f and seq no %d" %(ACK_STATUS[j],ACK_ID[j],TYPE[j],self.type,self.env.now,self.Queue[f].seq_no)
+ if(ACK_STATUS[j]==True and ACK_ID[j]==self.id and TYPE[j]==self.Queue[f].type and self.Queue[f].seq_no==SEQUENCE-1 ):
+ print "if a packet is ACKed and id is %d and we deque seq no %d"%(self.id,SEQUENCE-1)
+ #self.display()
+ self.Queue[f].ACKed=True
+ print "if the packet %d sent at %f is acked %r current time %0.4f delay %0.4f"%(f,self.Queue[f].time,self.Queue[f].ACKed,self.env.now,self.env.now-self.Queue[f].time)
+ temp=self.env.now-self.Queue[f].time
+ TotalTime=TotalTime+temp
+ self.deQueue(SEQUENCE-1)
+ PKT_ACKED_SUCCESFULLY+=1
+ ACK_STATUS[j]=False
+ ACK_ID[j]=0
+ count_keepAlive=0
+ count_Normal=0
+ count_Alarm=0
+ print"Total time : %f"%TotalTime
+ print"PKT_ACKED_SUCCESFULLY=%d"%PKT_ACKED_SUCCESFULLY
+
+ #if waiting for ACK time becomes greater than > 2RTT....RTT = size of transmitted packet * 8 /250(SM to BS) + mean loopback period i.e. 5 sec + 14 * 8/600 (BS to SM)
+ elif ((self.env.now-self.getDeparture(self.Queue[f].seq_no))>=2*((self.Queue[f].size*8/250)+(14*8/600)+5)and self.id>2 ):
+
+
+ ######################## Re Transmission for KEEPALIVE PACKET ####################################################################################################
+ #count_keepAlive < 1 means we are taking a maximum of 1 retransmission for keep alive packet
+ #print "Abhijeet!!*******entering the RETRANSMISSION block********"
+ #print "ACK status of SM %d of type %s is %r and f=%d"%(self.id,self.Queue[f].type,self.Queue[f].ACKed,f)
+ #print "Control Variables count_Normal=%d count_Alarm=%d "%(count_Normal,count_Alarm)
+ #self.display()
+ if(self.Queue[f].type=="keepAlive" and count_keepAlive<0 and self.Queue[f].ACKed==False ):
+ BackOff=random.randint(0,self.ContentionWindow)
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size,count_keepAlive+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,type=self.Queue[f].type,retransmitted=True,retrans_no=count_keepAlive)
+ count_keepAlive=Retp1.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ NoOfRetransmissionKeepAlive+=1
+ #print "No of Retransmission Keep Alive %d"%NoOfRetransmissionKeepAlive
+
+ ######################## Re Transmission for NORMAL AMI packets ####################################################################################################
+ #count_Normal < 2 means we are taking a maximum of 2 retransmission for normal packet
+ elif(self.Queue[f].type=="Normal" and count_Normal<2 and self.Queue[f].ACKed==False):
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Normal+1))*self.Queue[f].size*8/250
+ temp2=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp2
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Normal+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Normal)
+ count_Normal=Retp1.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ NoOfRetransmissionNormal+=1
+ print "No of Retransmission Normal%d"%NoOfRetransmissionNormal
+
+ ######################## Re Transmission for ALARM packets ####################################################################################################
+ #count_Alarm < 3 means we are taking a maximum of 3 retransmission for normal packet
+ elif(self.type=="Alarm" and count_Alarm<3 and self.Queue[f].ACKed==False):
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Normal+1))*self.Queue[f].size*8/250
+ temp3=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp3
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Alarm+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Alarm)
+ count_Alarm=Retp1.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ NoOfRetransmissionAlarm+=1
+ print "No of Retransmission Alarm %d"%NoOfRetransmissionAlarm
+
+ #if ACK not received ... deque the packet from the queue and reset the control variables
+ else:
+ self.deQueue(self.Queue[f].seq_no)
+ count_keepAlive=0
+ count_Normal=0
+ count_Alarm=0
+
+
+ #display the content of the Queue, used for debugging
+ def display(self):
+ print "queue at time %d in SM %d : %s"%(self.env.now,self.id,self.Queue)
+
+ #the function to fill the queue whenever a new packet is transmitted...or if an old packet is retranmsitted
+ def enQueue(self,pkt):
+ #print "in enQueue "
+ self.Queue.append(pkt)
+ #print"Queue %s at time %d"%(self.Queue,self.env.now)
+ while(len(self.Queue)>self.Queue_Size):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ self.deQueue(self.Queue[x].seq_no)
+
+ #this function returns the oldest packet in the queue
+ def giveOldestPacket(self):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ return self.Queue[x]
+
+ #this function is used to remove the packet from the queue when a packet gets an ACK response or if does not get any ACK after retransmission too
+ def deQueue(self,sq):
+ #print "in deQueue for %d whose length is %d and at time: %d"%(self.id,len(self.Queue),self.env.now)
+ #print "Dequeue from queue %s element with seq no %d"%(self.Queue,sq)
+ x=self.getIndex(self.Queue,sq)
+ #print "%s"%x
+ self.Queue.pop(x)
+ #print "After deQueue %s"%self.Queue
+
+ #this function return the index of the packet there in the queue
+ def getIndex(self,q,sq):
+ #print "queue length: %d and we search fr seq no: %d" % ((len(q)),sq)
+ for i in range(len(q)):
+ #print "queue seq no: %d"%(q[i].seq_no)
+ if (q[i].seq_no==sq):
+ return i
+ return 0
+
+ #get the packet from the queue... this is currently not used but can be used later as per the logic developed in the code
+ def getQueue(self,sq):
+ #print "in getQueue "
+ #min_departure_time = time
+ for i in range(len(self.Queue)):
+ if(self.Queue[i].seq_no<=sq):
+ return self.Queue[i]
+
+ #this can be used when we implement a logic for dynamic contention window based on collision
+ def calcBackOffTime(self,cw):
+ BackoffTime=random.randint(1,cw)
+ return BackoffTime
+
+ #returns the time at which the packet is sent by the Smart meter
+ def getDeparture(self,sq):
+ for i in range(len(self.Queue)):
+
+ if(self.Queue[i].seq_no==sq):
+ #print "found seq no"
+ return self.Queue[i].time
+
+ return self.env.now
+
+######################################## PacketSink Class ##############################################################################################################################
+
+class PacketSink(object):
+ """ Receives packets and collects delay information into the
+ waits list. You can then use this list to look at delay statistics.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ debug : boolean
+ if true then the contents of each packet will be printed as it is received.
+ rec_arrivals : boolean
+ if true then arrivals will be recorded
+ absolute_arrivals : boolean
+ if true absolute arrival times will be recorded, otherwise the time between consecutive arrivals
+ is recorded.
+ rec_waits : boolean
+ if true waiting time experienced by each packet is recorded
+ selector: a function that takes a packet and returns a boolean
+ used for selective statistics. Default none.
+ check_collision: for checking collision
+
+
+ """
+ def __init__(self, env,id, rec_arrivals=False, absolute_arrivals=False, rec_waits=True, debug=False, selector=None):
+ self.id=id
+ self.store = simpy.Store(env)
+ self.env = env
+ self.rec_waits = rec_waits
+ self.rec_arrivals = rec_arrivals
+ self.absolute_arrivals = absolute_arrivals
+ #self.check_collision = []
+ self.waits = []
+ self.arrivals = []
+ self.BS_List = []
+ self.channel_set = []
+ self.pktendtime=[]
+ self.prob_rec_BS1=[]
+ #self.prob_rec_BS2=[]
+ self.debug = debug
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.packets_rec = 0
+ self.bytes_rec = 0
+ self.selector = selector
+
+ #self.packetRecvStatus = True # by default it is true based on which the receiver generates ACK,
+ # but when collision it is false and receiver does not generate ACK
+ #self.type="keepAlive"
+ self.backLogPackets=0
+ def run(self):
+ last_arrival = 0.0
+
+ while True:
+ global print_control
+ msg = (yield self.store.get())
+ self.channel_set.append(msg.channel)
+ self.prob_rec_BS1.append(msg.prob_rec_BS1)
+ #self.prob_rec_BS2.append(msg.prob_rec_BS2)
+ if not self.selector or self.selector(msg):
+ now = self.env.now
+ if self.rec_waits:
+ self.waits.append(self.env.now - msg.time)
+ if self.rec_arrivals:
+ if self.absolute_arrivals:
+ self.arrivals.append(now)
+ else:
+ self.arrivals.append(now - last_arrival)
+ last_arrival = now
+ self.packets_rec += 1
+ self.bytes_rec += msg.size
+ #####to display the output __repr__ of class Packet##################
+ if self.debug:
+ #if((msg.type=="Normal" or msg.type=="Alarm") and msg.src>2):
+ print msg
+
+ #global STATUSA,STATUSB
+ #global STATUSA
+ global CollisionCount,collision_check
+ #global BS1_ACK_send_STATUS #if already base station 1 has send the ACK Base station 2 should not send...this Flag is used
+ #self.check_collision.append("False")
+ #global LoopBackPeriod
+ collision_check=0
+ global SEQUENCE,ACK_ID,ACK_STATUS,TYPE,N,ACK_PACKET_ID
+ downLinkRate=600
+ AckPacketSize=14
+ #print "print index check : %s and SINK id:%s"%(self.packets_rec-1,self.id)
+ if(self.id == 1 ):#if packet Sink is a base station we send here the ACKs based on collision free reception
+ #appending the packet end time to the pktendtime list
+ self.pktendtime.append(msg.size*8/msg.bitrate + self.arrivals[self.packets_rec-1])
+ #collision detection logic...
+ #if more than 1 packet received at Base station(for comparison) and channel used by prev and current packet is same
+ #and pkt end time of previous packet is larger than the arrival time of the current packet
+ #Then there is collision
+ #currently in my logic i am not sending ACK only for the current colliding packet and not for the previous colliding packet
+ #Because everytime there is no collision i am sending ACK packets
+ #Though i can evaluate the number of collision to be 2 times of the current collision count..
+ #but number of retransmission will be half..which is erroneous...i need a little algorithmic help here..
+ #if the previous and its previous packets overlaps with current packet
+ if (self.packets_rec>10):
+ for i in range(1,10):
+ if (self.channel_set[self.packets_rec-(i+1)]==self.channel_set[self.packets_rec-1]):
+ if((self.pktendtime[self.packets_rec-(i+1)]>self.arrivals[self.packets_rec-1]) and
+ (self.prob_rec_BS1[self.packets_rec-(i+1)]>=pthres and self.prob_rec_BS1[self.packets_rec-1]>=pthres)):
+ #print "Collision Detected at Base Station %s due to same channel %s and packet overlap with previous"%(self.id,self.channel_set[self.packets_rec-1])
+ #self.check_collision=[word.replace("False","True") for word in self.check_collision]
+ #print "SM ID:%s Packet Id:%s channel used: %s packets received: %s arrival time: %s packet end time :%s collision detected :%s "%(msg.src,msg.id,self.channel_set[self.packets_rec-1],self.packets_rec,self.arrivals[self.packets_rec-1],self.pktendtime[self.packets_rec-1],self.check_collision[self.packets_rec-1])
+ #print " No ACK transmitted due to collision"
+ collision_check=1
+ if(msg.type=="Normal" or msg.type=="Alarm"):
+ print i
+ CollisionCount+=1
+ print"collision count=%d"%CollisionCount
+ break
+ if(self.prob_rec_BS1[self.packets_rec-1]>=pthres and collision_check!=1):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+
+ elif(self.prob_rec_BS1[self.packets_rec-1]>=pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+
+
+
+
+ #if packet sink is a Smart meter....we check the ACK reception status
+ else:
+
+ #print "ACK received at SM %s"%self.id
+ for i in range(0,N):
+ #print "inside for loop %d and compared index %d"%(self.id,i+3)
+ if(self.id==i+3):
+ #print "inside if loop"
+ ACK_STATUS[i]=True
+ ACK_ID[i]=self.id
+ #ACK_PACKET_ID=msg.id
+ SEQUENCE=msg.seq_no
+ TYPE[i]=msg.type
+ #ACK_TIME[i]=self.env.now
+ #print msg.type
+
+ def put(self, pkt):
+ self.store.put(pkt)
\ No newline at end of file
diff --git a/SimLibraryOneBS_aug18_noretrans.py b/SimLibraryOneBS_aug18_noretrans.py
new file mode 100644
index 0000000..d36d936
--- /dev/null
+++ b/SimLibraryOneBS_aug18_noretrans.py
@@ -0,0 +1,231 @@
+import numpy
+import math
+import random
+import simpy
+
+from SimLibraryOneBS_aug18 import *
+import scipy.stats as stats
+
+############################################### Arrival Traffic Function Definitions#############################################
+#control variables
+k=1
+j=1
+i=1
+cache=0
+cache1=0
+cache2=0
+cache3=0
+cache4=0
+reportInterval_SM = 60 #60 sec time for keep alive
+reportInterval_SM_Normal = 300 #10 mins
+Mean_Report_Interval = 3600 # 1 hour for Aperiodic packets
+N=300#no of Smart meters
+itrn=1
+itrn2=1
+#LoopbackTime=12
+#for uplink packet from smart meter to BS
+SIMULATION=2000
+def ArrivalTimeSM_keepAlive():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache,k
+ #global reportInterval_SM,reportInterval_SM_Normal
+ reportInterval_SM = 60 #60 sec time for keep alive
+ a = 0
+ b = reportInterval_SM - 1
+ #print "k %s"%k
+ if(k<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+ k=k+1
+ #cache=random.randint(a,b)
+ cache=random.uniform(a,b)
+ return cache
+
+ else:#after all the smart meter have an initial offset the 60 sec interval follows
+ k=k+1
+ cache = reportInterval_SM #then the arrival rate of 60 follows
+ return cache
+
+
+#####Defining Arrival Rate for Normal packets#########
+def ArrivalTimeSM_Normal():
+ #need to set a random start time - any second within one hour - 0 to 3600 sec
+ global cache1,j
+ reportInterval_SM_Normal = 300#5 min time for Normal packets
+ a = 0
+ b = reportInterval_SM_Normal - 1
+ #print "k %s"%k
+ if(j<=N):#as we are using one Base station it is N...for 2 Base station it will be 2*N...for 3 it will be 3*N..for initial offset
+
+ j=j+1
+ #cache1=random.randint(a,b)
+ cache1=random.uniform(a,b)
+ return cache1
+
+ else:#the second packet sent to another Base station is the replica of the first one
+ j=j+1
+ cache1 = reportInterval_SM_Normal#then the arrival rate of 14400 follows
+ return cache1
+
+#####Defining Arrival Rate for Alarm packets#########
+def ArrivalTimeSM_Alarm():
+ global Mean_Report_Interval ,i ,cache2
+ i=i+1
+ cache2=math.ceil(random.expovariate(1.0/Mean_Report_Interval)) #exponential arrival rate with a mean of one hour
+ return cache2
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Household meters################################
+def upLinkUser_HouseHoldPkt(str): # Constant packet size distribution 90 percent of users
+ if(str=="keepAlive"):
+ #92 bytes the packet size+ 132 bits * (92/32)
+ #headers :40 bit MAC header, 12 bit Seq Counter, 40 bit node identifier, 16 bit Auth Hash, 8 bits CRC, 16 bits ECC
+ return 141.5 #constant payload of 92 bytes + 3*16.5 bytes(132 bits) as 92 byte/32 bytes= 3
+ elif(str=="Normal" ):
+ #254 bytes the packet size+ 132 bits *(254/32) = 254 + 8*16.5 bytes
+ return 386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 200 as per the discusiion with Proff
+ global itrn,cache3
+ mean=200
+ itrn+=1
+ size=random.expovariate(1.0/mean)
+ cache3= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache3
+
+
+
+
+#########Defining keepAlive,Normal and Alarm packets for Commercial meters################################
+def upLinkUser_CommercialPkt(str):
+ if(str=="keepAlive"):
+ #double of Household
+ return 2*141.5
+ elif(str=="Normal"):
+ #double of household
+ return 2*386
+ elif(str =="Alarm"):
+ #taking an exponential distribution for the size of the packet with mean 400 as per the discusiion with Proff
+
+ global itrn2,cache4
+ mean2=400
+
+ itrn2+=1
+ size=random.expovariate(1.0/mean2)
+ cache4= math.ceil(size+math.ceil(size/32)*16.5)
+ return cache4
+
+
+
+##################Start of Simulation###########################################
+start = True
+env = simpy.Environment() # Create the SimPy environment
+#log normal calculation, currently i havent utilized these in the consideration of collision
+d0 = 1 #reference distance = 1 meter
+prd0 = 0 #received signal at reference distance is 0 dBm
+n = 3.5 #path loss coefficient. Assume urban area
+prd_req = -120 #minimum required received power at base station
+sigma = 8 # standard deviation of 8 dB
+upLinkBitRate = 250
+downLinkBitRate= 600
+household=0
+commercial=0
+
+#ContentionWindow = 4 #for BackOff calculation
+BS1_id=1 #Base Station 1 ID
+#BS2_id=2
+
+#Base Station 1 and 2 SINK instantiated
+BS1_PS = PacketSink(env,BS1_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+#BS2_PS = PacketSink(env,BS2_id, rec_arrivals=True, absolute_arrivals=True, rec_waits=True, debug=True, selector=None) # debugging enable for simple output
+
+
+#Smart Meter ID would range from 3 to 102 (I am considering 100 Smart Meters)
+SM_id=3
+#creates a 100 x 2 matrix to store the Id
+#Channel ID would range from 1 to 8
+channel_size=8
+
+#sequence number would be used in further simulations..currently kept inactive
+#max_seq_Num=4095
+#seq_Num=0
+#seq_Num=1
+
+#base station co-ordinate
+BS1_Loc = numpy.array((1154,1000))
+#BS2_Loc = numpy.array((2885,1000))
+
+BS1_List =[]
+#BS2_List=[]
+#carrying out the experiment for 100 smart meters
+while(SM_id<3+N):
+
+ new=[]
+ new.append(SM_id)
+ a = random.normalvariate(5,0.217)
+ #assuming a square cell with a diagonal of 2000m
+ #x_cord = random.randint(0,3750) #x coordinate of the smart meter node
+ x_cord = random.randint(0,2308) #x coordinate of the smart meter node
+ y_cord = random.randint(0,2000) #y coordinate of the smart meter node
+ cord = numpy.array((x_cord,y_cord))#cord holds the coordinate of the smart meter
+ distBS1 = numpy.linalg.norm(cord-BS1_Loc)# Distance between the Smart meter and the Base Station
+ #distBS2 = numpy.linalg.norm(cord-BS2_Loc)
+
+ prd_mean_BS1=prd0 -10*n*math.log10(distBS1/d0)#power received at Base Station from the smart meters
+ #prd_mean_BS2=prd0 -10*n*math.log10(distBS2/d0)
+ #calculation of Q value...probability that the received signal is higher than -120dB
+ prob_rec_BS1=0.5*math.erfc((prd_req-prd_mean_BS1)/sigma*math.sqrt(2))
+ #prob_rec_BS2=0.5*math.erfc((prd_req-prd_mean_BS2)/sigma*math.sqrt(2))
+
+ if a<5.278:#for 0.9 probability for household Smart meters
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive,upLinkUser_HouseHoldPkt("keepAlive"),channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_HouseHoldPkt("Normal"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_HouseHoldPkt("Alarm"), channel_size,upLinkBitRate, prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ household=household+1
+ #array to hold the SM id and channel used
+ else:
+
+
+ #Keep Alive Packet from the smart meter
+ SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,0,"keepAlive")
+ #SM_PG3 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #SM_PG4 = PacketGenerator(env, SM_id,ArrivalTimeSM_keepAlive, upLinkUser_CommercialPkt("keepAlive"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"keepAlive")
+ #Normal data packet from the smart meter
+ SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,0,"Normal")
+ #SM_PG1 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #SM_PG2 = PacketGenerator(env, SM_id,ArrivalTimeSM_Normal, upLinkUser_CommercialPkt("Normal"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Normal")
+ #Alarm packet from the smart meter
+ SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,0,"Alarm")
+ #SM_PG5 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"), channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #SM_PG6 = PacketGenerator(env, SM_id,ArrivalTimeSM_Alarm, upLinkUser_CommercialPkt("Alarm"),channel_size,upLinkBitRate,prob_rec_BS1,prob_rec_BS2,0,"Alarm")
+ #as per the mail from Dr goulart the upLinkUserPkt() will have exponential distribution..poisson traffic.currently considering constant for single user
+ commercial=commercial+1
+
+ #SM_PG2.out = BS2_PS
+ SM_PG1.out = BS1_PS
+
+ #SM_PG4.out = BS2_PS
+ SM_PG3.out = BS1_PS
+
+ #SM_PG6.out = BS2_PS
+ SM_PG5.out = BS1_PS
+
+
+ #print"SM_id is %s "%SM_id
+
+ SM_id=SM_id+1
+env.run(until=SIMULATION) #until how much time we run the simulation
+#global CollisionCount,NoOfRetransmission
+#print "Total Packets received by the Base station is %s"%BS1_PS.packets_rec
diff --git a/SimLibraryTwoBS_aug18.py b/SimLibraryTwoBS_aug18.py
new file mode 100644
index 0000000..de8d6f4
--- /dev/null
+++ b/SimLibraryTwoBS_aug18.py
@@ -0,0 +1,604 @@
+import simpy
+import random
+import numpy
+import math
+
+#########################################control variables used in the code########################################################################################################
+N=300 #the number of smart meters that are communicating to the Base stations
+CollisionCount=0
+unsuccessful_due_dist=0
+NoOfRetransmission=0
+keepAliveCount=0 #keepAlive Packet count
+NormalCount=0 #normal packet count
+AlarmCount=0 #alarm packet Count
+NoOfRetransmissionAlarm=0 #total number of Alarm packet that got retransmitted
+NoOfRetransmissionKeepAlive=0 # total number of keepAlive packet that got retransmitted
+NoOfRetransmissionNormal=0 #total number of Normal packet that got retranmsitted
+STATUSA =False #this global variable is used for collision detection at Base Station 1
+STATUSB =False #this global variable is used for collision detection at Base Station 2
+TotalTime=0 #this variable holds the sum of delay time of all the packets that are generated from smart meters, to caluclate the average delay
+#LoopBackPeriod = 5 #ACK response time
+pthres=0.9 #probability of threshold for the Base station to detect the packet....based on the signal receiving capacity of the Base station
+#BS1_ACK_send_STATUS=False #this variable is used to prevent deduplication of ACK. if Base station has succesfully transmitted an ACK den BS2 should not transmit
+ACK_STATUS=numpy.full(N,False,dtype=bool) #this array holds ACK status of each packet that is ACKed by the Base station
+ACK_ID=numpy.zeros(N) #this array will hold the IDs of the Smart mter whose packet got ACKed..it is used in run() of PacketSink and Timer() of PacketGenerator
+SEQUENCE=0 #this variable stores the sequence number of the packet ACKed, so as to verify that at the transmitter
+TYPE = ["" for x in range(N)] #this is an array that stores the type of packet ACKed by the Base station. Goto run() of PacketSink to see its usage
+#ACK_TIME=numpy.zeros(N,dtype=numpy.float)
+ACK_PACKET_ID=0 #this variable holds the ID of the smart meter whose packet got ACKed.
+PKT_ACKED_SUCCESFULLY=0
+k=1 #this variable is used to use same channel for broadcasting at a Smart meter...
+ #goto __init__() of class PacketGenerator to see its implementation
+x=1 #this variable is used to logically prevent duplicate maintenance of packets in the smart meter queue....
+ #goto run() of Class PacketGenerator to see its usage
+cache=0 #this variable is used to use same channel for broadcasting at a Smart meter...
+ #goto __init__() of class PacketGenerator to see its implementation
+print_control=0
+######################################## Packet Class ##############################################################################################################################
+class Packet(object):
+ """ A very simple class that represents a packet.
+ This packet will run through a queue at a switch output port.
+ We use a float to represent the size of the packet in bytes so that
+ we can compare to ideal M/M/1 queues.
+
+ Parameters
+ ----------
+ time : float
+ the time the packet arrives at the output queue.
+ size : float
+ the size of the packet in bytes
+ id : int
+ an identifier for the packet
+ seq_no: int
+ it is the sequence number of the packet used for retransmission
+ src, dst : int
+ identifiers for source and destination
+ flow_id : int
+ small integer that can be used to identify a flow
+ channel : int
+ channel id used by the nodes to transmit that particular packet
+ bitrate : int
+ for uplink we take as 250 bits/sec and downlink we take 600 bits/sec
+ prob_rec_BS1,prob_rec_BS2 : float
+ it is the probabibilty of successful reception at two Base stations respectively
+ type : string
+ defines the type of packet...In our case we are considering the Normal, keepAlive, Alarm and ACK packets
+ retransmitted : boolean
+ defines whether the packet is a retransmitted or a non retransmitted packet
+ retrans_no :int
+ number of times the packet is retransmitted
+ """
+ def __init__(self, time, size, id,seq_no,src="a", dst="z", flow_id=0, channel=10,bitrate=0,prob_rec_BS1=1,prob_rec_BS2=1,type="ACK",retransmitted=False,retrans_no=0):
+ self.time = time
+ self.size = size
+ self.id = id
+ self.src = src
+ self.dst = dst
+ self.flow_id = flow_id
+ #self.channel=channel
+ global k,cache
+ if(self.src==1 or self.src==2):
+ self.channel=channel
+ elif(self.src >2 and (self.size ==283.0 or self.size ==772.0)): #if commercial packet
+ self.channel=1
+ elif(self.src >2 and k%2 ==1 and (self.size !=283.0 or self.size !=772.0)): #if household packet
+ k+=1
+ cache=random.randint(2,channel)
+ self.channel=cache
+ elif(self.src>2 and k%2 ==0and (self.size !=283.0 or self.size !=772.0)):
+ k+=1
+ self.channel=cache
+
+ self.bitrate=bitrate
+ self.prob_rec_BS1=prob_rec_BS1
+ self.prob_rec_BS2=prob_rec_BS2
+ self.type=type
+ self.retransmitted=retransmitted
+ self.seq_no=seq_no
+ if(self.retransmitted == True):
+ self.retrans_no=retrans_no
+ else:
+ self.retrans_no=0
+ self.ACKed=False
+ def __repr__(self):
+ if(self.src>2 ):
+ #print"*****************************************************************************************"
+ return "UPLINK {} Packet : id: {}, src: {},seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}, Prob_R at BS1:{}, Prob_R at BS2:{}, retransmitted:{} ".\
+ format(self.type,self.id, self.src,self.seq_no, self.time, self.size,self.channel,self.bitrate,self.prob_rec_BS1,self.prob_rec_BS2,self.retransmitted)
+
+ else:
+ #print"*****************************************************************************************"
+ return "DOWNLINK Packet : id: {}, src: {}, seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}".\
+ format(self.id, self.src,self.seq_no ,self.time, self.size,self.channel,self.bitrate)
+
+ #this function increments the retransmission for a packet
+ def noOfRetransmission(self):
+ self.retrans_no=self.retrans_no+1
+ return self.retrans_no
+
+######################################## PacketGenerator Class ##############################################################################################################################
+class PacketGenerator(object):
+ """ Generates packets with given inter-arrival time distribution.
+ Set the "out" member variable to the entity to receive the packet.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ adist : function
+ a no parameter function that returns the successive inter-arrival times of the packets
+ sdist : function
+ a no parameter function that returns the successive sizes of the packets
+
+ initial_delay : number
+ Starts generation after an initial delay. Default = 0
+ finish : number
+ Stops generation at the finish time. Default is infinite
+ pktType:either keepAlive,Alarm or Normal or ACK
+
+ """
+ def __init__(self, env, id, adist, sdist, channel, bitrate,prob_rec_BS1,prob_rec_BS2,seq_no,type="ACK",retransmitted=False,initial_delay=0, finish=float("inf"), flow_id=0,packetRecv=False):
+ self.id = id
+ self.env = env
+ self.adist = adist
+ self.sdist = sdist
+ self.initial_delay = initial_delay
+ self.finish = finish
+ self.out = None
+ self.type=type
+ self.retransmitted=retransmitted
+ self.packets_sent = 0
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.action = env.process(self.Timer()) #this is another timer () method that runs concurrently with the run() method...it is used to probe the received ACK at the Smart meters
+ self.flow_id = flow_id
+ self.ContentionWindow=4
+ self.channel=channel
+ #when the id =1, i.e. Base station ID then the same channel with which the packet was received by the Base station
+ #would be used for ACK transmission
+ #In the else part for Smartmeters it is random channel selection
+ #self.packetRecv=packetRecv
+ self.prob_rec_BS1=prob_rec_BS1
+ self.prob_rec_BS2=prob_rec_BS2
+ self.bitrate=bitrate
+
+ if(self.id==1 or self.id==2):
+ self.seq_no=seq_no #the sequence number used by the Base station here are the ACK number thats why they should be same as the seq number of the packet received at Base station
+ else:
+ self.seq_no=0 # A smart meter must initiates his packet generation with a sequence number of zero
+
+ self.Queue=[] #for storing the packets transmitted...so if they are not ACKed in the retransmission timeout period, they can be transmitted again by fetching from queue
+ self.Queue_Size=100#maximum size of a queue for a device would be 10
+
+ def run(self):
+ """The generator function used in simulations.
+ """
+ global x,keepAliveCount,NormalCount,AlarmCount
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish: #till infinite
+ self.packets_sent += 1
+ # wait for next transmission...yielding based on the type of packet generated as the ACK is conditioned we provide a constant rather than function based
+ if (self.id==1 or self.id==2 ): #sending the ACKs once for BS1 and BS2...that is why for packet_sent == 1 they just yield once... for packet_sent > 1, yield timeout is infinite.. that means they do not yield
+ if(self.packets_sent==1):
+ yield self.env.timeout(self.adist) #yielding for packet generated as ACK
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,prob_rec_BS2=self.prob_rec_BS2,type=self.type)
+ self.out.put(p)
+ else:#to make the Base station transmit one ACK for one reception of Data
+ yield self.env.timeout(float("inf")) #this is to prevent the continous transmission to ACK packets..when packets_sent=2,arrival time made infinite
+ else:#this is the normal,keepalive and alarm packet generation at Smart meters
+ yield self.env.timeout(self.adist()) #yielding for other packet
+ #here we need to implement the retransmission portion
+ self.seq_no+=1
+ if(self.seq_no>=4095):#wraps around at 4095 as 12 bits allocated to sequence counter
+ self.seq_no=0
+ #first packet arrival....so send the packet and enqueue it
+ #we should not yield twice....or the net yield gets added up....
+ #transmit original packet
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,prob_rec_BS2=self.prob_rec_BS2,type=self.type)
+ self.out.put(p)
+ if(self.type=="keepAlive"):
+ keepAliveCount+=1
+ #print "keepalive:%d"%keepAliveCount
+ elif(self.type=="Normal"):
+ NormalCount+=1
+ #print "Normal:%d"%NormalCount
+ if x%2==1:
+ x+=1
+ self.enQueue(p)
+ print "Normal:%d"%NormalCount
+ else:
+ x+=1
+ elif(self.type=="Alarm"):
+ AlarmCount+=1
+ #print "Alarm:%d"%AlarmCount
+ if x%2==1:
+ x+=1
+ self.enQueue(p)
+ print "Alarm:%d"%AlarmCount
+ else:
+ x+=1
+
+ def Timer(self):
+ global ACK_ID,ACK_STATUS,SEQUENCE,TYPE,N,ACK_PACKET_ID,PKT_ACKED_SUCCESFULLY,NoOfRetransmissionAlarm,NoOfRetransmissionKeepAlive,NoOfRetransmissionNormal,TotalTime
+ count_keepAlive=0
+ count_keepAlive1=0
+ count_Normal=0
+ count_Alarm=0
+ count_Normal1=0
+ count_Alarm1=0
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish:
+ yield self.env.timeout(0.2)
+ #print "in timer function"
+ #for i in range(0,100):
+ #if within 2 RTT ACK is received than dequeue the packet from the queue
+ #these if condition should be checked for individual packets....rather than an individual smart meter
+ #print "t=%d length of Queue at SM %d is %d"%(self.env.now,self.id,len(self.Queue))
+ #print"\n"
+ #print "ID of Base station or Smart meter %d"%self.id
+ for i in range(len(self.Queue)):
+ #print "SM id %d and its queue length %d and i value %d"%(self.id,len(self.Queue),i)
+ #print "the queue %s"%(self.Queue)
+ f=len(self.Queue)-1-i
+ #if current time - sent pkt time < 2 RTT i.e. packet gets acked before the retranmsission timeout i.e. before 2 RTT
+ if(self.env.now-self.getDeparture(self.Queue[f].seq_no)<=2*((self.Queue[f].size*8/250)+(14*8/600)+5) and self.id>2):
+ #print "current time%d wait time %d for %d wd seq no %d and 2*RTT %d"%(self.env.now,self.env.now-self.getDeparture(self.Queue[i].seq_no),self.id,self.Queue[i].seq_no,2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #self.display()
+ for j in range(0,N):
+ #print "ACK_STATUS%s and ACK_ID %d and Type %s and current type %s"%(ACK_STATUS[i],ACK_ID[i],TYPE[i],self.type)
+ if(ACK_STATUS[j]==True and ACK_ID[j]==self.id and TYPE[j]==self.Queue[f].type and self.Queue[f].seq_no==SEQUENCE-1 ):
+ #print"Ack status : %r and ID: %d and departure time: %d and wait time %d 2*RTT:%d"%(ACK_STATUS[i],ACK_ID[i],self.getDeparture(SEQUENCE-1),self.env.now - self.getDeparture(SEQUENCE-1),2*((self.sdist*8/250)+(14*8/600)))
+ #print "At time t= %d"%self.env.now
+ #print "if a packet is ACKed and id is %d and we deque seq no %d"%(self.id,SEQUENCE-1)
+ #self.display()
+ self.Queue[f].ACKed=True
+ #print "if the packet %d sent at %f is acked %r current time %0.4f delay %0.4f"%(f,self.Queue[f].time,self.Queue[f].ACKed,self.env.now,self.env.now-self.Queue[f].time)
+ temp=self.env.now-self.Queue[f].time
+ TotalTime=TotalTime+temp
+ self.deQueue(SEQUENCE-1)
+ PKT_ACKED_SUCCESFULLY+=1
+ ACK_STATUS[j]=False
+ ACK_ID[j]=0
+ count_keepAlive=0
+ count_keepAlive1=0
+ count_Normal=0
+ count_Normal1=0
+ count_Alarm=0
+ count_Alarm1=0
+ print"Total time : %f"%TotalTime
+ print"PKT_ACKED_SUCCESFULLY=%d"%PKT_ACKED_SUCCESFULLY
+
+ #if waiting for ACK time becomes greater than > 2RTT....RTT = size of transmitted packet * 8 /250(SM to BS) + mean loopback period i.e. 5 sec + 14 * 8/600 (BS to SM)
+ elif ((self.env.now-self.getDeparture(self.Queue[f].seq_no))>=2*((self.Queue[f].size*8/250)+(14*8/600)+5)and self.id>2 ):
+ #print "At time t= %d"%self.env.now
+ #print"either ACK received late or not received%0.4f %0.4f"%(self.env.now-self.getDeparture(self.Queue[i].seq_no),2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #print "size and rtt are %0.4f and %0.4f"%(self.Queue[i].size,2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #print "if the packet %d is acked %r current time %d"%(i,self.Queue[i].ACKed,self.env.now)
+
+ ######################## Re Transmission for KEEPALIVE PACKET ####################################################################################################
+ #count_keepAlive < 1 means we are taking a maximum of 1 retransmission for keep alive packet
+ #print "Abhijeet!!*******entering the RETRANSMISSION block********"
+ #print "ACK status of SM %d of type %s is %r and f=%d"%(self.id,self.Queue[f].type,self.Queue[f].ACKed,f)
+ #print "Control Variables count_Normal=%d count_Alarm=%d "%(count_Normal,count_Alarm)
+ #self.display()
+ if(self.Queue[f].type=="keepAlive" and count_keepAlive<0 and count_keepAlive1<0 and self.Queue[f].ACKed==False ):
+ BackOff=random.randint(0,self.ContentionWindow)
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size,count_keepAlive+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_keepAlive)
+ count_keepAlive=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_keepAlive1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_keepAlive1)
+ count_keepAlive1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionKeepAlive+=1
+ #print "No of Retransmission Keep Alive %d"%NoOfRetransmissionKeepAlive
+
+ ######################## Re Transmission for NORMAL AMI packets ####################################################################################################
+ #count_Normal < 2 means we are taking a maximum of 2 retransmission for normal packet
+ elif(self.Queue[f].type=="Normal" and count_Normal<2 and count_Normal1<2 and self.Queue[f].ACKed==False):
+ #simple random backoff
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ #binary exponential backoff..waits random(0,pow(2,n)) multiplied by packet duration...
+ #where pow(2,n) is the contention window and n is the retransmission count
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Normal+1))*self.Queue[f].size*8/250
+
+ #ideal backoff for random access pure ALOHA is 4N times a packet transmission time, where N = is the no. of active nodes..taking N=1
+ #BackOff=4*self.Queue[f].size*8/250
+ temp2=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp2
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Normal+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Normal)
+ count_Normal=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Normal1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Normal1)
+ count_Normal1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionNormal+=1
+ print "No of Retransmission Normal%d"%NoOfRetransmissionNormal
+
+ ######################## Re Transmission for ALARM packets ####################################################################################################
+ #count_Alarm < 3 means we are taking a maximum of 3 retransmission for normal packet
+ elif(self.type=="Alarm" and count_Alarm<3 and count_Alarm1<3 and self.Queue[f].ACKed==False):
+ #simple random backoff
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ #binary exponential backoff..waits random(0,pow(2,n)) multiplied by packet duration...
+ #where pow(2,n) is the contention window and n is the retransmission count
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Alarm+1))*self.Queue[f].size*8/250
+ #ideal backoff for random access pure ALOHA is 4N times a packet transmission time, where N = is the no. of active nodes..taking N=1
+ #BackOff=4*self.Queue[f].size*8/250
+ temp3=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp3
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Alarm+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Alarm)
+ count_Alarm=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Alarm1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Alarm1)
+ count_Alarm1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionAlarm+=1
+ print "No of Retransmission Alarm %d"%NoOfRetransmissionAlarm
+
+ #if ACK not received ... deque the packet from the queue and reset the control variables
+ else:
+ self.deQueue(self.Queue[f].seq_no)
+ count_keepAlive=0
+ count_Normal=0
+ count_Alarm=0
+ count_keepAlive1=0
+ count_Normal1=0
+ count_Alarm1=0
+
+ #display the content of the Queue, used for debugging
+ def display(self):
+ #print "queue at time %d : %s"%(self.env.now,self.Queue)
+ print "queue at time %d in SM %d : %s"%(self.env.now,self.id,self.Queue)
+
+ #the function to fill the queue whenever a new packet is transmitted...or if an old packet is retranmsitted
+ def enQueue(self,pkt):
+ #print "in enQueue "
+ self.Queue.append(pkt)
+ #print"Queue %s at time %d"%(self.Queue,self.env.now)
+ while(len(self.Queue)>self.Queue_Size):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ self.deQueue(self.Queue[x].seq_no)
+
+ #this function returns the oldest packet in the queue
+ def giveOldestPacket(self):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ return self.Queue[x]
+
+ #this function is used to remove the packet from the queue when a packet gets an ACK response or if does not get any ACK after retransmission too
+ def deQueue(self,sq):
+ #print "in deQueue for %d whose length is %d and at time: %d"%(self.id,len(self.Queue),self.env.now)
+ #print "Dequeue from queue %s element with seq no %d"%(self.Queue,sq)
+ x=self.getIndex(self.Queue,sq)
+ #print "%s"%x
+ self.Queue.pop(x)
+ #print "After deQueue %s"%self.Queue
+
+ #this function return the index of the packet there in the queue
+ def getIndex(self,q,sq):
+ #print "queue length: %d and we search fr seq no: %d" % ((len(q)),sq)
+ for i in range(len(q)):
+ #print "queue seq no: %d"%(q[i].seq_no)
+ if (q[i].seq_no==sq):
+ return i
+ return 0
+
+ #get the packet from the queue... this is currently not used but can be used later as per the logic developed in the code
+ def getQueue(self,sq):
+ #print "in getQueue "
+ #min_departure_time = time
+ for i in range(len(self.Queue)):
+ if(self.Queue[i].seq_no<=sq):
+ return self.Queue[i]
+
+ #returns the time at which the packet is sent by the Smart meter
+ def getDeparture(self,sq):
+ for i in range(len(self.Queue)):
+
+ if(self.Queue[i].seq_no==sq):
+ #print "found seq no"
+ return self.Queue[i].time
+
+ return self.env.now
+
+######################################## PacketSink Class ##############################################################################################################################
+
+class PacketSink(object):
+ """ Receives packets and collects delay information into the
+ waits list. You can then use this list to look at delay statistics.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ debug : boolean
+ if true then the contents of each packet will be printed as it is received.
+ rec_arrivals : boolean
+ if true then arrivals will be recorded
+ absolute_arrivals : boolean
+ if true absolute arrival times will be recorded, otherwise the time between consecutive arrivals
+ is recorded.
+ rec_waits : boolean
+ if true waiting time experienced by each packet is recorded
+ selector: a function that takes a packet and returns a boolean
+ used for selective statistics. Default none.
+ check_collision: for checking collision
+
+
+ """
+ def __init__(self, env,id, rec_arrivals=False, absolute_arrivals=False, rec_waits=True, debug=False, selector=None):
+ self.id=id
+ self.store = simpy.Store(env)
+ self.env = env
+ self.rec_waits = rec_waits
+ self.rec_arrivals = rec_arrivals
+ self.absolute_arrivals = absolute_arrivals
+ self.check_collision = []
+ self.waits = []
+ self.arrivals = []
+ self.BS_List = []
+ self.channel_set = []
+ self.pktendtime=[]
+ self.prob_rec_BS1=[]
+ self.prob_rec_BS2=[]
+ self.debug = debug
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.packets_rec = 0
+ self.bytes_rec = 0
+ self.selector = selector
+
+ #self.packetRecvStatus = True # by default it is true based on which the receiver generates ACK,
+ # but when collision it is false and receiver does not generate ACK
+ #self.type="keepAlive"
+ self.backLogPackets=0
+ def run(self):
+ last_arrival = 0.0
+
+ while True:
+ global print_control
+ msg = (yield self.store.get())
+ self.channel_set.append(msg.channel)
+ self.prob_rec_BS1.append(msg.prob_rec_BS1)
+ self.prob_rec_BS2.append(msg.prob_rec_BS2)
+ if not self.selector or self.selector(msg):
+ now = self.env.now
+ if self.rec_waits:
+ self.waits.append(self.env.now - msg.time)
+ if self.rec_arrivals:
+ if self.absolute_arrivals:
+ self.arrivals.append(now)
+ else:
+ self.arrivals.append(now - last_arrival)
+ last_arrival = now
+ self.packets_rec += 1
+ self.bytes_rec += msg.size
+ #####to display the output __repr__ of class Packet##################
+ if self.debug:
+ print_control=print_control+1
+ if(print_control%2==1):
+ if((msg.type=="Normal" or msg.type=="Alarm") and msg.src>2):
+ print msg
+
+ global STATUSA,STATUSB
+ global CollisionCount,unsuccessful_due_dist
+ #global BS1_ACK_send_STATUS #if already base station 1 has send the ACK Base station 2 should not send...this Flag is used
+ self.check_collision.append("False")
+ #global LoopBackPeriod
+ global SEQUENCE,ACK_ID,ACK_STATUS,TYPE,N,ACK_PACKET_ID
+ downLinkRate=600
+ AckPacketSize=14
+ #print "print index check : %s and SINK id:%s"%(self.packets_rec-1,self.id)
+ if(self.id == 1 or self.id==2):#if packet Sink is a base station we send here the ACKs based on collision free reception
+ #appending the packet end time to the pktendtime list
+ self.pktendtime.append(msg.size*8/msg.bitrate + self.arrivals[self.packets_rec-1])
+ #collision detection logic...
+ #if more than 1 packet received at Base station(for comparison) and channel used by prev and current packet is same
+ #and pkt end time of previous packet is larger than the arrival time of the current packet
+ #Then there is collision
+ #currently in my logic i am not sending ACK only for the current colliding packet and not for the previous colliding packet
+ #Because everytime there is no collision i am sending ACK packets
+ #Though i can evaluate the number of collision to be 2 times of the current collision count..
+ #but number of retransmission will be half..which is erroneous...i need a little algorithmic help here..
+ #if the previous and its previous packets overlaps with current packet
+ if (self.packets_rec>10):
+ for i in range(1,10):
+ if (self.channel_set[self.packets_rec-(i+1)]==self.channel_set[self.packets_rec-1]):
+ if((self.pktendtime[self.packets_rec-(i+1)]>self.arrivals[self.packets_rec-1]) and
+ ((self.prob_rec_BS1[self.packets_rec-(i+1)]>=pthres and self.prob_rec_BS1[self.packets_rec-1]>=pthres and self.id==1)or
+ (self.prob_rec_BS2[self.packets_rec-(i+1)]>=pthres and self.prob_rec_BS2[self.packets_rec-1]>=pthres and self.id==2))
+ ):
+ #print "Collision Detected at Base Station %s due to same channel %s and packet overlap with previous"%(self.id,self.channel_set[self.packets_rec-1])
+ #self.check_collision=[word.replace("False","True") for word in self.check_collision]
+ #print "SM ID:%s Packet Id:%s channel used: %s packets received: %s arrival time: %s packet end time :%s collision detected :%s "%(msg.src,msg.id,self.channel_set[self.packets_rec-1],self.packets_rec,self.arrivals[self.packets_rec-1],self.pktendtime[self.packets_rec-1],self.check_collision[self.packets_rec-1])
+ #print " No ACK transmitted due to collision"
+ if(self.id==1): #collision detected at BS1
+ STATUSA= True
+ elif(self.id==2): #collision detected at BS2
+ STATUSB= True
+
+
+ #concept of Co-operation between base station where only one Base station forwards packet to CUNB server and sends ACK back to the Smart meter
+
+ #i am using the ID of the packet generator to create a new packet sink to whom Base station will send the ACK
+ #now when we have two Base station only one of the Base station would be sending the ACK...
+ #that will be co-operatively decided based on the Probability calculation..
+ #two base station is considered
+ #co-operatively deciding who will be sending the ACK packets..there is no redundancy in ACK sending...only one BS sends ACK
+ #if there is no collision at BS1 and BS2 and prob_rec_BS1 > prob_rec_BS2 then BS1 sends the ACK
+ if (self.id==2):
+ if(STATUSA==False and STATUSB==False and msg.prob_rec_BS1 > msg.prob_rec_BS2 and msg.prob_rec_BS1>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is no collision at BS1 and BS2 and prob_rec_BS1 < prob_rec_BS2 then BS2 sends the ACK
+ elif (STATUSA==False and STATUSB==False and msg.prob_rec_BS1 < msg.prob_rec_BS2 and msg.prob_rec_BS2>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(2,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 2,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is collision at BS1 and prob_rec_BS2>pthres then BS2 sends the ACK
+ elif (STATUSA==True and STATUSB==False and msg.prob_rec_BS2>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(2,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 2,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is collision at BS2 and prob_rec_BS1>pthres then BS1 sends the ACK
+ elif(STATUSA==False and STATUSB==True and msg.prob_rec_BS1>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%sAT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+
+ elif(STATUSA==True and STATUSB==True):
+ #print " No ACK transmitted due to distance or collision"
+ if(msg.type=="Normal" or msg.type=="Alarm"):
+ CollisionCount+=1
+ print"collision count=%d"%CollisionCount
+ else:
+ if(msg.type=="Normal" or msg.type=="Alarm"):
+ unsuccessful_due_dist+=1
+ print"unsuccesful due to distance=%d"%unsuccessful_due_dist
+ STATUSA=False
+ STATUSB=False
+
+ #if packet sink is a Smart meter....we check the ACK reception status
+ else:
+
+ #print "ACK received at SM %s"%self.id
+ for i in range(0,N):
+ #print "inside for loop %d and compared index %d"%(self.id,i+3)
+ if(self.id==i+3):
+ #print "inside if loop"
+ ACK_STATUS[i]=True
+ ACK_ID[i]=self.id
+ #ACK_PACKET_ID=msg.id
+ SEQUENCE=msg.seq_no
+ TYPE[i]=msg.type
+ #ACK_TIME[i]=self.env.now
+ #print msg.type
+
+ def put(self, pkt):
+ self.store.put(pkt)
diff --git a/SimLibraryTwoBS_aug18_noretrans.py b/SimLibraryTwoBS_aug18_noretrans.py
new file mode 100644
index 0000000..b0d4838
--- /dev/null
+++ b/SimLibraryTwoBS_aug18_noretrans.py
@@ -0,0 +1,604 @@
+import simpy
+import random
+import numpy
+import math
+
+#########################################control variables used in the code########################################################################################################
+N=300 #the number of smart meters that are communicating to the Base stations
+CollisionCount=0
+unsuccessful_due_dist=0
+NoOfRetransmission=0
+keepAliveCount=0 #keepAlive Packet count
+NormalCount=0 #normal packet count
+AlarmCount=0 #alarm packet Count
+NoOfRetransmissionAlarm=0 #total number of Alarm packet that got retransmitted
+NoOfRetransmissionKeepAlive=0 # total number of keepAlive packet that got retransmitted
+NoOfRetransmissionNormal=0 #total number of Normal packet that got retranmsitted
+STATUSA =False #this global variable is used for collision detection at Base Station 1
+STATUSB =False #this global variable is used for collision detection at Base Station 2
+TotalTime=0 #this variable holds the sum of delay time of all the packets that are generated from smart meters, to caluclate the average delay
+#LoopBackPeriod = 5 #ACK response time
+pthres=0.9 #probability of threshold for the Base station to detect the packet....based on the signal receiving capacity of the Base station
+#BS1_ACK_send_STATUS=False #this variable is used to prevent deduplication of ACK. if Base station has succesfully transmitted an ACK den BS2 should not transmit
+ACK_STATUS=numpy.full(N,False,dtype=bool) #this array holds ACK status of each packet that is ACKed by the Base station
+ACK_ID=numpy.zeros(N) #this array will hold the IDs of the Smart mter whose packet got ACKed..it is used in run() of PacketSink and Timer() of PacketGenerator
+SEQUENCE=0 #this variable stores the sequence number of the packet ACKed, so as to verify that at the transmitter
+TYPE = ["" for x in range(N)] #this is an array that stores the type of packet ACKed by the Base station. Goto run() of PacketSink to see its usage
+#ACK_TIME=numpy.zeros(N,dtype=numpy.float)
+ACK_PACKET_ID=0 #this variable holds the ID of the smart meter whose packet got ACKed.
+PKT_ACKED_SUCCESFULLY=0
+k=1 #this variable is used to use same channel for broadcasting at a Smart meter...
+ #goto __init__() of class PacketGenerator to see its implementation
+x=1 #this variable is used to logically prevent duplicate maintenance of packets in the smart meter queue....
+ #goto run() of Class PacketGenerator to see its usage
+cache=0 #this variable is used to use same channel for broadcasting at a Smart meter...
+ #goto __init__() of class PacketGenerator to see its implementation
+print_control=0
+######################################## Packet Class ##############################################################################################################################
+class Packet(object):
+ """ A very simple class that represents a packet.
+ This packet will run through a queue at a switch output port.
+ We use a float to represent the size of the packet in bytes so that
+ we can compare to ideal M/M/1 queues.
+
+ Parameters
+ ----------
+ time : float
+ the time the packet arrives at the output queue.
+ size : float
+ the size of the packet in bytes
+ id : int
+ an identifier for the packet
+ seq_no: int
+ it is the sequence number of the packet used for retransmission
+ src, dst : int
+ identifiers for source and destination
+ flow_id : int
+ small integer that can be used to identify a flow
+ channel : int
+ channel id used by the nodes to transmit that particular packet
+ bitrate : int
+ for uplink we take as 250 bits/sec and downlink we take 600 bits/sec
+ prob_rec_BS1,prob_rec_BS2 : float
+ it is the probabibilty of successful reception at two Base stations respectively
+ type : string
+ defines the type of packet...In our case we are considering the Normal, keepAlive, Alarm and ACK packets
+ retransmitted : boolean
+ defines whether the packet is a retransmitted or a non retransmitted packet
+ retrans_no :int
+ number of times the packet is retransmitted
+ """
+ def __init__(self, time, size, id,seq_no,src="a", dst="z", flow_id=0, channel=10,bitrate=0,prob_rec_BS1=1,prob_rec_BS2=1,type="ACK",retransmitted=False,retrans_no=0):
+ self.time = time
+ self.size = size
+ self.id = id
+ self.src = src
+ self.dst = dst
+ self.flow_id = flow_id
+ #self.channel=channel
+ global k,cache
+ if(self.src==1 or self.src==2):
+ self.channel=channel
+ elif(self.src >2 and (self.size ==283.0 or self.size ==772.0)): #if commercial packet
+ self.channel=1
+ elif(self.src >2 and k%2 ==1 and (self.size !=283.0 or self.size !=772.0)): #if household packet
+ k+=1
+ cache=random.randint(2,channel)
+ self.channel=cache
+ elif(self.src>2 and k%2 ==0and (self.size !=283.0 or self.size !=772.0)):
+ k+=1
+ self.channel=cache
+
+ self.bitrate=bitrate
+ self.prob_rec_BS1=prob_rec_BS1
+ self.prob_rec_BS2=prob_rec_BS2
+ self.type=type
+ self.retransmitted=retransmitted
+ self.seq_no=seq_no
+ if(self.retransmitted == True):
+ self.retrans_no=retrans_no
+ else:
+ self.retrans_no=0
+ self.ACKed=False
+ def __repr__(self):
+ if(self.src>2 ):
+ #print"*****************************************************************************************"
+ return "UPLINK {} Packet : id: {}, src: {},seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}, Prob_R at BS1:{}, Prob_R at BS2:{}, retransmitted:{} ".\
+ format(self.type,self.id, self.src,self.seq_no, self.time, self.size,self.channel,self.bitrate,self.prob_rec_BS1,self.prob_rec_BS2,self.retransmitted)
+
+ else:
+ #print"*****************************************************************************************"
+ return "DOWNLINK Packet : id: {}, src: {}, seq_no={}, time: {}, size: {} ,channel:{}, bitrate:{}".\
+ format(self.id, self.src,self.seq_no ,self.time, self.size,self.channel,self.bitrate)
+
+ #this function increments the retransmission for a packet
+ def noOfRetransmission(self):
+ self.retrans_no=self.retrans_no+1
+ return self.retrans_no
+
+######################################## PacketGenerator Class ##############################################################################################################################
+class PacketGenerator(object):
+ """ Generates packets with given inter-arrival time distribution.
+ Set the "out" member variable to the entity to receive the packet.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ adist : function
+ a no parameter function that returns the successive inter-arrival times of the packets
+ sdist : function
+ a no parameter function that returns the successive sizes of the packets
+
+ initial_delay : number
+ Starts generation after an initial delay. Default = 0
+ finish : number
+ Stops generation at the finish time. Default is infinite
+ pktType:either keepAlive,Alarm or Normal or ACK
+
+ """
+ def __init__(self, env, id, adist, sdist, channel, bitrate,prob_rec_BS1,prob_rec_BS2,seq_no,type="ACK",retransmitted=False,initial_delay=0, finish=float("inf"), flow_id=0,packetRecv=False):
+ self.id = id
+ self.env = env
+ self.adist = adist
+ self.sdist = sdist
+ self.initial_delay = initial_delay
+ self.finish = finish
+ self.out = None
+ self.type=type
+ self.retransmitted=retransmitted
+ self.packets_sent = 0
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.action = env.process(self.Timer()) #this is another timer () method that runs concurrently with the run() method...it is used to probe the received ACK at the Smart meters
+ self.flow_id = flow_id
+ self.ContentionWindow=4
+ self.channel=channel
+ #when the id =1, i.e. Base station ID then the same channel with which the packet was received by the Base station
+ #would be used for ACK transmission
+ #In the else part for Smartmeters it is random channel selection
+ #self.packetRecv=packetRecv
+ self.prob_rec_BS1=prob_rec_BS1
+ self.prob_rec_BS2=prob_rec_BS2
+ self.bitrate=bitrate
+
+ if(self.id==1 or self.id==2):
+ self.seq_no=seq_no #the sequence number used by the Base station here are the ACK number thats why they should be same as the seq number of the packet received at Base station
+ else:
+ self.seq_no=0 # A smart meter must initiates his packet generation with a sequence number of zero
+
+ self.Queue=[] #for storing the packets transmitted...so if they are not ACKed in the retransmission timeout period, they can be transmitted again by fetching from queue
+ self.Queue_Size=100#maximum size of a queue for a device would be 10
+
+ def run(self):
+ """The generator function used in simulations.
+ """
+ global x,keepAliveCount,NormalCount,AlarmCount
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish: #till infinite
+ self.packets_sent += 1
+ # wait for next transmission...yielding based on the type of packet generated as the ACK is conditioned we provide a constant rather than function based
+ if (self.id==1 or self.id==2 ): #sending the ACKs once for BS1 and BS2...that is why for packet_sent == 1 they just yield once... for packet_sent > 1, yield timeout is infinite.. that means they do not yield
+ if(self.packets_sent==1):
+ yield self.env.timeout(self.adist) #yielding for packet generated as ACK
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,prob_rec_BS2=self.prob_rec_BS2,type=self.type)
+ self.out.put(p)
+ else:#to make the Base station transmit one ACK for one reception of Data
+ yield self.env.timeout(float("inf")) #this is to prevent the continous transmission to ACK packets..when packets_sent=2,arrival time made infinite
+ else:#this is the normal,keepalive and alarm packet generation at Smart meters
+ yield self.env.timeout(self.adist()) #yielding for other packet
+ #here we need to implement the retransmission portion
+ self.seq_no+=1
+ if(self.seq_no>=4095):#wraps around at 4095 as 12 bits allocated to sequence counter
+ self.seq_no=0
+ #first packet arrival....so send the packet and enqueue it
+ #we should not yield twice....or the net yield gets added up....
+ #transmit original packet
+ p = Packet(self.env.now, self.sdist, self.packets_sent, src=self.id,seq_no=self.seq_no, flow_id=self.flow_id,channel=self.channel,bitrate=self.bitrate,prob_rec_BS1=self.prob_rec_BS1,prob_rec_BS2=self.prob_rec_BS2,type=self.type)
+ self.out.put(p)
+ if(self.type=="keepAlive"):
+ keepAliveCount+=1
+ #print "keepalive:%d"%keepAliveCount
+ elif(self.type=="Normal"):
+ NormalCount+=1
+ #print "Normal:%d"%NormalCount
+ if x%2==1:
+ x+=1
+ self.enQueue(p)
+ print "Normal:%d"%NormalCount
+ else:
+ x+=1
+ elif(self.type=="Alarm"):
+ AlarmCount+=1
+ #print "Alarm:%d"%AlarmCount
+ if x%2==1:
+ x+=1
+ self.enQueue(p)
+ print "Alarm:%d"%AlarmCount
+ else:
+ x+=1
+
+ def Timer(self):
+ global ACK_ID,ACK_STATUS,SEQUENCE,TYPE,N,ACK_PACKET_ID,PKT_ACKED_SUCCESFULLY,NoOfRetransmissionAlarm,NoOfRetransmissionKeepAlive,NoOfRetransmissionNormal,TotalTime
+ count_keepAlive=0
+ count_keepAlive1=0
+ count_Normal=0
+ count_Alarm=0
+ count_Normal1=0
+ count_Alarm1=0
+ yield self.env.timeout(self.initial_delay)
+ while self.env.now < self.finish:
+ yield self.env.timeout(0.2)
+ #print "in timer function"
+ #for i in range(0,100):
+ #if within 2 RTT ACK is received than dequeue the packet from the queue
+ #these if condition should be checked for individual packets....rather than an individual smart meter
+ #print "t=%d length of Queue at SM %d is %d"%(self.env.now,self.id,len(self.Queue))
+ #print"\n"
+ #print "ID of Base station or Smart meter %d"%self.id
+ for i in range(len(self.Queue)):
+ #print "SM id %d and its queue length %d and i value %d"%(self.id,len(self.Queue),i)
+ #print "the queue %s"%(self.Queue)
+ f=len(self.Queue)-1-i
+ #if current time - sent pkt time < 2 RTT i.e. packet gets acked before the retranmsission timeout i.e. before 2 RTT
+ if(self.env.now-self.getDeparture(self.Queue[f].seq_no)<=2*((self.Queue[f].size*8/250)+(14*8/600)+5) and self.id>2):
+ #print "current time%d wait time %d for %d wd seq no %d and 2*RTT %d"%(self.env.now,self.env.now-self.getDeparture(self.Queue[i].seq_no),self.id,self.Queue[i].seq_no,2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #self.display()
+ for j in range(0,N):
+ #print "ACK_STATUS%s and ACK_ID %d and Type %s and current type %s"%(ACK_STATUS[i],ACK_ID[i],TYPE[i],self.type)
+ if(ACK_STATUS[j]==True and ACK_ID[j]==self.id and TYPE[j]==self.Queue[f].type and self.Queue[f].seq_no==SEQUENCE-1 ):
+ #print"Ack status : %r and ID: %d and departure time: %d and wait time %d 2*RTT:%d"%(ACK_STATUS[i],ACK_ID[i],self.getDeparture(SEQUENCE-1),self.env.now - self.getDeparture(SEQUENCE-1),2*((self.sdist*8/250)+(14*8/600)))
+ #print "At time t= %d"%self.env.now
+ #print "if a packet is ACKed and id is %d and we deque seq no %d"%(self.id,SEQUENCE-1)
+ #self.display()
+ self.Queue[f].ACKed=True
+ #print "if the packet %d sent at %f is acked %r current time %0.4f delay %0.4f"%(f,self.Queue[f].time,self.Queue[f].ACKed,self.env.now,self.env.now-self.Queue[f].time)
+ temp=self.env.now-self.Queue[f].time
+ TotalTime=TotalTime+temp
+ self.deQueue(SEQUENCE-1)
+ PKT_ACKED_SUCCESFULLY+=1
+ ACK_STATUS[j]=False
+ ACK_ID[j]=0
+ count_keepAlive=0
+ count_keepAlive1=0
+ count_Normal=0
+ count_Normal1=0
+ count_Alarm=0
+ count_Alarm1=0
+ print"Total time : %f"%TotalTime
+ print"PKT_ACKED_SUCCESFULLY=%d"%PKT_ACKED_SUCCESFULLY
+
+ #if waiting for ACK time becomes greater than > 2RTT....RTT = size of transmitted packet * 8 /250(SM to BS) + mean loopback period i.e. 5 sec + 14 * 8/600 (BS to SM)
+ elif ((self.env.now-self.getDeparture(self.Queue[f].seq_no))>=2*((self.Queue[f].size*8/250)+(14*8/600)+5)and self.id>2 ):
+ #print "At time t= %d"%self.env.now
+ #print"either ACK received late or not received%0.4f %0.4f"%(self.env.now-self.getDeparture(self.Queue[i].seq_no),2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #print "size and rtt are %0.4f and %0.4f"%(self.Queue[i].size,2.5*((self.Queue[i].size*8/250)+(14*8/600)))
+ #print "if the packet %d is acked %r current time %d"%(i,self.Queue[i].ACKed,self.env.now)
+
+ ######################## Re Transmission for KEEPALIVE PACKET ####################################################################################################
+ #count_keepAlive < 1 means we are taking a maximum of 1 retransmission for keep alive packet
+ #print "Abhijeet!!*******entering the RETRANSMISSION block********"
+ #print "ACK status of SM %d of type %s is %r and f=%d"%(self.id,self.Queue[f].type,self.Queue[f].ACKed,f)
+ #print "Control Variables count_Normal=%d count_Alarm=%d "%(count_Normal,count_Alarm)
+ #self.display()
+ if(self.Queue[f].type=="keepAlive" and count_keepAlive<0 and count_keepAlive1<0 and self.Queue[f].ACKed==False ):
+ BackOff=random.randint(0,self.ContentionWindow)
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size,count_keepAlive+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_keepAlive)
+ count_keepAlive=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_keepAlive1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_keepAlive1)
+ count_keepAlive1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionKeepAlive+=1
+ #print "No of Retransmission Keep Alive %d"%NoOfRetransmissionKeepAlive
+
+ ######################## Re Transmission for NORMAL AMI packets ####################################################################################################
+ #count_Normal < 2 means we are taking a maximum of 2 retransmission for normal packet
+ elif(self.Queue[f].type=="Normal" and count_Normal<0 and count_Normal1<0 and self.Queue[f].ACKed==False):
+ #simple random backoff
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ #binary exponential backoff..waits random(0,pow(2,n)) multiplied by packet duration...
+ #where pow(2,n) is the contention window and n is the retransmission count
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Normal+1))*self.Queue[f].size*8/250
+
+ #ideal backoff for random access pure ALOHA is 4N times a packet transmission time, where N = is the no. of active nodes..taking N=1
+ #BackOff=4*self.Queue[f].size*8/250
+ temp2=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp2
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Normal+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Normal)
+ count_Normal=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Normal1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Normal1)
+ count_Normal1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionNormal+=1
+ print "No of Retransmission Normal%d"%NoOfRetransmissionNormal
+
+ ######################## Re Transmission for ALARM packets ####################################################################################################
+ #count_Alarm < 3 means we are taking a maximum of 3 retransmission for normal packet
+ elif(self.type=="Alarm" and count_Alarm<0 and count_Alarm1<0 and self.Queue[f].ACKed==False):
+ #simple random backoff
+ #BackOff=random.randint(0,self.ContentionWindow)*self.Queue[f].size*8/250
+ #binary exponential backoff..waits random(0,pow(2,n)) multiplied by packet duration...
+ #where pow(2,n) is the contention window and n is the retransmission count
+ BackOff=random.randint(0,math.pow(self.ContentionWindow,count_Alarm+1))*self.Queue[f].size*8/250
+ #ideal backoff for random access pure ALOHA is 4N times a packet transmission time, where N = is the no. of active nodes..taking N=1
+ #BackOff=4*self.Queue[f].size*8/250
+ temp3=self.env.now+BackOff-self.getDeparture(self.Queue[f].seq_no)
+ TotalTime=TotalTime+temp3
+ Retp1 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Alarm+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Alarm)
+ count_Alarm=Retp1.noOfRetransmission()
+ Retp2 = Packet(self.env.now+BackOff, self.Queue[f].size, count_Alarm1+1, src=self.id,seq_no=self.Queue[f].seq_no, flow_id=self.Queue[f].flow_id,channel=self.channel,bitrate=self.Queue[f].bitrate,prob_rec_BS1=self.Queue[f].prob_rec_BS1,prob_rec_BS2=self.Queue[f].prob_rec_BS2,type=self.Queue[f].type,retransmitted=True,retrans_no=count_Alarm1)
+ count_Alarm1=Retp2.noOfRetransmission()
+ self.deQueue(self.Queue[f].seq_no)
+ self.enQueue(Retp1)
+ BS1_sink=PacketSink(self.env,1, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS1_sink.put(Retp1)
+ BS2_sink=PacketSink(self.env,2, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ BS2_sink.put(Retp2)
+ NoOfRetransmissionAlarm+=1
+ print "No of Retransmission Alarm %d"%NoOfRetransmissionAlarm
+
+ #if ACK not received ... deque the packet from the queue and reset the control variables
+ else:
+ self.deQueue(self.Queue[f].seq_no)
+ count_keepAlive=0
+ count_Normal=0
+ count_Alarm=0
+ count_keepAlive1=0
+ count_Normal1=0
+ count_Alarm1=0
+
+ #display the content of the Queue, used for debugging
+ def display(self):
+ #print "queue at time %d : %s"%(self.env.now,self.Queue)
+ print "queue at time %d in SM %d : %s"%(self.env.now,self.id,self.Queue)
+
+ #the function to fill the queue whenever a new packet is transmitted...or if an old packet is retranmsitted
+ def enQueue(self,pkt):
+ #print "in enQueue "
+ self.Queue.append(pkt)
+ #print"Queue %s at time %d"%(self.Queue,self.env.now)
+ while(len(self.Queue)>self.Queue_Size):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ self.deQueue(self.Queue[x].seq_no)
+
+ #this function returns the oldest packet in the queue
+ def giveOldestPacket(self):
+ min_time=self.env.now
+ for i in len(self.Queue):
+ if(self.Queue[i].time<min_time):
+ min_time=self.Queue[i].time
+ x=i
+ return self.Queue[x]
+
+ #this function is used to remove the packet from the queue when a packet gets an ACK response or if does not get any ACK after retransmission too
+ def deQueue(self,sq):
+ #print "in deQueue for %d whose length is %d and at time: %d"%(self.id,len(self.Queue),self.env.now)
+ #print "Dequeue from queue %s element with seq no %d"%(self.Queue,sq)
+ x=self.getIndex(self.Queue,sq)
+ #print "%s"%x
+ self.Queue.pop(x)
+ #print "After deQueue %s"%self.Queue
+
+ #this function return the index of the packet there in the queue
+ def getIndex(self,q,sq):
+ #print "queue length: %d and we search fr seq no: %d" % ((len(q)),sq)
+ for i in range(len(q)):
+ #print "queue seq no: %d"%(q[i].seq_no)
+ if (q[i].seq_no==sq):
+ return i
+ return 0
+
+ #get the packet from the queue... this is currently not used but can be used later as per the logic developed in the code
+ def getQueue(self,sq):
+ #print "in getQueue "
+ #min_departure_time = time
+ for i in range(len(self.Queue)):
+ if(self.Queue[i].seq_no<=sq):
+ return self.Queue[i]
+
+ #returns the time at which the packet is sent by the Smart meter
+ def getDeparture(self,sq):
+ for i in range(len(self.Queue)):
+
+ if(self.Queue[i].seq_no==sq):
+ #print "found seq no"
+ return self.Queue[i].time
+
+ return self.env.now
+
+######################################## PacketSink Class ##############################################################################################################################
+
+class PacketSink(object):
+ """ Receives packets and collects delay information into the
+ waits list. You can then use this list to look at delay statistics.
+
+ Parameters
+ ----------
+ env : simpy.Environment
+ the simulation environment
+ debug : boolean
+ if true then the contents of each packet will be printed as it is received.
+ rec_arrivals : boolean
+ if true then arrivals will be recorded
+ absolute_arrivals : boolean
+ if true absolute arrival times will be recorded, otherwise the time between consecutive arrivals
+ is recorded.
+ rec_waits : boolean
+ if true waiting time experienced by each packet is recorded
+ selector: a function that takes a packet and returns a boolean
+ used for selective statistics. Default none.
+ check_collision: for checking collision
+
+
+ """
+ def __init__(self, env,id, rec_arrivals=False, absolute_arrivals=False, rec_waits=True, debug=False, selector=None):
+ self.id=id
+ self.store = simpy.Store(env)
+ self.env = env
+ self.rec_waits = rec_waits
+ self.rec_arrivals = rec_arrivals
+ self.absolute_arrivals = absolute_arrivals
+ self.check_collision = []
+ self.waits = []
+ self.arrivals = []
+ self.BS_List = []
+ self.channel_set = []
+ self.pktendtime=[]
+ self.prob_rec_BS1=[]
+ self.prob_rec_BS2=[]
+ self.debug = debug
+ self.action = env.process(self.run()) # starts the run() method as a SimPy process
+ self.packets_rec = 0
+ self.bytes_rec = 0
+ self.selector = selector
+
+ #self.packetRecvStatus = True # by default it is true based on which the receiver generates ACK,
+ # but when collision it is false and receiver does not generate ACK
+ #self.type="keepAlive"
+ self.backLogPackets=0
+ def run(self):
+ last_arrival = 0.0
+
+ while True:
+ global print_control
+ msg = (yield self.store.get())
+ self.channel_set.append(msg.channel)
+ self.prob_rec_BS1.append(msg.prob_rec_BS1)
+ self.prob_rec_BS2.append(msg.prob_rec_BS2)
+ if not self.selector or self.selector(msg):
+ now = self.env.now
+ if self.rec_waits:
+ self.waits.append(self.env.now - msg.time)
+ if self.rec_arrivals:
+ if self.absolute_arrivals:
+ self.arrivals.append(now)
+ else:
+ self.arrivals.append(now - last_arrival)
+ last_arrival = now
+ self.packets_rec += 1
+ self.bytes_rec += msg.size
+ #####to display the output __repr__ of class Packet##################
+ if self.debug:
+ print_control=print_control+1
+ if(print_control%2==1):
+ if((msg.type=="Normal" or msg.type=="Alarm") and msg.src>2):
+ print msg
+
+ global STATUSA,STATUSB
+ global CollisionCount,unsuccessful_due_dist
+ #global BS1_ACK_send_STATUS #if already base station 1 has send the ACK Base station 2 should not send...this Flag is used
+ self.check_collision.append("False")
+ #global LoopBackPeriod
+ global SEQUENCE,ACK_ID,ACK_STATUS,TYPE,N,ACK_PACKET_ID
+ downLinkRate=600
+ AckPacketSize=14
+ #print "print index check : %s and SINK id:%s"%(self.packets_rec-1,self.id)
+ if(self.id == 1 or self.id==2):#if packet Sink is a base station we send here the ACKs based on collision free reception
+ #appending the packet end time to the pktendtime list
+ self.pktendtime.append(msg.size*8/msg.bitrate + self.arrivals[self.packets_rec-1])
+ #collision detection logic...
+ #if more than 1 packet received at Base station(for comparison) and channel used by prev and current packet is same
+ #and pkt end time of previous packet is larger than the arrival time of the current packet
+ #Then there is collision
+ #currently in my logic i am not sending ACK only for the current colliding packet and not for the previous colliding packet
+ #Because everytime there is no collision i am sending ACK packets
+ #Though i can evaluate the number of collision to be 2 times of the current collision count..
+ #but number of retransmission will be half..which is erroneous...i need a little algorithmic help here..
+ #if the previous and its previous packets overlaps with current packet
+ if (self.packets_rec>10):
+ for i in range(1,10):
+ if (self.channel_set[self.packets_rec-(i+1)]==self.channel_set[self.packets_rec-1]):
+ if((self.pktendtime[self.packets_rec-(i+1)]>self.arrivals[self.packets_rec-1]) and
+ ((self.prob_rec_BS1[self.packets_rec-(i+1)]>=pthres and self.prob_rec_BS1[self.packets_rec-1]>=pthres and self.id==1)or
+ (self.prob_rec_BS2[self.packets_rec-(i+1)]>=pthres and self.prob_rec_BS2[self.packets_rec-1]>=pthres and self.id==2))
+ ):
+ #print "Collision Detected at Base Station %s due to same channel %s and packet overlap with previous"%(self.id,self.channel_set[self.packets_rec-1])
+ #self.check_collision=[word.replace("False","True") for word in self.check_collision]
+ #print "SM ID:%s Packet Id:%s channel used: %s packets received: %s arrival time: %s packet end time :%s collision detected :%s "%(msg.src,msg.id,self.channel_set[self.packets_rec-1],self.packets_rec,self.arrivals[self.packets_rec-1],self.pktendtime[self.packets_rec-1],self.check_collision[self.packets_rec-1])
+ #print " No ACK transmitted due to collision"
+ if(self.id==1): #collision detected at BS1
+ STATUSA= True
+ elif(self.id==2): #collision detected at BS2
+ STATUSB= True
+
+
+ #concept of Co-operation between base station where only one Base station forwards packet to CUNB server and sends ACK back to the Smart meter
+
+ #i am using the ID of the packet generator to create a new packet sink to whom Base station will send the ACK
+ #now when we have two Base station only one of the Base station would be sending the ACK...
+ #that will be co-operatively decided based on the Probability calculation..
+ #two base station is considered
+ #co-operatively deciding who will be sending the ACK packets..there is no redundancy in ACK sending...only one BS sends ACK
+ #if there is no collision at BS1 and BS2 and prob_rec_BS1 > prob_rec_BS2 then BS1 sends the ACK
+ if (self.id==2):
+ if(STATUSA==False and STATUSB==False and msg.prob_rec_BS1 > msg.prob_rec_BS2 and msg.prob_rec_BS1>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is no collision at BS1 and BS2 and prob_rec_BS1 < prob_rec_BS2 then BS2 sends the ACK
+ elif (STATUSA==False and STATUSB==False and msg.prob_rec_BS1 < msg.prob_rec_BS2 and msg.prob_rec_BS2>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(2,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 2,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is collision at BS1 and prob_rec_BS2>pthres then BS2 sends the ACK
+ elif (STATUSA==True and STATUSB==False and msg.prob_rec_BS2>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%s AT TIME: %0.4f"%(2,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 2,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+ #if there is collision at BS2 and prob_rec_BS1>pthres then BS1 sends the ACK
+ elif(STATUSA==False and STATUSB==True and msg.prob_rec_BS1>pthres):
+ sendingACKtime=now+random.randint(4,6)+(msg.size*8/msg.bitrate)
+ #print "BS ID:%s sending ACK to SM ID:%sAT TIME: %0.4f"%(1,msg.src,sendingACKtime)
+ SinkObject=PacketSink(self.env,msg.src, rec_arrivals=True, absolute_arrivals=True, rec_waits=True,debug=True)
+ ACK=PacketGenerator(self.env, 1,sendingACKtime-now,AckPacketSize, msg.channel ,downLinkRate,1,1,msg.seq_no+1,msg.type)
+ ACK.out=SinkObject
+
+ elif(STATUSA==True and STATUSB==True):
+ #print " No ACK transmitted due to distance or collision"
+ if(msg.type=="Normal" or msg.type=="Alarm"):
+ CollisionCount+=1
+ print"collision count=%d"%CollisionCount
+ else:
+ if(msg.type=="Normal" or msg.type=="Alarm"):
+ unsuccessful_due_dist+=1
+ print"unsuccesful due to distance=%d"%unsuccessful_due_dist
+ STATUSA=False
+ STATUSB=False
+
+ #if packet sink is a Smart meter....we check the ACK reception status
+ else:
+
+ #print "ACK received at SM %s"%self.id
+ for i in range(0,N):
+ #print "inside for loop %d and compared index %d"%(self.id,i+3)
+ if(self.id==i+3):
+ #print "inside if loop"
+ ACK_STATUS[i]=True
+ ACK_ID[i]=self.id
+ #ACK_PACKET_ID=msg.id
+ SEQUENCE=msg.seq_no
+ TYPE[i]=msg.type
+ #ACK_TIME[i]=self.env.now
+ #print msg.type
+
+ def put(self, pkt):
+ self.store.put(pkt)