154 lines
6.0 KiB
Python
154 lines
6.0 KiB
Python
|
|
from CellData import CellData
|
|
import numpy as np
|
|
from scipy.optimize import curve_fit
|
|
import matplotlib.pyplot as plt
|
|
from warnings import warn
|
|
import functions as fu
|
|
|
|
|
|
class FICurve:
|
|
|
|
def __init__(self, cell_data: CellData, contrast: bool = True):
|
|
self.cell_data = cell_data
|
|
self.using_contrast = contrast
|
|
|
|
if contrast:
|
|
self.stimulus_value = cell_data.get_fi_contrasts()
|
|
else:
|
|
self.stimulus_value = cell_data.get_fi_intensities()
|
|
|
|
self.f_zeros = []
|
|
self.f_infinities = []
|
|
self.f_baselines = []
|
|
|
|
# f_max, f_min, k, x_zero
|
|
self.boltzmann_fit_vars = []
|
|
# offset increase
|
|
self.f_infinity_fit = []
|
|
|
|
self.all_calculate_frequency_points()
|
|
self.fit_line()
|
|
self.fit_boltzmann()
|
|
|
|
def all_calculate_frequency_points(self):
|
|
mean_frequencies = self.cell_data.get_mean_isi_frequencies()
|
|
if len(mean_frequencies) == 0:
|
|
warn("FICurve:all_calculate_frequency_points(): mean_frequencies is empty.\n"
|
|
"Was all_calculate_mean_isi_frequencies already called?")
|
|
|
|
for freq in mean_frequencies:
|
|
self.f_zeros.append(self.__calculate_f_zero__(freq))
|
|
self.f_baselines.append(self.__calculate_f_baseline__(freq))
|
|
self.f_infinities.append(self.__calculate_f_infinity__(freq))
|
|
|
|
def fit_line(self):
|
|
popt, pcov = curve_fit(fu.clipped_line, self.stimulus_value, self.f_infinities)
|
|
self.f_infinity_fit = popt
|
|
|
|
def fit_boltzmann(self):
|
|
max_f0 = float(max(self.f_zeros))
|
|
min_f0 = float(min(self.f_zeros))
|
|
mean_int = float(np.mean(self.stimulus_value))
|
|
|
|
total_increase = max_f0 - min_f0
|
|
total_change_int = max(self.stimulus_value) - min(self.stimulus_value)
|
|
start_k = float((total_increase / total_change_int * 4) / max_f0)
|
|
|
|
popt, pcov = curve_fit(fu.full_boltzmann, self.stimulus_value, self.f_zeros,
|
|
p0=(max_f0, min_f0, start_k, mean_int),
|
|
maxfev=10000, bounds=([0, 0, -np.inf, -np.inf], [3000, 3000, np.inf, np.inf]))
|
|
|
|
self.boltzmann_fit_vars = popt
|
|
|
|
def plot_fi_curve(self, savepath: str = None):
|
|
min_x = min(self.stimulus_value)
|
|
max_x = max(self.stimulus_value)
|
|
step = (max_x - min_x) / 5000
|
|
x_values = np.arange(min_x, max_x, step)
|
|
|
|
plt.plot(self.stimulus_value, self.f_baselines, color='blue', label='f_base')
|
|
|
|
plt.plot(self.stimulus_value, self.f_infinities, 'o', color='lime', label='f_inf')
|
|
plt.plot(x_values, [fu.clipped_line(x, self.f_infinity_fit[0], self.f_infinity_fit[1]) for x in x_values],
|
|
color='darkgreen', label='f_inf_fit')
|
|
|
|
plt.plot(self.stimulus_value, self.f_zeros, 'o', color='orange', label='f_zero')
|
|
popt = self.boltzmann_fit_vars
|
|
plt.plot(x_values, [fu.full_boltzmann(x, popt[0], popt[1], popt[2], popt[3]) for x in x_values],
|
|
color='red', label='f_0_fit')
|
|
|
|
plt.legend()
|
|
plt.ylabel("Frequency [Hz]")
|
|
if self.using_contrast:
|
|
plt.xlabel("Stimulus contrast")
|
|
else:
|
|
plt.xlabel("Stimulus intensity [mv]")
|
|
if savepath is None:
|
|
plt.show()
|
|
else:
|
|
plt.savefig(savepath + "fi_curve.png")
|
|
plt.close()
|
|
|
|
def __calculate_f_baseline__(self, frequency, buffer=0.025):
|
|
delay = self.cell_data.get_delay()
|
|
sampling_interval = self.cell_data.get_sampling_interval()
|
|
if delay < 0.1:
|
|
warn("FICurve:__calculate_f_baseline__(): Quite short delay at the start.")
|
|
|
|
idx_start = int(buffer/sampling_interval)
|
|
idx_end = int((delay-buffer)/sampling_interval)
|
|
return np.mean(frequency[idx_start:idx_end])
|
|
|
|
def __calculate_f_zero__(self, frequency, length_of_mean=0.1, buffer=0.025):
|
|
stimulus_start = self.cell_data.get_delay() + self.cell_data.get_stimulus_start()
|
|
sampling_interval = self.cell_data.get_sampling_interval()
|
|
|
|
start_idx = int((stimulus_start - buffer) / sampling_interval)
|
|
end_idx = int((stimulus_start + buffer*2) / sampling_interval)
|
|
|
|
freq_before = frequency[start_idx-(int(length_of_mean/sampling_interval)):start_idx]
|
|
fb_mean = np.mean(freq_before)
|
|
fb_std = np.std(freq_before)
|
|
|
|
peak_frequency = fb_mean
|
|
count = 0
|
|
for i in range(start_idx + 1, end_idx):
|
|
if fb_mean-3*fb_std <= frequency[i] <= fb_mean+3*fb_std:
|
|
continue
|
|
|
|
if abs(frequency[i] - fb_mean) > abs(peak_frequency - fb_mean):
|
|
peak_frequency = frequency[i]
|
|
count += 1
|
|
|
|
return peak_frequency
|
|
|
|
def __calculate_f_infinity__(self, frequency, length=0.2, buffer=0.025):
|
|
stimulus_end_time = \
|
|
self.cell_data.get_delay() + self.cell_data.get_stimulus_start() + self.cell_data.get_stimulus_duration()
|
|
|
|
start_idx = int((stimulus_end_time - length - buffer) / self.cell_data.get_sampling_interval())
|
|
end_idx = int((stimulus_end_time - buffer) / self.cell_data.get_sampling_interval())
|
|
|
|
return np.mean(frequency[start_idx:end_idx])
|
|
|
|
def get_f_zero_inverse_at_frequency(self, frequency):
|
|
b_vars = self.boltzmann_fit_vars
|
|
return fu.inverse_full_boltzmann(frequency, b_vars[0], b_vars[1], b_vars[2], b_vars[3])
|
|
|
|
def get_f_infinity_frequency_at_stimulus_value(self, stimulus_value):
|
|
infty_vars = self.f_infinity_fit
|
|
return fu.clipped_line(stimulus_value, infty_vars[0], infty_vars[1])
|
|
|
|
|
|
def get_f_infinity_slope(self):
|
|
return self.f_infinity_fit[1]
|
|
|
|
def get_fi_curve_slope_at(self, stimulus_value):
|
|
fit_vars = self.boltzmann_fit_vars
|
|
return fu.derivative_full_boltzmann(stimulus_value, fit_vars[0], fit_vars[1], fit_vars[2], fit_vars[3])
|
|
|
|
def get_fi_curve_slope_of_straight(self):
|
|
fit_vars = self.boltzmann_fit_vars
|
|
return fu.full_boltzmann_straight_slope(fit_vars[0], fit_vars[1], fit_vars[2], fit_vars[3])
|