import numpy as np import matplotlib.pyplot as plt import datetime as dt from scipy.optimize import curve_fit # Define linear fit function: def linear_fit(x, a, b): return a+b*x # Define smooth_transition function for correcting not-linear section in the beginning of the cooldown def smooth_transition(x, a, b, c, x0): """ A function that is constant before t0 and transitions smoothly into a linear function after t0. Parameters: t : array-like, time values t0 : float, transition point a : float, constant value before t0 b : float, slope of the linear function after t0 c : float, controls the smoothness of the transition Returns: array-like, function values """ return a + (b * (x - x0)) / (1 + np.exp(-c * np.clip(x - x0, -100, 100))) # Define the path to the converted CSV file data_path = r'/Users/alexandercierpka/Documents/Eigene Dokumente/Universität/Masterarbeit/Daten/TF_CRAFT_2025-03-06/calibrated_data_2025_03_06.csv' #Define the path to the points.txt file good_points_path = r'/Users/alexandercierpka/Documents/Eigene Dokumente/Universität/Masterarbeit/Daten/TF_CRAFT_2025-03-06/points/good points/good_points2.txt' # Load the CSV file as a numpy array data = np.loadtxt(data_path, delimiter=' ', dtype=float) # Load the CSV file as a numpy array, column 0 is time, column 1-8 are the temperatures of the 8 Cernox sensors, followed by AMR, followed by FG # Correct for imc timeshift: data[:,0] = data[:,0] - (1737650746.34 - 1737650711) - 4 -33 # Correct the time shift of the data 2025_03_06 # Load the points.txt file as a numpy array points = np.loadtxt(good_points_path, delimiter='\t', dtype=str, skiprows=1) # Load the points.txt file as a numpy array, column 0: t_start, column 1: t_stop, column 2: t_save, columne 3,4,5: B_start_x, y, z # GENERAL PARAMETERS # "Tc" measured by the two Cernox sensors (Temperature at which AMR sensors start to measure superconducting transition). This Tc is NOT the real Tc of the material Tc_top = 9.62 #Critical temperature of the superconductor for the top sensor Tc_bottom = 9.7 #Critical temperature of the superconductor for the bottom sensor Distance = 9.2 #Distance between Cernox 1 and 8 in cm Sample_length = 10 #Length of the sample in cm # Timepoints t_Tc_start / _stop are calculated automatically by checking time when Cernox 1 and 8 transition Tc_top and Tc_bottom. Use this delta to adjust the time interval. t_Tc_start_delta = 0 t_Tc_stop_delta = 0 #Define cooldown_array to save all cooldown parameters cooldown_parameters = np.empty((0,15)) # Go through all points and calculate the cooldown parameters total_points = len(points[:,0]) # Total number of points for i in range(total_points): t_start = points[i,0] t_stop = points[i,1] t_save = points[i,2] B_start = points[i,3:6] # Convert time strings to floats (seconds since 01.01.1970) time_format = '%Y-%m-%d_%H-%M-%S' t_start_sec = (dt.datetime.strptime(t_start, time_format) - dt.datetime(1970,1,1)).total_seconds() t_stop_sec = (dt.datetime.strptime(t_stop, time_format) - dt.datetime(1970,1,1)).total_seconds() t_save_sec = (dt.datetime.strptime(t_save, time_format) - dt.datetime(1970,1,1)).total_seconds() # Convert B_start to floats B_start = B_start.astype(float) # Find the indices of the data array which are between t_start and t_save cooldown_indices = np.where((data[:,0] >= t_start_sec) & (data[:,0] <= t_save_sec)) #Calculate t_Tc_start: Lowest timepoint where Tc is reached by Cernox 1 OR 8. "OR" is important, because CRAFT allows for negative gradients during cooldown t_Tc_start = np.min(data[cooldown_indices,0][0][np.where((data[cooldown_indices,1][0] <= Tc_top) | (data[cooldown_indices,8][0] <= Tc_bottom))]) #Calculate t_Tc_stop: Highest timepoint where Tc is reached by Cernox 1 OR 8 t_Tc_stop = np.max(data[cooldown_indices,0][0][np.where((data[cooldown_indices,1][0] >= Tc_top) | (data[cooldown_indices,8][0] >= Tc_bottom))]) # Smooth_transition fit to the temperature data of Cernox 1 and 8, from t_Tc_start - t_Tc_start_delta until t_Tc_stop + t_Tc_stop_delta # Often a linear fit is sufficient. But when the sc transitions starts immediately after cooldown start, the temperature data is not linear in the beginning. fit_indices = np.where((data[cooldown_indices,0][0] >= t_Tc_start - t_Tc_start_delta) & (data[cooldown_indices,0][0] <= t_Tc_stop + t_Tc_stop_delta)) # Indices of the data array which are in the interesting time interval t0 = data[cooldown_indices,0][0][fit_indices[0][0]] #Set t0 to the first timepoint of the fit_indices. Reduces the number of digits in the fit parameters... t_T1 = data[cooldown_indices,0][0][fit_indices] - t0 y_T1 = data[cooldown_indices,1][0][fit_indices] t_T8 = data[cooldown_indices,0][0][fit_indices] - t0 y_T8 = data[cooldown_indices,8][0][fit_indices] # Fit the smooth_transition function to the data popt_T1, pcov_T1 = curve_fit(smooth_transition, t_T1, y_T1, p0=[y_T1[0], -0.03, 0.1, 30], maxfev=10000) popt_T8, pcov_T8 = curve_fit(smooth_transition, t_T8, y_T8, p0=[y_T8[0], -0.03, 0.1, 30], maxfev=10000) y_T1_fit = smooth_transition(t_T1, *popt_T1) y_T8_fit = smooth_transition(t_T8, *popt_T8) # print(f"Fit parameters Cernox 1: {popt_T1}") # print(f"Fit parameters Cernox 8: {popt_T8}") # Linear fit for calculating cooldown speed popt_T1_linear, pcov_T1_linear = curve_fit(linear_fit, t_T1, y_T1) popt_T8_linear, pcov_T8_linear = curve_fit(linear_fit, t_T8, y_T8) y_T1_linearfit = linear_fit(t_T1, *popt_T1_linear) y_T8_linearfit = linear_fit(t_T8, *popt_T8_linear) #Calculate cooldown speed using the linear fit. cooldown_speed_T1 = popt_T1_linear[1] cooldown_speed_T1_std = np.sqrt(np.diag(pcov_T1_linear))[1] cooldown_speed_T8 = popt_T8_linear[1] cooldown_speed_T8_std = np.sqrt(np.diag(pcov_T8_linear))[1] #Calculate the mean cooldown speed cooldown_speed = np.mean([cooldown_speed_T1, cooldown_speed_T8]) #Calculate the std of the mean cooldown speed cooldown_speed_std = np.sqrt(cooldown_speed_T1_std**2 + cooldown_speed_T8_std**2) #Calculate the mean and std temperature gradient by calc. difference of y_T1 and y_T8 for each x inbetween t_Tc_start and t_Tc_stop. Here, smooth_transition fit could be crucial! Gradients = (y_T1_fit - y_T8_fit) / Distance Gradients = Gradients[np.where((t_T1 + t0 >= t_Tc_start) & (t_T1 +t0 <= t_Tc_stop))] mean_gradient = np.mean(Gradients) std_gradient = np.std(Gradients) #B0: B-field of AMR sensor 8 at t_start B0 = [data[cooldown_indices,16][0][0], data[cooldown_indices,31][0][0], data[cooldown_indices,46][0][0]] B0_std = 1.5 #Hardcoded error of the AMR sensor #Trapped flux: B-field of AMR sensor 8 at t_save (B=sqrt(Bx^2+By^2+Bz^2)) TF = np.sqrt(data[cooldown_indices,16][0][-1]**2 + data[cooldown_indices,31][0][-1]**2 + data[cooldown_indices,46][0][-1]**2) TF_std = 1.5 #Hardcoded error of the AMR sensor #Save the cooldown parameters to the cooldown_array cooldown_parameters = np.append(cooldown_parameters, [[t_start_sec, t_stop_sec, t_save_sec, t_Tc_start, t_Tc_stop, cooldown_speed, cooldown_speed_std, mean_gradient, std_gradient, TF, TF_std, B0[0], B0[1], B0[2], B0_std]], axis=0) print(f"Cooldown {i+1} done.") # Plot Cernox 1 and Cernox 8 and AMR 8y with two y-axes. #COMMENT THE FOLLOWING LINES TO PREVENT PLOTTING EACH COOLDOWN fig, ax1 = plt.subplots() ax1.plot(data[cooldown_indices,0][0], data[cooldown_indices,1][0], label='Sample Cernox 1', color='tab:blue') ax1.plot(data[cooldown_indices,0][0], data[cooldown_indices,8][0], label='Sample Cernox 8', color='tab:orange') ax1.set_xlabel("Time (s)") ax1.set_ylabel("Temperature (K)", color='tab:blue') ax1.tick_params(axis='y', labelcolor='tab:blue') ax2 = ax1.twinx() ax2.plot(data[cooldown_indices,0][0], np.abs(data[cooldown_indices,31][0]), label='AMR Sensor 8y', color='tab:green') ax2.plot(data[cooldown_indices,0][0], np.abs(data[cooldown_indices,25][0]), label='AMR Sensor 2y', color='tab:green') ax2.plot(data[cooldown_indices,0][0], np.abs(data[cooldown_indices,37][0]), label='AMR Sensor 14y', color='tab:green') ax2.set_ylabel("Absolute magnetic Field (μT)", color='tab:green') ax2.tick_params(axis='y', labelcolor='tab:green') plt.title(f"Cooldown {i+1}") # Plot the linear fits ax1.plot(t_T1+t0, smooth_transition(t_T1, *popt_T1), color='tab:red', linestyle='dashed', label='Fit Cernox 1') ax1.plot(t_T8+t0, smooth_transition(t_T8, *popt_T8), color='tab:purple', linestyle='dashed', label='Fit Cernox 8') # Plot t_start, t_stop, t_save as vertical dashed lines ax1.axvline(x=t_start_sec, color='black', linestyle='dashed') ax1.axvline(x=t_stop_sec, color='black', linestyle='dashed') ax1.axvline(x=t_save_sec, color='black', linestyle='dashed') plt.show() # COMMENT END # # Center the data by fitting a gauss + lorentz # def gauss_lorentz(x, a, b, c, d, e): # exponent = -b*(x-c)**2 # exponent_clip = np.clip(exponent, -100, 100) # return a*np.exp(exponent_clip) + d/(1+e*(x-c)**2) # # popt, pcov = curve_fit(gauss_lorentz, cooldown_parameters[:,7], cooldown_parameters[:,9], maxfev=10000) # # print(popt[2]) #Import mVTS data mVTS_data_path = r'/Users/alexandercierpka/Documents/Eigene Dokumente/Universität/Masterarbeit/Daten/mVTS Daten/LG-01/LG-01_TF_vs_Gradient.txt' mVTS_data = np.loadtxt(mVTS_data_path, delimiter='\t', dtype=float, skiprows=1) #Plot TF vs Gradient fig, ax1 = plt.subplots() ax1.errorbar(cooldown_parameters[:,7], cooldown_parameters[:,9], xerr=cooldown_parameters[:,8], yerr=cooldown_parameters[:,10], fmt='x', capsize= 3, label="CRAFT") ax1.set_xlabel("Temperature Gradient (K/cm)") ax1.set_ylabel("Trapped Flux (μT)") #Plot mVTS data # ax1.plot(mVTS_data[:,0], mVTS_data[:,1], 'x', label='mVTS') ax1.errorbar(mVTS_data[:,0], mVTS_data[:,1], xerr=mVTS_data[:,2], yerr=mVTS_data[:,3], fmt='x', capsize=3, label='mVTS') plt.title("Trapped Flux vs Temperature Gradient") plt.grid() plt.legend() plt.show() # Save the cooldown parameters to a txt file cooldown_parameters_path = r'/Users/alexandercierpka/Documents/Eigene Dokumente/Universität/Masterarbeit/Daten/TF_CRAFT_2025-03-06/Auswertung/Cooldowns_TF_vs_Gradient_V3.txt' # np.savetxt(cooldown_parameters_path, cooldown_parameters, delimiter='\t', header='t_start\tt_stop\tt_save\tt_Tc_start\tt_Tc_stop\tcooldown_speed\tcooldown_speed_std\tmean_gradient\tstd_gradient\tTF\tTF_std\tB0\tB0_std', comments='')