HardikMadaan
M.Sc. Aerospace Engineering at TU Darmstadt. Building safety-critical AI systems, ML pipelines & intelligent flight interfaces where aerospace meets machine intelligence.
Building at the
edge of aerospace
& intelligence.
I'm a Master's student in Aerospace Engineering at TU Darmstadt, specialising in machine learning pipelines, safety-critical AI, and human-machine interaction for aviation.
From predicting gas turbine health with custom asymmetric loss functions to building real-time simulator cockpit GUIs — I bring both rigorous engineering and clean software practices to every project.
Currently seeking roles in aerospace AI, MLOps, and safety-critical systems where precision isn't optional.
The full stack.
Interactive
code & results.
End-to-end ML pipeline predicting engine Remaining Useful Life (RUL) on the NASA C-MAPSS dataset. Custom Asymmetric Loss Function reduces safety violations from 12.4% to 1.09%. LSTM outperforms Random Forest baseline (RMSE 17.17 → 13.32 cycles).
# PHM System — RUL Prediction Pipeline import numpy as np import tensorflow as tf from sklearn.cluster import KMeans import mlflow def asymmetric_loss(y_true, y_pred): diff = y_pred - y_true alpha = tf.where(diff < 0, 2.0, 0.5) return tf.reduce_mean(alpha * tf.square(diff)) def build_lstm(seq_len=30, n_feat=25): inp = tf.keras.Input((seq_len, n_feat)) x = tf.keras.layers.LSTM(128, return_sequences=True)(inp) x = tf.keras.layers.Dropout(0.2)(x) x = tf.keras.layers.LSTM(64)(x) x = tf.keras.layers.Dense(32, activation='relu')(x) out = tf.keras.layers.Dense(1)(x) model = tf.keras.Model(inp, out) model.compile(optimizer='adam', loss=asymmetric_loss) return model with mlflow.start_run(): model = build_lstm() mlflow.log_metric("rmse", 13.32) mlflow.log_metric("safety_violations", 0.0109)
Modular GUI for single-pilot cockpit operations built with PySide6. Multi-threaded UDP network layer streams real-time telemetry from X-Plane 12 at 50 Hz. Earned a 1.3 grade for HMI performance and backend reliability.
import socket, struct, threading from PySide6.QtCore import QObject, Signal class XPlaneUDPReader(QObject): data_received = Signal(dict) def __init__(self): super().__init__() self.sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) self.sock.bind(("", 49001)) def start(self): t = threading.Thread( target=self._listen, daemon=True ) t.start() def _listen(self): while True: raw, _ = self.sock.recvfrom(4096) parsed = self._parse(raw) self.data_received.emit(parsed) def _parse(self, raw): result, offset = {}, 5 while offset + 36 <= len(raw): idx = struct.unpack_from('i', raw, offset)[0] vals = struct.unpack_from('8f', raw, offset+4) result[idx] = vals offset += 36 return result
Processed 30 years of runway incursion data to find collision avoidance patterns. Structured safety logic aligned with RTCA DO-323. Sensitivity analysis delivered recommendations directly to Boeing engineers.
import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.inspection import permutation_importance def load_incursion_data(path): df = pd.read_csv(path, parse_dates=['date']) df = df.dropna(subset=['severity', 'airport_id']) sev_map = {'A':4, 'B':3, 'C':2, 'D':1} df['sev_num'] = df['severity'].map(sev_map) return df def run_sensitivity(df, feature_cols): X = df[feature_cols].values y = df['sev_num'].values rf = RandomForestClassifier(n_estimators=200) rf.fit(X, y) result = permutation_importance(rf, X, y, n_repeats=10) return pd.Series( result.importances_mean, index=feature_cols ).sort_values(ascending=False) def assess_do323(event): risk = event['sev_num'] * event['traffic_density'] if risk > 8: return "CRITICAL" elif risk > 4: return "WARNING" return "NOMINAL"
Active stabilisation control logic for a mechatronic mowing system using MATLAB/Simulink. Physical prototypes designed in Fusion 360 and 3D-printed. System integration managed via agile SCRUM.
import numpy as np from scipy import signal class PIDController: def __init__(self, Kp, Ki, Kd, dt=0.01): self.Kp,self.Ki,self.Kd = Kp,Ki,Kd self.dt = dt self.integral = self.prev_err = 0.0 def step(self, setpoint, measured): err = setpoint - measured self.integral += err * self.dt deriv = (err - self.prev_err) / self.dt self.prev_err = err return self.Kp*err+self.Ki*self.integral+self.Kd*deriv def simulate(target_h=0.05, duration=2.0): pid = PIDController(Kp=8.5, Ki=2.1, Kd=0.4) t = np.arange(0, duration, 0.01) h = 0.0 history = [] for _ in t: u = pid.step(target_h, h) h += (u - h) * 0.01 / 0.08 history.append(h) return t, np.array(history)
Full-stack Python astrodynamics dashboard — Hohmann, Bi-Elliptic & Phasing maneuvers computed analytically, with a trained MLP surrogate achieving R² = 0.9993 on 40 k held-out mission scenarios. PySide6 HMI embeds live Matplotlib orbital visualisations.
import numpy as np import joblib GM = 3.986e14 # Earth μ m³/s² def hohmann(r1, r2): a_t = (r1 + r2) / 2 dv1 = np.sqrt(GM/r1) * (np.sqrt(2*r2/(r1+r2)) - 1) dv2 = np.sqrt(GM/r2) * (1 - np.sqrt(2*r1/(r1+r2))) t = np.pi * np.sqrt(a_t**3/GM) return dv1+dv2, t def fuel_mass(dv, isp, m_dry): return m_dry * (np.exp(dv/(isp*9.80665)) - 1) # AI surrogate — 200 k synthetic scenarios model = joblib.load('ml/surrogate.pkl') scaler = joblib.load('ml/scaler.pkl') def predict_dv(vc1, vc2, m_dry, isp): X = scaler.transform([[vc1, vc2, m_dry, isp]]) return model.predict(X)[0]