-
Notifications
You must be signed in to change notification settings - Fork 0
/
ISM-A_band_Power_Allocation_Game_simulation_program.py
174 lines (139 loc) · 5.47 KB
/
ISM-A_band_Power_Allocation_Game_simulation_program.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
from numpy import *
import pylab as P
# Simple structures for transmitter and receiver
# The only visible difference is - transmitter is characterized using
# additional parameter p - transmit power
class Transmitter:
def __init__(self, x, y, p):
self.x = x
self.y = y
self.p = p
class Receiver:
def __init__(self, x, y):
self.x = x
self.y = y
# Randomly place transmitter in a 100x100 square.
# Receiver are places around transmitters in 40x40 square
def allocateTransmitterAndReceiver():
transPosX = random.rand()*100
transPosY = random.rand()*100
transPower = 0.1
recPosX = transPosX + random.rand()*40
recPosY = transPosY + random.rand()*40
return (Transmitter(transPosX, transPosY, transPower), Receiver(recPosX, recPosY))
# Allocate a system of n transmitters and receivers
def allocateSystem(n):
transmitters = []
receivers = []
for i in range(n):
tra, rec = allocateTransmitterAndReceiver()
transmitters.append(tra)
receivers.append(rec)
return transmitters, receivers
def distance(node1, node2):
return sqrt((node1.x-node2.x)**2 + (node1.y-node2.y)**2)
####################################################################################################
#manhattan distance path loss
####
# path loss calculation acording to ITU model for indoor propagation
# ITU-R P.1238-7
def pathLoss(d):
dd = d
if d < 1:
dd = 1
L = 20*log10(2400)+30*log10(dd) + 14 - 28
return 1.0/(10.0**(L/10.0))
# function calculates SINR for user number k
# transList - list of transmitters in a system
# recList - list of receivers in a system
# sigmaSquared - white noise power at receivers
def sinr(k, transList, recList, sigmaSquared):
interf = 0.0
for j in range(len(transList)):
if j != k:
hjk = pathLoss(distance(transList[j], recList[k])) # kanalo perdavimo koeficientas is j-ojo k-tajam
interf = interf + hjk*transList[j].p
hkk = pathLoss(distance(transList[k], recList[k]))
return hkk*transList[k].p/(interf + sigmaSquared)
# calculate averge system capacity (capacity per user)
def systemCapacity(transList, recList, sigmaSquared):
c = 0
for i in range(len(transList)):
c = c + log2(1+sinr(i, transList, recList, sigmaSquared))
return c/(len(transList))
###################################################################################################
# This is somewhat simplified function for power changing for every user
# There is no any threashold of sensitivity, so it is assumed
# that every user changes its power sequentially
# as every change of power by any user results in changed SINR for any other user
# So users update there powers sequantially
# This is the most inportant function in all this simulation and
# it probably could be rewritten for other simulation scenarios
# At every step new powel configuration (new transmitters) are returned
# Names of parameters are self explaining
def nextPowerConfigurationSequential(transList, recList, sigmaSquared, pMax, c):
#pirma nukopijuokime sena transList i nauja
newTransList = list(range(len(transList)))
for i in range(len(transList)):
newTransList[i] = transList[i]
for i in range(len(newTransList)):
newP = 1.0/c - 1.0/sinr(i, newTransList, recList, sigmaSquared)*newTransList[i].p
if newP <= 0:
newP = 1e-10 #This is somewhat a hack. I dont want power of any transmitter to be exacly zero
if newP > pMax:
newP = pMax
newTransList[i] = Transmitter(transList[i].x, transList[i].y, newP)
return newTransList
def averageSystemCapacity(pMax, c, numUsers):
sigmaSq = 1e-12
cap = 0.0
numSimulation = 1000
for i in range(numSimulation):
tra, rec = allocateSystem(numUsers)
for iter in range(10):
tra = nextPowerConfigurationSequential(tra, rec, sigmaSq, pMax, c)
cap = cap + systemCapacity(tra, rec, sigmaSq)
return cap/numSimulation
# Plot graphs of power allocation for every user
# This function is esefull to assure yourself that system is really converging :)
def testSystemConvergence(pMax, c, numUsers):
sigmaSq = 1e-12
iterToConvergence = 20
powerData = zeros((numUsers, iterToConvergence+1))
tra, rec = allocateSystem(numUsers)
for i in range(numUsers):
powerData[i][0] = tra[i].p
print(systemCapacity(tra, rec, sigmaSq))
for iterr in range(iterToConvergence):
tra = nextPowerConfigurationSequential(tra, rec, sigmaSq, pMax, c)
for i in range(numUsers):
powerData[i][iterr+1] = tra[i].p
print(systemCapacity(tra, rec, sigmaSq))
P.figure()
for i in range(numUsers):
P.plot(powerData[i, :])
P.show()
# change number of users and observe the change of full or average system capacity
def systemCapacityVsNumberOfUsers(c):
users = arange(2, 21, 1)
cap1 = []
cap2 = []
cap3 = []
cap4 = []
for u in users:
cap1.append(averageSystemCapacity(0.1, c, u)*u) #multiplication by u should be removes if we are interested in
cap2.append(averageSystemCapacity(1.0, c, u)*u) #averaged capacity for one user
cap3.append(averageSystemCapacity(2.0, c, u)*u)
cap4.append(averageSystemCapacity(4.0, c, u)*u)
print(u)
P.figure()
P.plot(users, cap1, "k*-", label = "Pmax = 0.1 W")
P.plot(users, cap2, "ko-", label = "Pmax = 1 W")
P.plot(users, cap3, "k+-", label = "Pmax = 2 W")
P.plot(users, cap4, "k.-", label = "Pmax = 4 W")
P.legend(loc='upper left')
P.xlabel("Number of users")
P.ylabel("Full system capacity, bits/s/Hz")
P.show()
testSystemConvergence(2, 0.5, 10)
systemCapacityVsNumberOfUsers(0.25)