Files

126 lines
5.1 KiB
Python
Raw Permalink Normal View History

2026-08-03 00:18:00 +02:00
# Sorgenti a induzione in movimento sulla superficie esterna della fascetta.
#
# Il gruppo è formato da più sorgenti equidistanti che traslano insieme lungo
# x con la stessa velocità. Tutte percorrono la stessa generatrice, cioè la
# stessa posizione circonferenziale, definita dall'offset rispetto al punto
# osservato dal sensore.
#
# Il flusso termico incidente su un punto della superficie è
#
# q''(x, arco, t) = q_picco * somma_i exp(-((x - x_i(t))^2) / (2 sigma^2))
# * exp(-(delta_arco^2) / (2 sigma^2))
#
# dove delta_arco è la distanza circonferenziale minima tra il punto e il
# percorso delle sorgenti, misurata lungo la circonferenza e riavvolta su
# 2*pi*R: passare da un lato o dall'altro della fascetta è equivalente.
#
# Il flusso è quindi il prodotto di un fattore che dipende solo da x e varia
# nel tempo e di un fattore che dipende solo dall'arco ed è costante: questa
# separazione è sfruttata dall'assemblaggio del vettore sorgente.
import math
import numpy as np
def _spread_sorgenti_m(sorgente: dict) -> float:
# Distanza lungo x tra la prima e l'ultima sorgente del gruppo.
numero_sorgenti = sorgente.get("numero_sorgenti", 1)
distanza = sorgente.get("distanza_sorgenti_m", 0.0)
return (numero_sorgenti - 1) * distanza
def x_riferimento_iniziale_m(sorgente: dict, x_sensore_m: float) -> float:
# Posizione a t=0 della sorgente di indice 0. Le sorgenti i sono a
# x_i = riferimento + i * distanza, quindi per v >= 0 l'indice 0 è la
# più arretrata nel verso di marcia, per v < 0 è la più avanzata.
# x_inizio_m è la distanza dal sensore della sorgente più avanzata
# (quella che lo raggiunge per prima).
spread = _spread_sorgenti_m(sorgente)
x_inizio = sorgente["x_inizio_m"]
if sorgente["velocita_m_s"] >= 0:
return (x_sensore_m - x_inizio) - spread
return x_sensore_m + x_inizio
def x_riferimento_finale_m(sorgente: dict, x_sensore_m: float) -> float:
# Posizione di fine corsa della sorgente di indice 0. x_fine_m è la
# distanza dal sensore della sorgente più arretrata nel verso di marcia
# (quella che lo supera per ultima).
spread = _spread_sorgenti_m(sorgente)
x_fine = sorgente["x_fine_m"]
if sorgente["velocita_m_s"] >= 0:
return x_sensore_m + x_fine
return (x_sensore_m - x_fine) - spread
def _intervallo_attivo(inizio: float, fine: float, v: float, x_m: float) -> bool:
if v >= 0:
return inizio <= x_m <= fine
return fine <= x_m <= inizio
def theta_percorso_rad(sorgente: dict, raggio_medio_m: float) -> float:
# Posizione circonferenziale del percorso delle sorgenti, ricavata
# dall'offset in arco rispetto al sensore, che sta per convenzione a
# theta = 0.
return sorgente["offset_y_percorso_m"] / raggio_medio_m
def fattore_circonferenziale(
sorgente: dict, raggio_medio_m: float, arco_m: np.ndarray
) -> np.ndarray:
# Attenuazione gaussiana del flusso in funzione della distanza
# circonferenziale dal percorso delle sorgenti. La distanza è riavvolta
# sulla circonferenza, così la sorgente scalda anche i punti raggiunti
# "dall'altra parte" della fascetta.
circonferenza = 2.0 * math.pi * raggio_medio_m
delta = arco_m - sorgente["offset_y_percorso_m"]
delta = (delta + circonferenza / 2.0) % circonferenza - circonferenza / 2.0
sigma = sorgente["sigma_punto_m"]
return np.exp(-0.5 * (delta * delta) / (sigma * sigma))
def profilo_flusso_x_W_m2(
sorgente: dict, x_sensore_m: float, t_s: float, x_m: np.ndarray
) -> tuple[float, np.ndarray]:
# Restituisce la posizione della sorgente di riferimento e il fattore
# assiale del flusso efficace [W/m²], somma dei contributi di tutte le
# sorgenti attive valutata nei punti x richiesti.
x_rif_iniziale = x_riferimento_iniziale_m(sorgente, x_sensore_m)
x_rif_finale = x_riferimento_finale_m(sorgente, x_sensore_m)
x_riferimento = x_rif_iniziale + sorgente["velocita_m_s"] * t_s
numero_sorgenti = sorgente.get("numero_sorgenti", 1)
distanza = sorgente.get("distanza_sorgenti_m", 0.0)
v = sorgente["velocita_m_s"]
zero_dopo_fine = sorgente.get("zero_dopo_fine", True)
sigma = sorgente["sigma_punto_m"]
q_picco = (
sorgente["flusso_termico_picco_W_m2"] * sorgente["efficienza_riscaldamento"]
)
q_x = np.zeros_like(x_m)
for i in range(numero_sorgenti):
x_i = x_riferimento + i * distanza
if zero_dopo_fine:
inizio_i = x_rif_iniziale + i * distanza
fine_i = x_rif_finale + i * distanza
if not _intervallo_attivo(inizio_i, fine_i, v, x_i):
continue
dx = x_m - x_i
q_x += q_picco * np.exp(-0.5 * (dx * dx) / (sigma * sigma))
return x_riferimento, q_x
def posizioni_sorgenti_m(sorgente: dict, x_riferimento_m: float) -> np.ndarray:
# Posizioni lungo x di tutte le sorgenti del gruppo a partire da quella
# di riferimento.
numero_sorgenti = sorgente.get("numero_sorgenti", 1)
distanza = sorgente.get("distanza_sorgenti_m", 0.0)
return x_riferimento_m + np.arange(numero_sorgenti) * distanza