flimkit 0.12.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.
- flimkit/FLIM/__init__.py +0 -0
- flimkit/FLIM/assemble.py +254 -0
- flimkit/FLIM/batch.py +681 -0
- flimkit/FLIM/bg_tools.py +51 -0
- flimkit/FLIM/fit_tools.py +244 -0
- flimkit/FLIM/fitters.py +1471 -0
- flimkit/FLIM/irf_tools.py +617 -0
- flimkit/FLIM/models.py +391 -0
- flimkit/GPU/__init__.py +85 -0
- flimkit/GPU/_base.py +391 -0
- flimkit/GPU/cuda.py +10 -0
- flimkit/GPU/mlx_backend.py +381 -0
- flimkit/GPU/mps.py +10 -0
- flimkit/GPU/rocm.py +10 -0
- flimkit/GPU/torch_backend.py +385 -0
- flimkit/UI/app_state.py +10 -0
- flimkit/UI/controller.py +139 -0
- flimkit/UI/expert_settings.py +248 -0
- flimkit/UI/fit_help.py +206 -0
- flimkit/UI/fov_preview.py +1085 -0
- flimkit/UI/gui.py +3919 -0
- flimkit/UI/icon.icns +0 -0
- flimkit/UI/icon.ico +0 -0
- flimkit/UI/icon.png +0 -0
- flimkit/UI/irf_widget.py +103 -0
- flimkit/UI/mode_controller.py +118 -0
- flimkit/UI/modes/__init__.py +0 -0
- flimkit/UI/modes/base.py +3 -0
- flimkit/UI/modes/batch_mode.py +312 -0
- flimkit/UI/modes/fov_mode.py +164 -0
- flimkit/UI/modes/irf_mode.py +80 -0
- flimkit/UI/modes/phasor_mode.py +131 -0
- flimkit/UI/modes/stitch_mode.py +254 -0
- flimkit/UI/phasor_panel.py +1087 -0
- flimkit/UI/progress_window.py +113 -0
- flimkit/UI/project_panel.py +262 -0
- flimkit/UI/results_panel.py +332 -0
- flimkit/UI/roi_tools.py +794 -0
- flimkit/UI/utils.py +217 -0
- flimkit/__init__.py +0 -0
- flimkit/_version.py +41 -0
- flimkit/cli.py +120 -0
- flimkit/configs.py +148 -0
- flimkit/dialogs.py +46 -0
- flimkit/formats/BH/__init__.py +0 -0
- flimkit/formats/BH/reader.py +296 -0
- flimkit/formats/BH/writer.py +86 -0
- flimkit/formats/ISS/__init__.py +0 -0
- flimkit/formats/ISS/fdflim.py +86 -0
- flimkit/formats/ISS/image.py +114 -0
- flimkit/formats/ISS/reader.py +223 -0
- flimkit/formats/PS/__init__.py +0 -0
- flimkit/formats/PS/reader.py +202 -0
- flimkit/formats/PTU/__init__.py +0 -0
- flimkit/formats/PTU/decode.py +27 -0
- flimkit/formats/PTU/phu.py +85 -0
- flimkit/formats/PTU/reader.py +235 -0
- flimkit/formats/PTU/series.py +258 -0
- flimkit/formats/PTU/stitch.py +1182 -0
- flimkit/formats/PTU/tools.py +94 -0
- flimkit/formats/__init__.py +2 -0
- flimkit/formats/flim_file.py +232 -0
- flimkit/formats/phasor.py +132 -0
- flimkit/formats/signal.py +170 -0
- flimkit/image/tools.py +124 -0
- flimkit/interactive.py +1857 -0
- flimkit/mpl_backend.py +22 -0
- flimkit/phasor/__init__.py +40 -0
- flimkit/phasor/filters.py +127 -0
- flimkit/phasor/fret.py +654 -0
- flimkit/phasor/interactive.py +556 -0
- flimkit/phasor/peaks.py +186 -0
- flimkit/phasor/signal.py +90 -0
- flimkit/phasor_launcher.py +314 -0
- flimkit/plugins/__init__.py +137 -0
- flimkit/plugins/bindings.py +116 -0
- flimkit/plugins/builtin/__init__.py +3 -0
- flimkit/plugins/builtin/core_tools.py +28 -0
- flimkit/plugins/loader.py +371 -0
- flimkit/plugins/registry.py +406 -0
- flimkit/project.py +197 -0
- flimkit/synth.py +145 -0
- flimkit/utils/__init__.py +0 -0
- flimkit/utils/batch_fit.py +301 -0
- flimkit/utils/config_manager.py +119 -0
- flimkit/utils/config_snapshot.py +30 -0
- flimkit/utils/crash_handler.py +183 -0
- flimkit/utils/display.py +197 -0
- flimkit/utils/enhanced_outputs.py +345 -0
- flimkit/utils/fancy.py +103 -0
- flimkit/utils/lifetime_image.py +243 -0
- flimkit/utils/misc.py +111 -0
- flimkit/utils/plotting.py +190 -0
- flimkit/utils/roi.py +370 -0
- flimkit/utils/session.py +51 -0
- flimkit/utils/update_check.py +198 -0
- flimkit/utils/xlsx_tools.py +97 -0
- flimkit/utils/xml_utils.py +219 -0
- flimkit-0.12.0.dist-info/METADATA +356 -0
- flimkit-0.12.0.dist-info/RECORD +104 -0
- flimkit-0.12.0.dist-info/WHEEL +5 -0
- flimkit-0.12.0.dist-info/entry_points.txt +2 -0
- flimkit-0.12.0.dist-info/licenses/LICENSE.md +11 -0
- flimkit-0.12.0.dist-info/top_level.txt +1 -0
flimkit/FLIM/bg_tools.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from flimkit.formats import FLIMFile
|
|
3
|
+
|
|
4
|
+
def _resample_decay(decay, src_res, dst_res, n_bins):
|
|
5
|
+
decay = np.asarray(decay, dtype=float)
|
|
6
|
+
src_t = np.arange(decay.size, dtype=float) * src_res
|
|
7
|
+
dst_t = np.arange(n_bins, dtype=float) * dst_res
|
|
8
|
+
return np.interp(dst_t, src_t, decay)
|
|
9
|
+
|
|
10
|
+
def _fit_to_grid(decay, n_bins):
|
|
11
|
+
decay = np.asarray(decay, dtype=float)
|
|
12
|
+
if decay.size < n_bins:
|
|
13
|
+
return np.concatenate([decay, np.zeros(n_bins - decay.size)])
|
|
14
|
+
return decay[:n_bins]
|
|
15
|
+
|
|
16
|
+
def _normalize_profile(decay, normalize):
|
|
17
|
+
decay = np.asarray(decay, dtype=float)
|
|
18
|
+
total = float(decay.sum())
|
|
19
|
+
if total <= 0:
|
|
20
|
+
raise ValueError('Background profile has no photons.')
|
|
21
|
+
if normalize:
|
|
22
|
+
return decay / total
|
|
23
|
+
return decay
|
|
24
|
+
|
|
25
|
+
def tvb_from_reference_ptu(path, ptu_ref, channel=None, normalize=True):
|
|
26
|
+
ref = FLIMFile(path, verbose=False)
|
|
27
|
+
decay = ref.summed_decay(channel=channel)
|
|
28
|
+
total = decay.sum()
|
|
29
|
+
if total == 0 and channel is not None:
|
|
30
|
+
decay = ref.summed_decay(channel=None)
|
|
31
|
+
total = decay.sum()
|
|
32
|
+
if total > 0:
|
|
33
|
+
print(f" Background PTU has no photons on channel {channel}; "
|
|
34
|
+
f"using auto-detected channel {ref.photon_channel} instead")
|
|
35
|
+
if total == 0:
|
|
36
|
+
raise ValueError(f"Background PTU {path!r} has no photons.")
|
|
37
|
+
if abs(ref.tcspc_res - ptu_ref.tcspc_res) > 1e-15:
|
|
38
|
+
decay = _resample_decay(decay, ref.tcspc_res, ptu_ref.tcspc_res, ptu_ref.n_bins)
|
|
39
|
+
else:
|
|
40
|
+
decay = _fit_to_grid(decay, ptu_ref.n_bins)
|
|
41
|
+
print(f" TVB profile from PTU: {total:,.0f} photons")
|
|
42
|
+
return _normalize_profile(decay, normalize)
|
|
43
|
+
|
|
44
|
+
def tvb_from_decay(decay, n_bins, src_tcspc_res=None, dst_tcspc_res=None, normalize=True):
|
|
45
|
+
decay = np.asarray(decay, dtype=float)
|
|
46
|
+
if (src_tcspc_res is not None and dst_tcspc_res is not None
|
|
47
|
+
and abs(src_tcspc_res - dst_tcspc_res) > 1e-15):
|
|
48
|
+
decay = _resample_decay(decay, src_tcspc_res, dst_tcspc_res, n_bins)
|
|
49
|
+
else:
|
|
50
|
+
decay = _fit_to_grid(decay, n_bins)
|
|
51
|
+
return _normalize_profile(decay, normalize)
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.ndimage import gaussian_filter1d
|
|
3
|
+
from scipy.optimize import curve_fit
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def distribution_dof(n_fit, n_components=1, fit_tvb=False):
|
|
7
|
+
n_params = 3 * n_components + 1 + int(fit_tvb)
|
|
8
|
+
return max(int(n_fit) - n_params, 1)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def chi2_terms(data, model, axis=None):
|
|
12
|
+
data_arr, model_arr = np.broadcast_arrays(
|
|
13
|
+
np.asarray(data, dtype=float), np.asarray(model, dtype=float))
|
|
14
|
+
valid = np.all(
|
|
15
|
+
np.isfinite(data_arr) & (data_arr >= 0.0)
|
|
16
|
+
& np.isfinite(model_arr) & (model_arr >= 0.0),
|
|
17
|
+
axis=axis)
|
|
18
|
+
with np.errstate(divide='ignore', invalid='ignore', over='ignore'):
|
|
19
|
+
numerator = np.sum(
|
|
20
|
+
(data_arr - model_arr) ** 2 / np.maximum(model_arr, 1.0), axis=axis)
|
|
21
|
+
expected = np.sum(np.minimum(model_arr, 1.0), axis=axis)
|
|
22
|
+
return numerator, expected, valid
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def calibrated_from_terms(numerator, expected, valid):
|
|
26
|
+
if np.ndim(expected) == 0:
|
|
27
|
+
return (float(numerator / expected)
|
|
28
|
+
if valid and expected > 0 else np.nan)
|
|
29
|
+
result = np.full(np.shape(expected), np.nan, dtype=float)
|
|
30
|
+
return np.divide(
|
|
31
|
+
numerator, expected, out=result,
|
|
32
|
+
where=valid & (expected > 0) & np.isfinite(numerator))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def calibrated_chi2(data, model, axis=None):
|
|
36
|
+
numerator, expected, valid = chi2_terms(data, model, axis=axis)
|
|
37
|
+
if np.ndim(expected) == 0:
|
|
38
|
+
return float(numerator / expected) if valid and expected > 0 else np.nan
|
|
39
|
+
return calibrated_from_terms(numerator, expected, valid)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def coates_pileup_correction(decay: np.ndarray, n_sync: int):
|
|
43
|
+
m = np.asarray(decay, dtype=float)
|
|
44
|
+
n_s = float(n_sync or 0.0)
|
|
45
|
+
total = float(m.sum())
|
|
46
|
+
if n_s <= 0.0 or n_s <= total:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f'coates_pileup_correction needs the excitation-pulse count N_sync; got '
|
|
49
|
+
f'n_sync={n_s:,.0f} for {total:,.0f} photons. N_sync must exceed the photon count.')
|
|
50
|
+
cumulative = np.concatenate([[0.0], np.cumsum(m[:-1])])
|
|
51
|
+
denom = n_s - cumulative
|
|
52
|
+
# Argument of log: 1 - M(t)/(N_s - C(t))
|
|
53
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
|
54
|
+
ratio = np.where(denom > 0, m / denom, 0.0)
|
|
55
|
+
arg = 1.0 - ratio
|
|
56
|
+
safe = arg > 0.0
|
|
57
|
+
corrected = np.where(safe, -n_s * np.log(arg), 0.0)
|
|
58
|
+
return corrected
|
|
59
|
+
|
|
60
|
+
def bins_from_ns(value_ns, tcspc_res):
|
|
61
|
+
return int(round(float(value_ns) * 1e-9 / tcspc_res))
|
|
62
|
+
|
|
63
|
+
def build_fit_idx(fit_start, fit_end, n_bins, exclude_bins=None):
|
|
64
|
+
# explicit bin set the fit runs over: a contiguous window minus any excluded
|
|
65
|
+
# bands (eg a reflection peak mid-decay). Dropping bins keeps the fit linear
|
|
66
|
+
# in the amplitudes, so the per-pixel projection is unaffected.
|
|
67
|
+
idx = np.arange(max(0, int(fit_start)), min(int(n_bins), int(fit_end)), dtype=int)
|
|
68
|
+
if exclude_bins:
|
|
69
|
+
keep = np.ones(idx.shape, dtype=bool)
|
|
70
|
+
for lo, hi in exclude_bins:
|
|
71
|
+
keep &= ~((idx >= int(lo)) & (idx < int(hi)))
|
|
72
|
+
idx = idx[keep]
|
|
73
|
+
if idx.size == 0:
|
|
74
|
+
raise ValueError('fit window is empty (check the window and any exclusion bands)')
|
|
75
|
+
return idx
|
|
76
|
+
|
|
77
|
+
def find_irf_peak_bin(decay: np.ndarray, smooth_sigma: float = 1.5):
|
|
78
|
+
smoothed = gaussian_filter1d(decay.astype(float), sigma=smooth_sigma)
|
|
79
|
+
deriv = np.gradient(smoothed)
|
|
80
|
+
# Only search in the first half of the histogram (rising edge region)
|
|
81
|
+
half = len(decay) // 2
|
|
82
|
+
peak_bin = int(np.argmax(deriv[:half]))
|
|
83
|
+
return peak_bin
|
|
84
|
+
|
|
85
|
+
def estimate_bg(decay: np.ndarray, peak_bin: int, pre_gap: int = 5):
|
|
86
|
+
end = max(0, peak_bin - pre_gap)
|
|
87
|
+
region = decay[:end]
|
|
88
|
+
if len(region) >= 5:
|
|
89
|
+
return max(float(np.median(region)), 0.0)
|
|
90
|
+
return max(float(np.median(decay[-30:])), 0.0)
|
|
91
|
+
|
|
92
|
+
def estimate_bg_from_histogram(hist, pre_bins=20):
|
|
93
|
+
if hist.ndim == 3:
|
|
94
|
+
bg_region = hist[..., :pre_bins].mean()
|
|
95
|
+
else:
|
|
96
|
+
bg_region = hist[:pre_bins].mean()
|
|
97
|
+
return float(bg_region)
|
|
98
|
+
|
|
99
|
+
def find_fit_start(decay: np.ndarray, irf_prompt: np.ndarray,
|
|
100
|
+
tcspc_res: float, pre_bins: int = 5):
|
|
101
|
+
threshold = irf_prompt.max() * 1e-3
|
|
102
|
+
onset_bins = np.where(irf_prompt >= threshold)[0]
|
|
103
|
+
if len(onset_bins) == 0:
|
|
104
|
+
return 0
|
|
105
|
+
onset = int(onset_bins[0])
|
|
106
|
+
fit_start = max(0, onset - pre_bins)
|
|
107
|
+
return fit_start
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def find_tail_fit_start(decay, peak_bin, n_bins, frac=0.9):
|
|
111
|
+
d = np.asarray(decay, dtype=float)
|
|
112
|
+
peak_val = float(d[peak_bin]) if 0 <= peak_bin < n_bins else 0.0
|
|
113
|
+
if peak_val <= 0:
|
|
114
|
+
return min(peak_bin + 1, n_bins - 1)
|
|
115
|
+
below = np.where(d[peak_bin:] < frac * peak_val)[0]
|
|
116
|
+
if len(below) == 0:
|
|
117
|
+
return min(peak_bin + 1, n_bins - 1)
|
|
118
|
+
return int(min(peak_bin + below[0], n_bins - 1))
|
|
119
|
+
|
|
120
|
+
def _build_bounds_tail(n_exp, tau_min, tau_max, decay_peak, fit_bg,
|
|
121
|
+
bg_init=0.0, bg_upper=None,
|
|
122
|
+
fit_t0=False, t0_init=0.0, t0_range=0.0,
|
|
123
|
+
fit_tvb=False, tvb_init=0.0, tvb_upper=None):
|
|
124
|
+
lo = [tau_min] * n_exp + [0.0] * n_exp
|
|
125
|
+
hi = [tau_max] * n_exp + [10 * decay_peak] * n_exp
|
|
126
|
+
if fit_t0:
|
|
127
|
+
lo += [t0_init - t0_range]; hi += [t0_init + t0_range]
|
|
128
|
+
if fit_bg:
|
|
129
|
+
_bg_hi = bg_upper if bg_upper is not None else bg_init * 1.5 + 10
|
|
130
|
+
lo += [0.0]; hi += [_bg_hi]
|
|
131
|
+
if fit_tvb:
|
|
132
|
+
_tvb_hi = tvb_upper if tvb_upper is not None else tvb_init * 1.5 + 10
|
|
133
|
+
lo += [0.0]; hi += [_tvb_hi]
|
|
134
|
+
return lo, hi
|
|
135
|
+
|
|
136
|
+
def _pack_p0_tail(n_exp, tau_min, tau_max, decay_peak, fit_bg, bg_init,
|
|
137
|
+
tau_override=None, fit_t0=False, t0_init=0.0,
|
|
138
|
+
fit_tvb=False, tvb_init=0.0):
|
|
139
|
+
if tau_override is not None:
|
|
140
|
+
taus0 = np.asarray(tau_override)
|
|
141
|
+
else:
|
|
142
|
+
tmin = max(tau_min, 1e-14) * 1.001
|
|
143
|
+
tmax = tau_max * 0.999
|
|
144
|
+
taus0 = np.logspace(np.log10(tmin), np.log10(tmax), n_exp)
|
|
145
|
+
amps0 = np.full(n_exp, decay_peak / n_exp)
|
|
146
|
+
base = np.concatenate([taus0, amps0])
|
|
147
|
+
if fit_t0:
|
|
148
|
+
base = np.concatenate([base, [t0_init]])
|
|
149
|
+
if fit_bg:
|
|
150
|
+
base = np.concatenate([base, [bg_init]])
|
|
151
|
+
if fit_tvb:
|
|
152
|
+
base = np.concatenate([base, [tvb_init]])
|
|
153
|
+
return base
|
|
154
|
+
|
|
155
|
+
def find_fit_end(decay, peak_bin, tau_max_s, tcspc_res, n_bins):
|
|
156
|
+
candidate = min(n_bins, peak_bin + int(6.0 * tau_max_s / tcspc_res))
|
|
157
|
+
search_start = int(0.82 * n_bins)
|
|
158
|
+
tail = gaussian_filter1d(decay[search_start:].astype(float), sigma=2)
|
|
159
|
+
deriv = np.gradient(tail)
|
|
160
|
+
thresh = 3.0 * np.std(deriv[:max(1, len(deriv)//2)])
|
|
161
|
+
spikes = np.where(deriv > thresh)[0]
|
|
162
|
+
if len(spikes) > 0:
|
|
163
|
+
spike_abs = search_start + spikes[0]
|
|
164
|
+
if spike_abs < candidate:
|
|
165
|
+
print(f" Next-period artefact at bin {spike_abs} "
|
|
166
|
+
f"({spike_abs*tcspc_res*1e9:.2f} ns). Truncating fit window.")
|
|
167
|
+
candidate = spike_abs
|
|
168
|
+
return candidate
|
|
169
|
+
|
|
170
|
+
def _build_bounds(n_exp, tau_min, tau_max, decay_peak,
|
|
171
|
+
has_tail, fit_bg, fit_sigma, bg_init=0.0, bg_upper=None,
|
|
172
|
+
sigma_max=3.0, irf_shift_bins=5,
|
|
173
|
+
fit_tvb=False, tvb_init=0.0, tvb_upper=None):
|
|
174
|
+
lo = [tau_min] * n_exp + [0.0] * n_exp + [-float(irf_shift_bins)]
|
|
175
|
+
hi = [tau_max] * n_exp + [10 * decay_peak] * n_exp + [float(irf_shift_bins)]
|
|
176
|
+
if fit_sigma:
|
|
177
|
+
lo += [0.0]; hi += [sigma_max]
|
|
178
|
+
if fit_bg:
|
|
179
|
+
_bg_hi = bg_upper if bg_upper is not None else bg_init * 1.5 + 10
|
|
180
|
+
lo += [0.0]; hi += [_bg_hi]
|
|
181
|
+
if fit_tvb:
|
|
182
|
+
_tvb_hi = tvb_upper if tvb_upper is not None else tvb_init * 1.5 + 10
|
|
183
|
+
lo += [0.0]; hi += [_tvb_hi]
|
|
184
|
+
if has_tail:
|
|
185
|
+
lo += [0.0, 1.0]
|
|
186
|
+
hi += [5.0, 200.0]
|
|
187
|
+
return lo, hi
|
|
188
|
+
|
|
189
|
+
def _build_bounds_dist(n_components, tau_min, tau_max, decay_peak,
|
|
190
|
+
fit_bg, fit_sigma, bg_init=0.0, bg_upper=None,
|
|
191
|
+
sigma_max=3.0, irf_shift_bins=5,
|
|
192
|
+
fit_tvb=False, tvb_init=0.0, tvb_upper=None):
|
|
193
|
+
width_max = (tau_max - tau_min) / 2.0
|
|
194
|
+
width_min = tau_min / 20.0
|
|
195
|
+
lo = [tau_min] * n_components + [width_min] * n_components + [0.0] * n_components + [-float(irf_shift_bins)]
|
|
196
|
+
hi = [tau_max] * n_components + [width_max] * n_components + [10 * decay_peak] * n_components + [float(irf_shift_bins)]
|
|
197
|
+
if fit_sigma:
|
|
198
|
+
lo += [0.0]; hi += [sigma_max]
|
|
199
|
+
if fit_bg:
|
|
200
|
+
_bg_hi = bg_upper if bg_upper is not None else bg_init * 1.5 + 10
|
|
201
|
+
lo += [0.0]; hi += [_bg_hi]
|
|
202
|
+
if fit_tvb:
|
|
203
|
+
_tvb_hi = tvb_upper if tvb_upper is not None else tvb_init * 1.5 + 10
|
|
204
|
+
lo += [0.0]; hi += [_tvb_hi]
|
|
205
|
+
return lo, hi
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _pack_p0_dist(n_components, tau_min, tau_max, decay_peak,
|
|
209
|
+
fit_bg, fit_sigma, bg_init, fit_tvb=False, tvb_init=0.0):
|
|
210
|
+
tmin = max(tau_min, 1e-14) * 1.001
|
|
211
|
+
tmax = tau_max * 0.999
|
|
212
|
+
tau0 = np.logspace(np.log10(tmin), np.log10(tmax), n_components)
|
|
213
|
+
width0 = tau0 * 0.2
|
|
214
|
+
amp0 = np.full(n_components, decay_peak / n_components)
|
|
215
|
+
base = np.concatenate([tau0, width0, amp0, [0.0]])
|
|
216
|
+
if fit_sigma:
|
|
217
|
+
base = np.concatenate([base, [0.3]])
|
|
218
|
+
if fit_bg:
|
|
219
|
+
base = np.concatenate([base, [bg_init]])
|
|
220
|
+
if fit_tvb:
|
|
221
|
+
base = np.concatenate([base, [tvb_init]])
|
|
222
|
+
return base
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _pack_p0(n_exp, tau_min, tau_max, decay_peak,
|
|
226
|
+
has_tail, fit_bg, fit_sigma, bg_init,
|
|
227
|
+
tau_override=None, fit_tvb=False, tvb_init=0.0):
|
|
228
|
+
if tau_override is not None:
|
|
229
|
+
taus0 = np.asarray(tau_override)
|
|
230
|
+
else:
|
|
231
|
+
tmin = max(tau_min, 1e-14) * 1.001
|
|
232
|
+
tmax = tau_max * 0.999
|
|
233
|
+
taus0 = np.logspace(np.log10(tmin), np.log10(tmax), n_exp)
|
|
234
|
+
amps0 = np.full(n_exp, decay_peak / n_exp)
|
|
235
|
+
base = np.concatenate([taus0, amps0, [0.0]])
|
|
236
|
+
if fit_sigma:
|
|
237
|
+
base = np.concatenate([base, [0.3]])
|
|
238
|
+
if fit_bg:
|
|
239
|
+
base = np.concatenate([base, [bg_init]])
|
|
240
|
+
if fit_tvb:
|
|
241
|
+
base = np.concatenate([base, [tvb_init]])
|
|
242
|
+
if has_tail:
|
|
243
|
+
base = np.concatenate([base, [0.5, 20.0]])
|
|
244
|
+
return base
|