def test_waveform_model(): from ctapipe.image.toymodel import Gaussian geom = CameraGeometry.from_name("CHEC") readout = CameraReadout.from_name("CHEC") ref_duration = 67 n_ref_samples = 100 pulse_sigma = 3 ref_x_norm = np.linspace(0, ref_duration, n_ref_samples) ref_y_norm = norm.pdf(ref_x_norm, ref_duration / 2, pulse_sigma) readout.reference_pulse_shape = ref_y_norm[np.newaxis, :] readout.reference_pulse_sample_width = u.Quantity( ref_x_norm[1] - ref_x_norm[0], u.ns) readout.sampling_rate = u.Quantity(2, u.GHz) centroid_x = u.Quantity(0.05, u.m) centroid_y = u.Quantity(0.05, u.m) length = u.Quantity(0.03, u.m) width = u.Quantity(0.008, u.m) psi = u.Quantity(70, u.deg) time_gradient = u.Quantity(50, u.ns / u.m) time_intercept = u.Quantity(20, u.ns) _, charge, _ = Gaussian(x=centroid_x, y=centroid_y, width=width, length=length, psi=psi).generate_image(geom, 10000) time = obtain_time_image( geom.pix_x, geom.pix_y, centroid_x, centroid_y, psi, time_gradient, time_intercept, ) time[charge == 0] = 0 waveform_model = WaveformModel.from_camera_readout(readout) waveform = waveform_model.get_waveform(charge, time, 96) np.testing.assert_allclose(waveform.sum(axis=1), charge, rtol=1e-3) np.testing.assert_allclose(waveform.argmax(axis=1) / readout.sampling_rate.to_value(u.GHz), time, rtol=1e-1) time_2 = time + 1 time_2[charge == 0] = 0 waveform_2 = waveform_model.get_waveform(charge, time_2, 96) np.testing.assert_allclose(waveform_2.sum(axis=1), charge, rtol=1e-3) np.testing.assert_allclose( waveform_2.argmax(axis=1) / readout.sampling_rate.to_value(u.GHz), time_2, rtol=1e-1, ) assert (waveform_2.argmax(axis=1)[charge != 0] > waveform.argmax(axis=1)[charge != 0]).all()
def test_sw_pulse_lst(): """ Test function of sliding window extractor for LST camera pulse shape with the correction for the integration window completeness """ # prepare array with 1 LST subarray = SubarrayDescription( "LST1", tel_positions={1: np.zeros(3) * u.m}, tel_descriptions={ 1: TelescopeDescription.from_name(optics_name="LST", camera_name="LSTCam") }, ) telid = list(subarray.tel.keys())[0] n_pixels = subarray.tel[telid].camera.geometry.n_pixels n_samples = 40 readout = subarray.tel[telid].camera.readout random = np.random.RandomState(1) min_charge = 100 max_charge = 1000 charge_true = random.uniform(min_charge, max_charge, n_pixels) time_true = random.uniform(n_samples // 2 - 1, n_samples // 2 + 1, n_pixels) / readout.sampling_rate.to_value( u.GHz) waveform_model = WaveformModel.from_camera_readout(readout) waveform = waveform_model.get_waveform(charge_true, time_true, n_samples) selected_gain_channel = np.zeros(charge_true.size, dtype=np.int8) # define extractor config = Config({"SlidingWindowMaxSum": {"window_width": 8}}) extractor = SlidingWindowMaxSum(subarray=subarray) extractor = ImageExtractor.from_name("SlidingWindowMaxSum", subarray=subarray, config=config) dl1: DL1CameraContainer = extractor(waveform, telid, selected_gain_channel) print(dl1.image / charge_true) assert_allclose(dl1.image, charge_true, rtol=0.02) assert dl1.is_valid
def toymodel(subarray): telid = list(subarray.tel.keys())[0] n_pixels = subarray.tel[telid].camera.geometry.n_pixels n_samples = 96 readout = subarray.tel[telid].camera.readout random = np.random.RandomState(1) charge = random.uniform(100, 1000, n_pixels) mid = (n_samples // 2) / readout.sampling_rate.to_value(u.GHz) time = random.uniform(mid - 1, mid + 1, n_pixels) waveform_model = WaveformModel.from_camera_readout(readout) waveform = waveform_model.get_waveform(charge, time, n_samples) selected_gain_channel = np.zeros(charge.size, dtype=np.int) return waveform, subarray, telid, selected_gain_channel, charge, time
def test_Two_pass_window_sum_no_noise(subarray_1_LST): rng = np.random.default_rng(0) subarray = subarray_1_LST camera = subarray.tel[1].camera geometry = camera.geometry readout = camera.readout sampling_rate = readout.sampling_rate.to_value("GHz") n_samples = 30 # LSTCam & NectarCam specific max_time_readout = (n_samples / sampling_rate) * u.ns # True image settings x = 0.0 * u.m y = 0.0 * u.m length = 0.2 * u.m width = 0.05 * u.m psi = 45.0 * u.deg skewness = 0.0 # build the true time evolution in a way that # the whole image is about the readout window time_gradient = u.Quantity(max_time_readout.value / length.value, u.ns / u.m) time_intercept = u.Quantity(max_time_readout.value / 2, u.ns) intensity = 600 nsb_level_pe = 0 # create the image m = SkewedGaussian(x, y, length, width, psi, skewness) true_charge, true_signal, true_noise = m.generate_image( geometry, intensity=intensity, nsb_level_pe=nsb_level_pe, rng=rng) signal_pixels = true_signal > 2 # create a pulse-times image without noise # we can make new functions later time_noise = rng.uniform(0, 0, geometry.n_pixels) time_signal = obtain_time_image(geometry.pix_x, geometry.pix_y, x, y, psi, time_gradient, time_intercept) true_charge[(time_signal < 0) | (time_signal > (n_samples / sampling_rate))] = 0 true_time = np.average( np.column_stack([time_noise, time_signal]), weights=np.column_stack([true_noise, true_signal]) + 1, axis=1, ) # Define the model for the waveforms to fill with the information from # the simulated image waveform_model = WaveformModel.from_camera_readout(readout) waveforms = waveform_model.get_waveform(true_charge, true_time, n_samples) selected_gain_channel = np.zeros(true_charge.size, dtype=np.int64) # Define the extractor extractor = TwoPassWindowSum(subarray=subarray) # Select the signal pixels for which the integration window is well inside # the readout window (in this case we should require more accuracy) true_peaks = np.rint(true_time * sampling_rate).astype(np.int64) # integration of 5 samples centered on peak + 1 sample of error # to not be really on the edge min_good_sample = 2 + 1 max_good_sample = n_samples - 1 - min_good_sample integration_window_inside = (true_peaks >= min_good_sample) & ( true_peaks < max_good_sample) # Test only the 1st pass extractor.disable_second_pass = True dl1_pass1 = extractor(waveforms, 1, selected_gain_channel) assert_allclose( dl1_pass1.image[signal_pixels & integration_window_inside], true_charge[signal_pixels & integration_window_inside], rtol=0.15, ) assert_allclose( dl1_pass1.peak_time[signal_pixels & integration_window_inside], true_time[signal_pixels & integration_window_inside], rtol=0.15, ) # Test also the 2nd pass extractor.disable_second_pass = False dl1_pass2 = extractor(waveforms, 1, selected_gain_channel) # Check that we have gained signal charge by using the 2nd pass # This also checks that the test image has triggered the 2nd pass # (i.e. it is not so bad to have <3 pixels in the preliminary cleaned image) reco_charge1 = np.sum(dl1_pass1.image[signal_pixels & integration_window_inside]) reco_charge2 = np.sum(dl1_pass2.image[signal_pixels & integration_window_inside]) # since there is no noise in this test, 1st pass will find the peak and 2nd # can at most to the same assert (reco_charge2 / reco_charge1) < 1 assert dl1_pass1.is_valid == True # Test only signal pixels for which it is expected to find most of the # charge well inside the readout window assert_allclose( dl1_pass2.image[signal_pixels & integration_window_inside], true_charge[signal_pixels & integration_window_inside], rtol=0.3, atol=2.0, ) assert_allclose( dl1_pass2.peak_time[signal_pixels & integration_window_inside], true_time[signal_pixels & integration_window_inside], rtol=0.3, atol=2.0, )