detectors

lowpassdetector

responsivity

The detected photo-current \(I_p~[C/s]\) can be described in terms of the optical power \(P_o~[W]\) through the quantum efficiency \(\eta\) and the carrier frequency \(f=c/\lambda~[1/s]\) of the light:

\[\begin{align*} I_p = \eta \frac{q}{h f}P_o = \eta \frac{q \lambda}{h c}P_o \end{align*}\]

However, it’s often more useful to describe it in terms of a single quantity \(r~[A/W]\):

\[\begin{align*} I_p &= rP_o, \end{align*}\]

where we defined \(r~[A/W]\) as the responsivity of the detector. At a wavelength of \(1550nm\) and for a quantum efficiency of \(\eta=1\), we have:

\[\begin{align*} r &= \eta \frac{q \lambda}{h c} = 1.25 A/W, \end{align*}\]

hence a default value of 1 for the responsivity is appropriate.

implementation

A simple detector based on low-pass filtering the signal.

The LospassDetector performs the (differentiable) PyTorch equivalent of the following numpy/scipy function:

from scipy.signal import butter, lfilter
def detect(x, bitrate, samplerate, cutoff_frequency, responsivity, filter_order):
    normal_cutoff = cutoff_frequency / ( 0.5 * samplerate)
    b, a = butter(N=filter_order, Wn=normal_cutoff, btype='lowpass', analog=False)
    return lfilter(b, a, responsivity * x, axis=0)
class photontorch.detectors.lowpassdetector.LowpassDetector(bitrate=40000000000.0, samplerate=160000000000.0, cutoff_frequency=20000000000.0, filter_order=4, responsivity=1.0)

Bases: photontorch.nn.nn.Module

Detect by lowpass filtering the signal.

The LowpassDetector transforms a raw optical power [W] to a detection current [A].

__init__(bitrate=40000000000.0, samplerate=160000000000.0, cutoff_frequency=20000000000.0, filter_order=4, responsivity=1.0)
Parameters
  • bitrate (float) – [1/s] data rate of the signal to filter

  • samplerate (float) – [1/s] sample rate of the signal to filter

  • cutoff_frequency (float) – [1/s] cutoff frequency of the detector

  • filter_order (int) – filter order of the butter filter

  • responsivity (float) – [A/W] resonsivity of the detector

forward(signal, num_splits=1, split_padding=5, bitrate=None, samplerate=None, cutoff_frequency=None, filter_order=None, responsivity=None)

detect a bitstream by low-pass filtering

Parameters
  • signal (Tensor) – [W] optical power to detect.

  • num_splits (int) – number of parallel parts to split the timestream in

  • split_padding (int) – number of bits padding when splitting the timstream in parts.

  • bitrate (optional, float) – [1/s] override data rate of the signal to filter

  • samplerate (optional, float) – [1/s] override sample rate of the signal to filter

  • cutoff_frequency (optional, float) – [1/s] override cutoff frequency of the detector

  • filter_order (optional, int) – override filter order of the butter filter

  • responsivity (optional, float) – [A/W] override resonsivity of the detector

Note

If a bitrate and/or samplerate can be found in the current environment, those values will be regarded as keyword arguments and hence get precedence over the values given during the detector initialization.

Note

Splitting the signal in parts to be processed in parallel can considerably speed up the detection process. However, it remains an approximation, as in theory each detected signal point depends (with an exponentially decreasing factor) on all previous detected signals.

To partly circumvent any large discontinuities when recomposing the detected signal from the detected parts, a split_padding should be defined, which pads a number of bits from the previous / next signal part before and after the current signal part to detect.

training

photodetector

responsivity

As mentioned above, a responsivity of \(r=1 A/W\) is a valid value, but almost always it will be lower. If the detected signal is not as noisy as expected, you probably used a too high responsivity.

thermal noise

On top of the detected current, thermal noise should be added. The thermal noise variance \(\sigma_t^2\) [\(C^2/s^2\)] is given by:

\[\begin{align*} \sigma_t^2 &= N_t^2 f_c, \end{align*}\]

with \(f_c~[1/s]\) the cutoff frequency of the signal and \(N_t~[C/\sqrt s]\) the thermal noise spectral density. This represenation (which is the representation used in VPI for example) requires you to use a quantity with \(N_t~[C/\sqrt s]\) with weird units. We therefore prefer another representation (see for example wikipedia):

