simcats 1.1.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simcats/__init__.py +4 -3
- simcats/_default_configs.py +129 -13
- simcats/_simulation.py +451 -69
- simcats/config_samplers/_GaAs_v1_random_variations_v3_config_sampler.py +1059 -0
- simcats/config_samplers/__init__.py +9 -0
- simcats/distortions/_distortion_interfaces.py +1 -1
- simcats/distortions/_dot_jumps.py +8 -6
- simcats/distortions/_random_telegraph_noise.py +4 -4
- simcats/distortions/_transition_blurring.py +5 -5
- simcats/distortions/_white_noise.py +2 -2
- simcats/ideal_csd/geometric/_generate_lead_transition_mask.py +3 -3
- simcats/ideal_csd/geometric/_get_electron_occupation.py +5 -5
- simcats/ideal_csd/geometric/_ideal_csd_geometric.py +5 -5
- simcats/ideal_csd/geometric/_ideal_csd_geometric_class.py +9 -9
- simcats/ideal_csd/geometric/_tct_bezier.py +5 -5
- simcats/sensor/__init__.py +10 -6
- simcats/sensor/{_generic_sensor.py → _sensor_generic.py} +1 -1
- simcats/sensor/_sensor_interface.py +164 -11
- simcats/sensor/_sensor_rise_glf.py +229 -0
- simcats/sensor/_sensor_scan_sensor_generic.py +929 -0
- simcats/sensor/barrier_function/__init__.py +9 -0
- simcats/sensor/barrier_function/_barrier_function_glf.py +280 -0
- simcats/sensor/barrier_function/_barrier_function_interface.py +43 -0
- simcats/sensor/barrier_function/_barrier_function_multi_glf.py +157 -0
- simcats/sensor/deformation/__init__.py +9 -0
- simcats/sensor/deformation/_sensor_peak_deformation_circle.py +109 -0
- simcats/sensor/deformation/_sensor_peak_deformation_interface.py +65 -0
- simcats/sensor/deformation/_sensor_peak_deformation_linear.py +77 -0
- simcats/support_functions/__init__.py +11 -3
- simcats/support_functions/_generalized_logistic_function.py +146 -0
- simcats/support_functions/_linear_algebra.py +171 -0
- simcats/support_functions/_parameter_sampling.py +108 -19
- simcats/support_functions/_pixel_volt_transformation.py +24 -0
- simcats/support_functions/_reset_offset_mu_sens.py +43 -0
- {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/METADATA +93 -29
- simcats-2.0.0.dist-info/RECORD +53 -0
- {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/WHEEL +1 -1
- simcats-1.1.0.dist-info/RECORD +0 -37
- /simcats/sensor/{_gaussian_sensor_peak.py → _sensor_peak_gaussian.py} +0 -0
- /simcats/sensor/{_lorentzian_sensor_peak.py → _sensor_peak_lorentzian.py} +0 -0
- {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info/licenses}/LICENSE +0 -0
- {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains a sampler for SimCATS configurations, corresponding to the random_variations_v3 parameters.
|
|
3
|
+
The configurations can be used to initialize an object of the simulation class.
|
|
4
|
+
|
|
5
|
+
@author: f.hader, b.papajewski
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
import random
|
|
10
|
+
from copy import deepcopy
|
|
11
|
+
from typing import Dict, List, Tuple
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from simcats import Simulation, default_configs
|
|
16
|
+
from simcats.distortions import (
|
|
17
|
+
OccupationTransitionBlurringFermiDirac,
|
|
18
|
+
SensorPotentialPinkNoise,
|
|
19
|
+
SensorResponseWhiteNoise,
|
|
20
|
+
OccupationDistortionInterface, SensorPotentialDistortionInterface, SensorResponseDistortionInterface,
|
|
21
|
+
SensorPotentialRTN, SensorResponseRTN, OccupationDotJumps,
|
|
22
|
+
)
|
|
23
|
+
from simcats.ideal_csd import IdealCSDGeometric
|
|
24
|
+
from simcats.sensor import SensorGeneric, SensorPeakLorentzian, SensorScanSensorGeneric, SensorPeakInterface, \
|
|
25
|
+
SensorRiseGLF, SensorRiseInterface
|
|
26
|
+
from simcats.sensor.barrier_function import BarrierFunctionGLF, BarrierFunctionInterface
|
|
27
|
+
from simcats.sensor.deformation import SensorPeakDeformationLinear, SensorPeakDeformationCircle
|
|
28
|
+
from simcats.support_functions import (
|
|
29
|
+
NormalSamplingRange,
|
|
30
|
+
ExponentialSamplingRange,
|
|
31
|
+
rotate_points, UniformSamplingRange,
|
|
32
|
+
inverse_glf
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = []
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def sample_random_variations_v3_config(sensor_type: str = "SensorGeneric",
|
|
39
|
+
quality_multiplier: float = 1.0,
|
|
40
|
+
compensated_sensor: bool = False,
|
|
41
|
+
set_sensor_potential_offset_to_steepest_point: bool = False) -> Dict:
|
|
42
|
+
"""
|
|
43
|
+
Samples a full random_variations_v3 SimCATS config.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
sensor_type: The type of sensor implementation to use. Can be either "SensorGeneric" or
|
|
47
|
+
"SensorScanSensorGeneric". Defaults to "SensorGeneric".
|
|
48
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for distortions etc. is
|
|
49
|
+
used. This basically allows to restrict configurations to better data quality, as future improvements of the
|
|
50
|
+
sample quality are expected. The parameter further restricts the preset ranges for distortions (reducing the
|
|
51
|
+
allowed maximum for distortions) and things like the height of Coulomb peaks (increasing the minimum). The
|
|
52
|
+
factor must be in the range (0.0, 1.0]. Defaults to 1.0.
|
|
53
|
+
compensated_sensor: Whether the effect of the double quantum dot on the sensor dot is compensated (lever-arms of
|
|
54
|
+
the double dot gate voltages on the sensor are close to zero). Defaults to False.
|
|
55
|
+
set_sensor_potential_offset_to_steepest_point: Whether the steepest point of the sensor function is determined
|
|
56
|
+
and the corresponding potential is set as the potential offset (offset_mu_sens). This enables simple
|
|
57
|
+
"retuning" of the sensor by always resetting the potential offset before every CSD measurement. Defaults to
|
|
58
|
+
False.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Dict: Full config for the SimCATS Simulation class.
|
|
62
|
+
"""
|
|
63
|
+
if not (quality_multiplier > 0.0 and quality_multiplier <= 1.0):
|
|
64
|
+
raise ValueError(f"quality_multiplier must be in the range (0.0, 1.0], but {quality_multiplier} is given.")
|
|
65
|
+
config = dict()
|
|
66
|
+
config["volt_limits_g1"] = np.array([-0.2, -0.06])
|
|
67
|
+
config["volt_limits_g2"] = np.array([-0.2, -0.06])
|
|
68
|
+
config["volt_limits_sensor_g1"] = np.array([-1, 0])
|
|
69
|
+
config["volt_limits_sensor_g2"] = np.array([-1, 0])
|
|
70
|
+
config["ideal_csd_config"] = sample_IdealCSDGeometric()
|
|
71
|
+
if sensor_type == "SensorGeneric":
|
|
72
|
+
config["sensor"] = sample_SensorGeneric(quality_multiplier=quality_multiplier,
|
|
73
|
+
compensated_sensor=compensated_sensor,
|
|
74
|
+
set_sensor_potential_offset_to_steepest_point=set_sensor_potential_offset_to_steepest_point)
|
|
75
|
+
elif sensor_type == "SensorScanSensorGeneric":
|
|
76
|
+
config["sensor"] = sample_SensorScanSensorGeneric(quality_multiplier=quality_multiplier,
|
|
77
|
+
compensated_sensor=compensated_sensor
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"The parameter sensor_type must be either 'SensorGeneric' or 'SensorScanSensorGeneric'. The supplied value"
|
|
82
|
+
f" '{sensor_type}' is not supported.")
|
|
83
|
+
config["occupation_distortions"] = sample_occupation_distortions()
|
|
84
|
+
config["sensor_potential_distortions"] = sample_sensor_potential_distortions()
|
|
85
|
+
config["sensor_response_distortions"] = sample_sensor_response_distortions()
|
|
86
|
+
return config
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def sample_IdealCSDGeometric() -> IdealCSDGeometric:
|
|
90
|
+
"""
|
|
91
|
+
Samples a random_variations_v3 IdealCSDGeometric config.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
IdealCSDGeometric: IdealCSDGeometric object to be used as ideal_csd_config for the SimCATS Simulation class.
|
|
95
|
+
"""
|
|
96
|
+
# slopes of the lead transitions in 45°-rotated space
|
|
97
|
+
slope1_min = 0.21429
|
|
98
|
+
slope1_max = 0.54688
|
|
99
|
+
slope2_min = -0.44
|
|
100
|
+
slope2_max = -0.07692
|
|
101
|
+
# angle between lead transitions
|
|
102
|
+
angle_lead_min = 0.43760867228
|
|
103
|
+
angle_lead_max = 1.6789624091
|
|
104
|
+
# lengths of the lead transitions (between minima and maxima of a TCT)
|
|
105
|
+
length_min = 0.01
|
|
106
|
+
length_max = 0.025
|
|
107
|
+
# angle between interdot and first lead transition (slope1 is rotated counter-clockwise by this angle to get the direction of the interdot vector)
|
|
108
|
+
angle_interdot_min = 0.58153916891
|
|
109
|
+
angle_interdot_max = 1.396938844
|
|
110
|
+
# length of the interdot transition
|
|
111
|
+
interdot_length_min = 0.00261
|
|
112
|
+
interdot_length_max = 0.00987
|
|
113
|
+
interdot_length_mean = 0.004 # Currently not used, as we sample interdot length with a uniform distribution. Kept for the sake of completeness.
|
|
114
|
+
interdot_length_std = 0.0015 # Currently not used, as we sample interdot length with a uniform distribution. Kept for the sake of completeness.
|
|
115
|
+
# width of the interdot transition, larger values lead to more curved TCTs
|
|
116
|
+
interdot_width_min = 0.00043
|
|
117
|
+
interdot_width_max = 0.00814
|
|
118
|
+
# relation between width and length of the interdot transition
|
|
119
|
+
rel_interdot_length_width_min = 0.8692269873603532
|
|
120
|
+
rel_interdot_length_width_max = 9.055385138137407
|
|
121
|
+
# limits for the plunger gate voltages used for the simulation
|
|
122
|
+
volt_limits_g1 = np.array([-0.2, -0.06])
|
|
123
|
+
volt_limits_g2 = np.array([-0.2, -0.06])
|
|
124
|
+
# place for the first bezier anchor, which determines were the first interdot transition is located
|
|
125
|
+
first_bezier_point_min, first_bezier_point_max = -0.14, -0.14
|
|
126
|
+
# lookup table entries to use for the calculation of the tct_bezier
|
|
127
|
+
lut_entries = 1000
|
|
128
|
+
|
|
129
|
+
# create random number generator
|
|
130
|
+
rng = np.random.default_rng()
|
|
131
|
+
|
|
132
|
+
# sample slope
|
|
133
|
+
slope1 = np.array([1, rng.uniform(slope1_min, slope1_max)])
|
|
134
|
+
slope2 = np.array([1, rng.uniform(slope2_min, slope2_max)])
|
|
135
|
+
|
|
136
|
+
angle_lead = np.arccos(slope1.dot(slope2) / (np.linalg.norm(slope1) * np.linalg.norm(slope2)))
|
|
137
|
+
|
|
138
|
+
# create the IdealCSDGeometric object
|
|
139
|
+
# fresh default config
|
|
140
|
+
ideal_csd_geometric = deepcopy(default_configs["GaAs_v1"]["ideal_csd_config"])
|
|
141
|
+
|
|
142
|
+
# basic settings regarding volt_limits and lookup table entries
|
|
143
|
+
ideal_csd_geometric.lut_entries = lut_entries
|
|
144
|
+
|
|
145
|
+
# resample slope if angle_lead is not between angle_lead_min and angle_lead_max
|
|
146
|
+
while not (angle_lead_min <= angle_lead <= angle_lead_max):
|
|
147
|
+
slope1 = np.array([1, rng.uniform(slope1_min, slope1_max)])
|
|
148
|
+
slope2 = np.array([1, rng.uniform(slope2_min, slope2_max)])
|
|
149
|
+
angle_lead = np.arccos(slope1.dot(slope2) / (np.linalg.norm(slope1) * np.linalg.norm(slope2)))
|
|
150
|
+
|
|
151
|
+
# sample lengths
|
|
152
|
+
lengths = [
|
|
153
|
+
rng.uniform(length_min, length_max),
|
|
154
|
+
rng.uniform(length_min, length_max),
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
# sample interdot_vec
|
|
158
|
+
interdot_vec = rotate_points(slope1, rng.uniform(angle_interdot_min, angle_interdot_max))
|
|
159
|
+
# rotate interdot_vec like it would be in the CSD space
|
|
160
|
+
interdot_vec_rot = rotate_points(interdot_vec, -np.pi / 4)
|
|
161
|
+
while interdot_vec_rot[0] < 0 or interdot_vec_rot[1] < 0:
|
|
162
|
+
# interdot vector should not go backwards in the image space, so resample if the rotated vector has negative entries
|
|
163
|
+
interdot_vec = rotate_points(slope1, rng.uniform(angle_interdot_min, angle_interdot_max))
|
|
164
|
+
# rotate interdot_vec
|
|
165
|
+
interdot_vec_rot = rotate_points(interdot_vec, -np.pi / 4)
|
|
166
|
+
interdot_vec = interdot_vec / np.linalg.norm(interdot_vec)
|
|
167
|
+
|
|
168
|
+
# sample interdot_length
|
|
169
|
+
# usage of uniform distribution to get more diverse data
|
|
170
|
+
interdot_length = rng.uniform(interdot_length_min, interdot_length_max)
|
|
171
|
+
while interdot_length < interdot_length_min or interdot_length > interdot_length_max:
|
|
172
|
+
interdot_length = rng.uniform(interdot_length_min, interdot_length_max)
|
|
173
|
+
|
|
174
|
+
# sample bezier_width
|
|
175
|
+
bezier_width = rng.uniform(interdot_width_min, interdot_width_max)
|
|
176
|
+
# resample interdot_length and bezier_width until interdot_length / bezier_width is between rel_interdot_length_width_min and rel_interdot_length_width_max
|
|
177
|
+
while not (
|
|
178
|
+
rel_interdot_length_width_min <= interdot_length / bezier_width
|
|
179
|
+
and interdot_length / bezier_width <= rel_interdot_length_width_max
|
|
180
|
+
):
|
|
181
|
+
interdot_length = rng.uniform(interdot_length_min, interdot_length_max)
|
|
182
|
+
bezier_width = rng.uniform(interdot_width_min, interdot_width_max)
|
|
183
|
+
interdot_vec = interdot_vec * interdot_length
|
|
184
|
+
|
|
185
|
+
# place first bezier_point in lower left corner
|
|
186
|
+
bezier_point = rng.uniform(first_bezier_point_min, first_bezier_point_max, size=2)
|
|
187
|
+
bezier_point = rotate_points(bezier_point)
|
|
188
|
+
|
|
189
|
+
# calculate the second bezier point, so that it is in the correct direction
|
|
190
|
+
# direction for bezier_point is the mean of both slopes
|
|
191
|
+
direction = np.array([1, (slope1[1] + slope2[1]) / 2])
|
|
192
|
+
direction = direction / np.linalg.norm(direction)
|
|
193
|
+
bezier_point2 = bezier_point + bezier_width * direction
|
|
194
|
+
|
|
195
|
+
# set up shift vector to calculate next tct params
|
|
196
|
+
shift_vec = np.array([-lengths[1] + interdot_vec[0], interdot_vec[1] - lengths[1] * slope2[1]])
|
|
197
|
+
|
|
198
|
+
# set up first tct params
|
|
199
|
+
temp_params = np.array(
|
|
200
|
+
[
|
|
201
|
+
lengths[0],
|
|
202
|
+
lengths[1],
|
|
203
|
+
slope1[1],
|
|
204
|
+
slope2[1],
|
|
205
|
+
bezier_point[0],
|
|
206
|
+
bezier_point[1],
|
|
207
|
+
bezier_point2[0],
|
|
208
|
+
bezier_point2[1],
|
|
209
|
+
]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Add as many TCTs as required, by using a sensor and testing if sufficient TCTs were added to cover the whole
|
|
213
|
+
# voltage space
|
|
214
|
+
ideal_csd_geometric.tct_params = [temp_params]
|
|
215
|
+
running = True
|
|
216
|
+
while running:
|
|
217
|
+
try:
|
|
218
|
+
# set up simulation
|
|
219
|
+
temp_config = dict()
|
|
220
|
+
temp_config["volt_limits_g1"] = volt_limits_g1
|
|
221
|
+
temp_config["volt_limits_g2"] = volt_limits_g2
|
|
222
|
+
temp_config["ideal_csd_config"] = ideal_csd_geometric
|
|
223
|
+
sim = Simulation(**temp_config)
|
|
224
|
+
# measure
|
|
225
|
+
_ = sim.measure(volt_limits_g1, volt_limits_g2, resolution=np.array([10, 10]))
|
|
226
|
+
except IndexError as e:
|
|
227
|
+
ideal_csd_geometric.tct_params = _add_one_tct(ideal_csd_geometric.tct_params, shift_vec)
|
|
228
|
+
else:
|
|
229
|
+
running = False
|
|
230
|
+
|
|
231
|
+
return ideal_csd_geometric
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def sample_SensorGeneric(quality_multiplier: float = 1.0,
|
|
235
|
+
compensated_sensor: bool = False,
|
|
236
|
+
set_sensor_potential_offset_to_steepest_point: bool = False) -> SensorGeneric:
|
|
237
|
+
"""
|
|
238
|
+
Sample parameters and initialize a SensorGeneric object.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for Coulomb peak heights
|
|
242
|
+
etc. is used. This basically allows to restrict configurations to better data quality, as future
|
|
243
|
+
improvements of the sample quality are expected. The parameter further restricts the preset ranges for
|
|
244
|
+
things like the height of Coulomb peaks (increasing the minimum) and the strength of the lever-arms of the
|
|
245
|
+
double quantum dot gates towards the sensor. The factor must be in the range (0.0, 1.0]. Defaults to 1.0.
|
|
246
|
+
compensated_sensor: Whether the effect of the double quantum dot on the sensor dot is compensated (lever-arms of
|
|
247
|
+
the double dot gate voltages on the sensor are close to zero). Defaults to False.
|
|
248
|
+
set_sensor_potential_offset_to_steepest_point: Whether the steepest point of the sensor function is determined
|
|
249
|
+
and the corresponding potential is set as the potential offset (offset_mu_sens). This enables simple
|
|
250
|
+
"retuning" of the sensor by always resetting the potential offset before every CSD measurement. Defaults to
|
|
251
|
+
False.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
SensorGeneric: Fully initialized SensorGeneric object.
|
|
255
|
+
"""
|
|
256
|
+
# limits for the plunger gate voltages used for the simulation
|
|
257
|
+
volt_limits_g1 = np.array([-0.2, -0.06])
|
|
258
|
+
volt_limits_g2 = np.array([-0.2, -0.06])
|
|
259
|
+
num_sensor_peak_min, num_sensor_peak_max = 3, 6
|
|
260
|
+
# s_off is the offset of the peaks (y)
|
|
261
|
+
sensor_offset_min, sensor_offset_max = -0.42275, -0.0838
|
|
262
|
+
# mu_0 (offset_mu_sens) from sensor (x)
|
|
263
|
+
sensor_mu_0_min, sensor_mu_0_max = -0.12168, -0.03824
|
|
264
|
+
sensor_height_min, sensor_height_max = 0.02245, 0.19204
|
|
265
|
+
sensor_gamma_min, sensor_gamma_max = 0.0009636, 0.0029509
|
|
266
|
+
if compensated_sensor:
|
|
267
|
+
sensor_alpha_gate_1_min, sensor_alpha_gate_1_max = 0.0001, 0.0005
|
|
268
|
+
sensor_alpha_gate_2_min, sensor_alpha_gate_2_max = 0.0001, 0.0005 # Currently not used, as we sample alpha gate 2 in dependence on alpha gate 1. Kept for the sake of completeness.
|
|
269
|
+
else:
|
|
270
|
+
sensor_alpha_gate_1_min, sensor_alpha_gate_1_max = 0.02805, 0.15093
|
|
271
|
+
sensor_alpha_gate_2_min, sensor_alpha_gate_2_max = 0.03788, 0.19491 # Currently not used, as we sample alpha gate 2 in dependence on alpha gate 1. Kept for the sake of completeness.
|
|
272
|
+
sensor_alpha_dot_1_min, sensor_alpha_dot_1_max = -0.0007994, -0.0000961
|
|
273
|
+
sensor_alpha_dot_1_max = sensor_alpha_dot_1_min + quality_multiplier * (
|
|
274
|
+
sensor_alpha_dot_1_max - sensor_alpha_dot_1_min)
|
|
275
|
+
sensor_alpha_dot_2_min, sensor_alpha_dot_2_max = -0.0005214, -0.0000630
|
|
276
|
+
sensor_alpha_dot_2_max = sensor_alpha_dot_2_min + quality_multiplier * (
|
|
277
|
+
sensor_alpha_dot_2_max - sensor_alpha_dot_2_min)
|
|
278
|
+
|
|
279
|
+
quantile_relative_pos = 0.6 * quality_multiplier
|
|
280
|
+
quantile_percentage = 0.99
|
|
281
|
+
exp_scale_sensor_height = quantile_relative_pos / np.log(1 / (1 - quantile_percentage))
|
|
282
|
+
|
|
283
|
+
# create random number generator
|
|
284
|
+
rng = np.random.default_rng()
|
|
285
|
+
|
|
286
|
+
# sample alpha gates and alpha dots
|
|
287
|
+
sensor_alpha_gate_1 = rng.uniform(low=sensor_alpha_gate_1_min, high=sensor_alpha_gate_1_max)
|
|
288
|
+
sensor_alpha_gate_2 = rng.uniform(low=0.5 * sensor_alpha_gate_1, high=2 * sensor_alpha_gate_1)
|
|
289
|
+
|
|
290
|
+
# sample alpha dot 1 depending on alpha gate 1
|
|
291
|
+
# -0.03 / 100 = at least as much change for occ change (alpha dot) as change for sweeping one pixel (alpha gate)
|
|
292
|
+
# Keep in mind negative means, max is actually min (think of absolute values).
|
|
293
|
+
# Set to 2* alpha gate per pixel value, because stepping one pixel adds 1* and we want to jump back at least
|
|
294
|
+
# 1* pixel step (starting with random_variations_v2).
|
|
295
|
+
# Should actually always ensure to have higher min sensitivity (max = min because of negative values). Therefore,
|
|
296
|
+
# np.min with the actual value has been added (starting with random_variations_v3).
|
|
297
|
+
temp_sensor_alpha_dot_1_max = np.min([2 * sensor_alpha_gate_1 * -0.03 / 100,
|
|
298
|
+
sensor_alpha_dot_1_max])
|
|
299
|
+
sensor_alpha_dot_1 = rng.uniform(low=sensor_alpha_dot_1_min, high=temp_sensor_alpha_dot_1_max)
|
|
300
|
+
|
|
301
|
+
# sample alpha dot 2 depending on alpha gate 2 and alpha dot 1
|
|
302
|
+
# Set to 2* alpha gate per pixel value, because stepping one pixel adds 1* and we want to jump back at least
|
|
303
|
+
# 1* pixel step (starting with random_variations_v2).
|
|
304
|
+
# Should actually always ensure to have higher min sensitivity (max = min because of negative values). Therefore,
|
|
305
|
+
# np.min with the actual value has been added (starting with random_variations_v3).
|
|
306
|
+
temp_sensor_alpha_dot_2_max = np.min([0.5 * sensor_alpha_dot_1, 2 * sensor_alpha_gate_2 * -0.03 / 100,
|
|
307
|
+
sensor_alpha_dot_2_max])
|
|
308
|
+
if temp_sensor_alpha_dot_2_max < sensor_alpha_dot_2_min:
|
|
309
|
+
temp_sensor_alpha_dot_2_max = sensor_alpha_dot_2_max
|
|
310
|
+
# Should actually only ensure to be at most twice as strongly coupled compared to dot 1, but never stronger than
|
|
311
|
+
# given by the pre-defined range. Therefore, np.max with the actual value has been added (starting with
|
|
312
|
+
# random_variations_v3).
|
|
313
|
+
temp_sensor_alpha_dot_2_min = np.max([2 * sensor_alpha_dot_1, sensor_alpha_dot_2_min])
|
|
314
|
+
sensor_alpha_dot_2 = rng.uniform(low=temp_sensor_alpha_dot_2_min, high=temp_sensor_alpha_dot_2_max)
|
|
315
|
+
|
|
316
|
+
sensor = SensorGeneric(
|
|
317
|
+
sensor_peak_function=None,
|
|
318
|
+
alpha_dot=np.array([sensor_alpha_dot_1, sensor_alpha_dot_2]),
|
|
319
|
+
alpha_gate=np.array([sensor_alpha_gate_1, sensor_alpha_gate_2]),
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# calculate potential to find mu_sens limits
|
|
323
|
+
occupations = np.array([[0.0, 0.0], [5.0, 5.0]])
|
|
324
|
+
potentials = sensor.sensor_potential(occupations=occupations,
|
|
325
|
+
volt_limits_g1=volt_limits_g1,
|
|
326
|
+
volt_limits_g2=volt_limits_g2)
|
|
327
|
+
sensor_mu_0_min, sensor_mu_0_max = np.min(potentials), np.max(potentials)
|
|
328
|
+
|
|
329
|
+
# sample number of peaks
|
|
330
|
+
num_sensor_peak = rng.choice(np.arange(num_sensor_peak_min, num_sensor_peak_max + 1))
|
|
331
|
+
|
|
332
|
+
sensor_peak_functions = list()
|
|
333
|
+
|
|
334
|
+
sensor_height_sampler = ExponentialSamplingRange(
|
|
335
|
+
total_range=(sensor_height_max, sensor_height_min),
|
|
336
|
+
scale=exp_scale_sensor_height
|
|
337
|
+
) # using other sampler starting with random_variations_v2
|
|
338
|
+
|
|
339
|
+
# sample individual peaks
|
|
340
|
+
for i in range(num_sensor_peak):
|
|
341
|
+
sensor_gamma = rng.uniform(low=sensor_gamma_min, high=sensor_gamma_max)
|
|
342
|
+
sensor_mu_0 = rng.uniform(low=sensor_mu_0_min, high=sensor_mu_0_max)
|
|
343
|
+
if i > 0: # added a rule for the variation of mu0 between peaks of the same config (starting with random_variations_v2)
|
|
344
|
+
# make sure that sensors have at least (0.5 * potential_range) / number_of_peaks distance (for mu0)
|
|
345
|
+
counter = 0
|
|
346
|
+
# introduced this counter, because we could end up in a case where it is not possible to place the next peak,
|
|
347
|
+
# because two peaks can be slightly below twice min required distance apart from each other and therefore block 2x
|
|
348
|
+
# and not just 1.5x (sensor_mu_0_max - sensor_mu_0_min) / (num_sensor_peak). Try 1000 times and else allow 2x.
|
|
349
|
+
while (np.min([np.abs(sensor_mu_0 - sampled_peak.mu0) for sampled_peak in sensor_peak_functions]) <= (
|
|
350
|
+
sensor_mu_0_max - sensor_mu_0_min) / (num_sensor_peak * 1.5) and counter < 1000) or np.min(
|
|
351
|
+
[np.abs(sensor_mu_0 - sampled_peak.mu0) for sampled_peak in sensor_peak_functions]) <= (
|
|
352
|
+
sensor_mu_0_max - sensor_mu_0_min) / (num_sensor_peak * 2):
|
|
353
|
+
sensor_mu_0 = rng.uniform(low=sensor_mu_0_min, high=sensor_mu_0_max)
|
|
354
|
+
counter += 1
|
|
355
|
+
if i == 0: # added a rule for the variation of peak_offset between peaks of the same config (starting with random_variations_v2)
|
|
356
|
+
sensor_peak_offset = rng.uniform(low=sensor_offset_min, high=sensor_offset_max)
|
|
357
|
+
else:
|
|
358
|
+
# make sure to have at most 20% difference in peak_offset to first peak_offset
|
|
359
|
+
sensor_peak_offset = rng.uniform(low=sensor_peak_functions[0].offset * 1.2,
|
|
360
|
+
high=sensor_peak_functions[0].offset * 0.8)
|
|
361
|
+
if i == 0: # added a rule for the variation of height between peaks of the same config (starting with random_variations_v2)
|
|
362
|
+
sensor_height = sensor_height_sampler.sample_parameter()
|
|
363
|
+
else:
|
|
364
|
+
# make sure to have at most 20% difference in height to first height
|
|
365
|
+
sensor_height = rng.uniform(low=sensor_peak_functions[0].height * 0.8,
|
|
366
|
+
high=sensor_peak_functions[0].height * 1.2)
|
|
367
|
+
sensor_peak_functions.append(
|
|
368
|
+
SensorPeakLorentzian(
|
|
369
|
+
gamma=sensor_gamma,
|
|
370
|
+
mu0=sensor_mu_0,
|
|
371
|
+
height=sensor_height,
|
|
372
|
+
offset=sensor_peak_offset,
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
sensor.sensor_peak_function = sensor_peak_functions
|
|
376
|
+
|
|
377
|
+
if set_sensor_potential_offset_to_steepest_point:
|
|
378
|
+
# calculate steepest point of sensor peak flank for offset_mu_sens (used for the assumption of sensor retuning
|
|
379
|
+
# to shift sensor to this point)
|
|
380
|
+
sample_mu_sens = np.linspace(sensor_mu_0_min - 0.2 * (sensor_mu_0_max - sensor_mu_0_min),
|
|
381
|
+
sensor_mu_0_max + 0.2 * (sensor_mu_0_max - sensor_mu_0_min),
|
|
382
|
+
1000000)
|
|
383
|
+
sample_sens_response = sensor.sensor_response(sample_mu_sens)
|
|
384
|
+
sample_sens_response_grad = np.gradient(sample_sens_response)
|
|
385
|
+
sensor.offset_mu_sens = sample_mu_sens[np.argmax(sample_sens_response_grad)]
|
|
386
|
+
|
|
387
|
+
return sensor
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _sensor_peak_list_add_peak(peak_list: List[SensorPeakInterface],
|
|
391
|
+
ref_height: float,
|
|
392
|
+
base_offset: float = 0) -> list[SensorPeakInterface]:
|
|
393
|
+
"""
|
|
394
|
+
Method to add a single lorentzian peak to a list of sensor peaks.
|
|
395
|
+
|
|
396
|
+
This function is only required when sampling a SensorScanSensorGeneric.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
peak_list (List[SensorPeakInterface]): List of sensor peaks to which a peak is added
|
|
400
|
+
ref_height (float): Reference height of all peaks. Based on this, the height of the new peak is sampled at
|
|
401
|
+
random. The reference height is used as the mean value of a distribution from which the height of the new
|
|
402
|
+
peak is sampled.
|
|
403
|
+
base_offset (float): Potential offset of the first sensor peak. The default value is 0. This value has no effect
|
|
404
|
+
for every other peak.
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
List[SensorPeakInterface]: The list of sensor peaks with an extra lorentzian peak added.
|
|
408
|
+
"""
|
|
409
|
+
mu_dif_absolute_initial_lower_limit = 0
|
|
410
|
+
mu_dif_absolute_initial_upper_limit = 0.00367179654343025 * 4
|
|
411
|
+
mu_dif_absolute_initial_std = 0.00023884164727643042 / 2 # MAD
|
|
412
|
+
# mu_dif_absolute_initial_mean = 0.002902416771776037 * 1.5 # MEDIAN
|
|
413
|
+
mu_dif_absolute_initial_mean = 0.002902416771776037 * 2.5 # MEDIAN
|
|
414
|
+
mu_dif_relative_std = 0.09509839063162284 / 2 # MAD
|
|
415
|
+
mu_dif_relative_mean_fitted_line_slope = -0.0374000174907983 / 4
|
|
416
|
+
mu_dif_relative_max_deviation = 1
|
|
417
|
+
mu_dif_relative_mean_fitted_line_intercept = 1.0189427890611187
|
|
418
|
+
mu_dif_relative_line_max_peak_num = 10
|
|
419
|
+
|
|
420
|
+
gamma_absolute_initial_std = 3.6990706645585366e-05 /2 # MAD
|
|
421
|
+
gamma_absolute_initial_mean = 9.878642853157584e-05 * 2.5 # MEDIAN
|
|
422
|
+
gamma_relative_mean_fitted_line_slope = 0
|
|
423
|
+
gamma_relative_mean_fitted_line_intercept = 1.25
|
|
424
|
+
gamma_relative_std = 0.4695086254881995 / 2
|
|
425
|
+
gamma_relative_lower_limit = 0.85
|
|
426
|
+
gamma_relative_higher_limit = 1.5
|
|
427
|
+
gamma_rel_line_max_peak_num = 5
|
|
428
|
+
gamma_max_value = 0.002 #0.0025
|
|
429
|
+
gamma_max_value_deviation_percentage = 0.1
|
|
430
|
+
|
|
431
|
+
height_std = 0.04720315300812465 / 2 # MAD
|
|
432
|
+
|
|
433
|
+
if len(peak_list) == 0:
|
|
434
|
+
mu0 = base_offset
|
|
435
|
+
|
|
436
|
+
gamma = NormalSamplingRange(
|
|
437
|
+
total_range=(0, np.inf),
|
|
438
|
+
std=gamma_absolute_initial_std,
|
|
439
|
+
mean=gamma_absolute_initial_mean
|
|
440
|
+
).sample_parameter()
|
|
441
|
+
|
|
442
|
+
elif len(peak_list) == 1:
|
|
443
|
+
mu_dif = NormalSamplingRange(
|
|
444
|
+
total_range=(mu_dif_absolute_initial_lower_limit, mu_dif_absolute_initial_upper_limit),
|
|
445
|
+
std=mu_dif_absolute_initial_std,
|
|
446
|
+
mean=mu_dif_absolute_initial_mean
|
|
447
|
+
).sample_parameter()
|
|
448
|
+
mu0 = peak_list[0].mu0 + mu_dif
|
|
449
|
+
|
|
450
|
+
gamma_rel_dif = NormalSamplingRange(
|
|
451
|
+
total_range=(gamma_relative_lower_limit, gamma_relative_higher_limit),
|
|
452
|
+
std=gamma_relative_std,
|
|
453
|
+
mean=gamma_relative_mean_fitted_line_slope * (
|
|
454
|
+
len(peak_list) - 1) + gamma_relative_mean_fitted_line_intercept
|
|
455
|
+
).sample_parameter()
|
|
456
|
+
gamma = peak_list[-1].gamma * gamma_rel_dif
|
|
457
|
+
|
|
458
|
+
else:
|
|
459
|
+
mu_factor = peak_list[1].mu0 - peak_list[0].mu0
|
|
460
|
+
mu_peak_num = len(peak_list) if len(
|
|
461
|
+
peak_list) < mu_dif_relative_line_max_peak_num else mu_dif_relative_line_max_peak_num
|
|
462
|
+
mu_rel_dif = NormalSamplingRange(
|
|
463
|
+
total_range=(
|
|
464
|
+
-mu_dif_relative_max_deviation * mu_dif_relative_std,
|
|
465
|
+
mu_dif_relative_max_deviation * mu_dif_relative_std),
|
|
466
|
+
std=mu_dif_relative_std,
|
|
467
|
+
mean=0,
|
|
468
|
+
).sample_parameter() + mu_dif_relative_mean_fitted_line_slope * (
|
|
469
|
+
mu_peak_num - 1) + mu_dif_relative_mean_fitted_line_intercept
|
|
470
|
+
|
|
471
|
+
mu0 = peak_list[-1].mu0 + mu_rel_dif * mu_factor
|
|
472
|
+
|
|
473
|
+
gamma_peak_num = len(peak_list) if len(peak_list) < gamma_rel_line_max_peak_num else gamma_rel_line_max_peak_num
|
|
474
|
+
gamma_rel_dif = NormalSamplingRange(
|
|
475
|
+
total_range=(gamma_relative_lower_limit, gamma_relative_higher_limit),
|
|
476
|
+
std=gamma_relative_std,
|
|
477
|
+
mean=gamma_relative_mean_fitted_line_slope * (
|
|
478
|
+
gamma_peak_num - 1) + gamma_relative_mean_fitted_line_intercept
|
|
479
|
+
).sample_parameter()
|
|
480
|
+
gamma = peak_list[-1].gamma * gamma_rel_dif
|
|
481
|
+
|
|
482
|
+
if gamma > gamma_max_value:
|
|
483
|
+
gamma = UniformSamplingRange(
|
|
484
|
+
total_range=(gamma_max_value * (1 - gamma_max_value_deviation_percentage),
|
|
485
|
+
gamma_max_value * (1 + gamma_max_value_deviation_percentage)),
|
|
486
|
+
).sample_parameter()
|
|
487
|
+
|
|
488
|
+
height = ref_height + NormalSamplingRange(
|
|
489
|
+
total_range=(-ref_height, np.inf),
|
|
490
|
+
std=height_std,
|
|
491
|
+
mean=0
|
|
492
|
+
).sample_parameter()
|
|
493
|
+
|
|
494
|
+
return peak_list + [SensorPeakLorentzian(
|
|
495
|
+
mu0=mu0,
|
|
496
|
+
gamma=gamma,
|
|
497
|
+
height=height,
|
|
498
|
+
offset=0, # A minimum sensor response of 0 is assumed
|
|
499
|
+
), ]
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _sample_sensor_peak_list(num_peaks: int,
|
|
503
|
+
ref_height: float,
|
|
504
|
+
offset: float) -> List[SensorPeakLorentzian]:
|
|
505
|
+
"""
|
|
506
|
+
Function to sample a list of sensor peaks.
|
|
507
|
+
Objects of the SensorPeakLorentzian class are used as peaks here.
|
|
508
|
+
|
|
509
|
+
This function is only required when sampling a SensorScanSensorGeneric.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
num_peaks (int): Number of lorentzian peaks to sample.
|
|
513
|
+
ref_height (float): Reference height of all peaks. The reference height is used as the mean for the
|
|
514
|
+
distributions all peaks are sampled from.
|
|
515
|
+
offset (float): Potential offset of the first sensor peak.
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
List[SensorPeakLorentzian]: A list of Lorentzian peaks.
|
|
519
|
+
"""
|
|
520
|
+
peak_list = []
|
|
521
|
+
|
|
522
|
+
for i in range(num_peaks):
|
|
523
|
+
peak_list = _sensor_peak_list_add_peak(peak_list=peak_list, ref_height=ref_height, base_offset=offset)
|
|
524
|
+
|
|
525
|
+
return peak_list
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def sample_sensor_function(offset: float, quality_multiplier: float) -> Tuple[List[SensorPeakInterface], SensorRiseInterface]:
|
|
529
|
+
"""
|
|
530
|
+
Function to sample a whole sensor function.
|
|
531
|
+
A whole sensor function consists of a list of lorentzian sensor peaks and ends with a sigmoid sensor rise, which
|
|
532
|
+
represents an increase to the maximum conductivity.
|
|
533
|
+
|
|
534
|
+
This function is only required when sampling a SensorScanSensorGeneric.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
offset (float): Potential offset of the first sensor peak.
|
|
538
|
+
quality_multiplier (float): The quality multiplier of the sensor function sampler restricts the reference height
|
|
539
|
+
that specifies the mean of the sensor peak height. This also indirectly restricts the height of the final
|
|
540
|
+
rise, as this depends on the maximum height of the preceding sensor peaks. The factor must be in the range
|
|
541
|
+
(0.0, 1.0]. Defaults to 1.0.
|
|
542
|
+
|
|
543
|
+
Returns:
|
|
544
|
+
List[SensorPeakInterface]: A whole sensor function as a list returned as tuple. The tuple contains the sensor
|
|
545
|
+
peaks as a list of multiple lorentzian and the sensor rise, a rise to the maximum sensor response.
|
|
546
|
+
"""
|
|
547
|
+
peak_num_range = (20, 30)
|
|
548
|
+
|
|
549
|
+
height_ref_mean = 0.07543071921134054 * quality_multiplier # MEDIAN
|
|
550
|
+
height_ref_range = (0, 1)
|
|
551
|
+
height_ref_std = 0.04804196857755959
|
|
552
|
+
|
|
553
|
+
sensor_rise_max_multiplier = 1.05
|
|
554
|
+
sensor_rise_growth_rate_range = (400, 600)
|
|
555
|
+
sensor_rise_asymmetry_range = (0.01, 1)
|
|
556
|
+
sensor_rise_shape_factor_range = (0.01, 100)
|
|
557
|
+
# The distance of the sensor rise to the previous lorentzian peak is based on a multiple of the distance of the last
|
|
558
|
+
# two peaks. The value of the multiple is sampled from this range.
|
|
559
|
+
sensor_rise_dif_multiplier_range = (2, 3) # (4, 6)
|
|
560
|
+
sensor_rise_end_percentage = 0.95
|
|
561
|
+
|
|
562
|
+
# Sample reference peak height
|
|
563
|
+
ref_height = NormalSamplingRange(
|
|
564
|
+
total_range=height_ref_range,
|
|
565
|
+
std=height_ref_std,
|
|
566
|
+
mean=height_ref_mean
|
|
567
|
+
).sample_parameter()
|
|
568
|
+
|
|
569
|
+
# Sample Lorentzian peaks
|
|
570
|
+
num_peaks = int(UniformSamplingRange(total_range=peak_num_range).sample_parameter())
|
|
571
|
+
sensor_func = _sample_sensor_peak_list(num_peaks=num_peaks, ref_height=ref_height, offset=offset)
|
|
572
|
+
|
|
573
|
+
x_values = np.linspace(-5, 5, 500000)
|
|
574
|
+
sensor_resp = np.zeros(500000)
|
|
575
|
+
for func in sensor_func:
|
|
576
|
+
sensor_resp += func.sensor_function(x_values)
|
|
577
|
+
maximum = np.max(sensor_resp)
|
|
578
|
+
|
|
579
|
+
left_asymptote = 0 # A minimum sensor response of 0 is assumed
|
|
580
|
+
right_asymptote = maximum * sensor_rise_max_multiplier
|
|
581
|
+
|
|
582
|
+
param_dict = {
|
|
583
|
+
"asymptote_left": left_asymptote,
|
|
584
|
+
"asymptote_right": right_asymptote,
|
|
585
|
+
"growth_rate": UniformSamplingRange(total_range=sensor_rise_growth_rate_range).sample_parameter(),
|
|
586
|
+
"asymmetry": UniformSamplingRange(total_range=sensor_rise_asymmetry_range).sample_parameter(),
|
|
587
|
+
"shape_factor": UniformSamplingRange(total_range=sensor_rise_shape_factor_range).sample_parameter(),
|
|
588
|
+
"mu0": 0
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
sensor_rise = SensorRiseGLF(
|
|
592
|
+
fully_conductive_percentage=sensor_rise_end_percentage,
|
|
593
|
+
**param_dict
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
return sensor_func, sensor_rise
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def sample_barrier_function(
|
|
600
|
+
offset: float = 0,
|
|
601
|
+
height: float = 0.25,
|
|
602
|
+
quality_multiplier: float = 1.0,
|
|
603
|
+
) -> BarrierFunctionInterface:
|
|
604
|
+
"""
|
|
605
|
+
Method to sample a barrier function.
|
|
606
|
+
|
|
607
|
+
This function is only required when sampling a SensorScanSensorGeneric.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
offset (float): Potential offset of the barrier function. Without this offset the pinch of point of the barrier
|
|
611
|
+
function is at a potential of 0.
|
|
612
|
+
height (float): Maximal height and conductance value of the barrier function.
|
|
613
|
+
quality_multiplier (float): For the barrier function, the quality multiplier restricts the barrier height,
|
|
614
|
+
therefore, the factor is multiplied with the mean of the distribution the sensors are sampled from. The
|
|
615
|
+
factor must be in the range (0.0, 1.0]. Defaults to 1.0.
|
|
616
|
+
|
|
617
|
+
Returns:
|
|
618
|
+
BarrierFunctionInterface: A SimCATS barrier function.
|
|
619
|
+
"""
|
|
620
|
+
return _sample_simple_barrier_function(offset=offset, height=height, quality_multiplier=quality_multiplier,
|
|
621
|
+
pinch_off_percentage=0.001, fully_conductive_percentage=0.999)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def _sample_simple_barrier_function(offset: float = 0,
|
|
625
|
+
height: float = 0.25,
|
|
626
|
+
quality_multiplier: float = 1.0,
|
|
627
|
+
pinch_off_percentage: float = 0.05,
|
|
628
|
+
fully_conductive_percentage: float = 0.95) -> BarrierFunctionGLF:
|
|
629
|
+
"""
|
|
630
|
+
Method to sample a simple barrier function without any defects. For that a single GLF is used.
|
|
631
|
+
|
|
632
|
+
This function is only required when sampling a SensorScanSensorGeneric.
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
offset (float): Potential offset of the barrier function. Without this offset the pinch of point of the barrier
|
|
636
|
+
function is at a potential of 0.
|
|
637
|
+
height (float): Maximal height and conductance value of the barrier function.
|
|
638
|
+
quality_multiplier (float): For the barrier function, the quality multiplier restricts the barrier height,
|
|
639
|
+
therefore, the factor is multiplied with the mean of the distribution the sensors are sampled from. The
|
|
640
|
+
factor must be in the range (0.0, 1.0]. Defaults to 1.0.
|
|
641
|
+
pinch_off_percentage (float): Percentage of the barrier conductance range which is considered as the pinch-off
|
|
642
|
+
value. E.g.: If the barrier function goes from zero to one and the pinch_off_percentage is set to 0.01, then
|
|
643
|
+
the pinch-off is at the potential that leads to a conductance of 0.01. Defaults to 0.05.
|
|
644
|
+
fully_conductive_percentage (float): Percentage of the barrier conductance range which is considered as the
|
|
645
|
+
point where the barrier vanishes and becomes fully conductive. E.g.: If the barrier function goes from zero
|
|
646
|
+
to one and the fully_conductive_percentage is set to 0.99, then the fully conductive point is at the
|
|
647
|
+
potential that leads to a conductance of 0.99. Defaults to 0.95.
|
|
648
|
+
|
|
649
|
+
Returns:
|
|
650
|
+
BarrierFunctionGLF: A barrier function based on a GLF.
|
|
651
|
+
"""
|
|
652
|
+
barrier_func_asymmetry_range = (0.000001, 0.0001)
|
|
653
|
+
|
|
654
|
+
barrier_func_shape_factor_range = (0.01, 100)
|
|
655
|
+
barrier_func_growth_rate_range = (20,40)
|
|
656
|
+
|
|
657
|
+
param_dict = {
|
|
658
|
+
"asymptote_left": 0,
|
|
659
|
+
"asymptote_right": height * quality_multiplier,
|
|
660
|
+
"growth_rate": UniformSamplingRange(total_range=barrier_func_growth_rate_range).sample_parameter(),
|
|
661
|
+
"asymmetry": UniformSamplingRange(total_range=barrier_func_asymmetry_range).sample_parameter(),
|
|
662
|
+
"shape_factor": UniformSamplingRange(total_range=barrier_func_shape_factor_range).sample_parameter(),
|
|
663
|
+
"denominator_offset": 1,
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
pinch_off = inverse_glf(value=param_dict["asymptote_right"] * pinch_off_percentage, **param_dict)
|
|
667
|
+
param_dict["offset"] = offset - pinch_off
|
|
668
|
+
|
|
669
|
+
return BarrierFunctionGLF(
|
|
670
|
+
pinch_off_percentage=pinch_off_percentage,
|
|
671
|
+
fully_conductive_percentage=fully_conductive_percentage,
|
|
672
|
+
**param_dict
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def sample_SensorScanSensorGeneric(quality_multiplier: float = 1.0,
|
|
677
|
+
compensated_sensor: bool = False) -> SensorScanSensorGeneric:
|
|
678
|
+
"""
|
|
679
|
+
Sample parameters and initialize a SensorScanSensorGeneric object.
|
|
680
|
+
|
|
681
|
+
Args:
|
|
682
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for Coulomb peak heights
|
|
683
|
+
etc. is used. This basically allows to restrict configurations to better data quality, as future
|
|
684
|
+
improvements of the sample quality are expected. The parameter further restricts the preset ranges for
|
|
685
|
+
things like the height of Coulomb peaks (increasing the minimum) and the strength of the lever-arms of the
|
|
686
|
+
double quantum dot gates towards the sensor. The factor must be in the range (0.0, 1.0]. Defaults to 1.0.
|
|
687
|
+
compensated_sensor: Whether the effect of the double quantum dot on the sensor dot is compensated (lever-arms of
|
|
688
|
+
the double dot gate voltages on the sensor are close to zero). Defaults to False.
|
|
689
|
+
set_sensor_potential_offset_to_steepest_point: Whether the steepest point of the sensor function is determined
|
|
690
|
+
and the corresponding potential is set as the potential offset (offset_mu_sens). This enables simple
|
|
691
|
+
"retuning" of the sensor by always resetting the potential offset before every CSD measurement. Defaults to
|
|
692
|
+
False.
|
|
693
|
+
|
|
694
|
+
Returns:
|
|
695
|
+
SensorScanSensorGeneric: Fully initialized SensorScanSensorGeneric object.
|
|
696
|
+
"""
|
|
697
|
+
alpha_sensor_size = 0.1
|
|
698
|
+
alpha_barrier_size = 0.99
|
|
699
|
+
barrier_height = 0.25
|
|
700
|
+
|
|
701
|
+
alpha_sensor_gate_sensor_range = (0, 2)
|
|
702
|
+
alpha_sensor_gate_sensor_std = 0.0846429965722433
|
|
703
|
+
alpha_sensor_gate_sensor_mean = 0.9986776964521298
|
|
704
|
+
|
|
705
|
+
alpha_sensor_gate_barrier_range = (0.1, 0.3)
|
|
706
|
+
|
|
707
|
+
base_point_range = (-0.688, -0.509)
|
|
708
|
+
base_point_pot_offset = 0.005 * 10 # Offset that specifies how much sensor potential before the base point potential the wavefronts should begin
|
|
709
|
+
|
|
710
|
+
include_deformations = False
|
|
711
|
+
deformation_circular_percentage = 4.5
|
|
712
|
+
deformation_linear_percentage = 4.3
|
|
713
|
+
deformation_circular_radius_range = (1, 1.5)
|
|
714
|
+
deformation_linear_angle_range = (math.radians(85), math.radians(95)) # The angles have to be specified in radian
|
|
715
|
+
|
|
716
|
+
# Sample alpha gate sensor
|
|
717
|
+
# Sample alpha gate sensor - sensor
|
|
718
|
+
alpha_sensor_gate_sensor_ratio_sampler = NormalSamplingRange(total_range=alpha_sensor_gate_sensor_range,
|
|
719
|
+
std=alpha_sensor_gate_sensor_std,
|
|
720
|
+
mean=alpha_sensor_gate_sensor_mean)
|
|
721
|
+
alpha_sensor_gate_sensor_ratio = alpha_sensor_gate_sensor_ratio_sampler.sample_parameter()
|
|
722
|
+
alpha_sensor_gate_sensor = np.array([1, 1 / alpha_sensor_gate_sensor_ratio])
|
|
723
|
+
alpha_sensor_gate_sensor = (alpha_sensor_gate_sensor / np.max(alpha_sensor_gate_sensor)) * alpha_sensor_size
|
|
724
|
+
|
|
725
|
+
# Sample alpha gate sensor - barrier
|
|
726
|
+
alpha_sensor_gate_barrier_sampler = UniformSamplingRange(total_range=alpha_sensor_gate_barrier_range)
|
|
727
|
+
|
|
728
|
+
alpha_sensor_gate_barrier1 = np.array([alpha_barrier_size, alpha_sensor_gate_barrier_sampler.sample_parameter()])
|
|
729
|
+
alpha_sensor_gate_barrier2 = np.array([alpha_sensor_gate_barrier_sampler.sample_parameter(), alpha_barrier_size])
|
|
730
|
+
|
|
731
|
+
alpha_sensor_gate = np.array([
|
|
732
|
+
alpha_sensor_gate_sensor,
|
|
733
|
+
alpha_sensor_gate_barrier1,
|
|
734
|
+
alpha_sensor_gate_barrier2
|
|
735
|
+
])
|
|
736
|
+
|
|
737
|
+
if compensated_sensor:
|
|
738
|
+
alpha_gate_1_min, alpha_gate_1_max = 0.0001, 0.0005
|
|
739
|
+
alpha_gate_2_min, alpha_gate_2_max = 0.0001, 0.0005 # Currently not used, as we sample alpha gate 2 in dependence on alpha gate 1. Kept for the sake of completeness.
|
|
740
|
+
else:
|
|
741
|
+
alpha_gate_1_min, alpha_gate_1_max = 0.02805, 0.15093
|
|
742
|
+
alpha_gate_2_min, alpha_gate_2_max = 0.03788, 0.19491 # Currently not used, as we sample alpha gate 2 in dependence on alpha gate 1. Kept for the sake of completeness.
|
|
743
|
+
|
|
744
|
+
alpha_dot_1_min, alpha_dot_1_max = -0.0007994, -0.0000961
|
|
745
|
+
alpha_dot_1_max = alpha_dot_1_min + quality_multiplier * (
|
|
746
|
+
alpha_dot_1_max - alpha_dot_1_min)
|
|
747
|
+
alpha_dot_2_min, alpha_dot_2_max = -0.0005214, -0.0000630
|
|
748
|
+
alpha_dot_2_max = alpha_dot_2_min + quality_multiplier * (
|
|
749
|
+
alpha_dot_2_max - alpha_dot_2_min)
|
|
750
|
+
|
|
751
|
+
# create random number generator
|
|
752
|
+
rng = np.random.default_rng()
|
|
753
|
+
|
|
754
|
+
# sample alpha gates and alpha dots
|
|
755
|
+
alpha_gate_1 = rng.uniform(low=alpha_gate_1_min, high=alpha_gate_1_max)
|
|
756
|
+
alpha_gate_2 = rng.uniform(low=0.5 * alpha_gate_1, high=2 * alpha_gate_1)
|
|
757
|
+
|
|
758
|
+
# sample alpha dot 1 depending on alpha gate 1
|
|
759
|
+
# -0.03 / 100 = at least as much change for occ change (alpha dot) as change for sweeping one pixel (alpha gate)
|
|
760
|
+
# Keep in mind negative means, max is actually min (think of absolute values).
|
|
761
|
+
# Set to 2* alpha gate per pixel value, because stepping one pixel adds 1* and we want to jump back at least
|
|
762
|
+
# 1* pixel step (starting with random_variations_v2).
|
|
763
|
+
# Should actually always ensure to have higher min sensitivity (max = min because of negative values). Therefore,
|
|
764
|
+
# np.min with the actual value has been added (starting with random_variations_v3).
|
|
765
|
+
temp_alpha_dot_1_max = np.min([2 * alpha_gate_1 * -0.03 / 100,
|
|
766
|
+
alpha_dot_1_max])
|
|
767
|
+
alpha_dot_1 = rng.uniform(low=alpha_dot_1_min, high=temp_alpha_dot_1_max)
|
|
768
|
+
|
|
769
|
+
# sample alpha dot 2 depending on alpha gate 2 and alpha dot 1
|
|
770
|
+
# Set to 2* alpha gate per pixel value, because stepping one pixel adds 1* and we want to jump back at least
|
|
771
|
+
# 1* pixel step (starting with random_variations_v2).
|
|
772
|
+
# Should actually always ensure to have higher min sensitivity (max = min because of negative values). Therefore,
|
|
773
|
+
# np.min with the actual value has been added (starting with random_variations_v3).
|
|
774
|
+
temp_sensor_alpha_dot_2_max = np.min([0.5 * alpha_dot_1, 2 * alpha_gate_2 * -0.03 / 100,
|
|
775
|
+
alpha_dot_2_max])
|
|
776
|
+
if temp_sensor_alpha_dot_2_max < alpha_dot_2_min:
|
|
777
|
+
temp_sensor_alpha_dot_2_max = alpha_dot_2_max
|
|
778
|
+
# Should actually only ensure to be at most twice as strongly coupled compared to dot 1, but never stronger than
|
|
779
|
+
# given by the pre-defined range. Therefore, np.max with the actual value has been added (starting with
|
|
780
|
+
# random_variations_v3).
|
|
781
|
+
temp_sensor_alpha_dot_2_min = np.max([2 * alpha_dot_1, alpha_dot_2_min])
|
|
782
|
+
alpha_dot_2 = rng.uniform(low=temp_sensor_alpha_dot_2_min, high=temp_sensor_alpha_dot_2_max)
|
|
783
|
+
|
|
784
|
+
alpha_gate = np.array((alpha_gate_1, alpha_gate_2))
|
|
785
|
+
alpha_dot = np.array((alpha_dot_1, alpha_dot_2))
|
|
786
|
+
|
|
787
|
+
# Base Point
|
|
788
|
+
base_point_sampler = UniformSamplingRange(total_range=base_point_range)
|
|
789
|
+
base_point = np.array([base_point_sampler.sample_parameter(), base_point_sampler.sample_parameter()])
|
|
790
|
+
|
|
791
|
+
sensor_func_offset = np.sum(alpha_sensor_gate_sensor * base_point) - base_point_pot_offset
|
|
792
|
+
|
|
793
|
+
barrier_1_start = np.sum(alpha_sensor_gate_barrier1 * base_point)
|
|
794
|
+
barrier_2_start = np.sum(alpha_sensor_gate_barrier2 * base_point)
|
|
795
|
+
|
|
796
|
+
sensor_func, final_rise = sample_sensor_function(
|
|
797
|
+
offset=sensor_func_offset,
|
|
798
|
+
quality_multiplier=quality_multiplier
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
deformation_dict = {}
|
|
802
|
+
# Sample deformations
|
|
803
|
+
if include_deformations:
|
|
804
|
+
angle_sampler = UniformSamplingRange(
|
|
805
|
+
total_range=deformation_linear_angle_range)
|
|
806
|
+
radius_sampler = UniformSamplingRange(total_range=deformation_circular_radius_range)
|
|
807
|
+
|
|
808
|
+
for wavefront_num in range(len(sensor_func) - 1):
|
|
809
|
+
deformation_ran_num = random.random() * 100
|
|
810
|
+
|
|
811
|
+
if deformation_ran_num < deformation_linear_percentage:
|
|
812
|
+
deformation_dict[wavefront_num] = SensorPeakDeformationLinear(
|
|
813
|
+
angle=angle_sampler.sample_parameter()
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
elif deformation_ran_num < deformation_linear_percentage + deformation_circular_percentage:
|
|
817
|
+
sign = random.choice([-1, 1])
|
|
818
|
+
|
|
819
|
+
deformation_dict[wavefront_num] = SensorPeakDeformationCircle(
|
|
820
|
+
radius=sign * radius_sampler.sample_parameter()
|
|
821
|
+
)
|
|
822
|
+
|
|
823
|
+
return SensorScanSensorGeneric(
|
|
824
|
+
barrier_functions=(
|
|
825
|
+
sample_barrier_function(
|
|
826
|
+
offset=barrier_1_start,
|
|
827
|
+
height=barrier_height,
|
|
828
|
+
quality_multiplier=quality_multiplier
|
|
829
|
+
),
|
|
830
|
+
sample_barrier_function(
|
|
831
|
+
offset=barrier_2_start,
|
|
832
|
+
height=barrier_height,
|
|
833
|
+
quality_multiplier=quality_multiplier
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
),
|
|
837
|
+
sensor_peak_function=sensor_func,
|
|
838
|
+
final_rise = final_rise,
|
|
839
|
+
sensor_peak_deformations=deformation_dict,
|
|
840
|
+
alpha_sensor_gate=alpha_sensor_gate,
|
|
841
|
+
alpha_gate=alpha_gate,
|
|
842
|
+
alpha_dot=alpha_dot
|
|
843
|
+
)
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
def sample_occupation_distortions(quality_multiplier: float = 1.0) -> List[OccupationDistortionInterface]:
|
|
847
|
+
"""
|
|
848
|
+
Sample the list of occupation distortions for the SimCATS Simulation class.
|
|
849
|
+
|
|
850
|
+
Args:
|
|
851
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
852
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
853
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
854
|
+
1.0.
|
|
855
|
+
|
|
856
|
+
Returns:
|
|
857
|
+
List[OccupationDistortionInterface]: List of all occupation distortions for the GaAs_v1_random_variations_v3
|
|
858
|
+
configuration.
|
|
859
|
+
"""
|
|
860
|
+
return [_sample_occupation_transition_blurring_fermi_dirac(),
|
|
861
|
+
_sample_occupation_dot_jumps_g2(),
|
|
862
|
+
_sample_occupation_dot_jumps_g1()]
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
def sample_sensor_potential_distortions(quality_multiplier: float = 1.0) -> List[SensorPotentialDistortionInterface]:
|
|
866
|
+
"""
|
|
867
|
+
Sample the list of sensor potential distortions for the SimCATS Simulation class.
|
|
868
|
+
|
|
869
|
+
Args:
|
|
870
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
871
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
872
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
873
|
+
1.0.
|
|
874
|
+
|
|
875
|
+
Returns:
|
|
876
|
+
List[SensorPotentialDistortionInterface]: List of all sensor potential distortions for the
|
|
877
|
+
GaAs_v1_random_variations_v3 configuration.
|
|
878
|
+
"""
|
|
879
|
+
return [_sample_sensor_potential_pink_noise(quality_multiplier=quality_multiplier),
|
|
880
|
+
_sample_sensor_potential_rtn(quality_multiplier=quality_multiplier)]
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def sample_sensor_response_distortions(quality_multiplier: float = 1.0) -> List[SensorResponseDistortionInterface]:
|
|
884
|
+
"""
|
|
885
|
+
Sample the list of sensor response distortions for the SimCATS Simulation class.
|
|
886
|
+
|
|
887
|
+
Args:
|
|
888
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
889
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
890
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
891
|
+
1.0.
|
|
892
|
+
|
|
893
|
+
Returns:
|
|
894
|
+
List[SensorResponseDistortionInterface]: List of all sensor response distortions for the
|
|
895
|
+
GaAs_v1_random_variations_v3 configuration.
|
|
896
|
+
"""
|
|
897
|
+
return [_sample_sensor_response_rtn(quality_multiplier=quality_multiplier),
|
|
898
|
+
_sample_sensor_response_white_noise(quality_multiplier=quality_multiplier)]
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
def _add_one_tct(tct_params: List[np.ndarray],
|
|
902
|
+
shift_vec: np.ndarray) -> List[np.ndarray]:
|
|
903
|
+
"""
|
|
904
|
+
Helper function that adds one TCT to the list of TCTs, by shifting the last TCT by the shift vector.
|
|
905
|
+
|
|
906
|
+
Args:
|
|
907
|
+
tct_params: List of TCTs (or more precisely TCT parameters).
|
|
908
|
+
shift_vec: The vector that describes the shift between two adjacent TCTs.
|
|
909
|
+
|
|
910
|
+
Returns:
|
|
911
|
+
List[np.ndarray]: The list of TCTs including one additional TCT.
|
|
912
|
+
"""
|
|
913
|
+
temp_params = tct_params[-1].copy()
|
|
914
|
+
temp_params[4] += shift_vec[0]
|
|
915
|
+
temp_params[5] += shift_vec[1]
|
|
916
|
+
temp_params[6] += shift_vec[0]
|
|
917
|
+
temp_params[7] += shift_vec[1]
|
|
918
|
+
tct_params.append(temp_params)
|
|
919
|
+
return tct_params
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
def _sample_occupation_transition_blurring_fermi_dirac() -> OccupationTransitionBlurringFermiDirac:
|
|
923
|
+
"""
|
|
924
|
+
Sample parameters and initialize an OccupationTransitionBlurringFermiDirac object.
|
|
925
|
+
|
|
926
|
+
Returns:
|
|
927
|
+
OccupationTransitionBlurringFermiDirac: Fully initialized OccupationTransitionBlurringFermiDirac object.
|
|
928
|
+
"""
|
|
929
|
+
occ_trans_blur_fermi_dirac_sigma_min = (
|
|
930
|
+
0.25 * 0.03 / 100
|
|
931
|
+
)
|
|
932
|
+
occ_trans_blur_fermi_dirac_sigma_max = 2 * 0.03 / 100 # changed min and max starting with random_variations_v2
|
|
933
|
+
# use 3*sigma distance from mean to borders
|
|
934
|
+
std_transition_blurring = (occ_trans_blur_fermi_dirac_sigma_max - occ_trans_blur_fermi_dirac_sigma_min) / 6
|
|
935
|
+
return OccupationTransitionBlurringFermiDirac(
|
|
936
|
+
sigma=NormalSamplingRange(
|
|
937
|
+
total_range=(occ_trans_blur_fermi_dirac_sigma_min, occ_trans_blur_fermi_dirac_sigma_max),
|
|
938
|
+
std=std_transition_blurring,
|
|
939
|
+
) # using other sampler starting with random_variations_v2
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
def _sample_occupation_dot_jumps_g1() -> OccupationDotJumps:
|
|
944
|
+
"""
|
|
945
|
+
Sample parameters and initialize an OccupationDotJumps object affecting g1.
|
|
946
|
+
|
|
947
|
+
Returns:
|
|
948
|
+
OccupationDotJumps: Fully initialized OccupationDotJumps object.
|
|
949
|
+
"""
|
|
950
|
+
return OccupationDotJumps(ratio=0.01 / 6,
|
|
951
|
+
scale=100 * 0.03 / 100,
|
|
952
|
+
lam=6 * 0.03 / 100,
|
|
953
|
+
axis=1)
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def _sample_occupation_dot_jumps_g2() -> OccupationDotJumps:
|
|
957
|
+
"""
|
|
958
|
+
Sample parameters and initialize an OccupationDotJumps object affecting g2.
|
|
959
|
+
|
|
960
|
+
Returns:
|
|
961
|
+
OccupationDotJumps: Fully initialized OccupationDotJumps object.
|
|
962
|
+
"""
|
|
963
|
+
return OccupationDotJumps(ratio=0.01,
|
|
964
|
+
scale=100 * 0.03 / 100,
|
|
965
|
+
lam=6 * 0.03 / 100,
|
|
966
|
+
axis=0)
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
def _sample_sensor_potential_pink_noise(quality_multiplier: float = 1.0) -> SensorPotentialPinkNoise:
|
|
970
|
+
"""
|
|
971
|
+
Sample parameters and initialize a SensorPotentialPinkNoise object.
|
|
972
|
+
|
|
973
|
+
Args:
|
|
974
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
975
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
976
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
977
|
+
1.0.
|
|
978
|
+
|
|
979
|
+
Returns:
|
|
980
|
+
SensorPotentialPinkNoise: Fully initialized SensorPotentialPinkNoise object.
|
|
981
|
+
"""
|
|
982
|
+
sensor_pot_pink_sigma_min, sensor_pot_pink_sigma_max = 1e-10, 0.0005 # reduced max starting with random_variations_v2
|
|
983
|
+
quantile_relative_pos = 0.6 * quality_multiplier
|
|
984
|
+
quantile_percentage = 0.99
|
|
985
|
+
exp_scale_sensor_dot_pink = quantile_relative_pos / np.log(1 / (1 - quantile_percentage))
|
|
986
|
+
return SensorPotentialPinkNoise(
|
|
987
|
+
sigma=ExponentialSamplingRange(
|
|
988
|
+
total_range=(sensor_pot_pink_sigma_min, sensor_pot_pink_sigma_max),
|
|
989
|
+
scale=exp_scale_sensor_dot_pink
|
|
990
|
+
) # using other sampler starting with random_variations_v2
|
|
991
|
+
)
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
def _sample_sensor_potential_rtn(quality_multiplier: float = 1.0) -> SensorPotentialRTN:
|
|
995
|
+
"""
|
|
996
|
+
Sample parameters and initialize a SensorPotentialRTN object.
|
|
997
|
+
|
|
998
|
+
Args:
|
|
999
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
1000
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
1001
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
1002
|
+
1.0.
|
|
1003
|
+
|
|
1004
|
+
Returns:
|
|
1005
|
+
SensorPotentialRTN: Fully initialized SensorPotentialRTN object.
|
|
1006
|
+
"""
|
|
1007
|
+
return SensorPotentialRTN(
|
|
1008
|
+
scale=74.56704 * 0.03 / 100,
|
|
1009
|
+
std=3.491734e-05,
|
|
1010
|
+
height=2.53855325e-05,
|
|
1011
|
+
ratio=1 / 6 * quality_multiplier,
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
def _sample_sensor_response_rtn(quality_multiplier: float = 1.0) -> SensorResponseRTN:
|
|
1016
|
+
"""
|
|
1017
|
+
Sample parameters and initialize a SensorResponseRTN object.
|
|
1018
|
+
|
|
1019
|
+
Args:
|
|
1020
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
1021
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
1022
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
1023
|
+
1.0.
|
|
1024
|
+
|
|
1025
|
+
Returns:
|
|
1026
|
+
SensorResponseRTN: Fully initialized SensorResponseRTN object.
|
|
1027
|
+
"""
|
|
1028
|
+
return SensorResponseRTN(
|
|
1029
|
+
scale=10000 * 0.03 / 100,
|
|
1030
|
+
std=0.047453767599999995,
|
|
1031
|
+
height=0.0152373696,
|
|
1032
|
+
ratio=0.01 * quality_multiplier,
|
|
1033
|
+
# reduced to 0.01 from 0.03 (not required as often with lots of images)
|
|
1034
|
+
)
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
def _sample_sensor_response_white_noise(quality_multiplier: float = 1.0) -> SensorResponseWhiteNoise:
|
|
1038
|
+
"""
|
|
1039
|
+
Sample parameters and initialize a SensorResponseWhiteNoise object.
|
|
1040
|
+
|
|
1041
|
+
Args:
|
|
1042
|
+
quality_multiplier: The quality multiplier to use, which defines how much of the ranges for the strength of
|
|
1043
|
+
distortions is used. This basically allows to restrict configurations to better data quality, as future
|
|
1044
|
+
improvements of the sample quality are expected. The factor must be in the range (0.0, 1.0]. Defaults to
|
|
1045
|
+
1.0.
|
|
1046
|
+
|
|
1047
|
+
Returns:
|
|
1048
|
+
SensorResponseWhiteNoise: Fully initialized SensorResponseWhiteNoise object.
|
|
1049
|
+
"""
|
|
1050
|
+
sensor_res_white_sigma_min, sensor_res_white_sigma_max = 1e-10, 0.0005 # reduced max starting with random_variations_v2
|
|
1051
|
+
quantile_relative_pos = 0.6 * quality_multiplier
|
|
1052
|
+
quantile_percentage = 0.99
|
|
1053
|
+
exp_scale_res_white = quantile_relative_pos / np.log(1 / (1 - quantile_percentage))
|
|
1054
|
+
return SensorResponseWhiteNoise(
|
|
1055
|
+
sigma=ExponentialSamplingRange(
|
|
1056
|
+
total_range=(sensor_res_white_sigma_min, sensor_res_white_sigma_max),
|
|
1057
|
+
scale=exp_scale_res_white
|
|
1058
|
+
) # using other sampler starting with random_variations_v2
|
|
1059
|
+
)
|