Source code for ipfx.qc_features
import numpy as np
[docs]def measure_blowout(v, idx0):
return np.mean(v[idx0:])
[docs]def measure_electrode_0(curr, hz, t=0.005):
n_time_steps = int(t * hz)
# electrode 0 is the average current reading with zero voltage input
# (ie, the equivalent of resting potential in current-clamp mode)
if n_time_steps:
return np.mean(curr[0:n_time_steps])
else:
return None
[docs]def measure_seal(v, curr, t):
return 1e-9 * get_r_from_stable_pulse_response(v*1e-3, curr*1e-12, t)
[docs]def measure_initial_access_resistance(v, curr, t):
return 1e-6 * get_r_from_peak_pulse_response(v*1e-3, curr*1e-12, t)
[docs]def measure_vm(vals):
if len(vals) < 1:
return 0, 0
mean = np.mean(vals)
rms = np.sqrt(np.mean(np.square(vals-mean)))
return float(mean), float(rms)
[docs]def measure_vm_delta(mean_start, mean_end):
if mean_end is not None:
delta = abs(mean_start - mean_end)
return float(delta)
else:
return None
[docs]def get_r_from_stable_pulse_response(v, i, t):
"""Compute input resistance from the stable pulse response
Parameters
----------
v : float membrane voltage (V)
i : float input current (A)
t : time (s)
Returns
-------
ir: float input resistance
"""
up_idx, down_idx = get_square_pulse_idx(v)
dt = t[1] - t[0]
one_ms = int(0.001 / dt)
r = []
for ii in range(len(up_idx)):
# take average v and i one ms before start
end = up_idx[ii] - 1
start = end - one_ms
avg_v_base = np.mean(v[start:end])
avg_i_base = np.mean(i[start:end])
# take average v and i one ms before end
end = down_idx[ii]-1
start = end - one_ms
avg_v_steady = np.mean(v[start:end])
avg_i_steady = np.mean(i[start:end])
r_instance = (avg_v_steady-avg_v_base) / (avg_i_steady-avg_i_base)
r.append(r_instance)
return np.mean(r)
[docs]def get_r_from_peak_pulse_response(v, i, t):
up_idx, down_idx = get_square_pulse_idx(v)
dt = t[1] - t[0]
one_ms = int(0.001 / dt)
r = []
for ii in range(len(up_idx)):
# take average v and i one ms before
end = up_idx[ii] - 1
start = end - one_ms
avg_v_base = np.mean(v[start:end])
avg_i_base = np.mean(i[start:end])
# take average v and i one ms before end
start = up_idx[ii]
end = down_idx[ii] - 1
idx = start + np.argmax(i[start:end])
avg_v_peak = v[idx]
avg_i_peak = i[idx]
r_instance = (avg_v_peak-avg_v_base) / (avg_i_peak-avg_i_base)
r.append(r_instance)
return np.mean(r)
[docs]def get_square_pulse_idx(v):
"""
Get up and down indices of the square pulse(s).
Skipping the very first pulse (test pulse)
Parameters
----------
v: float
pulse trace
Returns
-------
up_idx, down_idx: list, list
up, down indices
"""
dv = np.diff(v)
up_idx = np.flatnonzero(dv > 0)[1:] # skip the very first pulse (test pulse)
down_idx = np.flatnonzero(dv < 0)[1:]
assert len(up_idx) == len(down_idx), "Truncated square pulse"
for up_ix, down_ix in zip(up_idx, down_idx):
assert up_ix < down_ix, "Negative square pulse"
return up_idx, down_idx