vlcSim 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vlcsim/simulator.py ADDED
@@ -0,0 +1,797 @@
1
+ """
2
+ The Module **Simulator** has all the Simulation Dynamics.
3
+ """
4
+
5
+ from .controller import *
6
+ from .scene import *
7
+ import numpy as np
8
+ from enum import Enum
9
+ from typing import Optional, List, Any
10
+
11
+
12
+ class Event:
13
+ """
14
+ The Event class has the information about the event, containing the time when the event occurs, the type of event, and the connection ID.
15
+ """
16
+
17
+ event = Enum("event", "ARRIVE DEPARTURE PAUSE RESUME NEXT_CONNECTION_TRY")
18
+ """
19
+ There are five event types. The **ARRIVE** event is used when a connection arrives to the scenario. **DEPARTURE** event when the connection leaves. **PAUSE** and **RESUME** is related to a connection that is currently served by an AP, but because of the frame-slot behavior is paused and resumed multiple times. Finally, **NEXT_CONNECTION_TRY** is used when a connection couldn't be stablished because capacity, and waits a random time and need to be served in future·
20
+ """
21
+
22
+ def __init__(
23
+ self, type: Optional[event] = None, time: float = -1, id_connection: int = -1
24
+ ) -> None:
25
+ self.__time: float = time
26
+ self.__id_connection: int = id_connection
27
+ if type is None:
28
+ self.__type: Event.event = Event.event.ARRIVE
29
+ else:
30
+ self.__type = type
31
+ self.__connection: Optional[Connection] = None
32
+
33
+ @property
34
+ def type(self) -> event:
35
+ """
36
+ The connection type. Could be one of the fives types described before.
37
+
38
+ :return: Connection type
39
+ :rtype: event
40
+ """
41
+ return self.__type
42
+
43
+ @property
44
+ def time(self) -> float:
45
+ """
46
+ The instant when this event occurs.
47
+
48
+ :return: Instant time of this event
49
+ :rtype: float
50
+ """
51
+ return self.__time
52
+
53
+ @property
54
+ def id_connection(self) -> int:
55
+ """
56
+ Connection ID of the connection related to this event
57
+
58
+ :return: Connection ID
59
+ :rtype: int
60
+ """
61
+ return self.__id_connection
62
+
63
+ @property
64
+ def connection(self) -> Optional[Connection]:
65
+ """
66
+ Connection object related to this event.
67
+
68
+ :return: Connection object
69
+ :rtype: Connection
70
+ """
71
+ return self.__connection
72
+
73
+ @connection.setter
74
+ def connection(self, value: Connection):
75
+ self.__connection = value
76
+
77
+
78
+ class Simulator:
79
+ """
80
+ Simulator class. In chanrge of randomness and the clock routine.
81
+ """
82
+
83
+ def __init__(self, x: float, y: float, z: float, nGrids: int, rho: float) -> None:
84
+ """
85
+ Simulator object constructor
86
+
87
+ :param x: Length of the scenario
88
+ :type x: float
89
+ :param y: Width of the scenario
90
+ :type y: float
91
+ :param z: Height of the scenario
92
+ :type z: float
93
+ :param nGrids: Number of segments on each dimension. Usefull for precision.
94
+ :type nGrids: int
95
+ :param rho: reflexion coefficient. A floating number between 0 and 1.
96
+ :type rho: float
97
+ """
98
+ self.__controller: Controller = Controller(x, y, z, nGrids, rho)
99
+ self.__events: List[Event] = []
100
+ self.__current_event: Optional[Event] = None
101
+
102
+ self.__initReady: Optional[bool] = None
103
+ self.__lambdaS: Optional[float] = None
104
+ self.__mu: Optional[float] = None
105
+ self.__seedArrive: Optional[int] = None
106
+ self.__seedDeparture: Optional[int] = None
107
+ self.__seedX: Optional[int] = None
108
+ self.__seedY: Optional[int] = None
109
+ self.__seedZ: Optional[int] = None
110
+ self.__seedRandomWait: Optional[int] = None
111
+ self.__seedCapacityRequired: Optional[int] = None
112
+ self.__numberOfConnections: int = 0
113
+ self.__goalConnections: int = 10000
114
+ self.__arrival_variable: Any = None
115
+ self.__departure_variable: Any = None
116
+ self.__x_variable: Any = None
117
+ self.__y_variable: Any = None
118
+ self.__z_variable: Any = None
119
+ self.__random_wait_variable: Any = None
120
+ self.__capacity_required_variable: Any = None
121
+ self.__rtn_allocation: Optional[Any] = None
122
+
123
+ self.__allocatedConnections: int = 0
124
+ # time
125
+ self.__clock: float = 0.0
126
+ self.__time_duration: Optional[float] = None
127
+
128
+ self.__upper_random_wait: Optional[float] = None
129
+ self.__lower_random_wait: Optional[float] = None
130
+
131
+ self.__upper_capacity_required: Optional[float] = None
132
+ self.__lower_capacity_required: Optional[float] = None
133
+
134
+ self.__users_by_vlc: List[int] = []
135
+ self.__users_by_rf: List[int] = []
136
+
137
+ self.default_values()
138
+
139
+ def default_values(self):
140
+ """
141
+ Set the default simulation values, that are:
142
+
143
+ * lambdaS = 3
144
+ * mu = 10
145
+ * seedArrive = 12345
146
+ * seedDeparture = 1234
147
+ * seedX = 1235
148
+ * seedY = 1245
149
+ * seedZ = 1345
150
+ * seedRandomWait = 1345
151
+ * seedCapacityRequired = 1345
152
+ * goalConnections = 10000
153
+ * lower_random_wait = 5
154
+ * upper_random_wait = 15
155
+ """
156
+ self.__initReady = False
157
+ self.__lambdaS = 3
158
+ self.__mu = 10
159
+ self.__seedArrive = 12345
160
+ self.__seedDeparture = 1234
161
+ self.__seedX = 1235
162
+ self.__seedY = 1245
163
+ self.__seedZ = 1345
164
+ self.__seedRandomWait = 1345
165
+ self.__seedCapacityRequired = 1345
166
+
167
+ self.__numberOfConnections = 0
168
+ self.__goalConnections: int = 10000
169
+ self.__lower_random_wait = 5
170
+ self.__upper_random_wait = 15
171
+ self.__allocatedConnections = 0
172
+ self.__controller.allocator = Controller.default_alloc
173
+
174
+ @property
175
+ def upper_capacity_required(self) -> Optional[float]:
176
+ """
177
+ The upper possible capacity required
178
+
179
+ :return: Upper capacity required
180
+ :rtype: float
181
+ """
182
+ return self.__upper_capacity_required
183
+
184
+ @upper_capacity_required.setter
185
+ def upper_capacity_required(self, value: float) -> None:
186
+ self.__upper_capacity_required = value
187
+
188
+ @property
189
+ def lower_capacity_required(self) -> Optional[float]:
190
+ """
191
+ The lower possible capacity required
192
+
193
+ :return: Lower capacity required
194
+ :rtype: float
195
+ """
196
+ return self.__lower_capacity_required
197
+
198
+ @lower_capacity_required.setter
199
+ def lower_capacity_required(self, value: float) -> None:
200
+ self.__lower_capacity_required = value
201
+
202
+ @property
203
+ def seedCapacityRequired(self) -> Optional[int]:
204
+ """
205
+ Seed of capacity required random generator
206
+
207
+ :return: random generator seed
208
+ :rtype: int
209
+ """
210
+ return self.__seedCapacityRequired
211
+
212
+ @seedCapacityRequired.setter
213
+ def seedCapacityRequired(self, value: int):
214
+ self.__seedCapacityRequired = value
215
+
216
+ @property
217
+ def upper_random_wait(self) -> Optional[float]:
218
+ """
219
+ the upper possible random wait
220
+
221
+ :return: upper waiting time
222
+ :rtype: float
223
+ """
224
+ return self.__upper_random_wait
225
+
226
+ @upper_random_wait.setter
227
+ def upper_random_wait(self, value: float) -> None:
228
+ self.__upper_random_wait = value
229
+
230
+ @property
231
+ def lower_random_wait(self) -> Optional[float]:
232
+ """
233
+ The lower possible random wait
234
+
235
+ :return: lower waiting time
236
+ :rtype: float
237
+ """
238
+ return self.__lower_random_wait
239
+
240
+ @lower_random_wait.setter
241
+ def lower_random_wait(self, value: float) -> None:
242
+ self.__lower_random_wait = value
243
+
244
+ @property
245
+ def lambdaS(self) -> Optional[float]:
246
+ """
247
+ Get or set the attribute lambda.
248
+
249
+ :return: lambda attribute
250
+ :rtype: float
251
+ """
252
+ return self.__lambdaS
253
+
254
+ @lambdaS.setter
255
+ def lambdaS(self, lambdaS: float) -> None:
256
+ if self.__initReady:
257
+ print(
258
+ "You can not set mu parameter AFTER calling init simulator " "method."
259
+ )
260
+ return
261
+ self.__lambdaS = lambdaS
262
+
263
+ @property
264
+ def mu(self) -> Optional[float]:
265
+ """
266
+ Get or set the attribute mu.
267
+
268
+ :return: mu attribute
269
+ :rtype: float
270
+ """
271
+ return self.__mu
272
+
273
+ @mu.setter
274
+ def mu(self, mu: float) -> None:
275
+ if self.__initReady:
276
+ print(
277
+ "You can not set mu parameter AFTER calling init simulator " "method."
278
+ )
279
+ return
280
+ self.__mu = mu
281
+
282
+ @property
283
+ def seedX(self) -> Optional[int]:
284
+ """
285
+ Get or set the attribute seedX.
286
+
287
+ :return: the seed of random X generator
288
+ :rtype: int
289
+ """
290
+ return self.__seedX
291
+
292
+ @seedX.setter
293
+ def seedX(self, seedX: int) -> None:
294
+ if self.__initReady:
295
+ print(
296
+ "You can not set mu parameter AFTER calling init simulator " "method."
297
+ )
298
+ return
299
+ self.__seedX = seedX
300
+
301
+ @property
302
+ def seedY(self) -> Optional[int]:
303
+ """
304
+ Get or set the attribute seedY.
305
+
306
+ :return: the seed of random Y generator
307
+ :rtype: int
308
+ """
309
+ return self.__seedY
310
+
311
+ @seedY.setter
312
+ def seedY(self, seedY: int) -> None:
313
+ if self.__initReady:
314
+ print(
315
+ "You can not set mu parameter AFTER calling init simulator " "method."
316
+ )
317
+ return
318
+ self.__seedY = seedY
319
+
320
+ @property
321
+ def seedZ(self) -> Optional[int]:
322
+ """
323
+ Get or set the attribute seedZ.
324
+
325
+ :return: the seed of random Z generator
326
+ :rtype: int
327
+ """
328
+ return self.__seedZ
329
+
330
+ @seedZ.setter
331
+ def seedZ(self, seedZ: int) -> None:
332
+ if self.__initReady:
333
+ print(
334
+ "You can not set mu parameter AFTER calling init simulator " "method."
335
+ )
336
+ return
337
+ self.__seedZ = seedZ
338
+
339
+ @property
340
+ def seedRandomWait(self) -> Optional[int]:
341
+ """
342
+ Get or set the attribute seedRandomWait.
343
+
344
+ :return: the seed of random random-wait generator
345
+ :rtype: int
346
+ """
347
+ return self.__seedRandomWait
348
+
349
+ @seedRandomWait.setter
350
+ def seedRandomWait(self, seedRandomWait: int) -> None:
351
+ if self.__initReady:
352
+ print(
353
+ "You can not set mu parameter AFTER calling init simulator " "method."
354
+ )
355
+ return
356
+ self.__seedRandomWait = seedRandomWait
357
+
358
+ @property
359
+ def goalConnections(self) -> Optional[int]:
360
+ """
361
+ Get or set the attribute goalConnections.
362
+
363
+ :return: The goal connections
364
+ :rtype: int
365
+ """
366
+ return self.__goalConnections
367
+
368
+ @goalConnections.setter
369
+ def goalConnections(self, goalConnections: int) -> None:
370
+ if self.__initReady:
371
+ print(
372
+ "You can not set mu parameter AFTER calling init simulator " "method."
373
+ )
374
+ return
375
+ self.__goalConnections = goalConnections
376
+
377
+ def print_initial_info(self):
378
+ """
379
+ Prints the initial info of simulation.
380
+ """
381
+ print(
382
+ "Scenario:\t %s x %s x %s"
383
+ % (
384
+ self.__controller.scenario.length,
385
+ self.__controller.scenario.width,
386
+ self.__controller.scenario.height,
387
+ )
388
+ )
389
+
390
+ print(f"Number of VLeds: {self.__controller.scenario.numberOfVLeds}")
391
+ print("Positions:")
392
+ print(" ID | X | Y | Z |")
393
+ print("-" * 47)
394
+ for vled in self.__controller.scenario.vleds:
395
+ print(
396
+ "{:>10} | {:8.4f} | {:8.4f} | {:8.4f} |".format(
397
+ vled.ID, vled.x, vled.y, vled.z
398
+ )
399
+ )
400
+ print()
401
+ print(f"Number of RFs: {self.__controller.scenario.numberOfRFs}")
402
+ print("Positions:")
403
+ print(" ID | X | Y | Z |")
404
+ print("-" * 47)
405
+ for rf in self.__controller.scenario.rfs:
406
+ print(
407
+ "{:>10} | {:8.4f} | {:8.4f} | {:8.4f} |".format(
408
+ rf.ID, rf.x, rf.y, rf.z
409
+ )
410
+ )
411
+ print()
412
+
413
+ print("=" * 146)
414
+ print("| Time ", end="")
415
+ print("| Event ", end="")
416
+ print("| Receiver ", end="")
417
+ print("| X ", end="")
418
+ print("| Y ", end="")
419
+ print("| Z ", end="")
420
+ print("| Access Point (A.C.) ", end="")
421
+ print("| Goal time ", end="")
422
+ print("| Elapsed time ", end="")
423
+ print("| SNR ", end="")
424
+ print("| Req. Cap. |")
425
+ print("=" * 146)
426
+
427
+ def print_row(self, event: Event) -> None:
428
+ """
429
+ print every simulation row
430
+
431
+ :param event: The event to print_
432
+ :type event: Event
433
+ """
434
+ text = ""
435
+ text = "{:9.4f}".format(event.time) + "|"
436
+ if event.type == Event.event.ARRIVE:
437
+ text += " ARRIVE |"
438
+ elif event.type == Event.event.RESUME:
439
+ text += " RESUME |"
440
+ elif event.type == Event.event.PAUSE:
441
+ text += " PAUSE |"
442
+ elif event.type == Event.event.DEPARTURE:
443
+ text += " DEPARTURE |"
444
+ elif event.type == Event.event.NEXT_CONNECTION_TRY:
445
+ text += " RETRYING |"
446
+ text += "{:>10}".format(event.id_connection) + " |"
447
+ if event.connection:
448
+ text += "{:8.4f}".format(event.connection.receiver.x) + " |"
449
+ text += "{:8.4f}".format(event.connection.receiver.y) + " |"
450
+ text += "{:8.4f}".format(event.connection.receiver.z) + " |"
451
+ else:
452
+ text += " N/A | N/A | N/A |"
453
+ if event.connection and isinstance(event.connection.AP, VLed):
454
+ text += (
455
+ " VLed: {:>5}".format(event.connection.AP.ID)
456
+ + " ({:^5})".format(
457
+ self.__controller.numberOfActiveConnections(event.connection.AP)
458
+ )
459
+ + " |"
460
+ )
461
+ elif event.connection and isinstance(event.connection.AP, RF):
462
+ text += (
463
+ " RF: {:>5}".format(event.connection.AP.ID)
464
+ + " ({:^5})".format(
465
+ self.__controller.numberOfActiveConnections(event.connection.AP)
466
+ )
467
+ + " |"
468
+ )
469
+ else:
470
+ text += " NOT_SELECTED |"
471
+ if event.connection and event.connection.allocated:
472
+ text += "{:10.4f}".format(event.connection.receiver.goalTime) + " |"
473
+ else:
474
+ text += " NOT_ALLOC |"
475
+ if event.connection:
476
+ text += "{:12.4f}".format(event.connection.receiver.timeActive) + " |"
477
+ else:
478
+ text += " N/A |"
479
+ # if event.connection != None:
480
+ # print(
481
+ # event.time,
482
+ # event.type,
483
+ # event.id_connection,
484
+ # event.connection.receiver.goalTime,
485
+ # event.connection.receiver.timeActive,
486
+ # )
487
+ # else:
488
+ # print(
489
+ # event.time,
490
+ # event.type,
491
+ # event.id_connection,
492
+ # )
493
+ if event.connection:
494
+ text += "{:10.2e}".format(event.connection.snr) + " |"
495
+ text += "{:10.2e}".format(event.connection.capacityRequired) + " |"
496
+ else:
497
+ text += " N/A | N/A |"
498
+ print(text)
499
+
500
+ def event_routine(self):
501
+ """
502
+ The event routine. This function selects the event and run the associated routine.
503
+ """
504
+ self.__current_event = self.__events[0]
505
+ self.__rtn_allocation = None
506
+ self.__clock = self.__current_event.time
507
+ # print()
508
+ # print(self.__controller.activeConnections[0])
509
+ # print(self.__controller.activeConnections[1])
510
+ # print(self.__controller.activeConnections[2])
511
+ # print(self.__controller.activeConnections[3])
512
+ # print(self.__controller.activeConnections[4])
513
+ if self.__current_event.type == Event.event.ARRIVE:
514
+ next_event_time = self.__clock + self.__arrival_variable.exponential(
515
+ self.__lambdaS
516
+ )
517
+ for pos in range(len(self.__events) - 1, -1, -1):
518
+ if self.__events[pos].time < next_event_time:
519
+ self.__events.insert(
520
+ pos + 1,
521
+ Event(
522
+ Event.event.ARRIVE,
523
+ next_event_time,
524
+ self.__numberOfConnections,
525
+ ),
526
+ )
527
+ self.__numberOfConnections += 1
528
+ break
529
+
530
+ self.__x = self.__x_variable.uniform(
531
+ low=self.__controller.scenario.start_x,
532
+ high=self.__controller.scenario.end_x,
533
+ )
534
+ self.__y = self.__y_variable.uniform(
535
+ low=self.__controller.scenario.start_y,
536
+ high=self.__controller.scenario.end_y,
537
+ )
538
+ self.__z = self.__z_variable.uniform(
539
+ low=0,
540
+ high=self.__controller.scenario.height,
541
+ )
542
+ receiver = Receiver(self.__x, self.__y, self.__z, 1e-4, 1.0, 1.5, 70.0)
543
+ connection = Connection(
544
+ self.__current_event.id_connection, receiver, self.__clock
545
+ )
546
+ connection.capacityRequired = self.__capacity_required_variable.uniform(
547
+ self.__lower_capacity_required, self.__upper_capacity_required
548
+ )
549
+ # connection.receiver.goalTime = connection.goalTime
550
+ next_status, time, connection = self.__controller.assignConnection(
551
+ connection, self.__clock
552
+ )
553
+ if (
554
+ next_status == Controller.nextStatus.RESUME
555
+ or next_status == Controller.nextStatus.PAUSE
556
+ ):
557
+ if type(connection.AP) == VLed and connection.AP.ID is not None:
558
+ self.__users_by_vlc[connection.AP.ID] += 1
559
+ elif type(connection.AP) == RF and connection.AP.ID is not None:
560
+ self.__users_by_rf[connection.AP.ID] += 1
561
+ self.__current_event.connection = connection
562
+ if next_status == Controller.nextStatus.RESUME:
563
+ for pos in range(len(self.__events) - 1, -1, -1):
564
+ if self.__events[pos].time <= time:
565
+ e = Event(
566
+ Event.event.RESUME,
567
+ time,
568
+ connection.id,
569
+ )
570
+ e.connection = connection
571
+ self.__events.insert(pos + 1, e)
572
+ break
573
+ self.__allocatedConnections += 1
574
+ elif next_status == Controller.nextStatus.RND_WAIT:
575
+ self.__current_event.connection = connection
576
+ next_event_time = self.__clock + self.__random_wait_variable.uniform(
577
+ low=self.__lower_random_wait,
578
+ high=self.upper_random_wait,
579
+ )
580
+ next_event = Event(
581
+ Event.event.NEXT_CONNECTION_TRY,
582
+ next_event_time,
583
+ connection.id,
584
+ )
585
+ next_event.connection = connection
586
+ connection.allocated = False
587
+ for pos in range(len(self.__events) - 1, -1, -1):
588
+ if self.__events[pos].time < next_event_time:
589
+ self.__events.insert(pos + 1, next_event)
590
+ break
591
+ elif self.__current_event.type == Event.event.NEXT_CONNECTION_TRY:
592
+ if not self.__current_event.connection:
593
+ return
594
+ next_status, time, connection = self.__controller.assignConnection(
595
+ self.__current_event.connection, self.__clock
596
+ )
597
+ if (
598
+ next_status == Controller.nextStatus.RESUME
599
+ or next_status == Controller.nextStatus.PAUSE
600
+ ):
601
+ connection.receiver.goalTime = self.__departure_variable.exponential(
602
+ self.__mu
603
+ )
604
+ connection.allocated = True
605
+ if next_status == Controller.nextStatus.RESUME:
606
+ for pos in range(len(self.__events) - 1, -1, -1):
607
+ if self.__events[pos].time <= time:
608
+ e = Event(
609
+ Event.event.RESUME,
610
+ time,
611
+ connection.id,
612
+ )
613
+ e.connection = connection
614
+ self.__events.insert(pos + 1, e)
615
+ break
616
+ self.__allocatedConnections += 1
617
+ elif next_status == Controller.nextStatus.RND_WAIT:
618
+ next_event_time = self.__clock + self.__random_wait_variable.uniform(
619
+ low=self.__lower_random_wait,
620
+ high=self.upper_random_wait,
621
+ )
622
+ next_event = Event(
623
+ Event.event.NEXT_CONNECTION_TRY,
624
+ next_event_time,
625
+ connection.id,
626
+ )
627
+ next_event.connection = connection
628
+ for pos in range(len(self.__events) - 1, -1, -1):
629
+ if self.__events[pos].time < next_event_time:
630
+ self.__events.insert(pos + 1, next_event)
631
+ break
632
+ elif self.__current_event.type == Event.event.PAUSE:
633
+ if not self.__current_event.connection:
634
+ return
635
+ next_status, time, connection = self.__controller.pauseConnection(
636
+ self.__current_event.connection, self.__clock
637
+ )
638
+ for pos in range(len(self.__events) - 1, -1, -1):
639
+ if self.__events[pos].time <= time:
640
+ e = Event(
641
+ Event.event.RESUME,
642
+ time,
643
+ connection.id,
644
+ )
645
+ e.connection = connection
646
+ self.__events.insert(pos + 1, e)
647
+ break
648
+ elif self.__current_event.type == Event.event.RESUME:
649
+ if not self.__current_event.connection:
650
+ return
651
+ next_status, time, connection = self.__controller.resumeConnection(
652
+ self.__current_event.connection, self.__clock
653
+ )
654
+ for pos in range(len(self.__events) - 1, -1, -1):
655
+ if self.__events[pos].time <= time:
656
+ e = None
657
+ if next_status == Controller.nextStatus.PAUSE:
658
+ e = Event(
659
+ Event.event.PAUSE,
660
+ time,
661
+ connection.id,
662
+ )
663
+ else:
664
+ e = Event(
665
+ Event.event.DEPARTURE,
666
+ time,
667
+ connection.id,
668
+ )
669
+ e.connection = connection
670
+ self.__events.insert(pos + 1, e)
671
+ break
672
+ elif self.__current_event.type == Event.event.DEPARTURE:
673
+ if not self.__current_event.connection:
674
+ return
675
+ next_status, time, connection = self.__controller.unassignConnection(
676
+ self.__current_event.connection, self.__clock
677
+ )
678
+ # if next_status == Controller.nextStatus.RESUME:
679
+ # for pos in range(len(self.__events) - 1, -1, -1):
680
+ # if self.__events[pos].time <= time:
681
+ # e = Event(
682
+ # Event.event.RESUME,
683
+ # time,
684
+ # connection.id,
685
+ # )
686
+ # e.connection = connection
687
+ # self.__events.insert(pos + 1, e)
688
+ # break
689
+ self.__events.pop(0)
690
+
691
+ return self.__rtn_allocation
692
+
693
+ def init(self):
694
+ """
695
+ Simulation init. Initialize every simulation parameter.
696
+ """
697
+ self.__initReady = True
698
+ self.__clock = 0
699
+ self.__arrival_variable = np.random.default_rng(self.__seedArrive)
700
+ self.__departure_variable = np.random.default_rng(self.__seedDeparture)
701
+ self.__x_variable = np.random.default_rng(self.__seedX)
702
+ self.__y_variable = np.random.default_rng(self.__seedY)
703
+ self.__z_variable = np.random.default_rng(self.__seedZ)
704
+ self.__random_wait_variable = np.random.default_rng(self.__seedZ)
705
+ self.__capacity_required_variable = np.random.default_rng(self.__seedZ)
706
+ self.__events.append(
707
+ Event(
708
+ Event.event.ARRIVE,
709
+ self.__arrival_variable.exponential(self.__lambdaS),
710
+ self.__numberOfConnections,
711
+ )
712
+ )
713
+ self.__numberOfConnections += 1
714
+ self.__allocatedConnections = 0
715
+ self.__controller.init()
716
+ if (
717
+ self.__controller.scenario.numberOfVLeds == 0
718
+ and self.__controller.scenario.numberOfRFs == 0
719
+ ):
720
+ raise ValueError("The scenario does not have any Vleds or RFs")
721
+ for _ in range(self.__controller.scenario.numberOfVLeds):
722
+ self.__users_by_vlc.append(0)
723
+ for _ in range(self.__controller.scenario.numberOfRFs):
724
+ self.__users_by_rf.append(0)
725
+ return
726
+
727
+ def run(self):
728
+ """
729
+ Run this simulation with the parameters.
730
+ """
731
+ self.print_initial_info()
732
+ while self.__numberOfConnections <= self.__goalConnections:
733
+ # for i in range(self.__goalConnections):
734
+ self.event_routine()
735
+ if self.__current_event:
736
+ self.print_row(self.__current_event)
737
+ self.aggregated_metrics()
738
+
739
+ def time_duration(self) -> float:
740
+ """
741
+ Duration time
742
+
743
+ :return: duration time
744
+ :rtype: float
745
+ """
746
+ return self.__time_duration if self.__time_duration is not None else 0.0
747
+
748
+ def get_Blocking_Probability(self) -> float:
749
+ """
750
+ Blocking probability
751
+
752
+ :return: blocking probability
753
+ :rtype: float
754
+ """
755
+ blocking = round(
756
+ 1 - self.__allocatedConnections / self.__numberOfConnections, 2
757
+ )
758
+ return blocking
759
+
760
+ def set_allocation_algorithm(
761
+ self,
762
+ alloc_alg: Callable[
763
+ [Receiver, Connection, Any, Controller], tuple[Any, Connection]
764
+ ],
765
+ ) -> None:
766
+ """
767
+ Set allocation algorithm.
768
+
769
+ :param alloc_alg: Allocation algorithm
770
+ """
771
+ self.__controller.allocator = alloc_alg
772
+
773
+ @property
774
+ def scenario(self):
775
+ """
776
+ Scenario used in this simulation
777
+
778
+ :return: Scenario
779
+ :rtype: Scenario
780
+ """
781
+ return self.__controller.scenario
782
+
783
+ def aggregated_metrics(self):
784
+ """
785
+ Number of users connected to each AP
786
+ """
787
+ print("Number of users connected to each VLed")
788
+ for i in range(self.__controller.scenario.numberOfVLeds):
789
+ id = self.__controller.scenario.vleds[i].ID
790
+ if id is not None:
791
+ print(f"VLed {id}: {self.__users_by_vlc[id]}")
792
+
793
+ print("Number of users connected to each RF")
794
+ for i in range(self.__controller.scenario.numberOfRFs):
795
+ id = self.__controller.scenario.rfs[i].ID
796
+ if id is not None:
797
+ print(f"RF {id}: {self.__users_by_rf[id]}")