"""Receiver device class for VLC simulation."""
import numpy as np
import math as m
from typing import Optional, Any
[docs]
class Receiver:
"""Represents a receiver device in the VLC scenario.
The Receiver class models a photodetector device with all physical and
electrical parameters required for VLC simulation, including optical and
electrical properties, timing information, and connection state.
Attributes:
receiversCreated: Class variable tracking the total number of receivers
created.
Properties:
- Position: x, y, z coordinates and position vector
- Optical: aDet (detector area), ts (symbol period), index (refractive index),
fov (field of view), gCon (concentrator gain)
- Electrical: q (electronic charge), s (photodetector responsivity),
b (bandwidth), ibg (background current), cb (Boltzmann constant),
tk (temperature), gv (voltage gain), n (capacitance), fr (noise factor),
gm (transconductance)
- Experimental: i1, i2 (calibration constants)
- Connection: capacityFromAP, timeFirstConnected, goalTime, timeActive,
timeFinished
Example:
>>> receiver = Receiver(
... x=2.5, y=3.0, z=0.85,
... aDet=1e-4, ts=0.1, index=1.5, fov=60.0
... )
>>> receiver.ID
0
"""
receiversCreated = 0
"""Class variable tracking the total number of receivers created."""
[docs]
def __init__(
self,
x: float,
y: float,
z: float,
aDet: float,
ts: float,
index: float,
fov: float,
q: float = 1.6e-19,
s: float = 0.54,
b: float = 10e6,
ibg: float = 5.1e-3,
cb: float = 1.380649e-23,
tk: float = 298.0,
a: float = 1.0,
gv: float = 10.0,
n: float = 1.12e-6,
fr: float = 1.5,
gm: float = 3e-2,
i1: float = 0.562,
i2: float = 0.0868,
) -> None:
"""Initialize a receiver device with physical and electrical properties.
Args:
x: X coordinate of the receiver position in meters
y: Y coordinate of the receiver position in meters
z: Z coordinate of the receiver position in meters
aDet: Photodetector active area in m²
ts: Symbol period in seconds
index: Refractive index of the optical concentrator
fov: Field of view half-angle in degrees
q: Electronic charge in coulombs (default: 1.6e-19 C)
s: Photodetector responsivity in A/W (default: 0.54 A/W)
b: Receiver bandwidth in Hz (default: 10 MHz)
ibg: Background current in amperes (default: 5.1e-3 A)
cb: Boltzmann constant in J/K (default: 1.380649e-23 J/K)
tk: Absolute temperature in Kelvin (default: 298.0 K)
a: Optical filter gain (default: 1.0)
gv: Open-loop voltage gain (default: 10.0)
n: Photodetector capacitance per unit area in F/m² (default: 1.12e-6 F/m²)
fr: FET channel noise factor (default: 1.5)
gm: FET transconductance in S (default: 3e-2 S)
i1: Experimental calibration constant (default: 0.562)
i2: Experimental calibration constant (default: 0.0868)
Note:
The receiver is automatically assigned a unique ID upon creation.
The concentrator gain (gCon) is calculated from the index and FOV.
"""
self.__x = x
self.__y = y
self.__z = z
self.__aDet = aDet
self.__ts = ts
self.__index = index
self.__fov = fov
self.__q = q
self.__s = s
self.__b = b
self.__ibg = ibg
self.__cb = cb
self.__tk = tk
self.__a = a
self.__gv = gv
self.__n = n
self.__fr = fr
self.__gm = gm
self.__i1 = i1
self.__i2 = i2
self.__timeFirstConnected: Optional[float] = None
self.__goalTime: Optional[float] = None
self.__timeActive: float = 0.0
self.__timeFinished: Optional[float] = None
self.__capacityFromAP: Optional[float] = None
self.__gCon = (index**2) / (m.sin(m.radians(fov)) ** 2)
self.__position = np.array([x, y, z])
self.__ID = Receiver.receiversCreated
Receiver.receiversCreated += 1
@property
def capacityFromAP(self) -> Optional[float]:
"""Get the capacity allocated from the access point.
Returns:
Optional[float]: Capacity from AP in bits/s, or None if not connected
"""
return self.__capacityFromAP
@capacityFromAP.setter
def capacityFromAP(self, value: float) -> None:
"""Set the capacity allocated from the access point.
Args:
value: Capacity value in bits/s
"""
self.__capacityFromAP = value
@property
def ID(self) -> int:
"""Get the unique identifier of this receiver.
Returns:
int: Unique receiver ID assigned at creation
"""
return self.__ID
@ID.setter
def ID(self, value: int) -> None:
"""Set the unique identifier of this receiver.
Args:
value: The ID value to set
"""
self.__ID = value
@property
def x(self) -> float:
"""Get the X coordinate of the receiver.
Returns:
float: X coordinate in meters
"""
return self.__x
@x.setter
def x(self, value: float) -> None:
"""Set the X coordinate of the receiver.
Args:
value: X coordinate in meters
"""
self.__x = value
@property
def y(self) -> float:
"""Get the Y coordinate of the receiver.
Returns:
float: Y coordinate in meters
"""
return self.__y
@y.setter
def y(self, value: float) -> None:
"""Set the Y coordinate of the receiver.
Args:
value: Y coordinate in meters
"""
self.__y = value
@property
def z(self) -> float:
"""Get the Z coordinate of the receiver.
Returns:
float: Z coordinate in meters
"""
return self.__z
@z.setter
def z(self, value: float) -> None:
"""Set the Z coordinate of the receiver.
Args:
value: Z coordinate in meters
"""
self.__z = value
@property
def aDet(self) -> float:
"""Get the photodetector active area.
Returns:
float: Photodetector active area in m²
"""
return self.__aDet
@aDet.setter
def aDet(self, value: float) -> None:
"""Set the photodetector active area.
Args:
value: Photodetector active area in m²
"""
self.__aDet = value
@property
def ts(self) -> float:
"""Get the symbol period.
Returns:
float: Symbol period in seconds
"""
return self.__ts
@ts.setter
def ts(self, value: float) -> None:
"""Set the symbol period.
Args:
value: Symbol period in seconds
"""
self.__ts = value
@property
def index(self) -> float:
"""Get the refractive index of the optical concentrator.
Returns:
float: Refractive index (dimensionless)
"""
return self.__index
@index.setter
def index(self, value: float) -> None:
"""Set the refractive index of the optical concentrator.
Args:
value: Refractive index value
"""
self.__index = value
@property
def fov(self) -> float:
"""Get the field of view half-angle.
Returns:
float: Field of view half-angle in degrees
"""
return self.__fov
@fov.setter
def fov(self, value: float) -> None:
"""Set the field of view half-angle.
Args:
value: Field of view half-angle in degrees
"""
self.__fov = value
@property
def gCon(self) -> float:
"""Get the concentrator gain.
This is a read-only property calculated from the refractive index and FOV.
Returns:
float: Concentrator gain (dimensionless)
"""
return self.__gCon
@property
def position(self) -> np.ndarray[Any, np.dtype[np.float64]]:
"""Get the position vector of the receiver.
Returns:
np.ndarray[Any, np.dtype[np.float64]]: Position as numpy array [x, y, z]
"""
return self.__position
@property
def q(self) -> float:
"""Get the electronic charge.
Returns:
float: Electronic charge in coulombs (default: 1.6e-19 C)
"""
return self.__q
@q.setter
def q(self, value: float) -> None:
"""Set the electronic charge.
Args:
value: Electronic charge in coulombs
"""
self.__q = value
@property
def s(self) -> float:
"""Get the photodetector responsivity.
Returns:
float: Photodetector responsivity in A/W (default: 0.54 A/W)
"""
return self.__s
@s.setter
def s(self, value: float) -> None:
"""Set the photodetector responsivity.
Args:
value: Photodetector responsivity in A/W
"""
self.__s = value
@property
def b(self) -> float:
"""Get the receiver bandwidth.
Returns:
float: Receiver bandwidth in Hz (default: 10 MHz)
"""
return self.__b
@b.setter
def b(self, value: float) -> None:
"""Set the receiver bandwidth.
Args:
value: Receiver bandwidth in Hz
"""
self.__b = value
@property
def ibg(self) -> float:
"""Get the background current.
Returns:
float: Background current in amperes (default: 5.1e-3 A)
"""
return self.__ibg
@ibg.setter
def ibg(self, value: float) -> None:
"""Set the background current.
Args:
value: Background current in amperes
"""
self.__ibg = value
@property
def cb(self) -> float:
"""Get the Boltzmann constant.
Returns:
float: Boltzmann constant in J/K (default: 1.380649e-23 J/K)
"""
return self.__cb
@cb.setter
def cb(self, value: float) -> None:
"""Set the Boltzmann constant.
Args:
value: Boltzmann constant in J/K
"""
self.__cb = value
@property
def tk(self) -> float:
"""Get the absolute temperature.
Returns:
float: Temperature in Kelvin (default: 298.0 K)
"""
return self.__tk
@tk.setter
def tk(self, value: float) -> None:
"""Set the absolute temperature.
Args:
value: Temperature in Kelvin
"""
self.__tk = value
@property
def a(self) -> float:
"""Get the optical filter gain.
Returns:
float: Optical filter gain (dimensionless, default: 1.0)
"""
return self.__a
@a.setter
def a(self, value: float) -> None:
"""Set the optical filter gain.
Args:
value: Optical filter gain value
"""
self.__a = value
@property
def gv(self) -> float:
"""Get the open-loop voltage gain.
Returns:
float: Open-loop voltage gain (dimensionless, default: 10.0)
"""
return self.__gv
@gv.setter
def gv(self, value: float) -> None:
"""Set the open-loop voltage gain.
Args:
value: Open-loop voltage gain value
"""
self.__gv = value
@property
def n(self) -> float:
"""Get the photodetector capacitance per unit area.
Returns:
float: Capacitance in F/m² (default: 1.12e-6 F/m²)
"""
return self.__n
@n.setter
def n(self, value: float) -> None:
"""Set the photodetector capacitance per unit area.
Args:
value: Capacitance in F/m²
"""
self.__n = value
@property
def fr(self) -> float:
"""Get the FET channel noise factor.
Returns:
float: FET noise factor (dimensionless, default: 1.5)
"""
return self.__fr
@fr.setter
def fr(self, value: float) -> None:
"""Set the FET channel noise factor.
Args:
value: FET noise factor value
"""
self.__fr = value
@property
def gm(self) -> float:
"""Get the FET transconductance.
Returns:
float: FET transconductance in siemens (default: 3e-2 S)
"""
return self.__gm
@gm.setter
def gm(self, value: float) -> None:
"""Set the FET transconductance.
Args:
value: FET transconductance in siemens
"""
self.__gm = value
@property
def i1(self) -> float:
"""Get the first experimental calibration constant.
Returns:
float: Calibration constant (default: 0.562)
"""
return self.__i1
@i1.setter
def i1(self, value: float) -> None:
"""Set the first experimental calibration constant.
Args:
value: Calibration constant value
"""
self.__i1 = value
@property
def i2(self) -> float:
"""Get the second experimental calibration constant.
Returns:
float: Calibration constant (default: 0.0868)
"""
return self.__i2
@i2.setter
def i2(self, value: float) -> None:
"""Set the second experimental calibration constant.
Args:
value: Calibration constant value
"""
self.__i2 = value
@property
def timeFirstConnected(self) -> Optional[float]:
"""Get the time when the receiver was first connected.
Returns:
Optional[float]: Connection time in seconds, or None if not connected yet
"""
return self.__timeFirstConnected
@timeFirstConnected.setter
def timeFirstConnected(self, value: float) -> None:
"""Set the time when the receiver was first connected.
Args:
value: Connection time in seconds
"""
self.__timeFirstConnected = value
@property
def goalTime(self) -> Optional[float]:
"""Get the goal connection time for this receiver.
The goal time represents the required connection duration based on SNR
and capacity requirements.
Returns:
Optional[float]: Goal time in seconds, or None if not set
"""
return self.__goalTime
@goalTime.setter
def goalTime(self, value: float) -> None:
"""Set the goal connection time for this receiver.
Args:
value: Goal time in seconds
"""
self.__goalTime = value
@property
def timeActive(self) -> float:
"""Get the effective time the receiver has been connected.
Returns:
float: Active connection time in seconds
"""
return self.__timeActive
@timeActive.setter
def timeActive(self, value: float) -> None:
"""Set the effective time the receiver has been connected.
Args:
value: Active time in seconds
"""
self.__timeActive = value
@property
def timeFinished(self) -> Optional[float]:
"""Get the time when the receiver finished its connection.
Returns:
Optional[float]: Disconnection time in seconds, or None if still active
"""
return self.__timeFinished
@timeFinished.setter
def timeFinished(self, value: float) -> None:
"""Set the time when the receiver finished its connection.
Args:
value: Disconnection time in seconds
"""
self.__timeFinished = value