-
Notifications
You must be signed in to change notification settings - Fork 3
/
packet.py
146 lines (127 loc) · 4.65 KB
/
packet.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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2019 Tugrul Yatagan <[email protected]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation;
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
import math
import random
import enum
collision_snir = [
[ 6, -16, -18, -19, -19, -20],
[-24, 6, -20, -22, -22, -22],
[-27, -27, 6, -23, -25, -25],
[-30, -30, -30, 6, -26, -28],
[-33, -33, -33, -33, 6, -29],
[-36, -36, -36, -36, -36, 6],
]
system_gain = 7 # total of system gains and system losses
@enum.unique
class PacketStatus(enum.Enum):
pending = 0
transmitted = 1
interfered = 2
under_sensitivity = 3
@enum.unique
class PacketSf(enum.Enum):
SF_Random = 0
SF_Lowest = 1
SF_Smart = 2
SF_7 = 7
SF_8 = 8
SF_9 = 9
SF_10 = 10
SF_11 = 11
SF_12 = 12
@staticmethod
def get_random():
return PacketSf(random.randint(7, 12))
class Packet:
def __init__(self, time, sf, source, size, destination=0):
self.time = time
self.sf = sf
self.source = source
self.destination = destination
self.status = PacketStatus.pending
self.size = size
self.duration = Packet.calculate_transmission_duration(sf, size)
self.bandwidth = 125 # TODO
self.tx_power_dbm = 14 # dBm TODO
self.tx_energy_j = Packet.calculate_energy(power_dbm=self.tx_power_dbm, duration=self.duration)
def __lt__(self, other):
return self.time < other.time
def __repr__(self):
return '(t={:.3f},src={},dst={},sf={},bw={},dur={:.3f},p={},e={:.4f},stat={})'.format(self.time, self.source, self.destination, self.sf.name, self.bandwidth, self.duration, self.tx_power_dbm, self.tx_energy_j, self.status.name)
@staticmethod
def calculate_transmission_duration(sf, size):
# TODO, consider BW
if sf == PacketSf.SF_7:
return (size * 8) / 5470.0
elif sf == PacketSf.SF_8:
return (size * 8) / 3125.0
elif sf == PacketSf.SF_9:
return (size * 8) / 1760.0
elif sf == PacketSf.SF_10:
return (size * 8) / 980.0
elif sf == PacketSf.SF_11:
return (size * 8) / 440.0
elif sf == PacketSf.SF_12:
return (size * 8) / 250.0
else:
raise Exception()
@staticmethod
def get_receive_sensitivity(sf):
# https://www.semtech.com/uploads/documents/DS_SX1276-7-8-9_W_APP_V5.pdf
if sf == PacketSf.SF_7:
return -123 - system_gain
elif sf == PacketSf.SF_8:
return -126 - system_gain
elif sf == PacketSf.SF_9:
return -129 - system_gain
elif sf == PacketSf.SF_10:
return -132 - system_gain
elif sf == PacketSf.SF_11:
return -133 - system_gain
elif sf == PacketSf.SF_12:
return -136 - system_gain
else:
raise Exception()
@staticmethod
def calculate_propagation_loss(distance):
# Assuming f = 868 MHz and h = 15 m
return 120.5 + 37.6 * math.log10(distance/1000)
@staticmethod
def get_lowest_sf(distance, erp=14):
# TODO erp
propagation_loss = Packet.calculate_propagation_loss(distance)
if erp - propagation_loss > Packet.get_receive_sensitivity(PacketSf.SF_7):
return PacketSf.SF_7
elif erp - propagation_loss > Packet.get_receive_sensitivity(PacketSf.SF_8):
return PacketSf.SF_8
elif erp - propagation_loss > Packet.get_receive_sensitivity(PacketSf.SF_9):
return PacketSf.SF_9
elif erp - propagation_loss > Packet.get_receive_sensitivity(PacketSf.SF_10):
return PacketSf.SF_10
elif erp - propagation_loss > Packet.get_receive_sensitivity(PacketSf.SF_11):
return PacketSf.SF_11
else:
return PacketSf.SF_12
@staticmethod
def calculate_energy(power_dbm, duration):
return Packet.dbm_to_watt(power_dbm) * duration
@staticmethod
def dbm_to_watt(dbm):
if dbm == 14:
# Pre calculated value for commonly used tx_power_dbm
return 0.025118864315095794
else:
return (10 ** (dbm/10)) / 1000.0