172 lines
6.2 KiB
Python
172 lines
6.2 KiB
Python
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)
|
||
|
||
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",
|
||
},
|
||
]
|
||
|
||
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),
|
||
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
|
||
("LEFTPADDING", (0, 0), (-1, -1), 8),
|
||
])
|
||
|
||
|
||
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)
|
||
|
||
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)
|
||
|
||
story = []
|
||
|
||
# --- Titolo ---
|
||
story.append(Paragraph("Report Analisi Termica Forno", style_title))
|
||
story.append(Paragraph("Analisi IR – Cevolani", styles["Normal"]))
|
||
story.append(Spacer(1, 0.5*cm))
|
||
story.append(HRFlowable(width="100%", thickness=1, color=HEADER_COLOR))
|
||
story.append(Spacer(1, 0.5*cm))
|
||
|
||
# --- Modello ---
|
||
story.append(Paragraph("Modello di fitting", style_h1))
|
||
story.append(Paragraph(
|
||
"Ogni intervallo è interpolato con il modello di raffreddamento di Newton:",
|
||
style_body))
|
||
story.append(Spacer(1, 0.2*cm))
|
||
story.append(Paragraph("T(t) = T_inf + A · exp( -(t - t0) / τ )", style_eq))
|
||
story.append(Paragraph(
|
||
"dove <b>T_inf = 22.99 °C</b> è la temperatura ambiente media ponderata. "
|
||
"La regressione non lineare usa il metodo <i>Trust Region Reflective</i> (TRF) "
|
||
"di <font name='Courier'>scipy.optimize.curve_fit</font>.",
|
||
style_body))
|
||
story.append(Spacer(1, 0.4*cm))
|
||
|
||
# --- Sezione per ogni induttore ---
|
||
for ind in INDUTTORI:
|
||
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.lightgrey))
|
||
story.append(Spacer(1, 0.2*cm))
|
||
story.append(Paragraph(ind["nome"], style_h1))
|
||
|
||
# Tabella intervallo
|
||
story.append(Paragraph("Intervallo di campionamento", style_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(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(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(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))
|
||
|
||
# --- Tabella riepilogativa ---
|
||
story.append(PageBreak())
|
||
story.append(Paragraph("Riepilogo", style_h1))
|
||
summary = [["Induttore", "Intervallo [s]", "A [°C]", "τ [s]", "R²"]]
|
||
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)
|
||
|
||
doc.build(story)
|
||
print(f"report_completo.pdf generato.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
build_doc()
|