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:

  1. Accept 4 parameters: receiver, connection, scenario, controller

  2. Return a tuple: (Controller.status, connection)

  3. 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 AP

  • Controller.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