Metadata-Version: 2.4
Name: vlcSim
Version: 0.7.0
Summary: Python Package of Event-Oriented Simulation for visible light communication
License: MIT
License-File: LICENSE.md
Keywords: vlc,visible light communication,simulation,event-oriented
Author: Danilo Bórquez-Paredes
Author-email: danilo.borquez.p@uai.cl
Requires-Python: >=3.9,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: numpy (>=1.24.0,<2.0.0)
Project-URL: Homepage, https://gitlab.com/DaniloBorquez/simvlc/
Project-URL: Repository, https://gitlab.com/DaniloBorquez/simvlc/
Description-Content-Type: text/markdown

# VLCSim - Visible Light Communication Simulator

![Python Version](https://img.shields.io/badge/python-3.9+-blue.svg)
![Poetry](https://img.shields.io/badge/poetry-2.3+-blue.svg)
![Coverage](https://img.shields.io/badge/coverage-72%25-brightgreen.svg)
![Tests](https://img.shields.io/badge/tests-173%20passing-brightgreen.svg)
![License](https://img.shields.io/badge/license-MIT-blue.svg)
![GitLab](https://img.shields.io/badge/gitlab-simvlc-orange.svg)
[![PyPI](https://img.shields.io/badge/PyPI-vlcSim-blue.svg)](https://pypi.org/project/vlcSim/)

VLCSim is an **Event-Oriented simulator** package for **Visible Light Communication (VLC)** systems. It provides a comprehensive framework for simulating dynamic VLC environments with support for resource allocation algorithms, RF fallback, and flexible room configurations.

## Features

- **Dynamic Environment**: Simulate real-time connections with arrivals and departures
- **Hybrid Communication**: VLC with RF fallback support
- **Flexible Resource Allocation**: Implement custom allocation algorithms
- **TDM Frame Management**: Time-Division Multiplexing with configurable slices
- **Configurable Parameters**: Customize VLC/room parameters for different scenarios
- **Event-Driven Simulation**: Efficient discrete event simulation engine
- **Performance Metrics**: Built-in SNR, capacity, blocking, waiting, and allocation metrics

## Installation

### From PyPI (Recommended)

```bash
# Install latest stable version
pip install vlcSim

# Or with Poetry
poetry add vlcSim
```

### From Source (Development)

```bash
git clone https://gitlab.com/DaniloBorquez/simvlc.git
cd simvlc

# Using Poetry (recommended)
poetry install

# Or using pip
pip install -e .
```

### Requirements

**Runtime dependencies:**
- `python` >= 3.9
- `numpy` >= 1.24.0: Numerical computations and random number generation

**Development dependencies:**
- `pytest` >= 7.4.0: Testing framework
- `pytest-cov` >= 4.1.0: Coverage reporting

See [pyproject.toml](pyproject.toml) for complete dependency specifications.

## Quick Start

### Using the Built-in Default Algorithm

The simplest way to use VLCSim - no custom allocation code required:

```python
from vlcsim import Simulator, VLed, RF

# Create a 10x10x3m room with 20 grids and 0.8 reflection coefficient
sim = Simulator(10.0, 10.0, 3.0, 20, 0.8)

# Add VLed access points
vled = VLed(5.0, 5.0, 3.0, 2, 2, 20, 60)  # x, y, z, nLedsX, nLedsY, power, theta
vled.sliceTime = 0.1
vled.slicesInFrame = 10
sim.scenario.addVLed(vled)

# Add RF access point as fallback
rf = RF(5.0, 5.0, 1.0)
rf.sliceTime = 0.1
rf.slicesInFrame = 10
sim.scenario.addRF(rf)

# Configure simulation parameters
sim.lambdaS = 3  # Arrival rate (Poisson)
sim.mu = 10  # Service rate (Exponential)
sim.goalConnections = 1000

# Initialize and run (default algorithm used automatically!)
sim.init()
sim.run()

# Get results
print(f"Blocking Probability: {sim.get_Blocking_Probability()}")
print(f"Waiting Probability: {sim.get_Waiting_Probability()}")
print(f"Attempted Connections: {sim.get_Attempted_Connections()}")
print(f"Allocated Connections: {sim.get_Allocated_Connections()}")
print(f"Waiting Connections: {sim.get_Waiting_Connections()}")
print(f"Blocked Connections: {sim.get_Blocked_Connections()}")
```

**The built-in default algorithm** (`Controller.default_alloc`):
- ✅ Selects VLeds with best SNR (maximum 5 connections per VLed)
- ✅ Falls back to RF if all VLeds are busy (maximum 12 connections per RF)
- ✅ Automatically allocates TDM frame/slice positions
- ✅ Works well for most VLC research scenarios

**You only need a custom algorithm if you want different allocation behavior.**

## Core Concepts

### Events

The simulator uses 5 types of events:

| Event         | Description                                  |
| ------------- | -------------------------------------------- |
| **ARRIVE**    | New connection arrives to the system         |
| **RESUME**    | Connection begins transmission               |
| **PAUSE**     | Connection pauses transmission               |
| **DEPARTURE** | Connection ends transmission                 |
| **RETRYING**  | Unallocated connection attempts to reconnect |

### Scenario Components

- **VLed**: Visible Light LED access points with configurable power and beam angle
- **RF**: Radio Frequency access points for fallback communication
- **Receiver**: Mobile devices with photodetector capabilities
- **Connection**: Represents a data transmission session with capacity requirements

### Resource Allocation

VLCSim includes a **built-in default allocation algorithm** that works for most scenarios. You can also implement **custom allocation algorithms** if you need different resource management strategies.

**When to use the default algorithm:**
- General VLC network simulations
- SNR-based allocation with RF fallback
- Standard research scenarios

**When to create a custom algorithm:**
- Testing novel allocation strategies
- Implementing specific QoS policies
- Research on resource optimization algorithms

## Custom Allocation Example

```python
from vlcsim import *

def custom_allocation_algorithm(receiver, connection: Connection, 
                                scenario: Scenario, controller: Controller):
    """Custom allocation: best VLed or RF fallback if overloaded"""
    vleds = scenario.vleds
    capacities = [scenario.capacityVled(receiver, vled) for vled in vleds]
    best_idx = capacities.index(max(capacities))
    
    # Use RF if VLed overloaded or no capacity
    if (controller.numberOfActiveConnections(vleds[best_idx]) > 5 
        or capacities[best_idx] == 0):
        connection.AP = scenario.rfs[0]
        connection.receiver.capacityFromAP = scenario.capacityRf(receiver, connection.AP)
    else:
        connection.AP = vleds[best_idx]
        connection.receiver.capacityFromAP = capacities[best_idx]
    
    # Calculate required slices
    numberOfSlices = connection.numberOfSlicesNeeded(
        connection.capacityRequired, connection.receiver.capacityFromAP
    )
    
    # Assign slices in frames
    actualSlice = connection.nextSliceInAPWhenArriving(connection.AP)
    assigned = 0
    
    # Try current frame
    for slice in range(actualSlice, connection.AP.slicesInFrame):
        if (not controller.framesState(connection.AP) 
            or not controller.framesState(connection.AP)[0][slice]):
            connection.assignFrameSlice(0, slice)
            assigned += 1
            if assigned == numberOfSlices:
                break
    
    # Assign remaining slices in future frames
    frameIndex = 1
    while assigned < numberOfSlices:
        if frameIndex >= len(controller.framesState(connection.AP)):
            connection.assignFrameSlice(frameIndex, 0)
        else:
            for slice in range(connection.AP.slicesInFrame):
                if not controller.framesState(connection.AP)[frameIndex][slice]:
                    connection.assignFrameSlice(frameIndex, slice)
                    break
        assigned += 1
        frameIndex += 1
    
    return Controller.status.ALLOCATED, connection

# Setup simulation with 20x20x2.15m room
sim = Simulator(20.0, 20.0, 2.15, 10, 0.8)

# Add 4 VLeds in a grid pattern
for x, y in [(-7.5, -7.5), (-7.5, 7.5), (7.5, -7.5), (7.5, 7.5)]:
    vled = VLed(x, y, 2.15, 60, 60, 20, 70)
    vled.sliceTime = 0.2
    vled.slicesInFrame = 10
    vled.B = 0.5e5
    sim.scenario.addVLed(vled)

# Add RF fallback
rf = RF(0, 0, 0.85)
rf.sliceTime = 0.2
rf.slicesInFrame = 10
rf.B = 0.5e5
sim.scenario.addRF(rf)

# Configure simulation parameters
sim.set_allocation_algorithm(custom_allocation_algorithm)
sim.goalConnections = 60
sim.lambdaS = 1  # 1 arrival per time unit
sim.mu = 30  # Average service time
sim.upper_random_wait = 20
sim.lower_random_wait = 2
sim.lower_capacity_required = 1e5
sim.upper_capacity_required = 5e5

# Run simulation
sim.init()
sim.run()
```

## Testing

VLCSim has comprehensive test coverage (72%) with 166 tests.

### Run Tests

```bash
# All tests
pytest tests/

# With coverage
pytest tests/ --cov=vlcsim --cov-report=term

# Specific module
pytest tests/test_controller.py -v
pytest tests/test_simulator.py -v
pytest tests/test_scenario.py -v
```

### Coverage by Module

| Module                            | Coverage |
| --------------------------------- | -------- |
| `vlcsim/__init__.py`              | 100%     |
| `vlcsim/scene/__init__.py`        | 100%     |
| `vlcsim/scene/access_point.py`    | 88%      |
| `vlcsim/scene/vled.py`            | 88%      |
| `vlcsim/scene/rf.py`              | 88%      |
| `vlcsim/scene/receiver.py`        | 88%      |
| `vlcsim/scene/scenario.py`        | 88%      |
| `vlcsim/controller/__init__.py`   | 100%     |
| `vlcsim/controller/connection.py` | 71%      |
| `vlcsim/controller/controller.py` | 71%      |
| `vlcsim/simulator.py`             | 49%      |
| **Total**                         | **72%**  |

## API Reference

### Simulator Class

Main simulation engine for event-driven VLC simulations.

```python
sim = Simulator(length, width, height, nGrids, rho)
sim.init()              # Initialize simulation
sim.run()               # Execute simulation
sim.set_allocation_algorithm(func)  # Set custom allocator
sim.print_initial_info()  # Display scenario configuration
```

**Key Parameters:**
- `lambdaS`: Arrival rate (connections per time unit)
- `mu`: Service rate parameter
- `goalConnections`: Total connections to simulate
- `seedX, seedY, seedZ`: Random seeds for position generation
- `upper_random_wait, lower_random_wait`: Retry delay bounds (seconds)
- `upper_capacity_required, lower_capacity_required`: Capacity bounds (bps)

**Key Metrics:**
- `get_Blocking_Probability()`: Ratio of definitively blocked (`NOT_ALLOCATED`) connections to attempted connections
- `get_Waiting_Probability()`: Ratio of currently waiting (`WAIT`) connections to attempted connections
- `get_Attempted_Connections()`: Connection arrivals processed by the simulator
- `get_Allocated_Connections()`: Connections assigned to an AP
- `get_Waiting_Connections()`: Connections currently waiting for retry
- `get_Blocked_Connections()`: Connections rejected with `NOT_ALLOCATED`
- `get_Response_Time()`: Per-connection time from arrival to first service
- `get_Average_Response_Time()`: Mean response time for completed connections
- `get_Turnaround_Time()`: Per-connection time from arrival to completion
- `get_Average_Turnaround_Time()`: Mean turnaround time for completed connections
- `get_Waiting_Time()`: Per-connection total waiting time, including TDM gaps between slots
- `get_Average_Waiting_Time()`: Mean total waiting time for completed connections

**Time Metrics:**

VLCSim reports time metrics for completed connections only:

```python
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 a connection.
`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, so it can be larger than
response time.

```python
sim.run()

avg_response_time = sim.get_Average_Response_Time()
avg_turnaround_time = sim.get_Average_Turnaround_Time()
avg_waiting_time = sim.get_Average_Waiting_Time()
```

### Scenario Class

Room configuration with access points.

```python
scenario.addVLed(vled)   # Add VLC access point
scenario.addRF(rf)       # Add RF access point
scenario.capacityVled(receiver, vled)  # Calculate VLC capacity
scenario.capacityRf(receiver, rf)      # Calculate RF capacity
```

### Controller Class

Manages connections and resource allocation.

```python
controller.assignConnection(connection, time)
controller.numberOfActiveConnections(ap)
controller.framesState(ap)
controller.APPosition(ap)
controller.init()  # Initialize controller with APs
```

### Connection Class

Represents a data transmission session.

```python
connection.assignFrameSlice(frame, slice)
connection.numberOfSlicesNeeded(capacity, rate)
connection.nextSliceInAPWhenArriving(ap)
```

**Key Properties:**
- `id`: Connection identifier
- `receiver`: Receiver object
- `AP`: Assigned access point (VLed or RF)
- `allocated`: Allocation status (boolean)
- `capacityRequired`: Required data rate (bps)
- `frameSlice`: Assigned TDM slices

## Configuration Parameters

### VLed Parameters

```python
vled = VLed(x, y, z, nLedsX, nLedsY, ledPower, theta)
```

- `x, y, z`: Position coordinates (meters)
- `nLedsX, nLedsY`: LED array dimensions (rows x columns)
- `ledPower`: LED power (mW)
- `theta`: Semi-angle at half illumination (degrees)
- `sliceTime`: Time slice duration (seconds)
- `slicesInFrame`: Number of slices per frame
- `B`: Bandwidth (Hz)

### RF Parameters

```python
rf = RF(x, y, z, bf=5e6, pf=40, BERf=10e-5)
```

- `x, y, z`: Position coordinates (meters)
- `bf`: Bandwidth (Hz)
- `pf`: Transmission power (dBm)
- `BERf`: Bit Error Rate target
- `sliceTime`: Time slice duration (seconds)
- `slicesInFrame`: Number of slices per frame

### Receiver Parameters

```python
receiver = Receiver(x, y, z, aDet, ts, index, fov)
```

- `x, y, z`: Position coordinates (meters)
- `aDet`: Detector area (m²)
- `ts`: Optical filter transmittance
- `index`: Refractive index
- `fov`: Field of view (degrees)

## Contributing

Contributions are welcome! We follow Git-Flow workflow and Conventional Commits standards.

**Quick Start:**

1. Fork the repository on GitLab
2. Clone your fork and set up development environment
   ```bash
   git clone https://gitlab.com/YOUR_USERNAME/simvlc.git
   cd simvlc
   poetry install
   ```
3. Create a feature branch using Git-Flow
   ```bash
   git flow feature start feature-name
   ```
4. Make your changes with tests
5. Run tests and ensure they pass
   ```bash
   poetry run pytest tests/ --cov=vlcsim
   ```
6. Commit changes with descriptive messages (use [Conventional Commits](https://www.conventionalcommits.org/))
   ```bash
   git commit -m 'feat: add new feature description'
   ```
7. Finish the feature branch
   ```bash
   git flow feature finish feature-name
   ```
8. Push to your fork and create a Merge Request

**For detailed guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md)**

Also see:
- [VERSIONING.md](VERSIONING.md) - Release workflow and Git-Flow process
- [CHANGELOG.md](CHANGELOG.md) - Project history and version changes

## Development

### Project Structure

```
vlcsim/
├── vlcsim/
│   ├── __init__.py         # Package initialization
│   ├── controller/         # Connection management and allocation module (modular structure)
│   │   ├── __init__.py       # Controller package exports
│   │   ├── connection.py     # Connection class (transmission session)
│   │   └── controller.py     # Controller class (resource allocation)
│   ├── scene/              # Physical infrastructure module (modular structure)
│   │   ├── __init__.py       # Scene package exports
│   │   ├── access_point.py   # AccessPoint base class
│   │   ├── vled.py           # VLed (Visible Light LED) class
│   │   ├── rf.py             # RF (Radio Frequency) class
│   │   ├── receiver.py       # Receiver device class
│   │   └── scenario.py       # Scenario environment class
│   └── simulator.py        # Event-driven simulation engine
├── tests/
│   ├── test_controller.py   # Controller tests (42 tests)
│   ├── test_simulator.py    # Simulator tests (40 tests)
│   ├── test_connection.py   # Connection tests (29 tests)
│   ├── test_scenario.py     # Scenario tests
│   ├── test_vled.py         # VLed tests
│   ├── test_rf.py           # RF tests
│   └── test_receiver.py     # Receiver tests
├── docs/                # Sphinx documentation
├── CHANGELOG.md         # Version history
├── VERSIONING.md        # Release workflow guide
├── README.md            # This file
├── pyproject.toml       # Poetry configuration
└── requirements.txt     # Pip fallback dependencies
```

### Setting Up Development Environment

```bash
# Clone repository
git clone https://gitlab.com/DaniloBorquez/simvlc.git
cd simvlc

# Install with Poetry (recommended)
poetry install

# Or with pip
pip install -e .

# Run tests
poetry run pytest tests/

# Run tests with coverage
poetry run pytest tests/ --cov=vlcsim --cov-report=html

# View coverage report
open htmlcov/index.html

# Build package (uses dynamic versioning from Git tags)
poetry build
```

### Release Process

This project uses **poetry-dynamic-versioning** for automatic version management from Git tags.
For detailed release instructions, see [VERSIONING.md](VERSIONING.md).

```bash
# Quick release workflow (Git-Flow)
git flow release start 0.5.0
# Update CHANGELOG.md
git flow release finish 0.5.0
git push origin --all && git push origin --tags
```

Releases to PyPI are automatically triggered when version tags are pushed to the `main` branch.

## License

This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.

## Project Statistics

- **Lines of Code**: ~2,500
- **Test Coverage**: 72%
- **Number of Tests**: 166 passing
- **Python Version**: 3.9+
- **Modules**: 3 main modules (controller, scene, simulator)
- **Package Manager**: Poetry with dynamic versioning
- **Latest Release**: See [CHANGELOG.md](CHANGELOG.md)

## Acknowledgments

- Based on research in Visible Light Communication systems
- Event-driven simulation methodology
- TDM resource allocation strategies
- Hybrid VLC/RF communication systems

## Contact

For questions, issues, or contributions, please:
- Open an issue on GitLab: https://gitlab.com/DaniloBorquez/vlcsim/-/issues
- Submit a merge request
- Contact the maintainers

---

**Made with dedication for VLC research and simulation**

