Skip to content

Commit

Permalink
Update node.py
Browse files Browse the repository at this point in the history
  • Loading branch information
tuyen.ta committed Apr 25, 2019
1 parent b929261 commit 3256d73
Showing 1 changed file with 137 additions and 127 deletions.
264 changes: 137 additions & 127 deletions lora/node.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
from __future__ import division
import numpy as np
from .loratools import getDistanceFromPower
from .packet import myPacket
from os.path import join

class myNode():
""" LPWAN Simulator: node
Base station class
|category /LoRa
|keywords lora
\param [IN] nodeid: id of the node
\param [IN] position: position of the node in format [x y]
\param [IN] transmitParams: physical layer's parameters
\param [IN] bsList: list of BS
\param [IN] interferenceThreshold: interference threshold
\param [IN] logDistParams: log shadowing channel parameters
\param [IN] sensi: sensitivity matrix
\param [IN] nSF: number of spreading factors
"""
Base station class
|category /LoRa
|keywords lora
\param [IN] nodeid: id of the node
\param [IN] position: position of the node in format [x y]
\param [IN] transmitParams: physical layer's parameters
\param [IN] bsList: list of BS
\param [IN] interferenceThreshold: interference threshold
\param [IN] logDistParams: log shadowing channel parameters
\param [IN] sensi: sensitivity matrix
\param [IN] nSF: number of spreading factors
"""
def __init__(self, nodeid, position, transmitParams, initial, sfSet, freqSet, powSet, bsList,
interferenceThreshold, logDistParams, sensi, node_mode, info_mode, horTime, simu_dir, fname):
interferenceThreshold, logDistParams, sensi, node_mode, info_mode, horTime, algo, simu_dir, fname):
self.nodeid = nodeid # id
self.x, self.y = position # location
if node_mode == 0:
Expand All @@ -38,34 +38,35 @@ def __init__(self, nodeid, position, transmitParams, initial, sfSet, freqSet, po

# generate proximateBS
self.proximateBS = self.generateProximateBS(bsList, interferenceThreshold, logDistParams)

# set of actions
self.freqSet = freqSet
self.powerSet = powSet

if self.info_mode == "NO":
self.sfSet = sfSet
else:
self.sfSet = self.generateHoppingSfFromDistance(sfSet, logDistParams)

self.setActions = [(self.sfSet[i], self.freqSet[j], self.powerSet[k]) for i in range(len(self.sfSet)) for j in range(len(self.freqSet)) for k in range(len(self.powerSet))]
self.nrActions = len(self.setActions)
self.initial = initial

# for reinforcement learning
if self.info_mode == "NO":
self.sfSet = sfSet
else:
self.sfSet = self.generateHoppingSfFromDistance(sfSet, logDistParams)

self.setActions = [(self.sfSet[i], self.freqSet[j], self.powerSet[k]) for i in range(len(self.sfSet)) for j in range(len(self.freqSet)) for k in range(len(self.powerSet))]
self.nrActions = len(self.setActions)
self.initial = initial

# learning algorithm
if algo == 'exp3':
self.learning_rate = np.minimum(1, np.sqrt((self.nrActions*np.log(self.nrActions))/((horTime)*(np.exp(1.0)-1))))
self.alpha = None
elif algo == 'exp3s':
self.learning_rate = np.minimum(1, np.sqrt((self.nrActions*np.log(self.nrActions*horTime))/horTime))
self.alpha = 1/horTime
# weight and prob for learning
self.weight = {x: 1 for x in range(0, self.nrActions)}
if self.initial=="RANDOM":
prob = np.random.rand(self.nrActions)
prob = prob/sum(prob)
prob = prob/sum(prob)
else:
prob = (1/self.nrActions) * np.ones(self.nrActions)
#else:
# probDict = np.load(join(simu_dir, str('prob_'+ fname)))
# prob = probDict[int(nodeid)]
self.prob = {x: prob[x] for x in range(0, self.nrActions)} # probability

# learning rate
self.learning_rate = np.minimum(1, np.sqrt((self.nrActions*np.log(self.nrActions))/((horTime)*(np.exp(1.0)-1))))
prob = (1/self.nrActions) * np.ones(self.nrActions)
self.prob = {x: prob[x] for x in range(0, self.nrActions)}

# generate packet and ack
self.packets = self.generatePacketsToBS(transmitParams, logDistParams)
Expand All @@ -76,141 +77,150 @@ def __init__(self, nodeid, position, transmitParams, initial, sfSet, freqSet, po
self.packetsTransmitted = 0
self.packetsSuccessful = 0
self.transmitTime = 0
self.energy = 0
def generateProximateBS(self, bsList, interferenceThreshold, logDistParams):
""" Generate dictionary of base-stations in proximity.
Parameters
----------
bsList : list
list of BSs.
interferenceThreshold: float
Interference threshold
logDistParams: list
Channel parameters
Returns
-------
proximateBS: list
List of proximated BS
"""

self.energy = 0
def generateProximateBS(self, bsList, interferenceThreshold, logDistParams):
""" Generate dictionary of base-stations in proximity.
Parameters
----------
bsList : list
list of BSs.
interferenceThreshold: float
Interference threshold
logDistParams: list
Channel parameters
Returns
-------
proximateBS: list
List of proximated BS
"""
maxInterferenceDist = getDistanceFromPower(self.pTXmax, interferenceThreshold, logDistParams)
dist = np.sqrt((bsList[:,1] - self.x)**2 + (bsList[:,2] - self.y)**2)
index = np.nonzero(dist <= maxInterferenceDist)

proximateBS = {} # create empty dictionary
for i in index[0]:
proximateBS[int(bsList[i,0])] = dist[i]

return proximateBS
def generatePacketsToBS(self, transmitParams, logDistParams):
""" Generate dictionary of base-stations in proximity.

