{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3a8dfc0e",
   "metadata": {},
   "source": [
    "# Analisi della molla statica 1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ff20b69",
   "metadata": {},
   "source": [
    "## Import delle librerie e set di variabili gloabali"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "f34c5b88",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import scipy as sc\n",
    "from scipy.stats import chi2\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib as mpl\n",
    "import statsmodels.api as sm\n",
    "\n",
    "\n",
    "g = 9.807\n",
    "ug = 0.001"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39d2ffea",
   "metadata": {},
   "source": [
    "## Lettura dei dati e calcolo delle deviazioni standard campionarie\n",
    "- Lettura del CSV\n",
    "- Creazione del data frame\n",
    "- Deviazioni standard\n",
    "- Permutazioni e calcolo dei Delta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "08efb2be",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv(r'statica1.csv')\n",
    "\n",
    "def calcola_stats(df, prefix, err_arbitrario):\n",
    "  cols = [col for col in df.columns if col.startswith(prefix)]\n",
    "\n",
    "  def riga_stats(row):\n",
    "    valori = row[cols].dropna()\n",
    "    n = len(valori)\n",
    "\n",
    "    if n == 0:\n",
    "      return pd.Series({prefix: np.nan, f\"u{prefix}\": np.nan})\n",
    "    elif n == 1:\n",
    "      return pd.Series({prefix: valori.iloc[0], f\"u{prefix}\": err_arbitrario})\n",
    "    else:\n",
    "      media = valori.mean()\n",
    "      sigma = valori.std(ddof=1)\n",
    "      return pd.Series({prefix: media, f\"u{prefix}\": sigma})\n",
    "\n",
    "  stats = df.apply(riga_stats, axis=1)\n",
    "  df[prefix] = stats[prefix]\n",
    "  df[f\"u{prefix}\"] = stats[f\"u{prefix}\"]\n",
    "\n",
    "  return df\n",
    "\n",
    "df = calcola_stats(df, \"Dx\", err_arbitrario=0.01)\n",
    "df = calcola_stats(df, \"m\", err_arbitrario=0.0028867513)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "5494409f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>m1</th>\n",
       "      <th>Dx1</th>\n",
       "      <th>Dx2</th>\n",
       "      <th>Dx3</th>\n",
       "      <th>Dx4</th>\n",
       "      <th>Dx5</th>\n",
       "      <th>Dx6</th>\n",
       "      <th>Dx</th>\n",
       "      <th>uDx</th>\n",
       "      <th>m</th>\n",
       "      <th>um</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>88.97</td>\n",
       "      <td>77.26</td>\n",
       "      <td>77.28</td>\n",
       "      <td>77.26</td>\n",
       "      <td>77.28</td>\n",
       "      <td>77.24</td>\n",
       "      <td>77.42</td>\n",
       "      <td>77.290000</td>\n",
       "      <td>0.065422</td>\n",
       "      <td>88.97</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>108.61</td>\n",
       "      <td>68.92</td>\n",
       "      <td>68.94</td>\n",
       "      <td>69.00</td>\n",
       "      <td>68.98</td>\n",
       "      <td>68.90</td>\n",
       "      <td>69.02</td>\n",
       "      <td>68.960000</td>\n",
       "      <td>0.047329</td>\n",
       "      <td>108.61</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>128.64</td>\n",
       "      <td>60.88</td>\n",
       "      <td>61.00</td>\n",
       "      <td>60.82</td>\n",
       "      <td>60.94</td>\n",
       "      <td>61.08</td>\n",
       "      <td>60.94</td>\n",
       "      <td>60.943333</td>\n",
       "      <td>0.090701</td>\n",
       "      <td>128.64</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>148.38</td>\n",
       "      <td>52.96</td>\n",
       "      <td>52.96</td>\n",
       "      <td>52.78</td>\n",
       "      <td>52.88</td>\n",
       "      <td>52.88</td>\n",
       "      <td>53.00</td>\n",
       "      <td>52.910000</td>\n",
       "      <td>0.079750</td>\n",
       "      <td>148.38</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>168.53</td>\n",
       "      <td>44.42</td>\n",
       "      <td>44.68</td>\n",
       "      <td>44.48</td>\n",
       "      <td>44.80</td>\n",
       "      <td>44.92</td>\n",
       "      <td>44.52</td>\n",
       "      <td>44.636667</td>\n",
       "      <td>0.196943</td>\n",
       "      <td>168.53</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       m1    Dx1    Dx2    Dx3    Dx4    Dx5    Dx6         Dx       uDx  \\\n",
       "0   88.97  77.26  77.28  77.26  77.28  77.24  77.42  77.290000  0.065422   \n",
       "1  108.61  68.92  68.94  69.00  68.98  68.90  69.02  68.960000  0.047329   \n",
       "2  128.64  60.88  61.00  60.82  60.94  61.08  60.94  60.943333  0.090701   \n",
       "3  148.38  52.96  52.96  52.78  52.88  52.88  53.00  52.910000  0.079750   \n",
       "4  168.53  44.42  44.68  44.48  44.80  44.92  44.52  44.636667  0.196943   \n",
       "\n",
       "        m        um  \n",
       "0   88.97  0.002887  \n",
       "1  108.61  0.002887  \n",
       "2  128.64  0.002887  \n",
       "3  148.38  0.002887  \n",
       "4  168.53  0.002887  "
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "976d5531",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]\n",
      "10\n",
      "############################################################\n",
      "[ 8.33       16.34666667 24.38       32.65333333  8.01666667 16.05\n",
      " 24.32333333  8.03333333 16.30666667  8.27333333]\n",
      "[0.08074652 0.11183321 0.10315038 0.2075251  0.10230673 0.09273618\n",
      " 0.20255041 0.12077527 0.21682558 0.21247745]\n",
      "############################################################\n",
      "[-19.64 -39.67 -59.41 -79.56 -20.03 -39.77 -59.92 -19.74 -39.89 -20.15]\n",
      "[0.00408248 0.00408248 0.00408248 0.00408248 0.00408248 0.00408248\n",
      " 0.00408248 0.00408248 0.00408248 0.00408248]\n"
     ]
    }
   ],
   "source": [
    "perm = [(x,i) for x in range(0,len(df)) for i in range(x+1,len(df))]\n",
    "\n",
    "este = np.array([df.Dx[x] - df.Dx[j] for x,j in perm])\n",
    "ueste = np.array([np.sqrt(df.uDx[x]**2 + df.uDx[j]**2) for x,j in perm])\n",
    "\n",
    "masse = np.array([df.m[x] - df.m[j] for x,j in perm])\n",
    "umasse = np.array([np.sqrt(df.um[x]**2 + df.um[j]**2) for x,j in perm])\n",
    "\n",
    "\n",
    "print(perm)\n",
    "print(len(perm))\n",
    "\n",
    "print(\"#\"* 60)\n",
    "print(este)\n",
    "print(ueste)\n",
    "\n",
    "print(\"#\"* 60)\n",
    "print(masse)\n",
    "print(umasse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b3b6776",
   "metadata": {},
   "source": [
    "## Calcolo dei K e media pesata\n",
    "- Calcolo del K\n",
    "- Calcolo della media pesata (sui K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "2ad19283",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[23.12238655 23.79957321 23.89802584 23.89480155 24.50322786 24.30058505\n",
      " 24.15933014 24.09836266 23.99026349 23.88530016]\n",
      "[0.22419984 0.16285763 0.10115386 0.15188559 0.31275403 0.14045171\n",
      " 0.2012065  0.36234381 0.31901124 0.61345112]\n"
     ]
    }
   ],
   "source": [
    "F = masse * g\n",
    "uF = np.sqrt((g * umasse)**2 + (masse * ug)**2)\n",
    "\n",
    "K = - F / este\n",
    "uK = np.sqrt((1/este)**2 * uF**2   +   (F / este**2)**2 * ueste**2  )\n",
    "\n",
    "\n",
    "print(K)\n",
    "print(uK)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "5f59d6c9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-medio: 23.951129031636384\n",
      "sigmaC:  0.057316734630371916\n"
     ]
    }
   ],
   "source": [
    "def mediaPesata(x, ux, dim = 0):\n",
    "  x_arr = x.to_numpy() if isinstance(x, (pd.Series, pd.DataFrame)) else np.asarray(x)\n",
    "  sigma_arr = ux.to_numpy() if isinstance(ux, (pd.Series, pd.DataFrame)) else np.asarray(ux)\n",
    "\n",
    "  w = 1.0 / (sigma_arr ** 2)\n",
    "\n",
    "  num = np.nansum(w * x_arr, axis=dim)\n",
    "  den = np.nansum(w, axis=dim)\n",
    "\n",
    "  media = num / den\n",
    "  sigma = np.sqrt(1.0 / den)\n",
    "\n",
    "  return media, sigma\n",
    "\n",
    "media, uA = mediaPesata(K, uK)\n",
    "print(\"K-medio:\", media)\n",
    "print(\"sigmaC: \", uA)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02fc45a9",
   "metadata": {},
   "source": [
    "## Analisi con regressioni e grafici\n",
    "Ogni blocco ha:\n",
    "- Regressione\n",
    "- grafico\n",
    "- chi^2\n",
    "\n",
    "Nota: Ax + B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "7e75ec05",
   "metadata": {},
   "outputs": [],
   "source": [
    "sns.set_theme(style=\"whitegrid\")\n",
    "\n",
    "data = pd.DataFrame({\n",
    "    \"x\": este,\n",
    "    \"ux\": ueste,\n",
    "    \"y\": - F,\n",
    "    \"uy\": uF\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "313237da",
   "metadata": {},
   "source": [
    "### Regressione lineare \"OLS\"\n",
    "\n",
    "Non tiene conto dei nostri errori, un risultato puro e semplice"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "aefe7756",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            OLS Regression Results                            \n",
      "==============================================================================\n",
      "Dep. Variable:                      y   R-squared:                       1.000\n",
      "Model:                            OLS   Adj. R-squared:                  1.000\n",
      "Method:                 Least Squares   F-statistic:                 2.238e+04\n",
      "Date:                Sat, 04 Apr 2026   Prob (F-statistic):           4.46e-15\n",
      "Time:                        19:37:55   Log-Likelihood:                -27.238\n",
      "No. Observations:                  10   AIC:                             58.48\n",
      "Df Residuals:                       8   BIC:                             59.08\n",
      "Df Model:                           1                                         \n",
      "Covariance Type:            nonrobust                                         \n",
      "==============================================================================\n",
      "                 coef    std err          t      P>|t|      [0.025      0.975]\n",
      "------------------------------------------------------------------------------\n",
      "const          0.0999      2.915      0.034      0.973      -6.621       6.821\n",
      "x             23.9687      0.160    149.602      0.000      23.599      24.338\n",
      "==============================================================================\n",
      "Omnibus:                        0.134   Durbin-Watson:                   0.595\n",
      "Prob(Omnibus):                  0.935   Jarque-Bera (JB):                0.285\n",
      "Skew:                          -0.202   Prob(JB):                        0.867\n",
      "Kurtosis:                       2.277   Cond. No.                         40.8\n",
      "==============================================================================\n",
      "\n",
      "Notes:\n",
      "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n",
      "\n",
      "RISULTATI REGRESSIONE:\n",
      "Aols  = 23.96871 ± 0.16022\n",
      "Bols  = 0.09993 ± 2.91472\n",
      "R² = 0.99964\n"
     ]
    }
   ],
   "source": [
    "X = sm.add_constant(data[\"x\"])\n",
    "model = sm.OLS(data[\"y\"], X).fit()\n",
    "\n",
    "print(model.summary())\n",
    "\n",
    "# Estrazione parametri\n",
    "Bols = model.params[\"const\"]\n",
    "Aols = model.params[\"x\"]\n",
    "uBols = model.bse[\"const\"]\n",
    "uAols = model.bse[\"x\"]\n",
    "R2 = model.rsquared\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE:\")\n",
    "print(f\"Aols  = {Aols:.5f} ± {uAols:.5f}\")\n",
    "print(f\"Bols  = {Bols:.5f} ± {uBols:.5f}\")\n",
    "print(f\"R² = {R2:.5f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "1d42b009",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 53936 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,6))\n",
    "\n",
    "# Seaborn scatter\n",
    "sns.scatterplot( data=data,\n",
    "  x=\"x\",\n",
    "  y=\"y\",\n",
    "  s=7\n",
    ")\n",
    "\n",
    "# Barre d’errore\n",
    "plt.errorbar(\n",
    "  data[\"x\"],\n",
    "  data[\"y\"],\n",
    "  xerr=data[\"ux\"],\n",
    "  yerr=data[\"uy\"],\n",
    "  fmt=\"none\",\n",
    "  ecolor=\"gray\",\n",
    "  elinewidth=1,\n",
    "  capsize=3,\n",
    "  alpha=0.7\n",
    ")\n",
    "\n",
    "# Linea di regressione\n",
    "xfit = np.linspace(0, data[\"x\"].max(), 200)\n",
    "yfit = Bols + Aols * xfit\n",
    "\n",
    "plt.plot(\n",
    "  xfit,\n",
    "  yfit,\n",
    "  color=\"crimson\",\n",
    "  linewidth=1,\n",
    "  zorder=10,\n",
    "  label=\"Fit lineare OLS\"\n",
    ")\n",
    "\n",
    "plt.xlim(left=0)\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "\n",
    "plt.xlabel(\"Δx (mm)\")\n",
    "plt.ylabel(\"Forza F (mN)\")\n",
    "plt.title(\"Legge di Hooke — punti permutati con errorbar\")\n",
    "plt.legend()\n",
    "plt.grid(True, linestyle=\"--\", alpha=0.1)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "986ff4a6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chi²      = 25.02317\n",
      "GdL       = 8\n",
      "Chi² rid  = 3.12790\n",
      "P(0, chi²)= 0.99846\n",
      "\n",
      "\n",
      "############################################################\n",
      "capiamo quale dato sta contribuendo maggiormente\n",
      "0    13.640283\n",
      "1     1.141735\n",
      "2     0.543390\n",
      "3     0.255239\n",
      "4     2.911852\n",
      "5     5.525531\n",
      "6     0.872959\n",
      "7     0.105774\n",
      "8     0.002341\n",
      "9     0.024062\n",
      "dtype: float64\n"
     ]
    }
   ],
   "source": [
    "F_fit = Bols + Aols * data[\"x\"]\n",
    "sigma = np.sqrt(data[\"uy\"]**2 + (Aols * data[\"ux\"])**2)\n",
    "\n",
    "chi2_val = np.sum( ((data[\"y\"] - F_fit) / sigma)**2 )\n",
    "\n",
    "N = len(data)\n",
    "nu = N - 2\n",
    "\n",
    "chi2_red = chi2_val / nu\n",
    "Pols = chi2.cdf(chi2_val, df=nu)\n",
    "\n",
    "\n",
    "print(f\"Chi²      = {chi2_val:.5f}\")\n",
    "print(f\"GdL       = {nu}\")\n",
    "print(f\"Chi² rid  = {chi2_red:.5f}\")\n",
    "print(f\"P(0, chi²)= {Pols:.5f}\")\n",
    "print(\"\\n\\n\" + \"#\"*60)\n",
    "print(\"capiamo quale dato sta contribuendo maggiormente\")\n",
    "print(((data[\"y\"] - F_fit) / sigma)**2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6015e6fd",
   "metadata": {},
   "source": [
    "### Regressione lineare Carpi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "2d4b7144",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ax + B : \n",
      "AC      = 24.0474 ± 0.1316\n",
      "BC      = -1.5698 ± 2.0811\n",
      "cov_ABC = -0.246370\n",
      "P(0, chi²)= 0.9979\n"
     ]
    }
   ],
   "source": [
    "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",
    "  chi = sc.stats.chi2.cdf(x2, dof)  # P(X² > x2)\n",
    "\n",
    "  return A, B, sigma_A, sigma_B, cov_AB, chi\n",
    "\n",
    "\n",
    "AC, BC, uAC, uBC, covABC, chiC = reg_lin(data[\"x\"], data[\"y\"], data[\"ux\"], data[\"uy\"])\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\"P(0, chi²)= {chiC:.4f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "e2407a04",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 60576 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,6))\n",
    "\n",
    "# Seaborn scatter\n",
    "sns.scatterplot(\n",
    "  data=data,\n",
    "  x=\"x\",\n",
    "  y=\"y\",\n",
    "  s=7\n",
    ")\n",
    "\n",
    "# Barre d’errore\n",
    "plt.errorbar(\n",
    "  data[\"x\"],\n",
    "  data[\"y\"],\n",
    "  xerr=data[\"ux\"],\n",
    "  yerr=data[\"uy\"],\n",
    "  fmt=\"none\",\n",
    "  ecolor=\"gray\",\n",
    "  elinewidth=1,\n",
    "  capsize=3,\n",
    "  alpha=0.7\n",
    ")\n",
    "\n",
    "# Linea di regressione\n",
    "xfit = np.linspace(0, data[\"x\"].max(), 200)\n",
    "yfit = BC + AC * xfit\n",
    "\n",
    "\n",
    "plt.plot(\n",
    "  xfit,\n",
    "  yfit,\n",
    "  color=\"crimson\",\n",
    "  linewidth=1,\n",
    "  zorder=10,\n",
    "  label=\"Fit lineare Carpi\"\n",
    ")\n",
    "\n",
    "\n",
    "plt.xlim(left=0)\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "\n",
    "plt.xlabel(\"Δx (mm)\")\n",
    "plt.ylabel(\"Forza F (mN)\")\n",
    "plt.title(\"Legge di Hooke — punti permutati con errorbar\")\n",
    "plt.legend()\n",
    "plt.grid(True, linestyle=\"--\", alpha=0.1)\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "32e9948f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chi²      = 24.13715\n",
      "GdL       = 8\n",
      "Chi² rid  = 3.01714\n",
      "P(0, chi²)= 0.99783\n",
      "\n",
      "\n",
      "############################################################\n",
      "capiamo quale dato sta contribuendo maggiormente\n",
      "0    9.978674\n",
      "1    0.850746\n",
      "2    0.696840\n",
      "3    0.467438\n",
      "4    4.507635\n",
      "5    6.377901\n",
      "6    0.776558\n",
      "7    0.464361\n",
      "8    0.014989\n",
      "9    0.002006\n",
      "dtype: float64\n"
     ]
    }
   ],
   "source": [
    "F_fit = BC + AC * data[\"x\"]\n",
    "sigma = np.sqrt(data[\"uy\"]**2 + (AC * data[\"ux\"])**2)\n",
    "\n",
    "\n",
    "chi2_val = np.sum( ((data[\"y\"] - F_fit) / sigma)**2 )\n",
    "\n",
    "N = len(data)\n",
    "nu = N - 2\n",
    "\n",
    "chi2_red = chi2_val / nu\n",
    "PC = chi2.cdf(chi2_val, df=nu)\n",
    "\n",
    "\n",
    "print(f\"Chi²      = {chi2_val:.5f}\")\n",
    "print(f\"GdL       = {nu}\")\n",
    "print(f\"Chi² rid  = {chi2_red:.5f}\")\n",
    "print(f\"P(0, chi²)= {PC:.5f}\")\n",
    "print(\"\\n\\n\" + \"#\"*60)\n",
    "print(\"capiamo quale dato sta contribuendo maggiormente\")\n",
    "print(((data[\"y\"] - F_fit) / sigma)**2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad1c81fc",
   "metadata": {},
   "source": [
    "### Regressione lineare pesata Yorkfit "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "bfb895c6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AY        = 24.0647990 ± 0.1318513\n",
      "BY        = -1.8175805 ± 2.0850560\n",
      "cov_ABY   = -0.2473126752648217\n",
      "chi²      = 24.11969\n",
      "chi² rid  = 3.01496\n",
      "P(0, chi²)= 0.99781\n"
     ]
    }
   ],
   "source": [
    "def york_fit(x, y, sx, sy, max_iter=50, tol=1e-15):\n",
    "  # Pesi iniziali\n",
    "  wx = 1 / sx**2\n",
    "  wy = 1 / sy**2\n",
    "\n",
    "  # Stima iniziale della pendenza (OLS y|x)\n",
    "  A = np.cov(x, y, aweights=wy)[0,1] / np.cov(x, x, aweights=wy)[0,1]\n",
    "\n",
    "  for _ in range(max_iter):\n",
    "    A_old = A\n",
    "\n",
    "    # 1) Pesi combinati\n",
    "    Wi = (wx * wy) / (A**2 * wy + wx)\n",
    "\n",
    "    # 2) x e y pesati (eq. 10)\n",
    "    X_bar = np.sum(Wi * x) / np.sum(Wi)\n",
    "    Y_bar = np.sum(Wi * y) / np.sum(Wi)\n",
    "\n",
    "    # 3) Variabili centrate\n",
    "    Ui = x - X_bar\n",
    "    Vi = y - Y_bar\n",
    "\n",
    "    # 4) beta\n",
    "    beta_i = Wi * (Ui / wy + A * Vi / wx)\n",
    "\n",
    "    # 5) Aggiornamento pendenza\n",
    "    A = np.sum(Wi * beta_i * Vi) / np.sum(Wi * beta_i * Ui)\n",
    "\n",
    "    # Convergenza\n",
    "    if abs(A - A_old) < tol:\n",
    "      break\n",
    "\n",
    "  # 6) Intercetta\n",
    "  B = Y_bar - A * X_bar\n",
    "\n",
    "  # S = somma Wi (xi - x)**2\n",
    "  S = np.sum(Wi * Ui**2)\n",
    "\n",
    "  sA = np.sqrt(1 / S)\n",
    "  sB = np.sqrt(1 / np.sum(Wi) + X_bar**2 * sA**2)\n",
    "\n",
    "  # cov(A,B)\n",
    "  cov_AB = -X_bar * sA**2\n",
    "\n",
    "  # CHI QUADRATO\n",
    "  chi2 = np.sum(Wi * (Vi - A * Ui)**2)\n",
    "  dof = len(x) - 2\n",
    "  chi2_red = chi2 / dof\n",
    "\n",
    "  return A, B, sA, sB, cov_AB, chi2, chi2_red\n",
    "\n",
    "AY, BY, uAY, uBY, cov_ABY, chi2_val, chi2_red = york_fit(data.x, data.y, data.ux, data.uy)\n",
    "PY = chi2.cdf(chi2_val, df=nu)\n",
    "\n",
    "\n",
    "print(f\"AY        = {AY:.7f} ± {uAY:.7f}\")\n",
    "print(f\"BY        = {BY:.7f} ± {uBY:.7f}\")\n",
    "print(f\"cov_ABY   = {cov_ABY}\")\n",
    "print(f\"chi²      = {chi2_val:.5f}\")\n",
    "print(f\"chi² rid  = {chi2_red:.5f}\")\n",
    "print(f\"P(0, chi²)= {PY:.5f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "202de438",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 60676 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,6))\n",
    "\n",
    "# Seaborn scatter\n",
    "sns.scatterplot( data=data,\n",
    "  x=\"x\",\n",
    "  y=\"y\",\n",
    "  s=7\n",
    ")\n",
    "\n",
    "# Barre d’errore\n",
    "plt.errorbar(\n",
    "  data[\"x\"],\n",
    "  data[\"y\"],\n",
    "  xerr=data[\"ux\"],\n",
    "  yerr=data[\"uy\"],\n",
    "  fmt=\"none\",\n",
    "  ecolor=\"gray\",\n",
    "  elinewidth=1,\n",
    "  capsize=3,\n",
    "  alpha=0.7\n",
    ")\n",
    "\n",
    "# Linea di regressione\n",
    "xfit = np.linspace(0, data[\"x\"].max(), 200)\n",
    "yfit = BY + AY * xfit\n",
    "\n",
    "plt.plot(\n",
    "  xfit,\n",
    "  yfit,\n",
    "  color=\"crimson\",\n",
    "  linewidth=1,\n",
    "  zorder=10,\n",
    "  label=\"Fit lineare York\"\n",
    ")\n",
    "\n",
    "plt.xlim(left=0)\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "\n",
    "plt.xlabel(\"Δx (mm)\")\n",
    "plt.ylabel(\"Forza F (mN)\")\n",
    "plt.title(\"Legge di Hooke — punti permutati con errorbar\")\n",
    "plt.legend()\n",
    "plt.grid(True, linestyle=\"--\", alpha=0.1)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63442336",
   "metadata": {},
   "source": [
    "## Raccolta finale dei dati"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "caf23dbe",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RISULTATI senza ERRORE STRUMENTALE INCLUSO:\n",
      "Media pesata K  = 23.95113 ± 0.05732\n",
      "\n",
      "RISULTATI REGRESSIONE OLS:\n",
      "Aols  = 23.96871 ± 0.16022\n",
      "Bols  = 0.09993 ± 2.91472\n",
      "P(0, chi²)= 0.99846\n",
      "\n",
      "RISULTATI REGRESSIONE Carpi:\n",
      "Ac  = 24.04738 ± 0.13160\n",
      "Bc  = -1.56983 ± 2.08108\n",
      "P(0, chi²)= 0.99783\n",
      "\n",
      "RISULTATI REGRESSIONE York:\n",
      "Ay  = 24.06480 ± 0.13185\n",
      "By  = -1.81758 ± 2.08506\n",
      "P(0, chi²)= 0.99781\n"
     ]
    }
   ],
   "source": [
    "print(\"RISULTATI senza ERRORE STRUMENTALE INCLUSO:\")\n",
    "print(f\"Media pesata K  = {media:.5f} ± {uA:.5f}\")\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE OLS:\")\n",
    "print(f\"Aols  = {Aols:.5f} ± {uAols:.5f}\")\n",
    "print(f\"Bols  = {Bols:.5f} ± {uBols:.5f}\")\n",
    "print(f\"P(0, chi²)= {Pols:.5f}\")\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE Carpi:\")\n",
    "print(f\"Ac  = {AC:.5f} ± {uAC:.5f}\")\n",
    "print(f\"Bc  = {BC:.5f} ± {uBC:.5f}\")\n",
    "print(f\"P(0, chi²)= {PC:.5f}\")\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE York:\")\n",
    "print(f\"Ay  = {AY:.5f} ± {uAY:.5f}\")\n",
    "print(f\"By  = {BY:.5f} ± {uBY:.5f}\")\n",
    "print(f\"P(0, chi²)= {PY:.5f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7692f792",
   "metadata": {},
   "source": [
    "## Aggiunta degli errori strumentali"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "8f5c8bb7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "u_strum_m    = 0.004082\n",
      "u_strum_Dx   = 0.020412\n",
      "uF_strum     = 0.089066\n",
      "uK_strum     = 0.662828\n"
     ]
    }
   ],
   "source": [
    "res_b = 0.01\n",
    "res_c = 0.05\n",
    "\n",
    "# Incertezza strumentale su una differenza: res/sqrt(12) * sqrt(2) = res/sqrt(6)\n",
    "u_strum_m  = res_b / np.sqrt(6)\n",
    "u_strum_Dx = res_c / np.sqrt(6)\n",
    "\n",
    "# Massimo tra campionario e strumentale, punto per punto\n",
    "ueste_strum  = np.maximum(ueste,  u_strum_Dx)\n",
    "umasse_strum = np.maximum(umasse, u_strum_m)\n",
    "\n",
    "# Worst-case scalare: prendi il massimo anche di ueste_strum\n",
    "uF_strum  = np.max(np.sqrt( (g * umasse_strum)**2 + (masse * ug)**2 ))\n",
    "uDx_strum = np.max(ueste_strum)\n",
    "\n",
    "uK_strum  = np.max(np.sqrt( (1/este)**2 * uF_strum**2 + (F/este**2)**2 * uDx_strum**2 ))\n",
    "\n",
    "print(f\"u_strum_m    = {u_strum_m:.6f}\")\n",
    "print(f\"u_strum_Dx   = {u_strum_Dx:.6f}\")\n",
    "print(f\"uF_strum     = {uF_strum:.6f}\")\n",
    "print(f\"uK_strum     = {uK_strum:.6f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8706126d",
   "metadata": {},
   "source": [
    "### Propapazione dell'errore strumentale max"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "a1dc24c9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Media pesata\n",
    "uA_fin   = np.sqrt(uA**2      + uK_strum**2)\n",
    "\n",
    "# OLS\n",
    "uAols_fin = np.sqrt(uAols**2  + uK_strum**2)\n",
    "uBols_fin = np.sqrt(uBols**2  + uK_strum**2)\n",
    "\n",
    "# Carpi\n",
    "uAC_fin  = np.sqrt(uAC**2     + uK_strum**2)\n",
    "uBC_fin  = np.sqrt(uBC**2     + uK_strum**2)\n",
    "\n",
    "# York\n",
    "uAY_fin  = np.sqrt(uAY**2     + uK_strum**2)\n",
    "uBY_fin  = np.sqrt(uBY**2     + uK_strum**2)\n",
    "\n",
    "\n",
    "# Nuovo uy e ux per ricalcolare i chi^2\n",
    "uy_fin = np.sqrt(data[\"uy\"]**2 + uF_strum**2)\n",
    "ux_fin = np.sqrt(data[\"ux\"]**2 + uDx_strum**2)\n",
    "\n",
    "# OLS\n",
    "F_fit_ols = Bols + Aols * data[\"x\"]\n",
    "sigma_ols = np.sqrt(uy_fin**2 + (Aols * ux_fin)**2)\n",
    "chi2_ols  = np.sum(((data[\"y\"] - F_fit_ols) / sigma_ols)**2)\n",
    "GdL       = len(data) - 2\n",
    "\n",
    "# Carpi\n",
    "F_fit_c   = BC + AC * data[\"x\"]\n",
    "sigma_c   = np.sqrt(uy_fin**2 + (AC * ux_fin)**2)\n",
    "chi2_c    = np.sum(((data[\"y\"] - F_fit_c) / sigma_c)**2)\n",
    "\n",
    "# York\n",
    "F_fit_y   = BY + AY * data[\"x\"]\n",
    "sigma_y_   = np.sqrt(uy_fin**2 + (AY * ux_fin)**2)\n",
    "chi2_y     = np.sum(((data[\"y\"] - F_fit_y) / sigma_y_)**2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e57c7d8",
   "metadata": {},
   "source": [
    "## Risutltati della propagazione dell'errore strumentale massimo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "c8e264fa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RISULTATI CON ERRORE STRUMENTALE INCLUSO:\n",
      "Media pesata K  = 23.95113 ± 0.66530\n",
      "\n",
      "RISULTATI REGRESSIONE OLS:\n",
      "Aols  = 23.96871 ± 0.68192\n",
      "Bols  = 0.09993 ± 2.98913\n",
      "Chi² OLS   = 3.95368  |  rid = 0.49421  |  P = 0.13872\n",
      "\n",
      "RISULTATI REGRESSIONE Carpi:\n",
      "AC  = 24.04738 ± 0.67577\n",
      "BC  = -1.56983 ± 2.18409\n",
      "Chi² Carpi = 4.03420  |  rid = 0.50428  |  P = 0.14598\n",
      "\n",
      "RISULTATI REGRESSIONE York:\n",
      "AY  = 24.06480 ± 0.67582\n",
      "BY  = -1.81758 ± 2.18788\n",
      "Chi² York  = 4.06701  |  rid = 0.50838  |  P = 0.14897\n"
     ]
    }
   ],
   "source": [
    "print(\"RISULTATI CON ERRORE STRUMENTALE INCLUSO:\")\n",
    "print(f\"Media pesata K  = {media:.5f} ± {uA_fin:.5f}\")\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE OLS:\")\n",
    "print(f\"Aols  = {Aols:.5f} ± {uAols_fin:.5f}\")\n",
    "print(f\"Bols  = {Bols:.5f} ± {uBols_fin:.5f}\")\n",
    "print(f\"Chi² OLS   = {chi2_ols:.5f}  |  rid = {chi2_ols/GdL:.5f}\" f\"  |  P = {chi2.cdf(chi2_ols, df=GdL):.5f}\")\n",
    "\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE Carpi:\")\n",
    "print(f\"AC  = {AC:.5f} ± {uAC_fin:.5f}\")\n",
    "print(f\"BC  = {BC:.5f} ± {uBC_fin:.5f}\")\n",
    "print(f\"Chi² Carpi = {chi2_c:.5f}  |  rid = {chi2_c/GdL:.5f}\" f\"  |  P = {chi2.cdf(chi2_c, df=GdL):.5f}\")\n",
    "\n",
    "\n",
    "print(\"\\nRISULTATI REGRESSIONE York:\")\n",
    "print(f\"AY  = {AY:.5f} ± {uAY_fin:.5f}\")\n",
    "print(f\"BY  = {BY:.5f} ± {uBY_fin:.5f}\")\n",
    "print(f\"Chi² York  = {chi2_y:.5f}  |  rid = {chi2_y/GdL:.5f}\" f\"  |  P = {chi2.cdf(chi2_y, df=GdL):.5f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e38b0bd",
   "metadata": {},
   "source": [
    "## Minima interpretazione (Mio commento -> Non necessario)\n",
    "Sovrastimando l'errore in modo molto marcato ovviamente il Chi² viene ridotto.\n",
    "Il Chi² che stiamo usando serve per stimare quale sia la probabilità di ottenere un Chi² minore o uguale a quello osservato.\n",
    "Sapendo che il valore buono è ~50% stiamo un po' allargando le distribuzioni in modo un po' esagerato.\n",
    "\n",
    "In generale con il Chi² vale:\n",
    "- \\~50%: Errori ottimamente stimati\n",
    "- \\<5% : Fit troppo grande\n",
    "- \\>95%: Fit troppo piccolo\n",
    "\n",
    "In generale mi sembra che nei paper se è presente un Chi² si riporta la probabilità complementare (probabilità di ottenere gli stessi risultati o peggio)"
   ]
  }
 ],
 "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
}
