emccd-detect 2.2.5__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.
- emccd_detect/__init__.py +2 -0
- emccd_detect/cosmics.py +124 -0
- emccd_detect/emccd_detect.py +693 -0
- emccd_detect/rand_em_gain.py +187 -0
- emccd_detect/util/__init__.py +1 -0
- emccd_detect/util/metadata.yaml +60 -0
- emccd_detect/util/read_metadata.py +90 -0
- emccd_detect/util/read_metadata_wrapper.py +157 -0
- emccd_detect-2.2.5.dist-info/METADATA +69 -0
- emccd_detect-2.2.5.dist-info/RECORD +12 -0
- emccd_detect-2.2.5.dist-info/WHEEL +5 -0
- emccd_detect-2.2.5.dist-info/top_level.txt +1 -0
emccd_detect/__init__.py
ADDED
emccd_detect/cosmics.py
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""Generate cosmic hits."""
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
|
7
|
+
def cosmic_hits(image_frame, cr_rate, frametime, pixel_pitch, max_val):
|
8
|
+
"""Generate cosmic hits.
|
9
|
+
|
10
|
+
This function does not return the values of the cosmics; instead it returns
|
11
|
+
the electron map which occurs as a result of the photelectric effect when
|
12
|
+
the cosmics strike the detector. This allows the user to ignore the
|
13
|
+
physical properties of the cosmics and focus only on their effect on the
|
14
|
+
detector. This is especially helpful when setting max_val greater than the
|
15
|
+
full well capacity, as it allows the user to create saturated cosmics.
|
16
|
+
|
17
|
+
Parameters
|
18
|
+
----------
|
19
|
+
image_frame : array_like
|
20
|
+
Image area frame (e-).
|
21
|
+
cr_rate : float
|
22
|
+
Cosmic ray rate (hits/cm^2/s).
|
23
|
+
frametime : float
|
24
|
+
Frame time (s).
|
25
|
+
pixel_pitch : float
|
26
|
+
Distance between pixel centers (m).
|
27
|
+
max_val : float
|
28
|
+
Maximum value of cosmic hit (e-).
|
29
|
+
|
30
|
+
Returns
|
31
|
+
-------
|
32
|
+
image_frame : array_like
|
33
|
+
Image area frame with cosmics added (e-).
|
34
|
+
|
35
|
+
"""
|
36
|
+
if cr_rate > 0:
|
37
|
+
# Find number of hits/frame
|
38
|
+
nr, nc = image_frame.shape
|
39
|
+
framesize = (nr*pixel_pitch * nc*pixel_pitch) / 10**-4 # cm^2
|
40
|
+
hits_per_second = cr_rate * framesize
|
41
|
+
hits_per_frame = int(round(hits_per_second * frametime))
|
42
|
+
|
43
|
+
# Generate hit locations
|
44
|
+
# Describe each hit as a gaussian centered at (hit_row, hit_col) and having
|
45
|
+
# a radius of hit_rad chosen between cr_min_radius and cr_max_radius
|
46
|
+
cr_min_radius = 0
|
47
|
+
cr_max_radius = 2
|
48
|
+
hit_row = np.random.uniform(low=0, high=nr-1, size=hits_per_frame)
|
49
|
+
hit_col = np.random.uniform(low=0, high=nc-1, size=hits_per_frame)
|
50
|
+
hit_rad = np.random.uniform(low=cr_min_radius, high=cr_max_radius,
|
51
|
+
size=hits_per_frame)
|
52
|
+
|
53
|
+
# Create hits
|
54
|
+
for i in range(hits_per_frame):
|
55
|
+
# Get pixels where cosmic lands
|
56
|
+
min_row = max(np.floor(hit_row[i] - hit_rad[i]).astype(int), 0)
|
57
|
+
max_row = min(np.ceil(hit_row[i] + hit_rad[i]).astype(int), nr-1)
|
58
|
+
min_col = max(np.floor(hit_col[i] - hit_rad[i]).astype(int), 0)
|
59
|
+
max_col = min(np.ceil(hit_col[i] + hit_rad[i]).astype(int), nc-1)
|
60
|
+
cols, rows = np.meshgrid(np.arange(min_col, max_col+1),
|
61
|
+
np.arange(min_row, max_row+1))
|
62
|
+
|
63
|
+
# Create gaussian
|
64
|
+
sigma = 0.5
|
65
|
+
a = 1 / (np.sqrt(2*np.pi) * sigma)
|
66
|
+
b = 2 * sigma**2
|
67
|
+
cosm_section = a * np.exp(-((rows-hit_row[i])**2 + (cols-hit_col[i])**2) / b)
|
68
|
+
|
69
|
+
# Scale by maximum value
|
70
|
+
cosm_section = cosm_section / np.max(cosm_section) * max_val
|
71
|
+
|
72
|
+
# Add cosmic to frame
|
73
|
+
image_frame[min_row:max_row+1, min_col:max_col+1] += cosm_section
|
74
|
+
|
75
|
+
return image_frame
|
76
|
+
|
77
|
+
|
78
|
+
def sat_tails(serial_frame, full_well_serial):
|
79
|
+
"""Simulate tails created by serial register saturation.
|
80
|
+
|
81
|
+
This is most prevalent in cosmic hits.
|
82
|
+
|
83
|
+
Parameters
|
84
|
+
----------
|
85
|
+
serial_frame : array_like
|
86
|
+
Serial register frame (e-).
|
87
|
+
full_well_serial : float
|
88
|
+
Serial (gain) register full well capacity (e-).
|
89
|
+
|
90
|
+
"""
|
91
|
+
overflow = 0.
|
92
|
+
overflow_i = 0.
|
93
|
+
for i, pix in enumerate(serial_frame):
|
94
|
+
serial_frame[i] += _set_tail_val(overflow, overflow_i, i)
|
95
|
+
|
96
|
+
if serial_frame[i] > full_well_serial:
|
97
|
+
overflow = serial_frame[i] - full_well_serial
|
98
|
+
overflow_i = i
|
99
|
+
|
100
|
+
return serial_frame
|
101
|
+
|
102
|
+
|
103
|
+
def _set_tail_val(overflow, overflow_i, i):
|
104
|
+
relative_i = i+1 - overflow_i
|
105
|
+
tail_val = overflow * 1 / relative_i
|
106
|
+
if tail_val < 1000:
|
107
|
+
tail_val = 0
|
108
|
+
|
109
|
+
return tail_val
|
110
|
+
|
111
|
+
|
112
|
+
if __name__ == '__main__':
|
113
|
+
import matplotlib.pyplot as plt
|
114
|
+
|
115
|
+
full_well_serial = 90000
|
116
|
+
|
117
|
+
row = np.ones(100)
|
118
|
+
row[2] = full_well_serial * 2
|
119
|
+
|
120
|
+
tail_row = sat_tails(row, full_well_serial)
|
121
|
+
|
122
|
+
plt.figure()
|
123
|
+
plt.plot(tail_row)
|
124
|
+
plt.show()
|