blob: b93a5dee5308fd1c009ae84f893bc2384d107759 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
#include "specs.h"
#include <detector.h>
#include <cstdlib> // system()
#include <random>
#include <complex>
using namespace std;
void Detector::on_port_in_changed()
{
// always initialize memory
m_memory_in[0] = 0;
// rng seed
init();
while (true) {
// Wait for a new input signal
wait();
const auto &p_in_read = p_in->read();
auto cur_wavelength_id = p_in_read.m_wavelength_id;
// Updating the field memory
m_memory_in[cur_wavelength_id] = p_in_read.m_field;
m_event_manual_trigger.notify();
}
}
void Detector::on_time_tick()
{
sc_time sampling_time = sc_time(m_sampling_time, SC_SEC);
if (sampling_time.value() == 0)
sampling_time = sc_time::from_value(1);
OpticalSignal::field_type total_field;
OpticalSignal::field_type::value_type total_power;
double photocurrent;
// Wait for enable signal
if (! enable.read().to_bool())
{
// cout << name() << " waiting for enable" << endl;
wait(enable.posedge_event());
cout << name() << " was enabled" << endl;
}
while(true)
{
if (sc_pending_activity()) {
wait(sampling_time, m_event_manual_trigger);
//wait(m_event_manual_trigger); // if only time-averaged signal is of interest
} else {
/* wait for reset */
//TODO (see CWSource code)
wait(); // effectively wait until the end of the simulation
}
/* Get current time tk*/
double tk = sc_time_stamp().to_seconds();
/* Calculate current output value based on present fields */
/* Calculate sum of fields at current time*/
total_field = 0;
total_power = 0;
for (auto field : m_memory_in)
{
double wl = specsGlobalConfig.wavelengths_vector[field.first];
double freq = 299792458 / wl;
total_field += field.second * exp(complex<double>(0, 2 * M_PI * freq * tk));
total_power += norm(field.second);
}
if (norm(total_field) == 0)
total_field = 1e-20*m_rngDist(m_rngGen);
photocurrent = norm(total_field) * m_responsivity_A_W;
m_cur_readout = photocurrent + (!m_noiseBypass)*noise_gen(photocurrent) + m_darkCurrent_A;
m_cur_readout_no_interf = total_power * m_responsivity_A_W + (!m_noiseBypass)*noise_gen(photocurrent) + m_darkCurrent_A;
//m_cur_readout = total_field.real();
// Write to output port
//p_readout->write(m_cur_readout);
}
}
/*
Generates a current noise to be applied to the noiseless_readout,
calculated from the responsivity.
Considers: TIA input referred, shot, and thermal
*/
double Detector::noise_gen(const double &noiseless_readout)
{
// elementary charge
const double q = 1.60217e-19;
// Boltzmann constant
const double K = 1.38064e-23;
double inoise_tia_2 = m_opFreq_Hz*pow(m_iTIA,2);
double inoise_shot_2 = m_opFreq_Hz*2*q*(noiseless_readout+m_darkCurrent_A);
double inoise_therm_2 = m_opFreq_Hz*4*K*m_temp_K/m_equivR_Ohm;
// the RMS value is also the variance of the random variable
double inoise_rms = inoise_tia_2 + inoise_shot_2 + inoise_therm_2;
// mean = noiseless, std = sqrt(variance)
// the second element of the product is the gaussian(0,1)
return sqrt(inoise_rms) * m_rngDist(m_rngGen);
}
/*
To be implemented in the future, user can specify the wavelength response
of the photodiode
*/
double Detector::wavelength_dependent_responsivity(const double &wavelength)
{
(void)wavelength;
if(true)
{
return m_responsivity_A_W;
}
else
{
// custom responsivity curve
return 0; // should return the new responsivity
}
}
void Detector::init()
{
std::random_device rd; // Will be used to obtain a seed for the random number engine
m_rngGen.seed(rd());
}
|