Least Squares Fitting -- Residuals:
Physics 238

Clear["Global`*"]; DateString[]

Data

SetDirectory[NotebookDirectory[]]

FilePrint["TO-static-20250212.csv", 5]

File is a CSV file, with 3 columns.  We just want columns 1 and 2.

rawdata = Import["TO-static-20250212.csv", "CSV"];

data3 = Select[rawdata, NumberQ[#[[1]]] && NumberQ[#[[2]]] &];

For this data, we want columns 1 and 2.

data = Table[{data3[[i, 1]] , data3[[i, 2]]}, {i, 1, Length[data3]}]

dataPlot = ListPlot[data,
LabelStyle -> Larger, AxesLabel -> {"Mass (g)", "Angle (radians)" }, ImageSize->Scaled[0.7]];

fit =LinearModelFit[data, x, x]

fit["ParameterConfidenceIntervalTable"]

Show[{dataPlot,Plot[fit[x] , {x, -400, 400}, PlotStyle -> Red]}]

residuals = Table[{data[[i, 1]], data[[i, 2]] - fit[data[[i, 1]]]}, {i, 1, Length[data]}]

ListPlot[residuals, PlotRange->All, LabelStyle->Larger, AxesLabel -> { "Mass (g)", "Residual Angle (radians)"}, ImageSize->Scaled[0.7]]

RMSE = Sqrt[fit["EstimatedVariance"]]

The RMS error is plausible, but there is a clear systematic trend in the residuals suggesting the data may behave differently for larger masses.

Limiting data to smaller torques

Bundle up all those commands into a single cell to consider different limits on data.  Select only a more narrow range of masses.

fitdata = Select[data, -400 <= #[[1]] <= 400 &];
dataPlot = ListPlot[data,
LabelStyle -> Larger, AxesLabel -> {"Mass (g)", "Angle (radians)" }, ImageSize->Scaled[0.7]];
fit =LinearModelFit[fitdata, x, x]
fit["ParameterConfidenceIntervalTable"]
Show[{dataPlot,Plot[fit[x] , {x, -400, 400}, PlotStyle -> Red]}]
residuals = Table[{data[[i, 1]], data[[i, 2]] - fit[data[[i, 1]]]}, {i, 1, Length[data]}];
ListPlot[residuals, PlotRange->All, LabelStyle->Larger, AxesLabel -> { "Mass (g)", "Residual Angle (radians)"}, ImageSize->Scaled[0.7]]
Sqrt[fit["EstimatedVariance"]]