Probability Course Fall 2025 — Professor: Tran Vinh Linh
In Computational Fluid Dynamics (CFD) simulations of building environments, accurate boundary conditions are critical. Dr. Nguyen Hop Minh's experimental setup requires precise knowledge of a hot bulb's surface temperature (200–300°C) to validate CFD models. However, direct measurement is impractical—sensors would melt at such temperatures.
We developed an indirect measurement approach using two air temperature sensors positioned at different distances from the heat source, combining their readings through a Kalman Filter to estimate the bulb's temperature.
Figure 1a: Real experimental setup showing the heat source box with two ambient temperature sensors at different distances.
Figure 1b: Schematic diagram - Hot bulb (center) radiates heat to Sensor A (close, dA = 5 cm) and Sensor B (far, dB = 15 cm).
Sensor A (Close): Positioned at dA = 5 cm from the bulb. Captures near-field temperature with higher signal but more noise (RA = 2.0). Experiences stronger thermal fluctuations due to convection effects.
Sensor B (Far): Positioned at dB = 15 cm from the bulb. Measures far-field temperature with lower signal but higher stability (RB = 0.5). Provides reliable baseline measurements.
The Kalman Filter implements optimal Bayesian estimation using Gaussian distributions:
The Kalman Filter computes the posterior mean (μpost) and variance (σ²post) in closed form through two steps:
We model heat diffusion from the bulb using a distance-based attenuation formula with characteristic length ℓ = 10 cm:
This leads to the observation model z = Hx + v where:
where vA ~ N(0, RA = 2.0°C²) and vB ~ N(0, RB = 0.5°C²) represent Gaussian measurement noise. The process noise Q = 0.1°C² accounts for natural bulb temperature fluctuations.
CSV Data Input: The raw measurements come from temperature_data.csv with columns:
Figure: Schematic diagram showing sensor geometry and distances from the heat source.
Purpose: Propagate previous estimate forward in time, accounting for process uncertainty.
Interpretation: Since we have no control input, the best prediction is the previous estimate. However, uncertainty increases by Q = 0.1°C² due to natural temperature fluctuations. This gives the prior p(x) = N(x; x̂pred, Ppred) before incorporating new measurements.
Purpose: Fuse prediction with sensor measurements to reduce uncertainty.
Sensor A Update: Combine prior p(x) = N(x; x̂pred, Ppred) with likelihood p(zA|x) = N(zA; HAx, RA)
Key Insight: KA balances trust in prediction vs measurement:
Sensor B Update: Sequentially update with second sensor p(zB|x) = N(zB; HBx, RB)
Result: Final estimate x̂new optimally fuses both sensors. Since RB < RA (Sensor B more reliable), it receives higher weight in fusion.
Figure 2: Real experimental data over 600 seconds showing Sensor A (orange), Sensor B (blue), and Kalman Filter estimate (green).
36.4 ± 2.1°C
30.5 ± 0.6°C
67.2 ± 2.2°C
The noise parameters RA and RB represent the variance of the measurement error. High noise means the sensor readings have large random fluctuations around the true value.
What Happens:
Mathematical Impact: With high R, the Kalman Gain K ≈ 0, so the update equation becomes:
This means the filter ignores the measurements and just uses its prediction!
What Happens:
Mathematical Impact: With low R, the Kalman Gain K ≈ 1, so:
The filter directly uses the measurements!
Optimal Trade-off:
Key Insight: The Kalman Filter is self-tuning — it automatically adjusts how much to trust each sensor based on their noise levels!
In the building environment experiment:
Try the Kalman Filter with your own parameters or simulate custom sensor data:
Each sensor measurement is a random variable following a Gaussian distribution N(μ, R). Use the slider to see the distribution at different time steps:
Below is the complete Python code used to analyze the experimental data. This implementation matches the mathematical framework described above.
import numpy as np
import pandas as pd
# Load data
data = pd.read_csv('temperature_data.csv')
time = data['Time'].values
sensor_a = data['Middle_Heat_Source'].values # Close to heat source
sensor_b = data['Air_Tube_Output'].values # Farther from heat source
# Kalman Filter parameters (simulating bulb temperature estimation)
# True bulb temperature would be higher than both measurements
Q = 0.1 # Process noise
R_A = 2.0 # Sensor A noise (more noisy, closer)
R_B = 0.5 # Sensor B noise (less noisy, farther)
# Distance factors (heat diffusion model)
d_A = 5.0 # cm, close to bulb
d_B = 15.0 # cm, farther from bulb
# Initialize
x_est = 45.0 # Initial bulb temperature estimate
P = 10.0 # Initial uncertainty
# Store results
bulb_estimates = []
# Kalman Filter loop
for i in range(len(time)):
# Prediction step
x_pred = x_est
P_pred = P + Q
# Update with Sensor A (accounting for distance)
H_A = 1.0 / (1 + d_A/10) # Observation model (heat decreases with distance)
innovation_A = sensor_a[i] - H_A * x_pred
S_A = H_A * P_pred * H_A + R_A
K_A = P_pred * H_A / S_A
x_est = x_pred + K_A * innovation_A
P = (1 - K_A * H_A) * P_pred
# Update with Sensor B
H_B = 1.0 / (1 + d_B/10) # Heat decreases more with distance
innovation_B = sensor_b[i] - H_B * x_est
S_B = H_B * P * H_B + R_B
K_B = P * H_B / S_B
x_est = x_est + K_B * innovation_B
P = (1 - K_B * H_B) * P
bulb_estimates.append(x_est)
# Save results
results = pd.DataFrame({
'Time': time,
'Sensor_A_Close': sensor_a,
'Sensor_B_Far': sensor_b,
'Bulb_Estimate': bulb_estimates
})
results.to_csv('kalman_results.csv', index=False)
# Calculate statistics
print('=== Temperature Statistics ===')
print(f'Sensor A (Close): Mean={sensor_a.mean():.2f}C, Std={sensor_a.std():.2f}C')
print(f'Sensor B (Far): Mean={sensor_b.mean():.2f}C, Std={sensor_b.std():.2f}C')
print(f'Bulb Estimate: Mean={np.mean(bulb_estimates):.2f}C, Std={np.std(bulb_estimates):.2f}C')
print(f'\nAt t=100s: Sensor A={sensor_a[10]:.1f}C, Sensor B={sensor_b[10]:.1f}C, Estimate={bulb_estimates[10]:.1f}C')
print(f'At t=300s: Sensor A={sensor_a[30]:.1f}C, Sensor B={sensor_b[30]:.1f}C, Estimate={bulb_estimates[30]:.1f}C')
print(f'At t=600s: Sensor A={sensor_a[60]:.1f}C, Sensor B={sensor_b[60]:.1f}C, Estimate={bulb_estimates[60]:.1f}C')
The CSV file contains three columns: Time, Middle_Heat_Source (Sensor A), and Air_Tube_Output (Sensor B). These represent measurements from the building environment performance evaluation box.
For each time step, the algorithm performs:
The code produces a CSV file with all estimates and prints statistics showing the bulb temperature is estimated at 67.2°C on average, significantly higher than both sensor readings (36.4°C and 30.5°C).
This project demonstrates three key concepts:
Future work could incorporate thermal dynamics modeling (heat capacity, cooling rates) and extend to multi-sensor arrays for spatial temperature field reconstruction.