def test_extract_amplitude_real_data(file_path): test_data = pd.read_csv(file_path + '/data/photovoltage_data.csv', skiprows=1) lia = LIA(test_data) actual_amplitude = lia.extract_signal_amplitude() desired_amplitude = (-0.0185371754 - 4.60284137e-11) * ureg.mV assert_equal_qt(actual_amplitude, desired_amplitude)
def test_with_large_dc(): test_data = pd.DataFrame({ 'time (ms)': [1, 2, 3, 4, 5, 6], 'val (V)': 10000 + np.array([1, 0, -1, 0, 1, 0]), 'Sync': [1, 0, 0, 0, 1, 0] }) lia = LIA(test_data) desired_amplitude = 1 * ureg.V / np.sqrt(2) actual_amplitude = lia.extract_signal_amplitude(sync_phase_delay=np.pi / 2) assert_allclose_qt(actual_amplitude, desired_amplitude, atol=1e-6)
def test_extract_zero_with_offset(): test_data = pd.DataFrame({ 'time (ms)': [0, 1, 2, 3, 4, 5, 6, 7], 'val (V)': [1, 1, 1, 1, 1, 1, 1, 1], 'Sync': [0, 0, 1, 0, 0, 0, 1, 0] }) lia = LIA(test_data) desired_amplitude = 0 * ureg.V actual_amplitude = lia.extract_signal_amplitude(sync_phase_delay=np.pi) assert_allclose_qt(actual_amplitude, desired_amplitude, atol=1e-6)
def test_extract_minus_pi_2_offset(): test_data = pd.DataFrame({ 'time (ms)': [1, 2, 3, 4, 5, 6, 7], 'val (V)': [1, 0, -1, 0, 1, 0, -1], 'Sync': [1, 0, 0, 0, 1, 0, 0] }) lia = LIA(test_data) desired_amplitude = 1 * ureg.V / np.sqrt(2) actual_amplitude = lia.extract_signal_amplitude(sync_phase_delay=np.pi / 2) assert_allclose_qt(actual_amplitude, desired_amplitude, atol=1e-6)
def modulated_photocurrent(data, cond): """ Returns the RMS value of the modulated photocurrent given the system gain and a dataset using lock-in amplification. """ lia = LIA(data=data) if 'sync_phase_delay' in cond: sync_phase_delay = cond['sync_phase_delay'] else: sync_phase_delay = np.pi extracted_voltage = lia.extract_signal_amplitude( mode='amplitude', sync_phase_delay=sync_phase_delay) extracted_current = (extracted_voltage / cond['gain']).to(ureg.pA) return extracted_current
def test_modulate_simple_pi(): test_data = pd.DataFrame({ 'time (ms)': [0, 1, 2, 3, 4.0, 5, 6, 7], 'Val (V)': [0, 1, 0, -1.0, 0, 1, 0, -1], 'Sync': [0, 0, 1, 0, 0, 0, 1, 0] }) lia = LIA(test_data) actual_data = lia.modulate(test_data, 250 * ureg.Hz, sync_phase_delay=np.pi, window='boxcar') desired_data = pd.DataFrame({ 'time (ms)': np.array([0, 1.0, 2, 3, 4, 5, 6, 7]), 'Val (V)': np.sqrt(2) * np.array([0, 1.0, 0, 1, 0, 1, 0, 1]), 'Sync': np.array([0, 0, 1, 0, 0, 0, 1, 0]) }) assert_frame_equal(actual_data, desired_data)
def test_modulate_simple_zero_phase(): test_data = pd.DataFrame({ 'time (ms)': [0, 1, 2, 3, 4.0, 5, 6], 'Val (V)': [0, 1, 0, -1.0, 0, 1, 0], 'Sync': [1, 0, 0, 0, 1, 0, 0] }) lia = LIA(test_data) actual_data = lia.modulate(test_data, 250 * ureg.Hz, sync_phase_delay=0, window='boxcar') desired_data = pd.DataFrame({ 'time (ms)': np.array([0, 1.0, 2, 3, 4, 5, 6]), 'Val (V)': np.sqrt(2) / 0.857142857 * np.array([0, 0.9, 0, 1.2, 0, 0.9, 0]), 'Sync': np.array([1, 0, 0, 0, 1, 0, 0]) }) assert_frame_equal(actual_data, desired_data)
def fit_lia(data, n_points=101, fit=True): """ Generates amplitude vs. phase for lock-in-amplifier type data. Optionally fits that phase to a cosine function and returns the fit parameters. :param data: pandas DataFrame which contains a 'Sync' column with synchronization points """ def cos_func(x, a=1, phase=0.1): return a*np.cos(x - phase) ylabel = data.columns[1] lia = LIA(data) phase_delays = np.linspace(-np.pi, np.pi, n_points) test_value = lia.extract_signal_amplitude(sync_phase_delay=0) extracted_v_np = np.vectorize(lia.extract_signal_amplitude) all_values = np.array([]) for phase in phase_delays: retval = lia.extract_signal_amplitude(sync_phase_delay=phase) if isinstance(retval, pint.Quantity): retval = retval.m all_values = np.append(all_values, retval) if fit: try: (amp, phase), pcov = curve_fit(cos_func, phase_delays, all_values) if amp < 0: amp *= -1 phase -= np.pi phase = np.mod(phase, 2*np.pi) except RuntimeError as e: breakpoint() else: (amp, phase) = (None, None) full_data = pd.DataFrame({ 'Phase (rad)': phase_delays, ylabel: all_values }) return full_data, (amp, phase)
def data(): data_length = 1000 sampling_frequency = 9700.0 * ureg.Hz signal_rms_amplitude = 36 * ureg.mV signal_frequency = 105.4 * ureg.Hz phase_delay = 0.34 samples_per_period = sampling_frequency / signal_frequency number_periods = int( np.floor(data_length / (sampling_frequency / signal_frequency))) number_sync_points = number_periods + 1 indices = np.arange(0, number_sync_points, 1) sync_indices = \ ((1/2*sampling_frequency / signal_frequency * \ (1 + 2*indices + phase_delay/np.pi)).astype(np.int)).magnitude times = np.arange(0, data_length, 1) * (1 / sampling_frequency) squared_mean = 0.999786189 # ONLY VALID FOR THIS DATA phases = 2 * np.pi * signal_frequency * times delayed_phases = phases - phase_delay sin_data = signal_rms_amplitude * np.sqrt(2) * np.sin(delayed_phases) sin_norm = np.sqrt(2) / squared_mean * np.sin(delayed_phases) sin_norm -= np.mean(sin_norm) zero_column = np.zeros(len(sin_data), dtype=np.int) zero_column[sync_indices] = 1 test_data = pd.DataFrame({ 'Time (s)': times.to(ureg.s).magnitude, 'Voltage (V)': sin_data.to(ureg.V).magnitude, 'Sync': zero_column }) lia = LIA(test_data) return { 'test_data': test_data, 'lia': lia, 'sampling_frequency': sampling_frequency, 'signal_frequency': signal_frequency, 'data_length': data_length, 'sin_norm': sin_norm.magnitude, 'sync_phase': np.pi, 'sync_indices': sync_indices, }
def data1(): data_length = 11 sampling_frequency = 10 * ureg.Hz signal_rms_amplitude = 1 * ureg.V signal_frequency = 1 * ureg.Hz samples_per_period = sampling_frequency / signal_frequency number_periods = 1 phase_delay = np.pi / 2 mod_phase_delay = -np.pi / 2 number_sync_points = 2 # This is the rare pathalogical case sync_indices = [0, 10] sync_points = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] times = ureg.s * np.array( [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]) sin_data = signal_rms_amplitude * np.sqrt(2) * np.sin( 2 * np.pi * signal_frequency * times - phase_delay) sin_norm = np.sqrt(2) * \ np.sin(2*np.pi * signal_frequency * times - phase_delay) sin_norm -= np.mean(sin_norm) squared_mean = np.mean(np.square(sin_norm)) sin_norm /= squared_mean data = pd.DataFrame({ 'Time (s)': times.to(ureg.s).magnitude, 'Amplitude (V)': sin_data.to(ureg.V).magnitude, 'Sync': sync_points }) lia = LIA(data) return { 'times': times, 'sin_data': sin_data, 'sin_norm': sin_norm.magnitude, 'sync_indices': sync_indices, 'data': data, 'lia': lia, 'sync_phase': phase_delay, 'sync_phase_delay': mod_phase_delay, 'sampling_frequency': sampling_frequency, 'signal_frequency': signal_frequency, 'data_length': data_length, }
def test_setup_no_sync(data): test_data = data['test_data'] test_data['Sync'] = 0 with pytest.raises(ValueError): lia = LIA(data=test_data)
def lia_units(lia_data_units): lia1 = LIA(lia_data_units) return lia1
def lia(lia_data): lia1 = LIA(lia_data) return lia1
def lia_complex(numpy_data_complex): lia = LIA(sampling_frequency=numpy_data_complex['sampling_frequency'], data=numpy_data_complex['test_data'], sync_indices=numpy_data_complex['sync_indices']) return lia