Advanced Usage
This section covers advanced topics for users who need to customize VLCSim beyond the default behavior.
Custom Allocation Algorithms
While VLCSim includes a built-in allocation algorithm that works for most scenarios, you can implement custom allocation strategies for research or specific requirements.
Algorithm Requirements
A custom allocation algorithm must:
Accept 4 parameters:
receiver,connection,scenario,controllerReturn a tuple:
(Controller.status, connection)Set the connection’s
AP,capacityFromAP, and assign frame/slices
Algorithm Signature
def custom_alloc(
receiver: Receiver,
connection: Connection,
scenario: Scenario,
controller: Controller
) -> tuple[Controller.status, Connection]:
# Your allocation logic here
return Controller.status.ALLOCATED, connection
Status Return Values
Your algorithm should return one of these statuses:
Controller.status.ALLOCATED: Connection successfully allocated to an APController.status.NOT_ALLOCATED: Connection refused (will not retry)Controller.status.WAIT: Connection will wait and retry later
NOT_ALLOCATED and WAIT are reported separately by simulator metrics:
blocking probability counts definitive refusals, while waiting probability counts
connections that are still scheduled for retry.
Example: Capacity-Based Allocation
This example allocates connections based on maximum capacity instead of SNR:
from vlcsim import *
import math
def alloc(receiver, connection: Connection, scenario: Scenario, controller: Controller):
vleds = scenario.vleds
capacities = []
for vled in vleds:
capacities.append(scenario.capacityVled(receiver, vled))
posBestCapacity = capacities.index(max(capacities))
numberOfSlices = 0
if (
controller.numberOfActiveConnections(vleds[posBestCapacity]) > 5
or capacities[posBestCapacity] == 0
):
connection.AP = scenario.rfs[0]
connection.receiver.capacityFromAP = scenario.capacityRf(
receiver, connection.AP
)
numberOfSlices = connection.numberOfSlicesNeeded(
connection.capacityRequired, connection.receiver.capacityFromAP
)
else:
connection.AP = vleds[posBestCapacity]
connection.receiver.capacityFromAP = capacities[posBestCapacity]
numberOfSlices = connection.numberOfSlicesNeeded(
connection.capacityRequired, capacities[posBestCapacity]
)
actualSlice = connection.nextSliceInAPWhenArriving(connection.AP)
aux = 0
auxFrame = 0
# Actual frame
for slice in range(actualSlice, connection.AP.slicesInFrame):
if (
len(controller.framesState(connection.AP)) == 0
or controller.framesState(connection.AP)[0][slice] == False
):
connection.assignFrameSlice(0, slice)
aux += 1
break
# next frames
for frameIndex in range(1, len(controller.framesState(connection.AP))):
for slice in range(connection.AP.slicesInFrame):
if controller.framesState(connection.AP)[frameIndex][slice] == False:
connection.assignFrameSlice(frameIndex, slice)
aux += 1
auxFrame = frameIndex
break
if aux == numberOfSlices:
break
frameIndex = auxFrame + 1
while aux < numberOfSlices:
connection.assignFrameSlice(frameIndex, 0)
frameIndex += 1
aux += 1
return Controller.status.ALLOCATED, connection
if __name__ == "__main__":
# Simulator Constructor: size of the room, with the numbrer of grids and the rho parameter
sim = Simulator(20.0, 20.0, 2.15, 10, 0.8)
# Adding Vleds to the room
vled = VLed(-7.5, -7.5, 2.15, 60, 60, 20, 70)
vled.sliceTime = 0.2
vled.slicesInFrame = 10
vled.B = 0.5e5
sim.scenario.addVLed(vled)
vled = VLed(-7.5, 7.5, 2.15, 60, 60, 20, 70)
vled.sliceTime = 0.2
vled.slicesInFrame = 10
vled.B = 0.5e5
sim.scenario.addVLed(vled)
vled = VLed(7.5, -7.5, 2.15, 60, 60, 20, 70)
vled.sliceTime = 0.2
vled.slicesInFrame = 10
vled.B = 0.5e5
sim.scenario.addVLed(vled)
vled = VLed(7.5, 7.5, 2.15, 60, 60, 20, 70)
vled.sliceTime = 0.2
vled.slicesInFrame = 10
vled.B = 0.5e5
sim.scenario.addVLed(vled)
# Adding rf
rf = RF(0, 0, 0.85)
rf.sliceTime = 0.2
rf.slicesInFrame = 10
rf.B = 0.5e5
sim.scenario.addRF(rf)
# setting algorithm and number of connections
sim.set_allocation_algorithm(alloc)
sim.goalConnections = 60
# changing Dynamic
sim.lambdaS = 1
sim.mu = 30
# changing random wait limits
sim.upper_random_wait = 20
sim.lower_random_wait = 2
sim.lower_capacity_required = 1e5
sim.upper_capacity_required = 5e5
# initialize and run
sim.init()
sim.run()
Simulation Time Metrics
The simulator reports response time once a connection reaches first service.
Turnaround and total waiting time are reported for completed connections. A
completed connection is one that reaches a DEPARTURE event.
Available methods:
get_Response_Time(): per-connection time from arrival to first service.get_Average_Response_Time(): mean response time.get_Turnaround_Time(): per-connection time from arrival to completion.get_Average_Turnaround_Time(): mean turnaround time.get_Waiting_Time(): per-connection total waiting time.get_Average_Waiting_Time(): mean total waiting time.
The formulas used are:
response_time = first_service_time - arrival_time
turnaround_time = finish_time - arrival_time
waiting_time = turnaround_time - active_service_time
first_service_time is the first RESUME event for the connection.
finish_time is the connection DEPARTURE time. active_service_time
is the effective transmission time accumulated by the receiver.
In TDM simulations, waiting time includes the initial delay before first service and the idle gaps between assigned slots or frames. For this reason, waiting time can be larger than response time when a connection needs multiple slots.
By default, run() stops when the arrival target is reached. To calculate
turnaround and total waiting time for every generated connection, ask the
simulator to complete pending active connections without creating new arrivals.
Example:
sim.run(complete_active_connections=True)
avg_response_time = sim.get_Average_Response_Time()
avg_turnaround_time = sim.get_Average_Turnaround_Time()
avg_waiting_time = sim.get_Average_Waiting_Time()
print(f"Average Response Time: {avg_response_time:.4f} seconds")
print(f"Average Turnaround Time: {avg_turnaround_time:.4f} seconds")
print(f"Average Waiting Time: {avg_waiting_time:.4f} seconds")
More Examples
For additional examples and learning resources, see the examples/ directory:
Ready-to-Run Examples
Basic Example (examples/basic_example.py)
Complete minimal workflow showing:
Scenario creation with 4 VLEDs and 1 RF
Default allocation algorithm usage
Blocking, waiting, allocation, and time metrics collection
Simple simulation setup
Run with: python examples/basic_example.py
Advanced Example (examples/advanced_example.py)
Shows the custom allocation strategy from this page in a complete working example with:
Multiple VLEDs and RFs with different configurations
Custom SNR-based allocation implementation
Detailed metrics and statistics
Advanced parameter configuration
Run with: python examples/advanced_example.py
Interactive Tutorial
Jupyter Notebook (examples/vlc_simulation_example.ipynb)
Step-by-step interactive tutorial featuring:
Detailed markdown explanations for each step
Custom allocation algorithm with load balancing
TDM resource allocation walkthrough
Hybrid VLC/RF configuration (3 VLEDs + 1 RF)
Results analysis and visualization
Troubleshooting tips for common issues
Open with: jupyter notebook examples/vlc_simulation_example.ipynb
Or use in Google Colab for cloud-based execution.
Example Documentation
See examples/README.md for:
Detailed description of each example
Usage instructions
Key features and learning objectives
Custom allocation algorithm guide
Requirements and setup information
Next Steps
Return to Getting Started for installation and basic usage
Explore API Reference for complete API reference
Check out the example files for hands-on learning