{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3a8dfc0e",
   "metadata": {},
   "source": [
    "# Analisi della molla statica con calibro 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ff20b69",
   "metadata": {},
   "source": [
    "## Import delle librerie e set di variabili gloabali"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "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": 106,
   "id": "08efb2be",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv(r'statica2.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": 107,
   "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>49.246667</td>\n",
       "      <td>212.10</td>\n",
       "      <td>211.64</td>\n",
       "      <td>212.00</td>\n",
       "      <td>212.18</td>\n",
       "      <td>212.52</td>\n",
       "      <td>212.04</td>\n",
       "      <td>212.080000</td>\n",
       "      <td>0.284816</td>\n",
       "      <td>49.246667</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>69.276667</td>\n",
       "      <td>150.92</td>\n",
       "      <td>150.26</td>\n",
       "      <td>150.02</td>\n",
       "      <td>150.16</td>\n",
       "      <td>150.40</td>\n",
       "      <td>150.18</td>\n",
       "      <td>150.323333</td>\n",
       "      <td>0.317847</td>\n",
       "      <td>69.276667</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>88.966667</td>\n",
       "      <td>90.34</td>\n",
       "      <td>90.34</td>\n",
       "      <td>90.38</td>\n",
       "      <td>90.52</td>\n",
       "      <td>90.26</td>\n",
       "      <td>90.28</td>\n",
       "      <td>90.353333</td>\n",
       "      <td>0.092664</td>\n",
       "      <td>88.966667</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>108.610000</td>\n",
       "      <td>29.82</td>\n",
       "      <td>30.18</td>\n",
       "      <td>30.10</td>\n",
       "      <td>30.20</td>\n",
       "      <td>30.10</td>\n",
       "      <td>30.40</td>\n",
       "      <td>30.133333</td>\n",
       "      <td>0.188750</td>\n",
       "      <td>108.610000</td>\n",
       "      <td>0.002887</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           m1     Dx1     Dx2     Dx3     Dx4     Dx5     Dx6          Dx  \\\n",
       "0   49.246667  212.10  211.64  212.00  212.18  212.52  212.04  212.080000   \n",
       "1   69.276667  150.92  150.26  150.02  150.16  150.40  150.18  150.323333   \n",
       "2   88.966667   90.34   90.34   90.38   90.52   90.26   90.28   90.353333   \n",
       "3  108.610000   29.82   30.18   30.10   30.20   30.10   30.40   30.133333   \n",
       "\n",
       "        uDx           m        um  \n",
       "0  0.284816   49.246667  0.002887  \n",
       "1  0.317847   69.276667  0.002887  \n",
       "2  0.092664   88.966667  0.002887  \n",
       "3  0.188750  108.610000  0.002887  "
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "id": "976d5531",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]\n",
      "6\n",
      "############################################################\n",
      "[ 61.75666667 121.72666667 181.94666667  59.97       120.19\n",
      "  60.22      ]\n",
      "[0.42678644 0.29951071 0.34168211 0.33107904 0.36966652 0.21026967]\n",
      "############################################################\n",
      "[-20.03       -39.72       -59.36333333 -19.69       -39.33333333\n",
      " -19.64333333]\n",
      "[0.00408248 0.00408248 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": 109,
   "id": "2ad19283",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[3.18077741 3.20007153 3.19970803 3.21994047 3.20943506 3.19897326]\n",
      "[0.02199359 0.00788745 0.00602168 0.01779203 0.00988225 0.01119435]\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": 110,
   "id": "5f59d6c9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-medio: 3.2015614337677185\n",
      "sigmaC:  0.003860508806765328\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": 111,
   "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": 112,
   "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:                 1.277e+05\n",
      "Date:                Mon, 06 Apr 2026   Prob (F-statistic):           3.68e-10\n",
      "Time:                        10:04:08   Log-Likelihood:                -7.2422\n",
      "No. Observations:                   6   AIC:                             18.48\n",
      "Df Residuals:                       4   BIC:                             18.07\n",
      "Df Model:                           1                                         \n",
      "Covariance Type:            nonrobust                                         \n",
      "==============================================================================\n",
      "                 coef    std err          t      P>|t|      [0.025      0.975]\n",
      "------------------------------------------------------------------------------\n",
      "const          0.0265      0.991      0.027      0.980      -2.724       2.777\n",
      "x              3.2014      0.009    357.408      0.000       3.177       3.226\n",
      "==============================================================================\n",
      "Omnibus:                          nan   Durbin-Watson:                   1.155\n",
      "Prob(Omnibus):                    nan   Jarque-Bera (JB):                0.275\n",
      "Skew:                          -0.058   Prob(JB):                        0.871\n",
      "Kurtosis:                       1.957   Cond. No.                         271.\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  = 3.20145 ± 0.00896\n",
      "Bols  = 0.02655 ± 0.99076\n",
      "R² = 0.99997\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/jack/uni/lab/.venv/lib/python3.13/site-packages/statsmodels/stats/stattools.py:74: ValueWarning: omni_normtest is not valid with less than 8 observations; 6 samples were given.\n",
      "  warn(\"omni_normtest is not valid with less than 8 observations; %i \"\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": 113,
   "id": "1d42b009",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59380 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": 114,
   "id": "986ff4a6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chi²      = 2.77690\n",
      "GdL       = 4\n",
      "Chi² rid  = 0.69422\n",
      "P(0, chi²)= 0.40417\n",
      "\n",
      "\n",
      "############################################################\n",
      "capiamo quale dato sta contribuendo maggiormente\n",
      "0    0.908593\n",
      "1    0.040832\n",
      "2    0.097969\n",
      "3    1.041094\n",
      "4    0.620684\n",
      "5    0.067728\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": 115,
   "id": "2d4b7144",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ax + B : \n",
      "AC      = 3.2005 ± 0.0092\n",
      "BC      = 0.1195 ± 0.9524\n",
      "cov_ABC = -0.007942\n",
      "P(0, chi²)= 0.4020\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": 116,
   "id": "e2407a04",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59548 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": 117,
   "id": "32e9948f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chi²      = 2.76835\n",
      "GdL       = 4\n",
      "Chi² rid  = 0.69209\n",
      "P(0, chi²)= 0.40269\n",
      "\n",
      "\n",
      "############################################################\n",
      "capiamo quale dato sta contribuendo maggiormente\n",
      "0    0.961357\n",
      "1    0.033834\n",
      "2    0.061166\n",
      "3    0.968819\n",
      "4    0.642604\n",
      "5    0.100572\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": 118,
   "id": "bfb895c6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AY        = 3.2006138 ± 0.0091837\n",
      "BY        = 0.1126344 ± 0.9516509\n",
      "cov_ABY   = -0.007930461708887697\n",
      "chi²      = 2.76829\n",
      "chi² rid  = 0.69207\n",
      "P(0, chi²)= 0.40268\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": 119,
   "id": "202de438",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59276 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": 120,
   "id": "caf23dbe",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RISULTATI senza ERRORE STRUMENTALE INCLUSO:\n",
      "Media pesata K  = 3.20156 ± 0.00386\n",
      "\n",
      "RISULTATI REGRESSIONE OLS:\n",
      "Aols  = 3.20145 ± 0.00896\n",
      "Bols  = 0.02655 ± 0.99076\n",
      "P(0, chi²)= 0.40417\n",
      "\n",
      "RISULTATI REGRESSIONE Carpi:\n",
      "Ac  = 3.20054 ± 0.00919\n",
      "Bc  = 0.11948 ± 0.95235\n",
      "P(0, chi²)= 0.40269\n",
      "\n",
      "RISULTATI REGRESSIONE York:\n",
      "Ay  = 3.20061 ± 0.00918\n",
      "By  = 0.11263 ± 0.95165\n",
      "P(0, chi²)= 0.40268\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": 121,
   "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.053018\n",
      "uK_strum     = 0.012599\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.average(np.sqrt( (g * umasse_strum)**2 + (masse * ug)**2 ))\n",
    "uDx_strum = np.average(ueste_strum)\n",
    "\n",
    "uK_strum  = np.average(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": 122,
   "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": [
    "## Risultati della propagazione dell'errore strumentale massimo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "id": "c8e264fa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RISULTATI CON ERRORE STRUMENTALE INCLUSO:\n",
      "Media pesata K  = 3.20156 ± 0.01318\n",
      "\n",
      "RISULTATI REGRESSIONE OLS:\n",
      "Aols  = 3.20145 ± 0.01546\n",
      "Bols  = 0.02655 ± 0.99084\n",
      "Chi² OLS   = 1.52520  |  rid = 0.38130  |  P = 0.17783\n",
      "\n",
      "RISULTATI REGRESSIONE Carpi:\n",
      "AC  = 3.20054 ± 0.01559\n",
      "BC  = 0.11948 ± 0.95244\n",
      "Chi² Carpi = 1.52143  |  rid = 0.38036  |  P = 0.17716\n",
      "\n",
      "RISULTATI REGRESSIONE York:\n",
      "AY  = 3.20061 ± 0.01559\n",
      "BY  = 0.11263 ± 0.95173\n",
      "Chi² York  = 1.52133  |  rid = 0.38033  |  P = 0.17714\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
}
