The data are read from the files taken at each height, whom structure is explained in the previous paragraph \ref{subsection:calib_capacitance_probes}. In the code below is presented the input section of the used code $Calibration\_MC\_Capacitance.py$. In it, the filenames are properly saved because they were previously saved in a summary file that connects the singular names to the corresponding height. Besides, the number of test is then saved keeping in account the number of file name read from the summary file. It's fundamental to remember that is the one read on the ruler external to the mockup, so the reference system is not the one in Figure \ref{fig:drawing_mockup_a}. The architecture of the summary file $Calibration\_ffile\_2023\_11\_06.csv$ is in such a way that near to the filename there's the corresponding height read on the external ruler, so at 30mm corresponds the highest water depth that the mockup can allow.\\
\begin{lstlisting}[language=Python]
# Input
#name_file = "CalibrationData"
path_file=r'OUTPUT CALIBRATION FILE COMPLETE PATH NAME'
path_file_orig=r'PATH OF THE CALIBRATION FILE IN INPUT'
#text_file = 'Calibration_Data.csv'
text_file='Calibration_file_2023_11_06.csv'
name_file = np.genfromtxt(path_file_orig+text_file, delimiter=',')
# Read the CSV file into a pandas DataFrame
df = pd.read_csv(path_file_orig+text_file, header=0)
size_tab = np.shape(name_file)
n_test = size_tab[0]
\end{lstlisting}
\captionof{lstlisting}{$Calibration\_MC\_Capacitance.py$: Input section}
\vspace{0.5cm}
In the code below, the initialization of the variables is presented. These variables are meant to contain the input PDF extracted from the data.\\
\begin{lstlisting}[language=Python]
#%% Variable initialisation
list_v=[]
ll=[]
list_c=[]
M_V=[] # Voltage
Results_C=[]
val_P = np.zeros((3, 8, n_test))  # Initialize the val_TC array with zeros
i_c = 0
tab_loi_norm = np.zeros((3, 3, n_test))
plt.ioff()
\end{lstlisting}
\captionof{lstlisting}{$Calibration\_MC\_Capacitance.py$: Variable initialization}
\vspace{0.5cm}
In the code below, an estimation of the input PDFs is provided. These functions are the input to the Monte Carlo method, that is applied later in this code file. The outer loop is used to move within the test cases (\texttt{for it in range (n$\_$test-1)}), extract the data from each of them (\texttt{abb = pd.read$\_$csv(path$\_$file+ligne$\_$test[0]+'.txt',delimiter="\t", decimal=",", header=22)}) and finally save them as numerical array, keeping in mind the architecture of those files (Figure \ref{fig:calibration_input_file}). Once the data are extracted, the inner loop provides the estimation of the mean value, the standard deviation, the minimum value and the maximum value of each of the probes for the selected file test (notice that the inner loop, \texttt{for i$\_$tc in range (3)}, is setted to count the three columns of the test file extracted in the outer loop). Then, by means of the package \texttt{norm}, on those data for the \texttt{i$\_$tc} probe a normal distribution is computed and saved on the already initialized array (\texttt{tab$\_$loi$\_$norm}, its architecture is in Figure \ref{fig:loi_norm_array}).
\begin{figure}[H]
    \centering 
    \includegraphics[scale=0.5]{immagini/setup/calibration_tab_loi_norm.png}
    \caption{Architecture of the summary array \texttt{tab$\_$loi$\_$norm}}
    \label{fig:loi_norm_array}
\end{figure}
\begin{lstlisting}[language=Python]
#%% Probes calculation
# Extraction of the value of the TC and calculation of several quantities
with tqdm(total=n_test-1, desc="Recuperation de points...") as pbar:
    for it in range(n_test-1):
        pbar.update(1)
        ligne_test = df.iloc[it, :]
        
        list_c.append(it)
        #ab = np.genfromtxt(ligne_test[9])  # Read data using NumPy
        abb = pd.read_csv(path_file+ligne_test[0]+'.txt',delimiter="\t", decimal=",", header=22)
               
        ab=abb.to_numpy()
        #ab0 = np.genfromtxt(path_file+ligne_test[0]+'.txt', delimiter=',') # Read data using NumPy
        #ab=ab0[1:] # Remove the first array of float
        for i_tc in range(3): #number of the capacitance probe
            val_P[i_tc, 0, i_c] = np.mean(ab[:, i_tc+1])
            val_P[i_tc, 1, i_c] = np.std(ab[:, i_tc+1])
            val_P[i_tc, 2, i_c] = np.min(ab[:, i_tc+1])
            val_P[i_tc, 3, i_c] = np.max(ab[:, i_tc+1])
            val_P[i_tc, 4, i_c] = 1  # input voltage
            val_P[i_tc, 5, i_c] = 1.96 * np.std(ab[:, i_tc])  # 97.5% confidence degree for an infinity of tests
            val_P[i_tc, 6, i_c] = 100 # freq acq
            val_P[i_tc, 7, i_c] = 200  # N points

            aa_norm = ab[:, i_tc+1]
            # pdf calculation - normal law - uncertainty - TC
            pdd = norm.fit(aa_norm)  # Fit a normal distribution
            tab_loi_norm[0, i_tc, it] = i_tc
            tab_loi_norm[1, i_tc, it] = pdd[0]  # Mean of the fitted distribution
            tab_loi_norm[2, i_tc, it] = pdd[1]  # Standard deviation of the fitted distribution

        i_c += 1
        Results_C.append(3)
