def plot_two_level_threshold(results, fig=100, plot_initial_estimate=False): plt.figure(fig) plt.clf() bin_centres = results['histogram']['bin_centres'] counts = results['histogram']['counts'] plt.bar(bin_centres, counts, width=bin_centres[1] - bin_centres[0], label='histogram') plt.ylabel('Counts') plt.xlabel('Signal [a.u.]') plot_vertical_line(results['signal_threshold'], label='threshold') plot_double_gaussian_fit(results['double_gaussian_fit'], bin_centres) plt.title('Result of two level threshold processing') if plot_initial_estimate: xdata = np.linspace(bin_centres[0], bin_centres[-1], 300) initial_estimate = results['double_gaussian_fit'][ 'parameters initial guess'] left0 = initial_estimate[::2][::-1] right0 = initial_estimate[1::2][::-1] plt.plot(xdata, gaussian(xdata, *left0), ':g', label='initial estimate left') plt.plot(xdata, gaussian(xdata, *right0), ':r', label='initial estimate right')
def test_gaussian(self): y = gaussian(np.array([0.0, 1., 2.]), 1.0, .2) self.assertIsInstance(y, np.ndarray) np.testing.assert_almost_equal( y, np.array([3.72665317e-06, 1.00000000e+00, 3.72665317e-06]), decimal=6)
def test_fit_gaussian_no_offset(self): x_data = np.linspace(0, 10, 100) gauss_data = gaussian(x_data, mean=4, std=1, amplitude=5) noise = np.random.rand(100) - .5 parameters, result_dict = fit_gaussian(x_data=x_data, y_data=(gauss_data + noise), estimate_offset=0) np.testing.assert_array_almost_equal(result_dict['fitted_parameters'], np.array([4, 1, 5.]), decimal=1) np.testing.assert_array_almost_equal(parameters, result_dict['fitted_parameters']) self.assertTrue(result_dict['reduced_chi_squared'] < .2)
def test_fit_gaussian(self): x_data = np.linspace(0, 10, 100) gauss_data = 0.1 + gaussian(x_data, mean=4, std=1, amplitude=5) noise = np.random.rand(100) - .5 [mean, s, amplitude, offset], _ = fit_gaussian(x_data=x_data, y_data=(gauss_data + noise)) self.assertTrue(3.5 < mean < 4.5) self.assertTrue(0.5 < s < 1.5) self.assertTrue(4.5 < amplitude < 5.5) self.assertAlmostEqual(offset, 0.1, places=0)
def _plot_rts_histogram(data, num_bins, double_gaussian_fit, split, figure_title): _, bins, _ = plt.hist(data, bins=num_bins) bincentres = np.array([(bins[i] + bins[i + 1]) / 2 for i in range(0, len(bins) - 1)]) get_left_mean_std_amplitude = operator.itemgetter(4, 2, 0) get_right_mean_std_amplitude = operator.itemgetter(5, 3, 1) left_gaussian = list(get_left_mean_std_amplitude(double_gaussian_fit)) right_gaussian = list(get_right_mean_std_amplitude(double_gaussian_fit)) plt.plot(bincentres, double_gaussian(bincentres, double_gaussian_fit), '-m', label='Fitted double gaussian') plt.plot(bincentres, gaussian(bincentres, *left_gaussian), 'g', label='Left Gaussian', alpha=.85, linewidth=.75) plt.plot(bincentres, gaussian(bincentres, *right_gaussian), 'r', label='Right Gaussian', alpha=.85, linewidth=.75) plt.plot(split, double_gaussian(split, double_gaussian_fit), 'ro', markersize=8, label='split: %.3f' % split) plt.xlabel('Measured value (a.u.)') plt.ylabel('Data points per bin') plt.legend() plt.title(figure_title)
def plot_two_level_threshold(results: dict, fig: int = 100, plot_initial_estimate: bool = False): separation = results['separation'] threshold = results['signal_threshold'] ax = get_axis(fig) bin_centres = results['histogram']['bin_centres'] counts = results['histogram']['counts'] ax.bar(bin_centres, counts, width=bin_centres[1] - bin_centres[0], label='histogram') ax.set_ylabel('Counts') ax.set_xlabel('Signal [a.u.]') plot_vertical_line(threshold, label='threshold') plot_double_gaussian_fit(results['double_gaussian_fit'], bin_centres) ax.set_title( f'Two-level signal: separation {separation:.3f}, threshold {threshold:.3g}' ) if plot_initial_estimate: xdata = np.linspace(bin_centres[0], bin_centres[-1], 300) initial_estimate = results['double_gaussian_fit'][ 'parameters initial guess'] left0 = initial_estimate[::2][::-1] right0 = initial_estimate[1::2][::-1] ax.plot(xdata, gaussian(xdata, *left0), ':g', label='initial estimate left') ax.plot(xdata, gaussian(xdata, *right0), ':r', label='initial estimate right')
def refit_double_gaussian(result_dict, x_data, y_data, gaussian_amplitude_ratio_threshold=8): """ Improve fit of double Gaussian by estimating the initial parameters based on an existing fit Args: result_dict(dict): Result dictionary from fit_double_gaussian x_data (array): Independent data y_data (array): Signal data gaussian_amplitude_ratio_threshold (float): If ratio between amplitudes of Gaussian peaks is larger than this fit, re-estimate Returns: Dictionary with improved fitting results """ mean = operator.itemgetter(0) std = operator.itemgetter(1) amplitude = operator.itemgetter(2) if amplitude(result_dict['left']) > amplitude(result_dict['right']): large_gaussian_parameters = result_dict['left'] small_gaussian_parameters = result_dict['right'] else: large_gaussian_parameters = result_dict['right'] small_gaussian_parameters = result_dict['left'] gaussian_ratio = amplitude(large_gaussian_parameters) / amplitude( small_gaussian_parameters) if gaussian_ratio > gaussian_amplitude_ratio_threshold: # re-estimate by fitting a single gaussian to the data remaining after removing the main gaussian y_residual = y_data - gaussian(x_data, *large_gaussian_parameters) idx = np.logical_and( x_data > mean(large_gaussian_parameters) - 1.5 * std(large_gaussian_parameters), x_data < mean(large_gaussian_parameters) + 1.5 * std(large_gaussian_parameters)) y_residual[idx] = 0 gauss_fit, _ = fit_gaussian(x_data, y_residual) initial_parameters = _double_gaussian_parameters( large_gaussian_parameters, gauss_fit[:3]) _, result_dict_refit = fit_double_gaussian( x_data, y_data, initial_params=initial_parameters) if result_dict_refit['reduced_chi_squared'] < result_dict[ 'reduced_chi_squared']: result_dict = result_dict_refit return result_dict
def gaussian_model(x, mean, sigma, amplitude): # type: ignore """ Gaussian helper function for lmfit """ y = gaussian(x, mean, sigma, amplitude) return y
def gaussian_model(x, mean, sigma, amplitude, offset): """ Gaussian helper function for lmfit """ y = gaussian(x, mean, sigma, amplitude, offset) return y
def _double_gaussian(x, A_dn, A_up, sigma_dn, sigma_up, mean_dn, mean_up): """ Double Gaussian helper function for lmfit """ gauss_dn = gaussian(x, mean_dn, sigma_dn, A_dn) gauss_up = gaussian(x, mean_up, sigma_up, A_up) double_gauss = gauss_dn + gauss_up return double_gauss
def setUp(self): x_data = np.arange(0, 100) y_data = np.random.rand(x_data.size) y_data += gaussian(x_data, 30, 6, 30) y_data += gaussian(x_data, 70, 8, 70) self.example_data = (x_data, y_data)