def analyze_response_strength(rec, source, remove_artifacts=False, deconvolve=True, lpf=True, bsub=True, lowpass=1000): """Perform a standardized strength analysis on a record selected by response_query or baseline_query. 1. Determine timing of presynaptic stimulus pulse edges and spike 2. Measure peak deflection on raw trace 3. Apply deconvolution / artifact removal / lpf 4. Measure peak deflection on deconvolved trace """ data = Trace(rec.data, sample_rate=db.default_sample_rate) if source == 'pulse_response': # Find stimulus pulse edges for artifact removal start = rec.pulse_start - rec.rec_start pulse_times = [start, start + rec.pulse_dur] if rec.spike_time is None: # these pulses failed QC, but we analyze them anyway to make all data visible spike_time = 11e-3 else: spike_time = rec.spike_time - rec.rec_start elif source == 'baseline': # Fake stimulus information to ensure that background data receives # the same filtering / windowing treatment pulse_times = [10e-3, 12e-3] spike_time = 11e-3 else: raise ValueError("Invalid source %s" % source) results = {} results['raw_trace'] = data results['pulse_times'] = pulse_times results['spike_time'] = spike_time # Measure crosstalk from pulse onset p1 = data.time_slice(pulse_times[0]-200e-6, pulse_times[0]).median() p2 = data.time_slice(pulse_times[0], pulse_times[0]+200e-6).median() results['crosstalk'] = p2 - p1 # crosstalk artifacts in VC are removed before deconvolution if rec.clamp_mode == 'vc' and remove_artifacts is True: data = remove_crosstalk_artifacts(data, pulse_times) remove_artifacts = False # Measure deflection on raw data results['pos_amp'], _ = measure_peak(data, '+', spike_time, pulse_times) results['neg_amp'], _ = measure_peak(data, '-', spike_time, pulse_times) # Deconvolution / artifact removal / filtering if deconvolve: tau = 15e-3 if rec.clamp_mode == 'ic' else 5e-3 else: tau = None dec_data = deconv_filter(data, pulse_times, tau=tau, lpf=lpf, remove_artifacts=remove_artifacts, bsub=bsub, lowpass=lowpass) results['dec_trace'] = dec_data # Measure deflection on deconvolved data results['pos_dec_amp'], results['pos_dec_latency'] = measure_peak(dec_data, '+', spike_time, pulse_times) results['neg_dec_amp'], results['neg_dec_latency'] = measure_peak(dec_data, '-', spike_time, pulse_times) return results
def analyze_response_strength(rec, source, remove_artifacts=False, lpf=True, bsub=True, lowpass=1000): """Perform a standardized strength analysis on a record selected by response_query or baseline_query. 1. Determine timing of presynaptic stimulus pulse edges and spike 2. Measure peak deflection on raw trace 3. Apply deconvolution / artifact removal / lpf 4. Measure peak deflection on deconvolved trace """ data = Trace(rec.data, sample_rate=db.default_sample_rate) if source == 'pulse_response': # Find stimulus pulse edges for artifact removal start = rec.pulse_start - rec.rec_start pulse_times = [start, start + rec.pulse_dur] if rec.spike_time is None: # these pulses failed QC, but we analyze them anyway to make all data visible spike_time = 11e-3 else: spike_time = rec.spike_time - rec.rec_start elif source == 'baseline': # Fake stimulus information to ensure that background data receives # the same filtering / windowing treatment pulse_times = [10e-3, 12e-3] spike_time = 11e-3 else: raise ValueError("Invalid source %s" % source) results = {} results['raw_trace'] = data results['pulse_times'] = pulse_times results['spike_time'] = spike_time # Measure crosstalk from pulse onset p1 = data.time_slice(pulse_times[0]-200e-6, pulse_times[0]).median() p2 = data.time_slice(pulse_times[0], pulse_times[0]+200e-6).median() results['crosstalk'] = p2 - p1 # crosstalk artifacts in VC are removed before deconvolution if rec.clamp_mode == 'vc' and remove_artifacts is True: data = remove_crosstalk_artifacts(data, pulse_times) remove_artifacts = False # Measure deflection on raw data results['pos_amp'], _ = measure_peak(data, '+', spike_time, pulse_times) results['neg_amp'], _ = measure_peak(data, '-', spike_time, pulse_times) # Deconvolution / artifact removal / filtering tau = 15e-3 if rec.clamp_mode == 'ic' else 5e-3 dec_data = deconv_filter(data, pulse_times, tau=tau, lpf=lpf, remove_artifacts=remove_artifacts, bsub=bsub, lowpass=lowpass) results['dec_trace'] = dec_data # Measure deflection on deconvolved data results['pos_dec_amp'], results['pos_dec_latency'] = measure_peak(dec_data, '+', spike_time, pulse_times) results['neg_dec_amp'], results['neg_dec_latency'] = measure_peak(dec_data, '-', spike_time, pulse_times) return results
def test_trace_timing(): # Make sure sample timing is handled exactly--need to avoid fp error here a = np.random.normal(size=300) sr = 50000 dt = 2e-5 t = np.arange(len(a)) * dt # trace with no timing information tr = Trace(a) assert not tr.has_timing assert not tr.has_time_values with raises(TypeError): tr.dt with raises(TypeError): tr.sample_rate with raises(TypeError): tr.time_values view = tr[100:200] assert not tr.has_timing assert not tr.has_time_values # invalid data with raises(ValueError): Trace(data=np.zeros((10, 10))) # invalid timing information with raises(TypeError): Trace(data=a, dt=dt, time_values=t) with raises(TypeError): Trace(data=a, sample_rate=sr, time_values=t) with raises(TypeError): Trace(data=a, dt=dt, t0=0, time_values=t) with raises(TypeError): Trace(data=a, dt=dt, t0=0, sample_rate=sr) with raises(ValueError): Trace(data=a, time_values=t[:-1]) # trace with only dt tr = Trace(a, dt=dt) assert tr.dt == dt assert np.allclose(tr.sample_rate, sr) assert np.all(tr.time_values == t) assert tr.has_timing assert not tr.has_time_values assert tr.regularly_sampled # test view view = tr[100:200] assert view.t0 == tr.time_values[100] assert view.time_values[0] == view.t0 assert view.dt == tr.dt assert view._meta['sample_rate'] is None assert not view.has_time_values view = tr.time_slice(100*dt, 200*dt) assert view.t0 == tr.time_values[100] assert view.time_values[0] == view.t0 assert view.dt == tr.dt assert view._meta['sample_rate'] is None assert not view.has_time_values # test nested view view2 = view.time_slice(view.t0 + 20*dt, view.t0 + 50*dt) assert view2.t0 == view.time_values[20] == tr.time_values[120] # trace with only sample_rate tr = Trace(a, sample_rate=sr) assert tr.dt == dt assert tr.sample_rate == sr assert np.all(tr.time_values == t) assert tr.has_timing assert not tr.has_time_values assert tr.regularly_sampled # test view view = tr[100:200] assert view.t0 == tr.time_values[100] assert view.time_values[0] == view.t0 assert view.sample_rate == tr.sample_rate assert view._meta['dt'] is None assert not view.has_time_values # trace with only regularly-sampled time_values tr = Trace(a, time_values=t) assert tr.dt == dt assert np.allclose(tr.sample_rate, sr) assert np.all(tr.time_values == t) assert tr.has_timing assert tr.has_time_values assert tr.regularly_sampled # test view view = tr[100:200] assert view.t0 == tr.time_values[100] assert view.time_values[0] == view.t0 assert view._meta['dt'] is None assert view._meta['sample_rate'] is None assert view.has_time_values assert view.regularly_sampled # trace with irregularly-sampled time values t1 = np.cumsum(np.random.normal(loc=1, scale=0.02, size=a.shape)) tr = Trace(a, time_values=t1) assert tr.dt == t1[1] - t1[0] assert np.all(tr.time_values == t1) assert tr.has_timing assert tr.has_time_values assert not tr.regularly_sampled # test view view = tr[100:200] assert view.t0 == tr.time_values[100] assert view.time_values[0] == view.t0 assert view._meta['dt'] is None assert view._meta['sample_rate'] is None assert view.has_time_values assert not view.regularly_sampled