diff --git a/report_completo.py b/report_completo.py
index 28b7d6e..e8e7860 100644
--- a/report_completo.py
+++ b/report_completo.py
@@ -1,171 +1,372 @@
+import re
from pathlib import Path
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
-from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table,
- TableStyle, Image, HRFlowable, PageBreak)
+from reportlab.lib.enums import TA_CENTER, TA_RIGHT
+from reportlab.platypus import (BaseDocTemplate, PageTemplate, Frame,
+ Paragraph, Spacer, Table, TableStyle,
+ Image, HRFlowable, PageBreak, NextPageTemplate)
+from reportlab.pdfgen import canvas as rl_canvas
+from datetime import date
BASE = Path(__file__).parent
-INDUTTORI = [
- {
- "nome": "Induttore 1",
- "intervallo": "110.81 – 111.56 s",
- "t0": "110.81",
- "t_end": "111.56",
- "n_punti": "5",
- "zona_exc": None,
- "A": "87.3140",
- "A_err": "0.0260",
- "tau": "15.7231",
- "tau_err": "0.2021",
- "r2": "0.999505",
- "png": BASE / "induttore1" / "induttore1.png",
- },
- {
- "nome": "Induttore 2",
- "intervallo": "112.02 – 113.95 s",
- "t0": "112.02",
- "t_end": "113.95",
- "n_punti": "13",
- "zona_exc": None,
- "A": "158.3430",
- "A_err": "0.2088",
- "tau": "13.2844",
- "tau_err": "0.2183",
- "r2": "0.997314",
- "png": BASE / "induttore2" / "induttore2.png",
- },
- {
- "nome": "Induttore 3",
- "intervallo": "115.0 – 133.7 s",
- "t0": "115.0",
- "t_end": "133.7",
- "n_punti": "125",
- "zona_exc": "115.9 – 117.2 s",
- "A": "185.1847",
- "A_err": "0.2706",
- "tau": "16.2654",
- "tau_err": "0.0464",
- "r2": "0.993827",
- "png": BASE / "induttore3" / "induttore3.png",
- },
-]
+# ─── Palette colori ───────────────────────────────────────────────────────────
+C_BLUE = colors.HexColor("#1a3a5c")
+C_BLUE_LIGHT= colors.HexColor("#2c5f8a")
+C_ACCENT = colors.HexColor("#e8f0f7")
+C_GRAY = colors.HexColor("#f5f5f5")
+C_BORDER = colors.HexColor("#c0c8d0")
-HEADER_COLOR = colors.HexColor("#2c5f8a")
-LIGHT_GRAY = colors.HexColor("#f2f2f2")
-
-TABLE_STYLE = TableStyle([
- ("BACKGROUND", (0, 0), (-1, 0), HEADER_COLOR),
- ("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
- ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
- ("FONTSIZE", (0, 0), (-1, 0), 10),
- ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, LIGHT_GRAY]),
- ("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
- ("FONTSIZE", (0, 1), (-1, -1), 9),
- ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#cccccc")),
- ("TOPPADDING", (0, 0), (-1, -1), 5),
+TABLE_HDR = TableStyle([
+ ("BACKGROUND", (0, 0), (-1, 0), C_BLUE_LIGHT),
+ ("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
+ ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
+ ("FONTSIZE", (0, 0), (-1, 0), 10),
+ ("ROWBACKGROUNDS",(0, 1), (-1, -1), [colors.white, C_GRAY]),
+ ("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
+ ("FONTSIZE", (0, 1), (-1, -1), 9),
+ ("GRID", (0, 0), (-1, -1), 0.4, C_BORDER),
+ ("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
- ("LEFTPADDING", (0, 0), (-1, -1), 8),
+ ("LEFTPADDING", (0, 0), (-1, -1), 8),
+ ("RIGHTPADDING", (0, 0), (-1, -1), 8),
+ ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
+])
+
+TABLE_SUMMARY = TableStyle([
+ ("BACKGROUND", (0, 0), (-1, 0), C_BLUE),
+ ("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
+ ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
+ ("FONTSIZE", (0, 0), (-1, 0), 10),
+ ("ROWBACKGROUNDS",(0, 1), (-1, -1), [colors.white, C_ACCENT]),
+ ("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
+ ("FONTSIZE", (0, 1), (-1, -1), 9),
+ ("GRID", (0, 0), (-1, -1), 0.4, C_BORDER),
+ ("TOPPADDING", (0, 0), (-1, -1), 6),
+ ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
+ ("LEFTPADDING", (0, 0), (-1, -1), 10),
+ ("RIGHTPADDING", (0, 0), (-1, -1), 10),
+ ("ALIGN", (2, 0), (-1, -1), "CENTER"),
+ ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
])
-def build_doc():
- out = str(BASE / "report_completo.pdf")
- doc = SimpleDocTemplate(out, pagesize=A4,
- leftMargin=2.5*cm, rightMargin=2.5*cm,
- topMargin=2.5*cm, bottomMargin=2.5*cm)
+# ─── Parser markdown ──────────────────────────────────────────────────────────
+def parse_md(md_path: Path) -> dict:
+ text = md_path.read_text(encoding="utf-8")
+ data = {}
- styles = getSampleStyleSheet()
- style_title = styles["Title"]
- style_h1 = styles["Heading1"]
- style_h2 = styles["Heading2"]
- style_body = styles["BodyText"]
- style_eq = ParagraphStyle("Equation", parent=styles["BodyText"],
- fontName="Courier", fontSize=10,
- leftIndent=20, spaceAfter=6)
+ m = re.search(r"^# (.+)$", text, re.MULTILINE)
+ data["nome"] = m.group(1).strip() if m else md_path.parent.name
+
+ kv = dict(re.findall(r"^\| (.+?) \| (.+?) \|$", text, re.MULTILINE))
+ kv = {k.strip(): v.strip() for k, v in kv.items() if k.strip() != "---"}
+
+ data["t0"] = kv.get("Inizio", "").replace(" s", "")
+ data["t_end"] = kv.get("Fine", "").replace(" s", "")
+ data["n_punti"] = kv.get("Numero di punti", "")
+ data["zona_exc"] = kv.get("Zona esclusa (peso = 0)", None)
+ data["r2"] = kv.get("R²", "")
+ data["intervallo"] = f"{data['t0']} – {data['t_end']} s"
+
+ m = re.search(r"\$\$(.+?)\$\$", text, re.DOTALL)
+ data["equazione_latex"] = m.group(1).strip() if m else ""
+ eq = data["equazione_latex"].replace(r"\cdot", "·").replace(r"\infty", "∞")
+ data["equazione"] = eq
+
+ rows3 = re.findall(r"^\| (.+?) \| (.+?) \| (.+?) \|$", text, re.MULTILINE)
+ params = {r[0].strip(): (r[1].strip(), r[2].strip())
+ for r in rows3 if r[0].strip() not in ("Parametro", "---")}
+ data["A"] = params.get("A", ("", ""))[0].replace(" °C", "")
+ data["A_err"] = (params.get("A", ("", ""))[1]
+ .replace("± ", "").replace("+/- ", "").replace(" °C", ""))
+ data["tau"] = params.get("τ", ("", ""))[0].replace(" s", "")
+ data["tau_err"] = (params.get("τ", ("", ""))[1]
+ .replace("± ", "").replace("+/- ", "").replace(" s", ""))
+
+ pngs = sorted(md_path.parent.glob("*.png"))
+ data["png"] = pngs[0] if pngs else None
+ return data
+
+
+def collect_induttori() -> list:
+ return [parse_md(md)
+ for folder in sorted(BASE.glob("induttore*/"))
+ for md in sorted(folder.glob("report*.md"))]
+
+
+# ─── Genera .tex ──────────────────────────────────────────────────────────────
+def generate_tex(induttori: list):
+ lines = []
+ lines += [
+ r"\documentclass[11pt,a4paper]{article}",
+ r"\usepackage[utf8]{inputenc}",
+ r"\usepackage[T1]{fontenc}",
+ r"\usepackage[margin=2.5cm]{geometry}",
+ r"\usepackage{amsmath,amssymb}",
+ r"\usepackage{booktabs}",
+ r"\usepackage{graphicx}",
+ r"\usepackage{float}",
+ r"\usepackage{caption}",
+ r"\usepackage[table]{xcolor}",
+ r"\usepackage{hyperref}",
+ r"\definecolor{hdrblue}{HTML}{1a3a5c}",
+ r"\usepackage{fancyhdr}",
+ r"\pagestyle{fancy}",
+ r"\fancyhf{}",
+ r"\rhead{\textcolor{hdrblue}{\small Analisi Termica Forno}}",
+ r"\lhead{\textcolor{hdrblue}{\small Cevolani}}",
+ r"\rfoot{\thepage}",
+ r"\title{\textbf{Report Analisi Termica Forno}}",
+ r"\author{Analisi IR -- Cevolani}",
+ r"\date{\today}",
+ r"\begin{document}",
+ r"\maketitle",
+ r"\tableofcontents",
+ r"\newpage",
+ "",
+ r"\section{Modello di fitting}",
+ r"Ogni intervallo è interpolato con il modello di raffreddamento di Newton:",
+ r"\begin{equation}",
+ r" T(t) = T_\infty + A \cdot e^{-(t-t_0)/\tau}",
+ r"\end{equation}",
+ r"dove $T_\infty = 22.99\,^\circ\mathrm{C}$ è la temperatura ambiente media ponderata.",
+ r"La regressione non lineare usa il metodo \textit{Trust Region Reflective} (TRF)",
+ r"di \texttt{scipy.optimize.curve\_fit}.",
+ "",
+ ]
+
+ for ind in induttori:
+ lines += [
+ rf"\section{{{ind['nome']}}}",
+ r"\subsection{Intervallo di campionamento}",
+ r"\begin{tabular}{ll}",
+ r"\toprule",
+ r"\textbf{Parametro} & \textbf{Valore} \\",
+ r"\midrule",
+ rf"Inizio & ${ind['t0']}$ s \\",
+ rf"Fine & ${ind['t_end']}$ s \\",
+ rf"Numero di punti & {ind['n_punti']} \\",
+ ]
+ if ind["zona_exc"]:
+ lines.append(rf"Zona esclusa (peso = 0) & {ind['zona_exc']} \\")
+ lines += [
+ r"\bottomrule",
+ r"\end{tabular}",
+ "",
+ r"\subsection{Equazione trovata}",
+ r"\begin{equation}",
+ f" {ind['equazione_latex']}",
+ r"\end{equation}",
+ r"\begin{tabular}{lll}",
+ r"\toprule",
+ r"\textbf{Parametro} & \textbf{Valore} & \textbf{Incertezza (1$\sigma$)} \\",
+ r"\midrule",
+ rf"$A$ & ${ind['A']}\,^\circ\mathrm{{C}}$ & $\pm\,{ind['A_err']}\,^\circ\mathrm{{C}}$ \\",
+ rf"$\tau$ & ${ind['tau']}\,\mathrm{{s}}$ & $\pm\,{ind['tau_err']}\,\mathrm{{s}}$ \\",
+ rf"$R^2$ & \multicolumn{{2}}{{l}}{{{ind['r2']}}} \\",
+ r"\bottomrule",
+ r"\end{tabular}",
+ "",
+ r"\subsection{Grafico}",
+ r"\begin{figure}[H]",
+ r"\centering",
+ rf"\includegraphics[width=0.9\textwidth]{{{ind['png']}}}",
+ rf"\caption{{Fit esponenziale -- {ind['nome']} [{ind['intervallo']}]}}",
+ r"\end{figure}",
+ r"\newpage",
+ "",
+ ]
+
+ # Riepilogo
+ lines += [
+ r"\section{Riepilogo}",
+ r"\begin{tabular}{lllll}",
+ r"\toprule",
+ r"\textbf{Induttore} & \textbf{Intervallo [s]} & \textbf{A [°C]} & \textbf{$\tau$ [s]} & \textbf{$R^2$} \\",
+ r"\midrule",
+ ]
+ for ind in induttori:
+ lines.append(
+ rf"{ind['nome']} & {ind['intervallo']} & {ind['A']} & {ind['tau']} & {ind['r2']} \\"
+ )
+ lines += [r"\bottomrule", r"\end{tabular}", "", r"\end{document}"]
+
+ out = BASE / "report_completo.tex"
+ out.write_text("\n".join(lines), encoding="utf-8")
+ print("report_completo.tex generato.")
+
+
+# ─── Header / footer per reportlab ───────────────────────────────────────────
+class NumberedCanvas(rl_canvas.Canvas):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._saved_page_states = []
+
+ def showPage(self):
+ self._saved_page_states.append(dict(self.__dict__))
+ self._startPage()
+
+ def save(self):
+ num_pages = len(self._saved_page_states)
+ for state in self._saved_page_states:
+ self.__dict__.update(state)
+ self._draw_page_decoration(num_pages)
+ super().showPage()
+ super().save()
+
+ def _draw_page_decoration(self, page_count):
+ w, h = A4
+ self.saveState()
+
+ if self._pageNumber > 1:
+ # Header
+ self.setFillColor(C_BLUE)
+ self.rect(2.5*cm, h - 2*cm, w - 5*cm, 0.6*cm, fill=1, stroke=0)
+ self.setFillColor(colors.white)
+ self.setFont("Helvetica-Bold", 9)
+ self.drawString(2.8*cm, h - 1.65*cm, "Analisi Termica Forno")
+ self.setFont("Helvetica", 9)
+ self.drawRightString(w - 2.5*cm, h - 1.65*cm, "Cevolani")
+
+ # Footer
+ self.setStrokeColor(C_BLUE_LIGHT)
+ self.setLineWidth(0.5)
+ self.line(2.5*cm, 1.8*cm, w - 2.5*cm, 1.8*cm)
+ self.setFillColor(C_BLUE)
+ self.setFont("Helvetica", 8)
+ self.drawString(2.5*cm, 1.3*cm, f"Report generato il {date.today().strftime('%d/%m/%Y')}")
+ self.drawRightString(w - 2.5*cm, 1.3*cm,
+ f"Pag. {self._pageNumber} / {page_count}")
+ self.restoreState()
+
+
+# ─── Genera PDF ───────────────────────────────────────────────────────────────
+def generate_pdf(induttori: list):
+ out = str(BASE / "report_completo.pdf")
+ w, h = A4
+ margin = 2.5*cm
+ frame_normal = Frame(margin, 2.5*cm, w - 2*margin, h - 5*cm,
+ id="normal", topPadding=0.8*cm)
+ frame_cover = Frame(margin, margin, w - 2*margin, h - 2*margin,
+ id="cover")
+
+ doc = BaseDocTemplate(out, pagesize=A4)
+ doc.addPageTemplates([
+ PageTemplate(id="cover", frames=[frame_cover]),
+ PageTemplate(id="normal", frames=[frame_normal]),
+ ])
+
+ styles = getSampleStyleSheet()
+ s_body = styles["BodyText"]
+ s_h1 = ParagraphStyle("H1", fontName="Helvetica-Bold", fontSize=14,
+ textColor=C_BLUE, spaceBefore=14, spaceAfter=6,
+ borderPad=4)
+ s_h2 = ParagraphStyle("H2", fontName="Helvetica-Bold", fontSize=11,
+ textColor=C_BLUE_LIGHT, spaceBefore=10, spaceAfter=4)
+ s_eq = ParagraphStyle("EQ", fontName="Courier", fontSize=10,
+ leftIndent=24, spaceBefore=4, spaceAfter=6,
+ backColor=C_ACCENT, borderPad=6)
+ s_cover_title = ParagraphStyle("CoverTitle", fontName="Helvetica-Bold",
+ fontSize=28, textColor=C_BLUE,
+ alignment=TA_CENTER, spaceAfter=10)
+ s_cover_sub = ParagraphStyle("CoverSub", fontName="Helvetica",
+ fontSize=14, textColor=C_BLUE_LIGHT,
+ alignment=TA_CENTER, spaceAfter=6)
+ s_cover_date = ParagraphStyle("CoverDate", fontName="Helvetica",
+ fontSize=11, textColor=colors.grey,
+ alignment=TA_CENTER)
story = []
- # --- Titolo ---
- story.append(Paragraph("Report Analisi Termica Forno", style_title))
- story.append(Paragraph("Analisi IR – Cevolani", styles["Normal"]))
+ # ── Cover page ──
+ story.append(Spacer(1, 5*cm))
+ story.append(HRFlowable(width="100%", thickness=3, color=C_BLUE))
story.append(Spacer(1, 0.5*cm))
- story.append(HRFlowable(width="100%", thickness=1, color=HEADER_COLOR))
+ story.append(Paragraph("Report Analisi Termica Forno", s_cover_title))
+ story.append(Spacer(1, 0.3*cm))
+ story.append(Paragraph("Analisi IR – Cevolani", s_cover_sub))
story.append(Spacer(1, 0.5*cm))
+ story.append(HRFlowable(width="100%", thickness=3, color=C_BLUE))
+ story.append(Spacer(1, 1*cm))
+ story.append(Paragraph(f"Data: {date.today().strftime('%d %B %Y')}", s_cover_date))
+ story.append(Paragraph(f"Induttori analizzati: {len(induttori)}", s_cover_date))
+ story.append(NextPageTemplate("normal"))
+ story.append(PageBreak())
- # --- Modello ---
- story.append(Paragraph("Modello di fitting", style_h1))
- story.append(Paragraph(
- "Ogni intervallo è interpolato con il modello di raffreddamento di Newton:",
- style_body))
+ # ── Modello ──
+ story.append(Paragraph("Modello di fitting", s_h1))
+ story.append(HRFlowable(width="100%", thickness=1, color=C_BLUE_LIGHT))
story.append(Spacer(1, 0.2*cm))
- story.append(Paragraph("T(t) = T_inf + A · exp( -(t - t0) / τ )", style_eq))
+ story.append(Paragraph(
+ "Ogni intervallo è interpolato con il modello di raffreddamento di Newton:", s_body))
+ story.append(Paragraph("T(t) = T_inf + A · exp( -(t - t0) / τ )", s_eq))
story.append(Paragraph(
"dove T_inf = 22.99 °C è la temperatura ambiente media ponderata. "
- "La regressione non lineare usa il metodo Trust Region Reflective (TRF) "
- "di scipy.optimize.curve_fit.",
- style_body))
- story.append(Spacer(1, 0.4*cm))
+ "La regressione usa il metodo Trust Region Reflective (TRF) "
+ "di scipy.optimize.curve_fit.", s_body))
+ story.append(Spacer(1, 0.5*cm))
- # --- Sezione per ogni induttore ---
- for ind in INDUTTORI:
- story.append(HRFlowable(width="100%", thickness=0.5, color=colors.lightgrey))
+ # ── Sezione per ogni induttore ──
+ for ind in induttori:
+ story.append(Paragraph(ind["nome"], s_h1))
+ story.append(HRFlowable(width="100%", thickness=1, color=C_BLUE_LIGHT))
story.append(Spacer(1, 0.2*cm))
- story.append(Paragraph(ind["nome"], style_h1))
- # Tabella intervallo
- story.append(Paragraph("Intervallo di campionamento", style_h2))
+ # Intervallo
+ story.append(Paragraph("Intervallo di campionamento", s_h2))
rows = [["Parametro", "Valore"],
["Inizio", f"{ind['t0']} s"],
["Fine", f"{ind['t_end']} s"],
["Numero di punti", ind["n_punti"]]]
if ind["zona_exc"]:
rows.append(["Zona esclusa (peso = 0)", ind["zona_exc"]])
- t = Table(rows, colWidths=[8*cm, 6*cm])
- t.setStyle(TABLE_STYLE)
- story.append(t)
+ story.append(Table(rows, colWidths=[8*cm, 6*cm], style=TABLE_HDR))
story.append(Spacer(1, 0.3*cm))
# Equazione
- story.append(Paragraph("Equazione trovata", style_h2))
- eq = (f"T(t) = 22.99 + {ind['A']} · exp( -(t - {ind['t0']}) / {ind['tau']} )")
- story.append(Paragraph(eq, style_eq))
+ story.append(Paragraph("Equazione trovata", s_h2))
+ story.append(Paragraph(ind["equazione"], s_eq))
story.append(Spacer(1, 0.2*cm))
-
- # Tabella parametri
- param_rows = [
- ["Parametro", "Valore", "Incertezza (1σ)"],
- ["A", f"{ind['A']} °C", f"± {ind['A_err']} °C"],
- ["τ", f"{ind['tau']} s", f"± {ind['tau_err']} s"],
- ["R²", ind["r2"], ""],
- ]
- t2 = Table(param_rows, colWidths=[4*cm, 6*cm, 5*cm])
- t2.setStyle(TABLE_STYLE)
- story.append(t2)
+ story.append(Table([
+ ["Parametro", "Valore", "Incertezza (1σ)"],
+ ["A", f"{ind['A']} °C", f"± {ind['A_err']} °C"],
+ ["τ", f"{ind['tau']} s", f"± {ind['tau_err']} s"],
+ ["R²", ind["r2"], ""],
+ ], colWidths=[3.5*cm, 6*cm, 5*cm], style=TABLE_HDR))
story.append(Spacer(1, 0.3*cm))
# Plot
- story.append(Paragraph("Grafico", style_h2))
- img = Image(str(ind["png"]), width=14*cm, height=8.4*cm)
- story.append(img)
- story.append(Spacer(1, 0.5*cm))
+ if ind["png"] and Path(ind["png"]).exists():
+ story.append(Paragraph("Grafico", s_h2))
+ story.append(Image(str(ind["png"]), width=14*cm, height=8.4*cm))
+ story.append(Spacer(1, 0.4*cm))
- # --- Tabella riepilogativa ---
+ # ── Riepilogo ──
story.append(PageBreak())
- story.append(Paragraph("Riepilogo", style_h1))
+ story.append(Paragraph("Riepilogo", s_h1))
+ story.append(HRFlowable(width="100%", thickness=1, color=C_BLUE_LIGHT))
+ story.append(Spacer(1, 0.3*cm))
summary = [["Induttore", "Intervallo [s]", "A [°C]", "τ [s]", "R²"]]
- for ind in INDUTTORI:
+ for ind in induttori:
summary.append([ind["nome"], ind["intervallo"],
ind["A"], ind["tau"], ind["r2"]])
- t3 = Table(summary, colWidths=[3.5*cm, 4.5*cm, 3*cm, 3*cm, 3*cm])
- t3.setStyle(TABLE_STYLE)
- story.append(t3)
+ story.append(Table(summary,
+ colWidths=[3.5*cm, 4.5*cm, 3*cm, 3*cm, 3*cm],
+ style=TABLE_SUMMARY))
- doc.build(story)
- print(f"report_completo.pdf generato.")
+ doc.build(story, canvasmaker=NumberedCanvas)
+ print(f"report_completo.pdf generato ({len(induttori)} induttori).")
+# ─── Entry point ──────────────────────────────────────────────────────────────
if __name__ == "__main__":
- build_doc()
+ induttori = collect_induttori()
+ if not induttori:
+ print("Nessun report*.md trovato nelle cartelle induttore*/.")
+ else:
+ generate_tex(induttori)
+ generate_pdf(induttori)
diff --git a/report_completo.tex b/report_completo.tex
index 51a7204..7154ac3 100644
--- a/report_completo.tex
+++ b/report_completo.tex
@@ -1,177 +1,149 @@
-\documentclass{article}%
-\usepackage[T1]{fontenc}%
-\usepackage[utf8]{inputenc}%
-\usepackage{lmodern}%
-\usepackage{textcomp}%
-\usepackage{lastpage}%
-\usepackage{geometry}%
-\geometry{margin=2.5cm}%
-\usepackage{booktabs}%
-\usepackage{graphicx}%
-\usepackage{amsmath}%
-\usepackage{float}%
-\usepackage{caption}%
-%
-\title{Report Analisi Termica Forno}%
-\author{Analisi IR {-}{-} Cevolani}%
-\date{\today}%
-%
-\begin{document}%
-\normalsize%
-\maketitle%
-\section{Modello di fitting}%
-\label{sec:Modellodifitting}%
-Ogni intervallo è interpolato con il modello di raffreddamento di Newton:%
-\[%
-T(t) = T_\infty + A \cdot e^{-(t - t_0)/\tau}%
-\]%
-dove $T_\infty = 22.99\,^\circ\mathrm{C}$ è la temperatura ambiente media ponderata. La regressione non lineare usa il metodo \textit{Trust Region Reflective} (TRF) di \texttt{scipy.optimize.curve\_fit}.
+\documentclass[11pt,a4paper]{article}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{amsmath,amssymb}
+\usepackage{booktabs}
+\usepackage{graphicx}
+\usepackage{float}
+\usepackage{caption}
+\usepackage[table]{xcolor}
+\usepackage{hyperref}
+\definecolor{hdrblue}{HTML}{1a3a5c}
+\usepackage{fancyhdr}
+\pagestyle{fancy}
+\fancyhf{}
+\rhead{\textcolor{hdrblue}{\small Analisi Termica Forno}}
+\lhead{\textcolor{hdrblue}{\small Cevolani}}
+\rfoot{\thepage}
+\title{\textbf{Report Analisi Termica Forno}}
+\author{Analisi IR -- Cevolani}
+\date{\today}
+\begin{document}
+\maketitle
+\tableofcontents
+\newpage
-%
-\section{Induttore 1}%
-\label{sec:Induttore1}%
-\subsection{Intervallo di campionamento}%
-\label{subsec:Intervallodicampionamento}%
-\begin{tabular}{|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}\\%
-\hline%
-Inizio&110.81 s\\%
-Fine&111.56 s\\%
-Numero di punti&5\\%
-\hline%
+\section{Modello di fitting}
+Ogni intervallo è interpolato con il modello di raffreddamento di Newton:
+\begin{equation}
+ T(t) = T_\infty + A \cdot e^{-(t-t_0)/\tau}
+\end{equation}
+dove $T_\infty = 22.99\,^\circ\mathrm{C}$ è la temperatura ambiente media ponderata.
+La regressione non lineare usa il metodo \textit{Trust Region Reflective} (TRF)
+di \texttt{scipy.optimize.curve\_fit}.
+
+\section{Report Induttore 1}
+\subsection{Intervallo di campionamento}
+\begin{tabular}{ll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} \\
+\midrule
+Inizio & $110.81$ s \\
+Fine & $111.56$ s \\
+Numero di punti & 5 \\
+\bottomrule
\end{tabular}
-%
-\subsection{Equazione trovata}%
-\label{subsec:Equazionetrovata}%
-\[%
-T(t) = 22.99 + 87.3140 \cdot e^{-(t - 110.81) / 15.7231}%
-\]%
-\vspace{4pt}%
-\begin{tabular}{|l|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}&\textbf{Incertezza (1σ)}\\%
-\hline%
-A&$87.3140\,^\circ\mathrm{C}$&$\pm\,0.0260\,^\circ\mathrm{C}$\\%
-$\tau$&$15.7231\,\mathrm{s}$&$\pm\,0.2021\,\mathrm{s}$\\%
-\hline%
-\end{tabular}%
-\vspace{4pt}%
-$R^2 = 0.999505$
+\subsection{Equazione trovata}
+\begin{equation}
+ T(t) = 22.99 + 87.3140 \cdot e^{-(t - 110.81) / 15.7231}
+\end{equation}
+\begin{tabular}{lll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} & \textbf{Incertezza (1$\sigma$)} \\
+\midrule
+$A$ & $87.3140\,^\circ\mathrm{C}$ & $\pm\,0.0260\,^\circ\mathrm{C}$ \\
+$\tau$ & $15.7231\,\mathrm{s}$ & $\pm\,0.2021\,\mathrm{s}$ \\
+$R^2$ & \multicolumn{2}{l}{0.999505} \\
+\bottomrule
+\end{tabular}
-%
-\subsection{Grafico}%
-\label{subsec:Grafico}%
-
-
-\begin{figure}[H]%
-\centering%
-\includegraphics[width=0.9\textwidth]{C:/Users/davide.grilli/Desktop/vs/temperatura/induttore1/induttore1.png}%
-\caption{Fit esponenziale — Induttore 1 {[}110.81 – 111.56 s{]}}%
+\subsection{Grafico}
+\begin{figure}[H]
+\centering
+\includegraphics[width=0.9\textwidth]{C:\Users\davide.grilli\Desktop\vs\temperatura\induttore1\induttore1.png}
+\caption{Fit esponenziale -- Report Induttore 1 [110.81 – 111.56 s]}
\end{figure}
+\newpage
-%
-\section{Induttore 2}%
-\label{sec:Induttore2}%
-\subsection{Intervallo di campionamento}%
-\label{subsec:Intervallodicampionamento}%
-\begin{tabular}{|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}\\%
-\hline%
-Inizio&112.02 s\\%
-Fine&113.95 s\\%
-Numero di punti&13\\%
-\hline%
+\section{Report Induttore 2}
+\subsection{Intervallo di campionamento}
+\begin{tabular}{ll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} \\
+\midrule
+Inizio & $112.02$ s \\
+Fine & $113.95$ s \\
+Numero di punti & 12 \\
+\bottomrule
\end{tabular}
-%
-\subsection{Equazione trovata}%
-\label{subsec:Equazionetrovata}%
-\[%
-T(t) = 22.99 + 158.3430 \cdot e^{-(t - 112.02) / 13.2844}%
-\]%
-\vspace{4pt}%
-\begin{tabular}{|l|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}&\textbf{Incertezza (1σ)}\\%
-\hline%
-A&$158.3430\,^\circ\mathrm{C}$&$\pm\,0.2088\,^\circ\mathrm{C}$\\%
-$\tau$&$13.2844\,\mathrm{s}$&$\pm\,0.2183\,\mathrm{s}$\\%
-\hline%
-\end{tabular}%
-\vspace{4pt}%
-$R^2 = 0.997314$
+\subsection{Equazione trovata}
+\begin{equation}
+ T(t) = 22.99 + 158.3430 \cdot e^{-(t - 112.02) / 13.2844}
+\end{equation}
+\begin{tabular}{lll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} & \textbf{Incertezza (1$\sigma$)} \\
+\midrule
+$A$ & $158.3430\,^\circ\mathrm{C}$ & $\pm\,0.2088\,^\circ\mathrm{C}$ \\
+$\tau$ & $13.2844\,\mathrm{s}$ & $\pm\,0.2183\,\mathrm{s}$ \\
+$R^2$ & \multicolumn{2}{l}{0.997314} \\
+\bottomrule
+\end{tabular}
-%
-\subsection{Grafico}%
-\label{subsec:Grafico}%
-
-
-\begin{figure}[H]%
-\centering%
-\includegraphics[width=0.9\textwidth]{C:/Users/davide.grilli/Desktop/vs/temperatura/induttore2/induttore2.png}%
-\caption{Fit esponenziale — Induttore 2 {[}112.02 – 113.95 s{]}}%
+\subsection{Grafico}
+\begin{figure}[H]
+\centering
+\includegraphics[width=0.9\textwidth]{C:\Users\davide.grilli\Desktop\vs\temperatura\induttore2\induttore2.png}
+\caption{Fit esponenziale -- Report Induttore 2 [112.02 – 113.95 s]}
\end{figure}
+\newpage
-%
-\section{Induttore 3}%
-\label{sec:Induttore3}%
-\subsection{Intervallo di campionamento}%
-\label{subsec:Intervallodicampionamento}%
-\begin{tabular}{|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}\\%
-\hline%
-Inizio&115.0 s\\%
-Fine&133.7 s\\%
-Numero di punti&125\\%
-Zona esclusa (peso = 0)&115.9 – 117.2 s\\%
-\hline%
+\section{Report Induttore 3}
+\subsection{Intervallo di campionamento}
+\begin{tabular}{ll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} \\
+\midrule
+Inizio & $115.0$ s \\
+Fine & $133.7$ s \\
+Numero di punti & 125 \\
+\bottomrule
\end{tabular}
-%
-\subsection{Equazione trovata}%
-\label{subsec:Equazionetrovata}%
-\[%
-T(t) = 22.99 + 185.1847 \cdot e^{-(t - 115.0) / 16.2654}%
-\]%
-\vspace{4pt}%
-\begin{tabular}{|l|l|l|}%
-\hline%
-\textbf{Parametro}&\textbf{Valore}&\textbf{Incertezza (1σ)}\\%
-\hline%
-A&$185.1847\,^\circ\mathrm{C}$&$\pm\,0.2706\,^\circ\mathrm{C}$\\%
-$\tau$&$16.2654\,\mathrm{s}$&$\pm\,0.0464\,\mathrm{s}$\\%
-\hline%
-\end{tabular}%
-\vspace{4pt}%
-$R^2 = 0.993827$
+\subsection{Equazione trovata}
+\begin{equation}
+ T(t) = 22.99 + 185.1847 \cdot e^{-(t - 115.0) / 16.2654}
+\end{equation}
+\begin{tabular}{lll}
+\toprule
+\textbf{Parametro} & \textbf{Valore} & \textbf{Incertezza (1$\sigma$)} \\
+\midrule
+$A$ & $185.1847\,^\circ\mathrm{C}$ & $\pm\,0.2706\,^\circ\mathrm{C}$ \\
+$\tau$ & $16.2654\,\mathrm{s}$ & $\pm\,0.0464\,\mathrm{s}$ \\
+$R^2$ & \multicolumn{2}{l}{0.993827} \\
+\bottomrule
+\end{tabular}
-%
-\subsection{Grafico}%
-\label{subsec:Grafico}%
-
-
-\begin{figure}[H]%
-\centering%
-\includegraphics[width=0.9\textwidth]{C:/Users/davide.grilli/Desktop/vs/temperatura/induttore3/induttore3.png}%
-\caption{Fit esponenziale — Induttore 3 {[}115.0 – 133.7 s{]}}%
+\subsection{Grafico}
+\begin{figure}[H]
+\centering
+\includegraphics[width=0.9\textwidth]{C:\Users\davide.grilli\Desktop\vs\temperatura\induttore3\induttore3.png}
+\caption{Fit esponenziale -- Report Induttore 3 [115.0 – 133.7 s]}
\end{figure}
+\newpage
-%
-\section{Riepilogo}%
-\label{sec:Riepilogo}%
-\begin{tabular}{|l|l|l|l|l|}%
-\hline%
-\textbf{Induttore}&\textbf{Intervallo {[}s{]}}&\textbf{A {[}°C{]}}&\textbf{$\tau$ [s]}&\textbf{$R^2$}\\%
-\hline%
-Induttore 1&110.81 – 111.56 s&87.3140&15.7231&0.999505\\%
-Induttore 2&112.02 – 113.95 s&158.3430&13.2844&0.997314\\%
-Induttore 3&115.0 – 133.7 s&185.1847&16.2654&0.993827\\%
-\hline%
+\section{Riepilogo}
+\begin{tabular}{lllll}
+\toprule
+\textbf{Induttore} & \textbf{Intervallo [s]} & \textbf{A [°C]} & \textbf{$\tau$ [s]} & \textbf{$R^2$} \\
+\midrule
+Report Induttore 1 & 110.81 – 111.56 s & 87.3140 & 15.7231 & 0.999505 \\
+Report Induttore 2 & 112.02 – 113.95 s & 158.3430 & 13.2844 & 0.997314 \\
+Report Induttore 3 & 115.0 – 133.7 s & 185.1847 & 16.2654 & 0.993827 \\
+\bottomrule
\end{tabular}
-%
\end{document}
\ No newline at end of file