{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bdf377b8",
   "metadata": {},
   "source": [
    "# Analisi completa della molla 1\n",
    "Tutto quello che c'è da sapere sulla molla 1, possibilmente con la massima chiarezza."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "3a34cc3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Heavy lifting\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from scipy import stats\n",
    "\n",
    "# Mostrare i dati\n",
    "import ipysheet\n",
    "from IPython.display import display\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "# Calcolo simbolico\n",
    "import sympy as sp\n",
    "\n",
    "\n",
    "G = 9.806\n",
    "uG = 0.004"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0eaece9c",
   "metadata": {},
   "source": [
    "# Analisi dati del calibro"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "960e68a5",
   "metadata": {},
   "source": [
    "## Import dei dati calibro (criterio di Chauvenet)\n",
    "- Primo test di implementazione 1\n",
    "- Scrittura con logica chiara   2\n",
    "- Codice pulito per bene        3 (sono abbastanza soddisfatto)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "1e2fabea",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Blocco funzioni per Chauvenet\n",
    "# Probabilità\n",
    "def p_t_student(valori, err_strumentale):\n",
    "  n   = len(valori)\n",
    "  GdL = n - 1\n",
    "  if n <= 2:\n",
    "    return np.ones(n)\n",
    "\n",
    "  media = valori.mean()\n",
    "  s     = valori.std(ddof=1)\n",
    "  if s == 0:\n",
    "    return np.ones(n)\n",
    "\n",
    "  s = np.sqrt(s**2 + err_strumentale**2)\n",
    "  return 2 * (1 - stats.t.cdf(np.abs(valori - media) / s, df=GdL))\n",
    "\n",
    "# Indice del peggiore outlier o None\n",
    "def trova_outlier(valori, err_strumentale):\n",
    "  n       = len(valori)\n",
    "  soglia  = 1 / (2 * n)\n",
    "  p       = p_t_student(valori, err_strumentale)\n",
    "  idx_min = np.argmin(p)\n",
    "\n",
    "  if p[idx_min] < soglia:\n",
    "      return idx_min\n",
    "  return None\n",
    "\n",
    "# Rimuove outlier\n",
    "def rimuovi_outlier(valori, err_strumentale):\n",
    "  rimossi  = []\n",
    "  campione = valori.copy()\n",
    "\n",
    "  while len(campione) > 2:\n",
    "    idx = trova_outlier(campione, err_strumentale)\n",
    "\n",
    "    if idx is None: # nessun outlier: stop\n",
    "      break\n",
    "\n",
    "    rimossi.append(campione[idx])\n",
    "    campione = np.delete(campione, idx)\n",
    "\n",
    "  return campione, rimossi\n",
    "\n",
    "# return media u rimossi []\n",
    "def stats_riga(valori_raw, err_strumentale):\n",
    "  # caso 0\n",
    "  if len(valori_raw) == 0:\n",
    "    return {\"media\": np.nan, \"u\": np.nan, \"n\": 0, \"rimossi\": []}\n",
    "\n",
    "  # caso 1\n",
    "  if len(valori_raw) == 1:\n",
    "    return {\"media\": valori_raw[0], \"u\": err_strumentale, \"n\": 1, \"rimossi\": []}\n",
    "\n",
    "  # caso n>1\n",
    "  puliti, rimossi = rimuovi_outlier(valori_raw, err_strumentale)\n",
    "\n",
    "  media = puliti.mean()\n",
    "\n",
    "  s = puliti.std(ddof=1)\n",
    "  n = len(puliti)\n",
    "  s = s / np.sqrt(n)\n",
    "  s = np.sqrt(s**2 + err_strumentale**2)\n",
    "\n",
    "  return {\"media\": media, \"u\": s, \"n\": n, \"rimossi\": rimossi}\n",
    "\n",
    "# Calcola la statistica con Criterio di Chauvenet\n",
    "def calcola_stats(df, prefix, err_strumentale):\n",
    "  cols = [col for col in df.columns if col.startswith(prefix)]\n",
    "\n",
    "  for i, row in df.iterrows():\n",
    "    valori = row[cols].dropna().values.astype(float)\n",
    "    ans    = stats_riga(valori, err_strumentale)\n",
    "\n",
    "    df.at[i, prefix]         = ans[\"media\"]\n",
    "    df.at[i, f\"u{prefix}\"]   = ans[\"u\"]\n",
    "    df.at[i, f\"n{prefix}\"]   = int(ans[\"n\"])\n",
    "    df.at[i, f\"out{prefix}\"] = str(ans[\"rimossi\"])\n",
    "\n",
    "  return df\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "a5ff5ff5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "F  = g*m\n",
      "sigma_F = sqrt(g**2*sigma_m**2 + m**2*sigma_g**2)\n",
      "\n",
      "Formula LaTeX:\n",
      "F = g m\n",
      "sigma_F = \\sqrt{g^{2} \\sigma_{m}^{2} + m^{2} \\sigma_{g}^{2}}\n"
     ]
    }
   ],
   "source": [
    "# Blocco funzioni calcolo simbolico la forza\n",
    "# simboli\n",
    "m, x, g = sp.symbols('m x g', positive=True)\n",
    "sigma_m, sigma_x, sigma_g = sp.symbols('sigma_m sigma_x sigma_g', positive=True)\n",
    "\n",
    "F = m * g\n",
    "\n",
    "# derivate parziali\n",
    "dF_dm = sp.diff(F, m)\n",
    "dF_dg = sp.diff(F, g)\n",
    "\n",
    "sigma_F = sp.sqrt((dF_dm * sigma_m)**2 + (dF_dg * sigma_g)**2)\n",
    "\n",
    "print(\"F  =\", F)\n",
    "print(\"sigma_F =\", sigma_F)\n",
    "print(\"\\nFormula LaTeX:\")\n",
    "print(f\"F = {sp.latex(F)}\")\n",
    "print(f\"sigma_F = {sp.latex(sigma_F.simplify())}\")\n",
    "\n",
    "# funzioni numeriche\n",
    "F_fn  = sp.lambdify((m, g),  F,  'numpy')\n",
    "uF_fn = sp.lambdify((m, sigma_m, g, sigma_g), sigma_F, 'numpy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "e649eddc",
   "metadata": {},
   "outputs": [],
   "source": [
    "dfCalibro = pd.read_csv(r'molla1Calibro.csv')\n",
    "\n",
    "# Costanti strumentali\n",
    "ERR_CALIBRO = 0.02 / np.sqrt(12)\n",
    "ERR_BILANCIA = 0.01 / np.sqrt(12)\n",
    "\n",
    "# Chauvenet e poi statistica di base\n",
    "dfCalibro = calcola_stats(dfCalibro, \"dx\", ERR_CALIBRO)\n",
    "dfCalibro = calcola_stats(dfCalibro, \"m\",  ERR_BILANCIA)\n",
    "\n",
    "# Aggiunta delle forze\n",
    "dfCalibro[\"F\"]  = F_fn(dfCalibro[\"m\"],  G)\n",
    "dfCalibro[\"uF\"] = uF_fn(dfCalibro[\"m\"], dfCalibro[\"um\"], G, uG)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "42ff21d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "145bf1a6c8534204b2aa7b50bad128a2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=4, row_start=0, squeeze_row=False, type='numeric', val…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sheet = ipysheet.from_dataframe(dfCalibro)\n",
    "\n",
    "display(sheet)\n",
    "# dfCalibro.head(2).to_json(orient=\"records\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c58a6e26",
   "metadata": {},
   "source": [
    "## Regressione lineare Carpi dati del calibro\n",
    "chi² Come persone normali"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "dfab4331",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Blocco di funzione regressione Carpi\n",
    "def sigma_y_equiv(x, y, sigma_x, sigma_y):\n",
    "  # Stima iniziale di A con sola sigma_y\n",
    "  sy2 = sigma_y**2\n",
    "  Sw   = np.sum(1 / sy2)\n",
    "  Sx   = np.sum(x / sy2)\n",
    "  Sxx  = np.sum(x**2 / sy2)\n",
    "  Sy   = np.sum(y / sy2)\n",
    "  Sxy  = np.sum(x * y / sy2)\n",
    "  delta = Sxx * Sw - Sx**2\n",
    "  A_est = (Sxy * Sw - Sx * Sy) / delta\n",
    "\n",
    "  # Propagazione\n",
    "  sigma_eq = np.sqrt(sigma_y**2 + A_est**2 * sigma_x**2)\n",
    "  return sigma_eq\n",
    "\n",
    "\n",
    "def reg_lin(x, y, sigma_x, sigma_y):\n",
    "  x = np.asarray(x, dtype=float)\n",
    "  y = np.asarray(y, dtype=float)\n",
    "  sigma_x = np.asarray(sigma_x, dtype=float)\n",
    "  sigma_y = np.asarray(sigma_y, dtype=float)\n",
    "\n",
    "  # Propagazione errore x → y\n",
    "  sigma_y_eq = sigma_y_equiv(x, y, sigma_x, sigma_y)\n",
    "\n",
    "  # Somme pesate\n",
    "  w    = 1.0 / sigma_y_eq**2\n",
    "  Sw   = np.sum(w)\n",
    "  Sx   = np.sum(w * x)\n",
    "  Sxx  = np.sum(w * x**2)\n",
    "  Sy   = np.sum(w * y)\n",
    "  Sxy  = np.sum(w * x * y)\n",
    "  delta = Sxx * Sw - Sx**2\n",
    "\n",
    "  # Parametri\n",
    "  A      = (Sxy * Sw - Sx * Sy)  / delta\n",
    "  B      = (Sxx * Sy - Sxy * Sx) / delta\n",
    "  sigma_A = np.sqrt(Sw  / delta)\n",
    "  sigma_B = np.sqrt(Sxx / delta)\n",
    "  cov_AB  = -Sx / delta\n",
    "\n",
    "  # Chi quadro\n",
    "  x2  = np.sum((y - A * x - B)**2 / sigma_y_eq**2)\n",
    "  dof = len(x) - 2\n",
    "  P = stats.chi2.sf(x2, dof)\n",
    "\n",
    "  return A, B, sigma_A, sigma_B, cov_AB, x2, P"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "5d7ca0a0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Residuo:\n",
      "  r = x + B/A - y/A\n",
      "\n",
      "Formula LaTeX:\n",
      "  r       = x + \\frac{B}{A} - \\frac{y}{A}\n",
      "  sigma_r = \\sqrt{\\frac{A^{4} \\sigma_{x}^{2} + A^{2} \\left(\\sigma_{B}^{2} + \\sigma_{y}^{2}\\right) - 2 A cov_{AB} \\left(B - y\\right) + \\sigma_{A}^{2} \\left(B - y\\right)^{2}}{A^{4}}}\n"
     ]
    }
   ],
   "source": [
    "# Blocco calcolo simbolico residui\n",
    "A, B, x, y = sp.symbols('A B x y', real=True)\n",
    "sigma_A, sigma_B, sigma_x, sigma_y = sp.symbols('sigma_A sigma_B sigma_x sigma_y', positive=True)\n",
    "cov_AB = sp.symbols('cov_AB', real=True)\n",
    "\n",
    "# Residuo: r = x - (y/A - B/A)\n",
    "r = x - (y / A - B / A)\n",
    "\n",
    "# Propagazione errore (con covarianza A,B)\n",
    "dr_dA  = sp.diff(r, A)\n",
    "dr_dB  = sp.diff(r, B)\n",
    "dr_dx  = sp.diff(r, x)\n",
    "dr_dy  = sp.diff(r, y)\n",
    "\n",
    "sigma_r  = sp.sqrt(\n",
    "  (dr_dA * sigma_A)**2 +\n",
    "  (dr_dB * sigma_B)**2 +\n",
    "  (dr_dx * sigma_x)**2 +\n",
    "  (dr_dy * sigma_y)**2 +\n",
    "  2 * dr_dA * dr_dB * cov_AB\n",
    ")\n",
    "\n",
    "# Funzioni numeriche\n",
    "r_fn      = sp.lambdify((x , y , A , B ), r, 'numpy')\n",
    "sigma_r_fn = sp.lambdify(\n",
    "  (x , y , A , B , sigma_x , sigma_y , sigma_A , sigma_B , cov_AB ),\n",
    "  sigma_r , 'numpy'\n",
    ")\n",
    "\n",
    "print(\"Residuo:\")\n",
    "print(f\"  r = {r }\")\n",
    "print(f\"\\nFormula LaTeX:\")\n",
    "print(f\"  r       = {sp.latex(r)}\")\n",
    "print(f\"  sigma_r = {sp.latex(sp.simplify(sigma_r))}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "cd68b201",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ax + B : \n",
      "AC      = 23.9437 ± 0.0424\n",
      "BC      = 2719.8777 ± 2.8546\n",
      "cov_ABC = 0.119914\n",
      "chi²    = 55.1017\n",
      "P(chi², ∞)= 0.0000\n"
     ]
    }
   ],
   "source": [
    "AC, BC, uAC, uBC, covABC, chiC, PC = reg_lin(-dfCalibro[\"dx\"], dfCalibro[\"F\"], dfCalibro[\"udx\"], dfCalibro[\"uF\"])\n",
    "print(\"Ax + B : \")\n",
    "print(f\"AC      = {AC:.4f} ± {uAC:.4f}\")\n",
    "print(f\"BC      = {BC:.4f} ± {uBC:.4f}\")\n",
    "print(f\"cov_ABC = {covABC:.6f}\")\n",
    "print(f\"chi²    = {chiC:.4f}\")\n",
    "print(f\"P(chi², ∞)= {PC:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "f98a3612",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Calcolo numerico residui sul dfCalibro\n",
    "dfCalibro[\"r\"] = r_fn(\n",
    "  -dfCalibro[\"dx\"],\n",
    "  dfCalibro[\"F\"],\n",
    "  AC,\n",
    "  BC\n",
    ")\n",
    "\n",
    "dfCalibro[\"ur\"] = sigma_r_fn(\n",
    "  -dfCalibro[\"dx\"], dfCalibro[\"F\"],\n",
    "  AC, BC,\n",
    "  dfCalibro[\"udx\"], dfCalibro[\"uF\"],\n",
    "  uAC, uBC, covABC\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5de53d0e",
   "metadata": {},
   "source": [
    "### Grafici calibro"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "68eb66dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 58412 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Fit\n",
    "SCALA = 10\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "x_data = -dfCalibro[\"dx\"]\n",
    "y_data =  dfCalibro[\"F\"]\n",
    "\n",
    "x_fit = np.linspace(x_data.min(), x_data.max(), 300)\n",
    "y_fit = AC * x_fit + BC\n",
    "\n",
    "ax.errorbar(\n",
    "    x_data, y_data,\n",
    "    xerr=SCALA * dfCalibro[\"udx\"], yerr=SCALA * dfCalibro[\"uF\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=f\"Dati (barre errore x{SCALA})\"\n",
    ")\n",
    "ax.plot(\n",
    "    x_fit, y_fit,\n",
    "    color='red', linewidth=1.5,\n",
    "    label=f\"Fit: $A={AC:.3f}\\\\pm{uAC:.3f}$\\n\"\n",
    "          f\"     $B={BC:.2f}\\\\pm{uBC:.2f}$\\n\"\n",
    ")\n",
    "\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"$- x$  [mm]\")\n",
    "ax.set_ylabel(\"F  [mN]\")\n",
    "ax.set_title(\"Fit lineare — Molla 1 (calibro)\")\n",
    "ax.legend(fontsize=9)\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "831a4ac6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 50412 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "# Residui con barre d'errore\n",
    "ax.errorbar(\n",
    "    dfCalibro[\"F\"], dfCalibro[\"r\"],\n",
    "    xerr=dfCalibro[\"uF\"], yerr=dfCalibro[\"ur\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=\"Residui\"\n",
    ")\n",
    "\n",
    "# Linea dello zero\n",
    "ax.axhline(0, color='red', linestyle='--', linewidth=1)\n",
    "\n",
    "# Estetica\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(\"F  [mN]\")\n",
    "ax.set_ylabel(r\"Residuo $x_i - \\left(\\frac{y_i}{A} - \\frac{B}{A}\\right)$  [mm]\")\n",
    "ax.set_title(\"Residui della regressione — Molla 1 (calibro)\")\n",
    "ax.legend()\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5e02e3d",
   "metadata": {},
   "source": [
    "### Sezione non espressamente richiesta\n",
    "Dal grafico dei residui risulta chiaro che tutti i punti sono \"sotto\" mentre uno solo è \"sopra\".\n",
    "Per diletto personale ho voluto vedere cosa sarebbe successo escludendo quel punto.\n",
    "\n",
    "La sezione riguarda solo **Esclusione del punto 1**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "17cbeaea",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fit completo:   chi²=55.10,  P=0.0000\n",
      "Senza punto 1:  chi²=1.794,  P=0.4078\n",
      "\n",
      "A:  23.9437 ± 0.0424  to  23.8835 ± 0.0432\n",
      "B:  2719.8777 ± 2.8546  to  2718.1378 ± 2.8613\n"
     ]
    }
   ],
   "source": [
    "mask = dfCalibro.index != 1\n",
    "dfCalibro_senza1 = dfCalibro.loc[mask]\n",
    "dfCalibro_senza1 = dfCalibro_senza1.copy()\n",
    "\n",
    "AC2, BC2, uAC2, uBC2, covABC2, chiC2, PC2 = reg_lin(-dfCalibro_senza1[\"dx\"], dfCalibro_senza1[\"F\"], dfCalibro_senza1[\"udx\"], dfCalibro_senza1[\"uF\"])\n",
    "\n",
    "print(f\"Fit completo:   chi²={chiC:.2f},  P={PC:.4f}\")\n",
    "print(f\"Senza punto 1:  chi²={chiC2:.3f},  P={PC2:.4f}\")\n",
    "print()\n",
    "print(f\"A:  {AC:.4f} ± {uAC:.4f}  to  {AC2:.4f} ± {uAC2:.4f}\")\n",
    "print(f\"B:  {BC:.4f} ± {uBC:.4f}  to  {BC2:.4f} ± {uBC2:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "0bc01605",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dataFrame  CALIBRO\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fa8fc6ccb620432abcaf6c87e53ff735",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=4, row_start=0, squeeze_row=False, type='numeric', val…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "dataFrame  CALIBRO TOLTO DATO 1\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d661c6a9648a4cadbc73d47d6b177805",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_start=0, squeeze_row=False, type='numeric', value=[88.97, …"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Ricalcolo Residui\n",
    "dfCalibro_senza1[\"r\"] = r_fn(\n",
    "  -dfCalibro_senza1[\"dx\"],\n",
    "   dfCalibro_senza1[\"F\"],\n",
    "   AC2, BC2\n",
    ")\n",
    "\n",
    "dfCalibro_senza1[\"ur\"] = sigma_r_fn(\n",
    "  -dfCalibro_senza1[\"dx\"], dfCalibro_senza1[\"F\"],\n",
    "   AC2, BC2,\n",
    "   dfCalibro_senza1[\"udx\"], dfCalibro_senza1[\"uF\"],\n",
    "   uAC2, uBC2, covABC2\n",
    ")\n",
    "\n",
    "print(\"dataFrame  CALIBRO\")\n",
    "sheet = ipysheet.from_dataframe(dfCalibro)\n",
    "display(sheet)\n",
    "\n",
    "print(\"\\ndataFrame  CALIBRO TOLTO DATO 1\")\n",
    "sheet = ipysheet.from_dataframe(dfCalibro_senza1)\n",
    "display(sheet)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "d2c1a550",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 66216 characters]",
      "text/plain": [
       "<Figure size 1300x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Grafico ringraziate Cloude per l'idea super compatta di questo codice\n",
    "# WARNING: non intuitivo, ma molto molto figo\n",
    "fig, axes = plt.subplots(1, 2, figsize=(13, 5), sharey=True)\n",
    "\n",
    "for ax, (r_col, ur_col, f_col, uf_col, df_plot, titolo) in zip(axes, [\n",
    "  (\"r\",  \"ur\",  \"F\", \"uF\", dfCalibro, \"Fit completo (tutti i punti)\"),\n",
    "  (\"r\", \"ur\", \"F\", \"uF\",   dfCalibro_senza1,  \"Fit senza punto 1\"),\n",
    "]):\n",
    "  ax.errorbar(\n",
    "    df_plot[f_col], df_plot[r_col],\n",
    "    xerr=df_plot[uf_col], yerr=df_plot[ur_col],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=\"Residui\"\n",
    "  )\n",
    "  ax.axhline(0, color='red', linestyle='--', linewidth=1)\n",
    "  sns.despine(ax=ax)\n",
    "  ax.set_xlabel(\"F  [mN]\")\n",
    "  ax.set_title(titolo)\n",
    "  ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "axes[0].set_ylabel(r\"Residuo $x_i - \\left(\\frac{y_i}{A} - \\frac{B}{A}\\right)$  [mm]\")\n",
    "fig.suptitle(\"Confronto residui — Molla 1 (calibro)\", y=1.02)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "8f79348f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 60052 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Fit senza un dato\n",
    "SCALA = 10\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "x_data = -dfCalibro_senza1[\"dx\"]\n",
    "y_data =  dfCalibro_senza1[\"F\"]\n",
    "\n",
    "x_fit = np.linspace(x_data.min(), x_data.max(), 300)\n",
    "y_fit = AC2 * x_fit + BC2\n",
    "\n",
    "ax.errorbar(\n",
    "    x_data, y_data,\n",
    "    xerr=SCALA * dfCalibro_senza1[\"udx\"], yerr=SCALA * dfCalibro_senza1[\"uF\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=f\"Dati (barre errore x{SCALA})\"\n",
    ")\n",
    "ax.plot(\n",
    "    x_fit, y_fit,\n",
    "    color='red', linewidth=1.5,\n",
    "    label=f\"Fit: $A={AC2:.3f}\\\\pm{uAC2:.3f}$\\n\"\n",
    "          f\"     $B={BC2:.2f}\\\\pm{uBC2:.2f}$\\n\"\n",
    ")\n",
    "\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"$- x$  [mm]\")\n",
    "ax.set_ylabel(\"F  [mN]\")\n",
    "ax.set_title(\"Fit lineare — Molla 1 (calibro tolto dato 1)\")\n",
    "ax.legend(fontsize=9)\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b952c206",
   "metadata": {},
   "source": [
    "# Analisi dati sonar"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e347644",
   "metadata": {},
   "source": [
    "## Import dei dati sonar (semidispersioni)\n",
    "- masse trattate come prima\n",
    "- $\\omega$, c trattati con semidispersione"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "d6195b96",
   "metadata": {},
   "outputs": [],
   "source": [
    "dfSonar = pd.read_csv(r'molla1Sonar.csv')\n",
    "\n",
    "# Bilancia trattata esattamente come prima\n",
    "dfSonar = calcola_stats(dfSonar, \"m\",  ERR_BILANCIA)\n",
    "\n",
    "# Semidispersioni su w e uw\n",
    "dfSonar['w']  = (dfSonar['w1'] + dfSonar['w2']) / 2\n",
    "dfSonar['uw'] = np.maximum((dfSonar['w1'] - dfSonar['w2']).abs() / 2,\n",
    "                            np.sqrt(dfSonar['uw1']**2 + dfSonar['uw2']**2))\n",
    "\n",
    "# Semidispersione su c e uc\n",
    "dfSonar['c']  = (dfSonar['c1'] + dfSonar['c2']) / 2\n",
    "dfSonar['uc'] = np.maximum((dfSonar['c1'] - dfSonar['c2']).abs() / 2,\n",
    "                            np.sqrt(dfSonar['uc1']**2 + dfSonar['uc2']**2))\n",
    "\n",
    "# Aggiunta delle forze\n",
    "dfSonar[\"F\"]  = F_fn(dfSonar[\"m\"],  G)\n",
    "dfSonar[\"uF\"] = uF_fn(dfSonar[\"m\"], dfSonar[\"um\"], G, uG)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "02e2d183",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "440939c283e448e3952454bb3231a234",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_start=0, squeeze_row=False, type='numeric', value=[108.61,…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'[{\"m1\":108.61,\"m2\":108.61,\"m3\":108.61,\"a1\":9.21,\"ua1\":0.029,\"w1\":14.2459,\"uw1\":0.0008,\"c1\":268.151,\"uc1\":0.02,\"a2\":10.69,\"ua2\":0.04,\"w2\":14.2434,\"uw2\":0.0009,\"c2\":268.326,\"uc2\":0.026,\"alp\":0.333333,\"ualp\":0.000001,\"m\":108.61,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":14.24465,\"uw\":0.00125,\"c\":268.2385,\"uc\":0.0875,\"F\":1065.02966,\"uF\":0.4353612606},{\"m1\":128.64,\"m2\":128.63,\"m3\":128.64,\"a1\":10.037,\"ua1\":0.025,\"w1\":13.1939,\"uw1\":0.0007,\"c1\":259.605,\"uc1\":0.018,\"a2\":9.744,\"ua2\":0.027,\"w2\":13.1913,\"uw2\":0.0009,\"c2\":259.745,\"uc2\":0.02,\"alp\":0.333333,\"ualp\":0.000001,\"m\":128.6366666667,\"um\":0.0044095855,\"nm\":3.0,\"outm\":\"[]\",\"w\":13.1926,\"uw\":0.0013,\"c\":259.675,\"uc\":0.07,\"F\":1261.4111533333,\"uF\":0.5163603432},{\"m1\":148.38,\"m2\":148.38,\"m3\":148.38,\"a1\":9.93,\"ua1\":0.03,\"w1\":12.3469,\"uw1\":0.0007,\"c1\":251.525,\"uc1\":0.021,\"a2\":11.41,\"ua2\":0.03,\"w2\":12.3461,\"uw2\":0.0006,\"c2\":251.542,\"uc2\":0.023,\"alp\":0.333333,\"ualp\":0.000001,\"m\":148.38,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":12.3465,\"uw\":0.0009219544,\"c\":251.5335,\"uc\":0.031144823,\"F\":1455.01428,\"uF\":0.5941946685},{\"m1\":168.53,\"m2\":168.53,\"m3\":168.53,\"a1\":11.34,\"ua1\":0.03,\"w1\":11.6345,\"uw1\":0.0005,\"c1\":243.211,\"uc1\":0.021,\"a2\":11.5,\"ua2\":0.03,\"w2\":11.6344,\"uw2\":0.0006,\"c2\":243.13,\"uc2\":0.021,\"alp\":0.333333,\"ualp\":0.000001,\"m\":168.53,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":11.63445,\"uw\":0.000781025,\"c\":243.1705,\"uc\":0.0405,\"F\":1652.60518,\"uF\":0.6747140787}]'"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sheet = ipysheet.from_dataframe(dfSonar)\n",
    "\n",
    "display(sheet)\n",
    "dfSonar.head(4).to_json(orient=\"records\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e12f76c",
   "metadata": {},
   "source": [
    "## Regressione lineare Carpi dati del sonar Caso statico\n",
    "chi² Come persone normali"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "06f9ccef",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ax + B : \n",
      "AS      = 23.5225 ± 0.0853\n",
      "BS      = 7371.9487 ± 21.4728\n",
      "cov_ABS = 1.830281\n",
      "chi²    = 3.8872\n",
      "P(chi², ∞)= 0.1432\n"
     ]
    }
   ],
   "source": [
    "AS, BS, uAS, uBS, covABS, chiS, PS = reg_lin(-dfSonar[\"c\"], dfSonar[\"F\"], dfSonar[\"uc\"], dfSonar[\"uF\"])\n",
    "print(\"Ax + B : \")\n",
    "print(f\"AS      = {AS:.4f} ± {uAS:.4f}\")\n",
    "print(f\"BS      = {BS:.4f} ± {uBS:.4f}\")\n",
    "print(f\"cov_ABS = {covABS:.6f}\")\n",
    "print(f\"chi²    = {chiS:.4f}\")\n",
    "print(f\"P(chi², ∞)= {PS:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "09445aac",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Calcolo numerico residui sul dfSonar\n",
    "dfSonar[\"r\"] = r_fn(\n",
    "  -dfSonar[\"c\"],\n",
    "  dfSonar[\"F\"],\n",
    "  AS,\n",
    "  BS\n",
    ")\n",
    "\n",
    "dfSonar[\"ur\"] = sigma_r_fn(\n",
    "  -dfSonar[\"c\"], dfSonar[\"F\"],\n",
    "  AS, BS,\n",
    "  dfSonar[\"uc\"], dfSonar[\"uF\"],\n",
    "  uAS, uBS, covABS\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6641e08",
   "metadata": {},
   "source": [
    "### Grafici sonar valori statici"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "75653d7a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 54184 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Fit\n",
    "SCALA = 10\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "x_data = -dfSonar[\"c\"]\n",
    "y_data =  dfSonar[\"F\"]\n",
    "\n",
    "x_fit = np.linspace(x_data.min(), x_data.max(), 300)\n",
    "y_fit = AS * x_fit + BS\n",
    "\n",
    "ax.errorbar(\n",
    "    x_data, y_data,\n",
    "    xerr=SCALA * dfSonar[\"uc\"], yerr=SCALA * dfSonar[\"uF\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=f\"Dati (barre errore x{SCALA})\"\n",
    ")\n",
    "ax.plot(\n",
    "    x_fit, y_fit,\n",
    "    color='red', linewidth=1.5,\n",
    "    label=f\"Fit: $A={AS:.3f}\\\\pm{uAS:.3f}$\\n\"\n",
    "          f\"     $B={BS:.2f}\\\\pm{uBS:.2f}$\\n\"\n",
    ")\n",
    "\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"$- x$  [mm]\")\n",
    "ax.set_ylabel(\"F  [mN]\")\n",
    "ax.set_title(\"Fit lineare — Molla 1 (sonar)\")\n",
    "ax.legend(fontsize=9)\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "1ecf9ab2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 43552 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Grafico Residui\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "# Residui con barre d'errore\n",
    "ax.errorbar(\n",
    "    dfSonar[\"F\"], dfSonar[\"r\"],\n",
    "    xerr=dfSonar[\"uF\"], yerr=dfSonar[\"ur\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=\"Residui\"\n",
    ")\n",
    "\n",
    "# Linea dello zero\n",
    "ax.axhline(0, color='red', linestyle='--', linewidth=1)\n",
    "\n",
    "# Estetica\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(\"F  [mN]\")\n",
    "ax.set_ylabel(r\"Residuo $x_i - \\left(\\frac{y_i}{A} - \\frac{B}{A}\\right)$  [mm]\")\n",
    "ax.set_title(\"Residui della regressione — Molla 1 (sonar statico)\")\n",
    "ax.legend()\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4eebafaf",
   "metadata": {},
   "source": [
    "### Sezione non espressamente richiesta\n",
    "La velocità del suono è chiaramente un fattore moltiplicativo che viene ignorato.\n",
    "\n",
    "Formula di Cramer 1993"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "4088453c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "c = 0.00301841231512225*c_raw*v0/sqrt(0.00366099212886692*T + 1)\n",
      "sigma_c = v0*sqrt(3.05277451303515e-11*c_raw**2*sigma_T**2 + 9.11081290408163e-6*sigma_c_raw**2*(0.00366099212886692*T + 1)**2)/(0.00366099212886692*T + 1)**(3/2)\n",
      "\n",
      "Formula LaTeX:\n",
      "c = \\frac{0.00301841231512225 c_{raw} v_{0}}{\\sqrt{0.00366099212886692 T + 1}}\n",
      "sigma_c = \\frac{v_{0} \\sqrt{3.05277451303515 \\cdot 10^{-11} c_{raw}^{2} \\sigma_{T}^{2} + 9.11081290408163 \\cdot 10^{-6} \\sigma_{c raw}^{2} \\left(0.00366099212886692 T + 1\\right)^{2}}}{\\left(0.00366099212886692 T + 1\\right)^{\\frac{3}{2}}}\n"
     ]
    }
   ],
   "source": [
    "# propagazione dell'errore con la temperatura\n",
    "# simboli\n",
    "v0, T, c_raw = sp.symbols('v0 T c_raw', positive=True)\n",
    "sigma_T, sigma_c_raw = sp.symbols('sigma_T sigma_c_raw', positive=True)\n",
    "\n",
    "# velocità corretta e posizione\n",
    "v = 331.3 * sp.sqrt(1 + T / 273.15)\n",
    "c = c_raw * v0 / v\n",
    "\n",
    "# derivate parziali\n",
    "dc_dcraw = sp.diff(c, c_raw)\n",
    "dc_dT    = sp.diff(c, T)\n",
    "\n",
    "sigma_c = sp.sqrt((dc_dcraw * sigma_c_raw)**2 + (dc_dT * sigma_T)**2)\n",
    "\n",
    "print(\"c =\", c)\n",
    "print(\"sigma_c =\", sigma_c.simplify())\n",
    "print(\"\\nFormula LaTeX:\")\n",
    "print(f\"c = {sp.latex(c)}\")\n",
    "print(f\"sigma_c = {sp.latex(sigma_c.simplify())}\")\n",
    "\n",
    "# funzioni numeriche\n",
    "c_fn  = sp.lambdify((c_raw, T, v0), c, 'numpy')\n",
    "uc_fn = sp.lambdify((c_raw, sigma_c_raw, T, sigma_T, v0), sigma_c, 'numpy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "1584a5d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "Temperatura = 22.6\n",
    "uTemperatura = 0.7 / np.sqrt(12)\n",
    "Velocita_impostata = 343.0\n",
    "\n",
    "dfSonarCorrezione = dfSonar.copy()\n",
    "\n",
    "dfSonarCorrezione['c']  =  c_fn(dfSonarCorrezione['c'], Temperatura, Velocita_impostata)\n",
    "dfSonarCorrezione['uc'] = uc_fn(dfSonarCorrezione['c'], dfSonarCorrezione['uc'],\n",
    "                      Temperatura, uTemperatura,\n",
    "                      Velocita_impostata)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "ac4860fa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b64011848560421ba1ea35f3a415cd00",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_start=0, squeeze_row=False, type='numeric', value=[108.61,…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'[{\"m1\":108.61,\"m2\":108.61,\"m3\":108.61,\"a1\":9.21,\"ua1\":0.029,\"w1\":14.2459,\"uw1\":0.0008,\"c1\":268.151,\"uc1\":0.02,\"a2\":10.69,\"ua2\":0.04,\"w2\":14.2434,\"uw2\":0.0009,\"c2\":268.326,\"uc2\":0.026,\"alp\":0.333333,\"ualp\":0.000001,\"m\":108.61,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":14.24465,\"uw\":0.00125,\"c\":268.2385,\"uc\":0.0875,\"F\":1065.02966,\"uF\":0.4353612606,\"r\":-0.1151157394,\"ur\":0.1108576},{\"m1\":128.64,\"m2\":128.63,\"m3\":128.64,\"a1\":10.037,\"ua1\":0.025,\"w1\":13.1939,\"uw1\":0.0007,\"c1\":259.605,\"uc1\":0.018,\"a2\":9.744,\"ua2\":0.027,\"w2\":13.1913,\"uw2\":0.0009,\"c2\":259.745,\"uc2\":0.02,\"alp\":0.333333,\"ualp\":0.000001,\"m\":128.6366666667,\"um\":0.0044095855,\"nm\":3.0,\"outm\":\"[]\",\"w\":13.1926,\"uw\":0.0013,\"c\":259.675,\"uc\":0.07,\"F\":1261.4111533333,\"uF\":0.5163603432,\"r\":0.0997008545,\"ur\":0.0835641852},{\"m1\":148.38,\"m2\":148.38,\"m3\":148.38,\"a1\":9.93,\"ua1\":0.03,\"w1\":12.3469,\"uw1\":0.0007,\"c1\":251.525,\"uc1\":0.021,\"a2\":11.41,\"ua2\":0.03,\"w2\":12.3461,\"uw2\":0.0006,\"c2\":251.542,\"uc2\":0.023,\"alp\":0.333333,\"ualp\":0.000001,\"m\":148.38,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":12.3465,\"uw\":0.0009219544,\"c\":251.5335,\"uc\":0.031144823,\"F\":1455.01428,\"uF\":0.5941946685,\"r\":0.010632976,\"ur\":0.0484884905},{\"m1\":168.53,\"m2\":168.53,\"m3\":168.53,\"a1\":11.34,\"ua1\":0.03,\"w1\":11.6345,\"uw1\":0.0005,\"c1\":243.211,\"uc1\":0.021,\"a2\":11.5,\"ua2\":0.03,\"w2\":11.6344,\"uw2\":0.0006,\"c2\":243.13,\"uc2\":0.021,\"alp\":0.333333,\"ualp\":0.000001,\"m\":168.53,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":11.63445,\"uw\":0.000781025,\"c\":243.1705,\"uc\":0.0405,\"F\":1652.60518,\"uF\":0.6747140787,\"r\":-0.0264654245,\"ur\":0.0645469948}]'"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sheet = ipysheet.from_dataframe(dfSonarCorrezione)\n",
    "\n",
    "display(sheet)\n",
    "dfSonar.head(4).to_json(orient=\"records\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "8917049c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fit completo:   chi²=3.89,  P=0.1432\n",
      "Temperatura :  chi²=1.632,  P=0.4422\n",
      "\n",
      "A:  23.5225 ± 0.0853  to  23.6160 ± 0.1404\n",
      "B:  7371.9487 ± 21.4728  to  7365.6372 ± 35.4592\n"
     ]
    }
   ],
   "source": [
    "AS2, BS2, uAS2, uBS2, covABS2, chiS2, PS2 = reg_lin(-dfSonarCorrezione[\"c\"], dfSonarCorrezione[\"F\"], dfSonarCorrezione[\"uc\"], dfSonarCorrezione[\"uF\"])\n",
    "\n",
    "\n",
    "print(f\"Fit completo:   chi²={chiS:.2f},  P={PS:.4f}\")\n",
    "print(f\"Temperatura :  chi²={chiS2:.3f},  P={PS2:.4f}\")\n",
    "print()\n",
    "print(f\"A:  {AS:.4f} ± {uAS:.4f}  to  {AS2:.4f} ± {uAS2:.4f}\")\n",
    "print(f\"B:  {BS:.4f} ± {uBS:.4f}  to  {BS2:.4f} ± {uBS2:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "e35a9456",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Calcolo numerico residui sul dfSonar\n",
    "dfSonarCorrezione[\"r\"] = r_fn(\n",
    "  -dfSonarCorrezione[\"c\"],\n",
    "  dfSonarCorrezione[\"F\"],\n",
    "  AS2,\n",
    "  BS2\n",
    ")\n",
    "\n",
    "dfSonarCorrezione[\"ur\"] = sigma_r_fn(\n",
    "  -dfSonarCorrezione[\"c\"], dfSonarCorrezione[\"F\"],\n",
    "  AS2, BS2,\n",
    "  dfSonarCorrezione[\"uc\"], dfSonarCorrezione[\"uF\"],\n",
    "  uAS2, uBS2, covABS2\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "d5646b8c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 57032 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Fit\n",
    "SCALA = 10\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "x_data = -dfSonarCorrezione[\"c\"]\n",
    "y_data =  dfSonarCorrezione[\"F\"]\n",
    "\n",
    "x_fit = np.linspace(x_data.min(), x_data.max(), 300)\n",
    "y_fit = AS2 * x_fit + BS2\n",
    "\n",
    "ax.errorbar(\n",
    "    x_data, y_data,\n",
    "    xerr=SCALA * dfSonarCorrezione[\"uc\"], yerr=SCALA * dfSonarCorrezione[\"uF\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=f\"Dati (barre errore x{SCALA})\"\n",
    ")\n",
    "ax.plot(\n",
    "    x_fit, y_fit,\n",
    "    color='red', linewidth=1.5,\n",
    "    label=f\"Fit: $A={AS2:.3f}\\\\pm{uAS2:.3f}$\\n\"\n",
    "          f\"     $B={BS2:.2f}\\\\pm{uBS2:.2f}$\\n\"\n",
    ")\n",
    "\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"$- x$  [mm]\")\n",
    "ax.set_ylabel(\"F  [mN]\")\n",
    "ax.set_title(\"Fit lineare — Molla 1 (sonar Correzione della temperatura)\")\n",
    "ax.legend(fontsize=9)\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "8de2a48e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 43672 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Grafico Residui\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "# Residui con barre d'errore\n",
    "ax.errorbar(\n",
    "    dfSonarCorrezione[\"F\"], dfSonarCorrezione[\"r\"],\n",
    "    xerr=dfSonarCorrezione[\"uF\"], yerr=dfSonarCorrezione[\"ur\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=\"Residui\"\n",
    ")\n",
    "\n",
    "# Linea dello zero\n",
    "ax.axhline(0, color='red', linestyle='--', linewidth=1)\n",
    "\n",
    "# Estetica\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(\"F  [mN]\")\n",
    "ax.set_ylabel(r\"Residuo $x_i - \\left(\\frac{y_i}{A} - \\frac{B}{A}\\right)$  [mm]\")\n",
    "ax.set_title(\"Residui della regressione — Molla 1 (sonar statico)\")\n",
    "ax.legend()\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9c20bd0",
   "metadata": {},
   "source": [
    "## Analisi dati sonar dinamica\n",
    "Ancora non abbiamo il parametro $\\alpha$, quindi useremo $\\alpha = \\frac 1 3$. Lo imposto nel csv così è più facile da cambiare con il metodo della molla"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "af6143df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Massa molla = 29.8933 ± 0.0044\n"
     ]
    }
   ],
   "source": [
    "# Calcolo della massa della molla per bene\n",
    "dfMasse = pd.DataFrame([[29.90, 29.89, 29.89]], columns=[\"m1\", \"m2\", \"m3\"])\n",
    "dfMasse = calcola_stats(dfMasse, \"m\",  ERR_BILANCIA)\n",
    "\n",
    "massaMolla  = dfMasse.m[0]\n",
    "umassaMolla = dfMasse.um[0]\n",
    "print(f\"Massa molla = {massaMolla:.4f} ± {umassaMolla:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "a1e69bd3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Meq = 1000/(alp*m_molla + m_osc)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sigma_Meq = 1000*sqrt(alp**2*sigma_m_molla**2 + m_molla**2*sigma_alp**2 + sigma_m_osc**2)/(alp*m_molla + m_osc)**2\n",
      "\n",
      "Formula LaTeX:\n",
      "Meq = \\frac{1000}{alp m_{molla} + m_{osc}}\n",
      "sigma_Meq = \\frac{1000 \\sqrt{alp^{2} \\sigma_{m molla}^{2} + m_{molla}^{2} \\sigma_{alp}^{2} + \\sigma_{m osc}^{2}}}{\\left(alp m_{molla} + m_{osc}\\right)^{2}}\n"
     ]
    }
   ],
   "source": [
    "#massa della molla equivalente\n",
    "# simboli\n",
    "m_osc, alp, m_molla = sp.symbols('m_osc alp m_molla', positive=True)\n",
    "sigma_m_osc, sigma_alp, sigma_m_molla = sp.symbols('sigma_m_osc sigma_alp sigma_m_molla', positive=True)\n",
    "\n",
    "# massa equivalente\n",
    "Meq = 1 / (m_osc + alp * m_molla) * 1000\n",
    "\n",
    "# derivate parziali\n",
    "dMeq_dm_osc   = sp.diff(Meq, m_osc)\n",
    "dMeq_dalp     = sp.diff(Meq, alp)\n",
    "dMeq_dm_molla = sp.diff(Meq, m_molla)\n",
    "\n",
    "sigma_Meq = sp.sqrt(\n",
    "    (dMeq_dm_osc   * sigma_m_osc  )**2 +\n",
    "    (dMeq_dalp     * sigma_alp    )**2 +\n",
    "    (dMeq_dm_molla * sigma_m_molla)**2\n",
    ")\n",
    "\n",
    "print(\"Meq =\", Meq)\n",
    "print(\"sigma_Meq =\", sigma_Meq.simplify())\n",
    "print(\"\\nFormula LaTeX:\")\n",
    "print(f\"Meq = {sp.latex(Meq)}\")\n",
    "print(f\"sigma_Meq = {sp.latex(sigma_Meq.simplify())}\")\n",
    "\n",
    "# funzioni numeriche\n",
    "Meq_fn  = sp.lambdify((m_osc, alp, m_molla), Meq, 'numpy')\n",
    "uMeq_fn = sp.lambdify((m_osc, sigma_m_osc, alp, sigma_alp, m_molla, sigma_m_molla), sigma_Meq, 'numpy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "56679fc4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w2 = w**2\n",
      "sigma_w2 = 2*sigma_w*w\n",
      "\n",
      "Formula LaTeX:\n",
      "w2 = w^{2}\n",
      "sigma_w2 = 2 \\sigma_{w} w\n"
     ]
    }
   ],
   "source": [
    "# w in w^2\n",
    "# simboli\n",
    "w = sp.symbols('w', positive=True)\n",
    "sigma_w = sp.symbols('sigma_w', positive=True)\n",
    "\n",
    "# omega^2\n",
    "w2 = w**2\n",
    "\n",
    "# derivata parziale\n",
    "dw2_dw = sp.diff(w2, w)\n",
    "\n",
    "sigma_w2 = sp.sqrt((dw2_dw * sigma_w)**2)\n",
    "\n",
    "print(\"w2 =\", w2)\n",
    "print(\"sigma_w2 =\", sigma_w2.simplify())\n",
    "print(\"\\nFormula LaTeX:\")\n",
    "print(f\"w2 = {sp.latex(w2)}\")\n",
    "print(f\"sigma_w2 = {sp.latex(sigma_w2.simplify())}\")\n",
    "\n",
    "# funzioni numeriche\n",
    "w2_fn  = sp.lambdify((w), w2, 'numpy')\n",
    "uw2_fn = sp.lambdify((w, sigma_w), sigma_w2, 'numpy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "455271a9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3e41f715ecf9427790522ae267be1968",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Sheet(cells=(Cell(column_end=0, column_start=0, row_start=0, squeeze_row=False, type='numeric', value=[108.61,…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'[{\"m1\":108.61,\"m2\":108.61,\"m3\":108.61,\"a1\":9.21,\"ua1\":0.029,\"w1\":14.2459,\"uw1\":0.0008,\"c1\":268.151,\"uc1\":0.02,\"a2\":10.69,\"ua2\":0.04,\"w2\":14.2434,\"uw2\":0.0009,\"c2\":268.326,\"uc2\":0.026,\"alp\":0.333333,\"ualp\":0.000001,\"m\":108.61,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":14.24465,\"uw\":0.00125,\"c\":268.2385,\"uc\":0.0875,\"F\":1065.02966,\"uF\":0.4353612606,\"r\":-0.1151157394,\"ur\":0.1108576,\"Meq\":8.4335211413,\"uMeq\":0.000230411,\"Omega2\":202.9100536225,\"uOmega2\":0.035611625},{\"m1\":128.64,\"m2\":128.63,\"m3\":128.64,\"a1\":10.037,\"ua1\":0.025,\"w1\":13.1939,\"uw1\":0.0007,\"c1\":259.605,\"uc1\":0.018,\"a2\":9.744,\"ua2\":0.027,\"w2\":13.1913,\"uw2\":0.0009,\"c2\":259.745,\"uc2\":0.02,\"alp\":0.333333,\"ualp\":0.000001,\"m\":128.6366666667,\"um\":0.0044095855,\"nm\":3.0,\"outm\":\"[]\",\"w\":13.1926,\"uw\":0.0013,\"c\":259.675,\"uc\":0.07,\"F\":1261.4111533333,\"uF\":0.5163603432,\"r\":0.0997008545,\"ur\":0.0835641852,\"Meq\":7.2149498938,\"uMeq\":0.0002419647,\"Omega2\":174.04469476,\"uOmega2\":0.03430076},{\"m1\":148.38,\"m2\":148.38,\"m3\":148.38,\"a1\":9.93,\"ua1\":0.03,\"w1\":12.3469,\"uw1\":0.0007,\"c1\":251.525,\"uc1\":0.021,\"a2\":11.41,\"ua2\":0.03,\"w2\":12.3461,\"uw2\":0.0006,\"c2\":251.542,\"uc2\":0.023,\"alp\":0.333333,\"ualp\":0.000001,\"m\":148.38,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":12.3465,\"uw\":0.0009219544,\"c\":251.5335,\"uc\":0.031144823,\"F\":1455.01428,\"uF\":0.5941946685,\"r\":0.010632976,\"ur\":0.0484884905,\"Meq\":6.3153466889,\"uMeq\":0.0001292051,\"Omega2\":152.43606225,\"uOmega2\":0.0227658211},{\"m1\":168.53,\"m2\":168.53,\"m3\":168.53,\"a1\":11.34,\"ua1\":0.03,\"w1\":11.6345,\"uw1\":0.0005,\"c1\":243.211,\"uc1\":0.021,\"a2\":11.5,\"ua2\":0.03,\"w2\":11.6344,\"uw2\":0.0006,\"c2\":243.13,\"uc2\":0.021,\"alp\":0.333333,\"ualp\":0.000001,\"m\":168.53,\"um\":0.0028867513,\"nm\":3.0,\"outm\":\"[]\",\"w\":11.63445,\"uw\":0.000781025,\"c\":243.1705,\"uc\":0.0405,\"F\":1652.60518,\"uF\":0.6747140787,\"r\":-0.0264654245,\"ur\":0.0645469948,\"Meq\":5.6024155762,\"uMeq\":0.0001016801,\"Omega2\":135.3604268025,\"uOmega2\":0.0181735919}]'"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dfSonar['Meq'] = Meq_fn(dfSonar['m'], dfSonar['alp'], massaMolla)\n",
    "dfSonar['uMeq']= uMeq_fn(dfSonar['m'], dfSonar['um'], dfSonar['alp'], dfSonar['ualp'], massaMolla, umassaMolla)\n",
    "\n",
    "dfSonar['Omega2'] = w2_fn(dfSonar['w'])\n",
    "dfSonar['uOmega2']= uw2_fn(dfSonar['w'], dfSonar['uw'])\n",
    "\n",
    "\n",
    "sheet = ipysheet.from_dataframe(dfSonar)\n",
    "display(sheet)\n",
    "dfSonar.head(4).to_json(orient=\"records\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5dda09cd",
   "metadata": {},
   "source": [
    "## Regressione lineare Carpi dati del sonar Caso Dinamico"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "02119d66",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ax + B : \n",
      "AD      = 23.8854 ± 0.0133\n",
      "BD      = 1.5710 ± 0.0856\n",
      "cov_ABD = -0.001129\n",
      "chi²    = 27.0310\n",
      "P(chi², ∞)= 0.0000\n"
     ]
    }
   ],
   "source": [
    "AD, BD, uAD, uBD, covABD, chiD, PD = reg_lin( dfSonar[\"Meq\"], dfSonar[\"Omega2\"], dfSonar[\"uMeq\"], dfSonar[\"uOmega2\"])\n",
    "\n",
    "print(\"Ax + B : \")\n",
    "print(f\"AD      = {AD:.4f} ± {uAD:.4f}\")\n",
    "print(f\"BD      = {BD:.4f} ± {uBD:.4f}\")\n",
    "print(f\"cov_ABD = {covABD:.6f}\")\n",
    "print(f\"chi²    = {chiD:.4f}\")\n",
    "print(f\"P(chi², ∞)= {PD:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "96f12fe6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Calcolo numerico residui sul dfSonar caso dinamico\n",
    "dfSonar[\"R\"] = r_fn(\n",
    "  dfSonar[\"Meq\"],\n",
    "  dfSonar[\"Omega2\"],\n",
    "  AD,\n",
    "  BD\n",
    ")\n",
    "\n",
    "dfSonar[\"uR\"] = sigma_r_fn(\n",
    "  dfSonar[\"Meq\"], dfSonar[\"Omega2\"],\n",
    "  AD, BD,\n",
    "  dfSonar[\"uMeq\"], dfSonar[\"uOmega2\"],\n",
    "  uAD, uBD, covABD\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "de571f32",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 56308 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Fit\n",
    "SCALA = 10\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "x_data =  dfSonar[\"Meq\"]\n",
    "y_data =  dfSonar[\"Omega2\"]\n",
    "\n",
    "x_fit = np.linspace(0, x_data.max(), 300)\n",
    "y_fit = AD * x_fit + BD\n",
    "\n",
    "ax.errorbar(\n",
    "    x_data, y_data,\n",
    "    xerr=SCALA * dfSonar[\"uMeq\"], yerr=SCALA * dfSonar[\"uOmega2\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=f\"Dati (barre errore x{SCALA})\"\n",
    ")\n",
    "ax.plot(\n",
    "    x_fit, y_fit,\n",
    "    color='red', linewidth=1.5,\n",
    "    label=f\"Fit: $A={AD:.3f}\\\\pm{uAD:.3f}$\\n\"\n",
    "          f\"     $B={BD:.2f}\\\\pm{uBD:.2f}$\\n\"\n",
    ")\n",
    "\n",
    "\n",
    "plt.xlim(left=0)\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"Meq  [Kg$^{-1}$]\")\n",
    "ax.set_ylabel(r\"$\\omega^2$  [s$^{-2}$]\")\n",
    "ax.set_title(\"Fit lineare — Molla 1 (sonar Dinamico)\")\n",
    "ax.legend(fontsize=9)\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "c87033e0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 53380 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Grafico Residui\n",
    "fig, ax = plt.subplots(figsize=(8, 5))\n",
    "\n",
    "# Residui con barre d'errore\n",
    "ax.errorbar(\n",
    "    dfSonar[\"Omega2\"], dfSonar[\"R\"],\n",
    "    xerr=dfSonar[\"uOmega2\"], yerr=dfSonar[\"uR\"],\n",
    "    fmt='o', color=sns.color_palette()[0],\n",
    "    ecolor='gray', elinewidth=1, capsize=3,\n",
    "    markersize=5, label=\"Residui\"\n",
    ")\n",
    "\n",
    "# Linea dello zero\n",
    "ax.axhline(0, color='red', linestyle='--', linewidth=1)\n",
    "\n",
    "# Estetica\n",
    "sns.despine(ax=ax)\n",
    "ax.set_xlabel(r\"$\\omega^2$  [s$^{-2}$]\")\n",
    "ax.set_ylabel(r\"Residuo $x_i - \\left(\\frac{y_i}{A} - \\frac{B}{A}\\right)$  [Kg$^{-1}$]\")\n",
    "ax.set_title(\"Residui della regressione — Molla 1 (sonar dinamico)\")\n",
    "ax.legend()\n",
    "ax.grid(True, linestyle=':', linewidth=0.5, alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5ca1727",
   "metadata": {},
   "source": [
    "# Raccolta finale di tutti i dati"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "e87e24b7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Calibro Con tutti i dati\n",
      "AC      = 23.9437 ± 0.0424\n",
      "BC      = 2719.8777 ± 2.8546\n",
      "cov_ABC = 0.119914\n",
      "chi²    = 55.1017\n",
      "GdL     = 5\n",
      "P(chi², ∞)= 0.0000\n",
      "\n",
      "Calibro tolto il dato 1\n",
      "AC      = 23.8835 ± 0.0432\n",
      "BC      = 2718.1378 ± 2.8613\n",
      "cov_ABC = 0.121602\n",
      "chi²    = 1.7942\n",
      "GdL     = 4\n",
      "P(chi², ∞)= 0.4078\n",
      "\n",
      "Sonar caso statico (temperatura non considerata)\n",
      "AS      = 23.5225 ± 0.0853\n",
      "BS      = 7371.9487 ± 21.4728\n",
      "cov_ABS = 1.830281\n",
      "chi²    = 3.8872\n",
      "GdL     = 4\n",
      "P(chi², ∞)= 0.1432\n",
      "\n",
      "Sonar caso statico (temperatura considerata)\n",
      "AS      = 23.6160 ± 0.1404\n",
      "BS      = 7365.6372 ± 35.4592\n",
      "cov_ABS = 4.976670\n",
      "chi²    = 1.6321\n",
      "GdL     = 4\n",
      "P(chi², ∞)= 0.4422\n",
      "\n",
      "Sonar caso Dinamico\n",
      "AD      = 23.8854 ± 0.0133\n",
      "BD      = 1.5710 ± 0.0856\n",
      "cov_ABD = -0.001129\n",
      "chi²    = 27.0310\n",
      "GdL     = 4\n",
      "P(chi², ∞)= 0.0000\n"
     ]
    }
   ],
   "source": [
    "print(\"Calibro Con tutti i dati\")\n",
    "print(f\"AC      = {AC:.4f} ± {uAC:.4f}\")\n",
    "print(f\"BC      = {BC:.4f} ± {uBC:.4f}\")\n",
    "print(f\"cov_ABC = {covABC:.6f}\")\n",
    "print(f\"chi²    = {chiC:.4f}\")\n",
    "print(f\"GdL     = {len(dfCalibro)}\")\n",
    "print(f\"P(chi², ∞)= {PC:.4f}\")\n",
    "\n",
    "print(\"\\nCalibro tolto il dato 1\")\n",
    "print(f\"AC      = {AC2:.4f} ± {uAC2:.4f}\")\n",
    "print(f\"BC      = {BC2:.4f} ± {uBC2:.4f}\")\n",
    "print(f\"cov_ABC = {covABC2:.6f}\")\n",
    "print(f\"chi²    = {chiC2:.4f}\")\n",
    "print(f\"GdL     = {len(dfCalibro_senza1)}\")\n",
    "print(f\"P(chi², ∞)= {PC2:.4f}\")\n",
    "\n",
    "print(\"\\nSonar caso statico (temperatura non considerata)\")\n",
    "print(f\"AS      = {AS:.4f} ± {uAS:.4f}\")\n",
    "print(f\"BS      = {BS:.4f} ± {uBS:.4f}\")\n",
    "print(f\"cov_ABS = {covABS:.6f}\")\n",
    "print(f\"chi²    = {chiS:.4f}\")\n",
    "print(f\"GdL     = {len(dfSonar)}\")\n",
    "print(f\"P(chi², ∞)= {PS:.4f}\")\n",
    "\n",
    "print(\"\\nSonar caso statico (temperatura considerata)\")\n",
    "print(f\"AS      = {AS2:.4f} ± {uAS2:.4f}\")\n",
    "print(f\"BS      = {BS2:.4f} ± {uBS2:.4f}\")\n",
    "print(f\"cov_ABS = {covABS2:.6f}\")\n",
    "print(f\"chi²    = {chiS2:.4f}\")\n",
    "print(f\"GdL     = {len(dfSonar)}\")\n",
    "print(f\"P(chi², ∞)= {PS2:.4f}\")\n",
    "\n",
    "print(\"\\nSonar caso Dinamico\")\n",
    "print(f\"AD      = {AD:.4f} ± {uAD:.4f}\")\n",
    "print(f\"BD      = {BD:.4f} ± {uBD:.4f}\")\n",
    "print(f\"cov_ABD = {covABD:.6f}\")\n",
    "print(f\"chi²    = {chiD:.4f}\")\n",
    "print(f\"GdL     = {len(dfSonar)}\")\n",
    "print(f\"P(chi², ∞)= {PD:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "id": "d4af85a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def p_t_student_compatibilita(x, ux, gx, y, uy, gy):\n",
    "  GdL = gx + gy - 2\n",
    "  s2 = ( (gx - 1) * ux**2  +  (gy - 1) * uy**2 ) / GdL\n",
    "  sigma2 = ( s2 / gx )  + ( s2 / gy )\n",
    "  t = abs(x - y) / np.sqrt( sigma2 )\n",
    "\n",
    "  return {\"p\": 2 * (1 - stats.t.cdf(abs(t), df=GdL)), \"t\": t}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "id": "57de948b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Compatibilità: Calibro (tolto dato 1) vs Sonar statico (T considerata)\n",
      "Sigma             t    p-value\n",
      "------------------------------\n",
      "1σ           2.5752     0.1235\n",
      "2σ           1.2876     0.3268\n",
      "3σ           0.8584     0.4811\n",
      "\n",
      "\n",
      "Compatibilità: Calibro (tolto dato 1) vs Sonar dinamico\n",
      "Sigma             t    p-value\n",
      "------------------------------\n",
      "1σ           0.0591     0.9582\n",
      "2σ           0.0296     0.9791\n",
      "3σ           0.0197     0.9861\n",
      "\n",
      "\n",
      "Compatibilità: Sonar Dinamico vs Sonar statico (T considerata)\n",
      "Sigma             t    p-value\n",
      "------------------------------\n",
      "1σ           2.7009     0.1141\n",
      "2σ           1.3505     0.3094\n",
      "3σ           0.9003     0.4630\n"
     ]
    }
   ],
   "source": [
    "# Ringraziate Cloude per questo incredibile print\n",
    "print(\"Compatibilità: Calibro (tolto dato 1) vs Sonar statico (T considerata)\")\n",
    "print(f\"{'Sigma':<10} {'t':>8} {'p-value':>10}\")\n",
    "print(\"-\" * 30)\n",
    "for n in [1, 2, 3]:\n",
    "    res = p_t_student_compatibilita(AC2, uAC2*n, len(dfCalibro_senza1)-2,\n",
    "                                    AS2,  uAS2*n, len(dfSonar)-2)\n",
    "    print(f\"{n}σ         {res['t']:>8.4f} {res['p']:>10.4f}\")\n",
    "\n",
    "print(\"\\n\\nCompatibilità: Calibro (tolto dato 1) vs Sonar dinamico\")\n",
    "print(f\"{'Sigma':<10} {'t':>8} {'p-value':>10}\")\n",
    "print(\"-\" * 30)\n",
    "for n in [1, 2, 3]:\n",
    "    res = p_t_student_compatibilita(AC2, uAC2*n, len(dfCalibro_senza1)-2,\n",
    "                                    AD,  uAD*n,  len(dfSonar)-2)\n",
    "    print(f\"{n}σ         {res['t']:>8.4f} {res['p']:>10.4f}\")\n",
    "\n",
    "print(\"\\n\\nCompatibilità: Sonar Dinamico vs Sonar statico (T considerata)\")\n",
    "print(f\"{'Sigma':<10} {'t':>8} {'p-value':>10}\")\n",
    "print(\"-\" * 30)\n",
    "for n in [1, 2, 3]:\n",
    "    res = p_t_student_compatibilita(AD,  uAD*n,  len(dfSonar)-2,\n",
    "                                    AS2, uAS2*n, len(dfSonar)-2)\n",
    "    print(f\"{n}σ         {res['t']:>8.4f} {res['p']:>10.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b66ccc91",
   "metadata": {},
   "source": [
    "# Note finali\n",
    "Chiaramente i dati presi con il sonar statico soffrono di altri errori che dovremmo discutere come introdurre, sicuramente soffrono della precisione con cui abbiamo puntato il sonar.\n",
    "\n",
    "La temperatura sfortunatamente è stata presa con troppa poca attenzione e questo fa perdere di integrità hai nostri dati, ma altro per ora non mi viene su 2 piedi.\n",
    "\n",
    "Abbiamo almeno una buona basa su cui poter ragionare."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
