# 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