def generatePacketsToBS(self, transmitParams, logDistParams):
""" Generate dictionary of base-stations in proximity.
Parameters
----------
transmitParams : list
Transmission parameters.
Transmission parameters.
logDistParams: list
Channel parameters
Channel parameters
Returns
-------
packets: packet
packets at BS
packets at BS
"""
packets = {} # empty dictionary to store packets originating at a node

for bsid, dist in self.proximateBS.items():
packets[bsid] = myPacket(self.nodeid, bsid, dist, transmitParams, logDistParams, self.sensi, self.setActions, self.nrActions, self.sfSet, self.prob) #choosenAction)
return packets
#print("probability of node " +str(self.nodeid)+" is: " +str(self.prob))
packets = {} # empty dictionary to store packets originating at a node
for bsid, dist in self.proximateBS.items():
packets[bsid] = myPacket(self.nodeid, bsid, dist, transmitParams, logDistParams, self.sensi, self.setActions, self.nrActions, self.sfSet, self.prob) #choosenAction)
return packets
#print("probability of node " +str(self.nodeid)+" is: " +str(self.prob))

def generateHoppingSfFromDistance(self, sfSet, logDistParams):
""" Generate the sf hopping sequence from distance
def generateHoppingSfFromDistance(self, sfSet, logDistParams):
""" Generate the sf hopping sequence from distance
Parameters
----------
logDistParams: list in format [gamma, Lpld0, d0]
Parameters for log shadowing channel model.
Parameters for log shadowing channel model.
Returns
-------
"""
sfBuckets = []
gamma, Lpld0, d0 = logDistParams
dist = self.proximateBS[0]
if self.bw == 125:
bwInd = 0
else:
bwInd = 1
Lpl = self.pTXmax - self.sensi[:, bwInd+1]

LplMatrix = Lpl.reshape((6,1))
distMatrix =np.dot(d0, np.power(10, np.divide(LplMatrix - Lpld0, 10*gamma)))

for i in range(6):
if dist <= distMatrix[0, 0]:
minSF = 7
elif distMatrix[i, 0 ]<= dist < distMatrix[i+1, 0]:
minSF = (i + 1) + 7
tempSF = [sf for sf in sfSet if sf >= minSF]
sfBuckets.extend(tempSF)

return sfBuckets

def updateProb(self):
""" Update the probability of each action by using EXP3 algorithm.
"""
sfBuckets = []
gamma, Lpld0, d0 = logDistParams
dist = self.proximateBS[0]

if self.bw == 125:
bwInd = 0
else:
bwInd = 1
Lpl = self.pTXmax - self.sensi[:, bwInd+1]

LplMatrix = Lpl.reshape((6,1))
distMatrix =np.dot(d0, np.power(10, np.divide(LplMatrix - Lpld0, 10*gamma)))

for i in range(6):
if dist <= distMatrix[0, 0]:
minSF = 7
elif distMatrix[i, 0 ]<= dist < distMatrix[i+1, 0]:
minSF = (i + 1) + 7
tempSF = [sf for sf in sfSet if sf >= minSF]
sfBuckets.extend(tempSF)

return sfBuckets

def updateProb(self, algo):
""" Update the probability of each action by using EXP3 algorithm.
Parameters
----------
Returns
-------
"""
prob = [self.prob[x] for x in self.prob]
weight = [self.weight[x] for x in self.weight]
# update weight and prob
if self.node_mode == "SMART":
# update weight
prob = [self.prob[x] for x in self.prob]
weight = [self.weight[x] for x in self.weight]
reward = np.zeros(self.nrActions)
# compute reward
if self.node_mode == "SMART":
# no and partial information case:
if self.info_mode in ["NO", "PARTIAL"]:
# with ACK -> update, no ACK -> no update
# with ACK -> 1, no ACK -> 0
if self.ack:
weight[self.packets[0].choosenAction] *= np.exp((1 * self.learning_rate)/(self.nrActions * self.prob[self.packets[0].choosenAction]))
else:
weight[self.packets[0].choosenAction] *= np.exp((0 * self.learning_rate)/(self.nrActions * self.prob[self.packets[0].choosenAction]))
reward[self.packets[0].choosenAction] = 1/prob[self.packets[0].choosenAction]
else:
reward[self.packets[0].choosenAction] = 0
# full information case:
else:
# with ACK and no collision -> full update, with ACK and collision -> half update, no ACK -> no update
if self.ack:
# receive ACK and no collision -> full update
if not self.ack[0].isCollision:
weight[self.packets[0].choosenAction] *= np.exp((1 * self.learning_rate)/(self.nrActions * self.prob[self.packets[0].choosenAction]))
# receive ACK but collision -> half update
reward[self.packets[0].choosenAction] = 1/prob[self.packets[0].choosenAction]
else:
weight[self.packets[0].choosenAction] *= np.exp((0.5 * self.learning_rate)/(self.nrActions * self.prob[self.packets[0].choosenAction]))
reward[self.packets[0].choosenAction] = 0.5/prob[self.packets[0].choosenAction]
else:
weight[self.packets[0].choosenAction] *= np.exp((0 * self.learning_rate)/(self.nrActions * self.prob[self.packets[0].choosenAction]))
# update prob
reward[self.packets[0].choosenAction] = 0

# update weight
for j in range(0, self.nrActions):
if algo == "exp3":
weight[j] *= np.exp((self.learning_rate * reward[j])/self.nrActions)
elif algo == "exp3s":
weight[j] *= np.exp((self.learning_rate * reward[j])/self.nrActions)
weight[j] += ((np.exp(1) * self.alpha)/self.nrActions) * sum(weight)

# update prob
if self.node_mode == "SMART":
for j in range(0, self.nrActions):
prob[j] = (1-self.learning_rate) * (weight[j]/sum(weight)) + (self.learning_rate/self.nrActions)
elif self.node_mode == "RANDOM":
prob = np.random.rand(self.nrActions)
prob = prob/sum(prob)
elif self.node_mode == "RANDOM":
prob = np.random.rand(self.nrActions)
prob = prob/sum(prob)
else:
prob = (1/self.nrActions) * np.ones(self.nrActions)

# trick: force the small value (<1/5000) to 0 and normalize
prob = np.array(prob)
prob[prob<0.0002] = 0
prob[prob<0.0005] = 0
prob = prob/sum(prob)

self.weight = {x: weight[x] for x in range(0, self.nrActions)}
self.weight = {x: weight[x] for x in range(0, self.nrActions)}
self.prob = {x: prob[x] for x in range(0, self.nrActions)}
def resetACK(self):
"""Reset ACK"""

def resetACK(self):
"""Reset ACK"""
self.ack = {}

def addACK(self, bsid, packet):
"""Send an ACK to the node"""
self.ack[bsid] = packet
self.ack[bsid] = packet

def updateTXSettings(self):
"""Update TX setting"""
pass
pass

0 comments on commit 3256d73

Please sign in to comment.