\end{lstlisting}
\captionof{lstlisting}{$Calibration\_MC\_Capacitance.py$: Probes calculation}
\vspace{0.5cm}
The code below sets the height of reference for each of the calibration file. In particular, it's setted that the mean value is the one read from the external ruler on the mockup (Figure \ref{fig:ALFRED_a}) and the standard deviation on it coincides with the ruler error equal to $0.5mm$. The array named \texttt{tab$\_$loi$\_$normpt} is dedicated to save these mean values and standard deviations.
\\
\begin{lstlisting}[language=Python]
#%% Height calculation
tab_loi_normpt = np.zeros((2, n_test))
df_shape=df.shape

with tqdm(total=n_test-1, desc="Height...") as pbar:
    for it in range(n_test-1):
        pbar.update(1)
        
        ligne_test = df.iloc[it, :]
        
        mean_normpt = ligne_test[1]
        std_normpt = 0.5 #reading mistake ruler
        
        tab_loi_normpt[:, it] = [mean_normpt, std_normpt]

        plt.close('all')
\end{lstlisting}
\captionof{lstlisting}{$Calibration\_MC\_Capacitance.py$: Height calculation}
\vspace{0.5cm}
The code below perform 50000 repetition of the Monte Carlo method on the PDFs extracted previously. First, fitting variable are initialized: \texttt{fit$\_$list$\_$mont} for storing the random values of fitting slope, intercepts and correlation indexes; \texttt{m$\_$fit} the final slope of the calibration law for each of the probes; \texttt{q$\_$fit} the final intercepts of the calibration law for each of the probes; \texttt{dx$\_$fit} the uncertainty for each probe measurement.\\
The code is divided in three loops. The outer loop enters each of the probe data (\texttt{i$\_$tc} index in range(3)). The first inner loop sets the number of the Monte Carlo repetitions to 50000 cycles. Besides, it creates the array for saving the random values. The third loop generates a random number (\texttt{rtc} for the probes and \texttt{rtp} for the height on the external ruler) based on the normal distribution, which mean value and standard deviation are stored in \texttt{tab$\_$loi$\_$norm}. These values are then saved queuing the arrays \texttt{r$\_$listtc} and \texttt{r$\_$listpt}. Outside this last loop and at the end of the second, these arrays are needed to upload the \texttt{fit$\_$list$\_$mont}, whom save the slope (0), the intercept(1) and the correlation (2) (\texttt{fit$\_$list$\_$mont}[\textbf{1},2,3]) for each repetition (\texttt{fit$\_$list$\_$mont}[1,\textbf{2},3]) of each probe (\texttt{fit$\_$list$\_$mont}[1,2,\textbf{3}]). In fact, a computation of the interpolation for the linear fit is provided: \texttt{fitxy$\_$pt = np.polyfit(r$\_$listtc, r$\_$listpt, 1)}. The correlation index is equal to \texttt{rsq$\_$ikk = np.corrcoef(r$\_$listtc, r$\_$listpt)[0, 1]$^2$} and express how much a linear fit is suitable for the statistical analysis.
\\
\begin{lstlisting}[language=Python]
#%% Monte Carlo calculation
from scipy.stats import norm

# Calculate the sizes of the matrices
s_norm_tc = tab_loi_norm.shape
s_norm_pt = tab_loi_normpt.shape

# Initialize variables
fit_list_mont = np.zeros((3, 50000, 3))
m_fin = np.zeros((3, 2))
q_fin = np.zeros((3, 2))
dx_fin = np.zeros((3, 1))

# Loop over different i_tc values
for i_tc in tqdm(range(3), desc="i_tc loop"): #each probe
    # Display progress bar for Monte Carlo runs
    with tqdm(total=50000, desc=f"i_tc {i_tc + 1} - Monte Carlo runs") as pbar_ikk: 
        # Loop over ikk values
        for ikk in range(50000):
            pbar_ikk.update(1)
            
            # Initialize arrays to store random values
            r_listtc = []
            r_listpt = []
            
            # Loop over i_essai values
            for i_essai in range(s_norm_tc[2]):
                # Generate random values based on normal distribution
                rtc = np.random.normal(tab_loi_norm[1, i_tc, i_essai], tab_loi_norm[2, i_tc, i_essai])
                r_listtc.append(rtc)
                rpt = np.random.normal(tab_loi_normpt[0, i_essai], tab_loi_normpt[1, i_essai])
                r_listpt.append(rpt)
            
            # Fit linear polynomial to the generated data
            fitxy_pt = np.polyfit(r_listtc, r_listpt, 1) # fit of the h_liq = f(Voltage)
            rsq_ikk = np.corrcoef(r_listtc, r_listpt)[0, 1] ** 2
            
            # Store the results in the fit_list_mont array
            fit_list_mont[0, ikk, i_tc] = fitxy_pt[0]
            fit_list_mont[1, ikk, i_tc] = fitxy_pt[1]
            fit_list_mont[2, ikk, i_tc] = rsq_ikk
\end{lstlisting}
\captionof{lstlisting}{$Calibration\_MC\_Capacitance.py$: Monte Carlo Calculation}
\vspace{0.5cm}    
In the last part of the code, a norm distribution is built on the 50000 values for the slope and the intercept of each probe, stored in \texttt{fit$\_$list$\_$mont}. At the end, the code gives in output for each probe a mean value for the slope $m_i$ of the curve, its intercept $q_i$ and their standard deviation $\delta m_i$ and $\delta q_i$. The law for each $i-probe$ is the following,
\begin{equation}
    h_i=m_iXV_i+q_i
\end{equation}
with $h_i$ the free surface height (mm), $V_i$ the output voltage (V) and $m_i$ and $q_i$ the fitting couple.