\[\begin{align*} \sigma_t^2 = \frac{4kT}{R_L} f_c \end{align*}\]

To find a good default value for the load resistance \(R_L\), we can equate this equation with the previous one using the default VPI value for \(N_t=10^{-11}C/\sqrt s\):

\[\begin{align} R_L = 166 \Omega \end{align}\]

where we assumed for the room temparture \(T=300K\).

shot noise

The shot noise variance \(\sigma_t^2\) [\(C^2/s^2\)] for a PIN photodetector is given by:

\[\begin{align*} \sigma_s^2 = 2 q (I_p + I_d)f_c \end{align*}\]

with \(q~[C]\) the elementary charge and \(I_d\) the dark current of the photodetector. Notice that this power is dependent on the photocurrent \(I_p~[C/s]\) itself.

In some representations, \(\mu_p=\left< I_p \right>~[C/s]\) is used instead. We choose not to take this average to have a more accurate reprentation. Moreover, low-pass filtering already takes a kind of moving average into account.

total noise

The total post-detection noise variance \(\sigma_p^2\) [\(C^2/s^2\)] now depends on the thermal noise variance \(\sigma_t^2\) and the shot noise variance \(\sigma_s^2\):

\[\begin{align*} \sigma_p^2 &= \sigma_t^2 + \sigma_s^2 \end{align*}\]

implementation

Photodetector

The photodetector in this module transforms a raw optical power [W] to a (possibly noisy) detection current [A]. It takes thermal noise and shot noise into account.

class photontorch.detectors.photodetector.Photodetector(bitrate=40000000000.0, samplerate=160000000000.0, cutoff_frequency=20000000000.0, responsivity=1.0, dark_current=1e-10, load_resistance=166, filter_order=4, seed=None)

Bases: photontorch.detectors.lowpassdetector.LowpassDetector

Realistic Photodector Model.

The photodetector transforms a raw optical power [W] to a (possibly noisy) detection current [A].

This photodetector takes thermal noise and shot noise into account.

__init__(bitrate=40000000000.0, samplerate=160000000000.0, cutoff_frequency=20000000000.0, responsivity=1.0, dark_current=1e-10, load_resistance=166, filter_order=4, seed=None)
Parameters
  • bitrate (float) – [1/s] data rate of the signal to filter

  • samplerate (float) – [1/s] sample rate of the signal to filter

  • cutoff_frequency (float) – [1/s] cutoff frequency of the detector

  • responsivity (float) – [A/W] responsivity of the photodector

  • dark_current (float) – [A] dark current adding to the noise

  • load_resistance (float) – [Ohm] load resistance of the detector

  • filter_order (int) – filter order of the butter filter

  • seed (int) – random seed for the detector noise

forward(signal, num_splits=1, split_padding=5, bitrate=None, samplerate=None, cutoff_frequency=None, responsivity=None, filter_order=None, dark_current=None, load_resistance=None)

detect a bitstream by first adding physical noise and then low-pass filtering.

Parameters
  • signal (Tensor) – signal to detect.

  • num_splits (int) – number of parallel parts to split the timestream in

  • split_padding (int) – number of bits padding when splitting the timstream in parts.

  • bitrate (optional, float) – [1/s] override data rate of the signal to filter

  • samplerate (optional, float) – [1/s] override sample rate of the signal to filter

  • cutoff_frequency (optional, float) – [1/s] override cutoff frequency of the detector

  • filter_order (optional, int) – override filter order of the butter filter

  • responsivity (optional, float) – [A/W] override responsivity of the photodector

  • dark_current (optional, float) – [A] override dark current adding to the noise

  • load_resistance (optional, float) – [Ohm] override load resistance of the detector

Note

If a bitrate and/or samplerate can be found in the current environment, those values will be regarded as keyword arguments and hence get precedence over the values given during the detector initialization.

Note

Splitting the signal in parts to be processed in parallel can considerably speed up the detection process. However, it remains an approximation, as in theory each detected signal point depends (with an exponentially decreasing factor) on all previous detected signals.

To partly circumvent any large discontinuities when recomposing the detected signal from the detected parts, a split_padding should be defined, which pads a number of bits from the previous / next signal part before and after the current signal part to detect.

training