Paing Hein Htet CV PDF

Machine learning for clinical data, and the hardware that collects it.

Second-year MEng Biomedical Engineering student at UCL. I design the boards, write the firmware and train the models, and spend most of my time checking whether the numbers are real.

Looking for a summer 2027 internship in medical imaging, biosignals or embedded systems. Available full-time from mid-June to late September 2027.

Download CV zcemphh@ucl.ac.uk

Degree
MEng Biomedical Engineering, UCL, 2025 to 2029
Year one
First Class
Preprint
doi:10.5281/zenodo.22782147
Memberships
IEEE and IET, student member
Based in
London
A band of 383 vertical stripes in shades of pink, red and brown, one per photograph, with no visible trend from left to right
Each stripe is one of the 383 distinct photographs in the CP-AnemiC dataset, drawn in its measured conjunctiva colour and ordered by the child's laboratory haemoglobin. The tick is the WHO threshold for anaemia. There is no clean fade from pale to red. The signal is real but subtle, which is why it had to be measured properly. From PallorHb, below.

Selected work

PallorHb

Anaemia screening from photographs of the eyelid, and an audit of the benchmark it is tested on

Preprint on Zenodo, September 2026. Sole author.

I set out to estimate haemoglobin from conjunctiva photographs on the public CP-AnemiC dataset. Its 710 published records turned out to be 383 distinct photographs. The copies cross hospitals and carry conflicting haemoglobin values, so grouping folds by site, the standard safeguard, still left two-fifths of the inflation in place.

Python, scikit-learn, NumPy, SciPy

Distinct photographs
383 of 710 records
Inflation from a naive split
+0.176 AUROC (95% CI +0.120 to +0.232)
Corrected baseline
AUROC 0.706 (95% CI 0.653 to 0.757)
What the image adds
+0.182 AUROC over demographics alone (DeLong p = 2 × 10⁻⁶)
Limit
A triage screen, not a haemoglobin meter: Bland-Altman limits of agreement span 7.8 g/dL
Reproducibility
62 tests. Every number in the manuscript is regenerated and checked by script.
Figure from the preprint: the same conjunctiva photograph filed as Image_143 at one hospital with haemoglobin 12.5 g/dL and as Image_165 at another with 12.8 g/dL, beside the near-zero difference between them after a 3 pixel shift
One photograph filed under two identifiers, at two hospitals, with two haemoglobin values. The third panel is the difference after a 3 pixel shift. Images: CP-AnemiC dataset (Asare, Mendeley Data), CC BY 4.0.

Unseen Alleles

Do protein foundation models help predict peptide-HLA stability on binding grooves they have never seen?

Built in 48 hours at the London AI x Science Hackathon, October 2026, with Radin Moradi, Sina Ahani and Andy Kaça. Team work, not mine alone.

How long a peptide stays bound to an HLA molecule predicts T cell response better than binding strength does, but it has been measured for only 75 alleles and for none of HLA-C. A patient has no obligation to carry one of the 75, so the question is extrapolation to a groove nobody has measured. We tried hard to make a protein language model win it, and it lost. The work that mattered was the test: every allele in this panel has a near-twin, so holding out one allele at a time measures copying rather than generalisation. We clustered the grooves at 80% identity over their 34 peptide-contact residues and held out whole clusters instead.

Python, PyTorch, Hugging Face Transformers, scikit-learn, NumPy, SciPy, 3Dmol.js

Conventional network, BLOSUM62 and one-hot
Median per-allele Spearman 0.265 over 21 held-out groove clusters
Best language-model arm
0.164, the best of eleven configurations across three encoder families, including one fine-tuned end to end
The configuration most people use
0.092 for frozen mean-pooled ESM-2, which is not distinguishable from a control that is never shown which allele it is predicting for
Margin
The conventional network wins on 19 of 21 folds, median margin +0.080, Wilcoxon p = 1.3 × 10⁻⁵
Why they lose
Under ESM-2 the 75 alleles sit at 0.97 to 0.99 mean pairwise similarity, against 0.60 under one-hot. The pretrained representation has smoothed away the differences between grooves, which are the entire signal.
Limit, printed not buried
The fold unit is a cluster, so 80.9% of test rows carry a peptide that also appears in training against some other allele. Restricted to genuinely novel peptides the result survives, 0.299 against 0.307, but on only 12 of the 21 folds.
Audit
17 leakage checks, including a negative control in which the guard is made to fire on purpose, and a check that predictions are bit-identical under scrambled bookkeeping columns
A ladder chart titled Four escalating best shots, none of them closed the gap. Eight rows, one per model, each a horizontal line of 21 dots with a thick median tick. The conventional supervised net sits highest at 0.31, then ESM-2 un-pooled at 0.19, fine-tuned at 0.17, ESM-2 650M at 0.14, a peptide-mean lookup table at 0.13, off-the-shelf ESM-2 at 0.11, an allele-blind control at 0.06 and a null at minus 0.01.
Every arm on one scale, one dot per held-out groove cluster. A lookup table with no model and no allele information beats frozen ESM-2 off the shelf. Drawn with the deployed five-seed ensemble, where the conventional net reads 0.31; the numbers above use the per-fold mean over seeds, the stricter of the two conventions. The ordering is the same either way.
The explorer's structure tab: a nine-residue peptide in teal lying in the slate binding groove of HLA-A*02:01, its two anchor positions in brick, with a T cell receptor in olive docked across the top, above buttons for the receptor, the position labels, the anchors and the groove surface.
The public explorer at peptidehla.com. Pick one of the ten trained models, type a peptide, and see the prediction beside the half-life the experiment actually measured. The structure is a crystal template, PDB 3GSN, not a predicted fold, and the page says so in place.

PURSUIT-1

A 92 mm quadcopter whose circuit board is its own airframe, built to follow one enrolled person

Rev A board built and bench-tested. Not yet flown.

There is no separate frame. The 4-layer board is the structure, and the motors clamp into rings at the ends of its arms. The board is generated from a Python netlist. The flight firmware runs on an ESP32-S3 and is written from the IMU registers up. Detection and identity run on a laptop, which sends setpoints over WiFi.

KiCad and its Python API, ngspice, C++, PlatformIO, Python, ONNX Runtime, OpenCV

Boards
Rev A fabricated and brought up on the bench, August 2026. Rev C released for fabrication.
Link
0 corrupt in 3,828 command and 2,551 telemetry packets, with the control loop at about 1.09 kHz
Identity
0 false accepts in 24,110 impostor faces. Held lock on 391 of 400 frames with a second person in view, and never transferred.
Stability
Uncompensated, the vision loop goes unstable at about 17 ms of delay, and the measured round trip is 20 ms. With attitude compensation it settles past 200 ms, in simulation.
Caught on the bench
The IMU sat 180 degrees out in yaw, which would have flipped the aircraft on take-off. The host tests had passed on synthetic data.
Tests
369: 128 firmware, 227 vision, 14 flight simulation
Next
Measure hover throttle on a scale, tune each axis with the aircraft restrained, then hover at 1 m
Render of the PURSUIT-1 board: an X-shaped circuit board with a motor ring at the end of each of its four arms, marked REV C
Rev C board. KiCad render.

EIT-16CH

A 16-electrode electrical impedance tomography instrument, and how to reconstruct images from it

Simulation only. Boards designed, nothing powered yet.

EIT images a cross-section from voltages measured at the surface. It is the method used at the bedside to watch a lung inflate. My first learned reconstruction, trained on clean simulations, lost to the classical Gauss-Newton solver as soon as noise was added. Trained with the noise model the instrument will actually have, a small U-Net beat it at every noise level tested.

KiCad, ESP32-S3, PlatformIO, PyTorch, NumPy, pyEIT

At 20 dB
Correlation with the truth 0.566, against 0.170 for Gauss-Newton
Clean data
0.825 against 0.791
Uncertainty
Five-member ensemble: the confident half of each image is 8 to 18 times more accurate than the doubtful half
Hardware
A 4-layer 100 x 100 mm board with 104 footprints, and a 2-layer through-hole version for hand assembly. Neither is fabricated.
Next
Measure the real signal-to-noise ratio in a saline tank and test the simulation-trained model against it
Grid of reconstructions: ground truth, classical Gauss-Newton and the learned method, on clean data and at 30 dB and 20 dB of noise. The classical images break up as noise rises; the learned ones keep both inclusions.
Ground truth, Gauss-Newton and the U-Net at three noise levels. Simulated data.
Render of the EIT-16CH measurement board: a square board with multiplexers, amplifiers and an ESP32-S3 module
The 4-layer board. KiCad render.

TT-Scout

Table tennis match analysis from one phone on a tripod

Checked by hand against real match video.

Film a match from the side of the table. TT-Scout finds every point and who won it, keeps the score, and measures each shot's speed in 3D with its own error bar. The table is the calibration: it is exactly 2.74 by 1.525 m, so its four corners recover where the phone stood. Ball tracking is classical, so when it goes wrong you can find the frame and see why.

Python, OpenCV, NumPy, PyTorch, Apple Vision

Point winners
Correct on all 21 endings that could be judged by eye: 16 of 16 on the recording the rules were tuned on, 5 of 5 checked blind on another
Shot speed
Median error 3% on simulated shots with noise, spin and hidden contacts. Not yet measured against a real ball.
Table found automatically
8 of 8 own recordings, 12 of 12 OpenTTGames clips
Learned detector, research only
Finds the ball in 98% of labelled frames against 77% for the classical detector, on 7 held-out clips
A frame from a generated point clip: Sina and Radin at a table in a sports hall, pose skeletons drawn on both players, the ball's trail over the net with the bounce ringed, a scoreboard reading Sina 5 Radin 6, a ball speed gauge at 45 km/h, a small table diagram of where each shot landed, and a coach's note about topspin
One point as TT-Scout draws it: ball trail, bounce, score, shot speed, both players' poses and a coaching note. Sina, left, receiving Radin's serve, filmed on a phone from the side of the table. Both players agreed to be filmed.

Crank Charger

A hand-crank phone charger: printed planetary drive, stepper motor as alternator

Built. First charging icon seen 12 October 2026; predicted 10 W into the phone, nothing measured yet. The measured test is due 25 October 2026.

A 236 mm hand wheel turns a 91-tooth ring gear. Three 37-tooth planets on fixed steel pins drive a 17-tooth sun on a NEMA23 stepper, so the motor turns 5.35 times faster than the hand. The gears are herringbone and printed in one job, already meshed. Run as an alternator the stepper is inductance-limited: its current, and so its torque, barely rises with speed, which is why the drive multiplies speed and not torque. Two Schottky bridges, a 1000 uF capacitor and a buck converter make 5 V for the phone. The design document works through every number from 90 rpm at the hand to 10 W at the phone, and the prediction is written down before the first crank so that the USB meter can disagree with it.

Fusion 360, Blender, ngspice, Python, PETG on a Bambu P1S

Drive
One planetary stage, ring 91, planets 37, sun 17, module 2.4: 5.35 to 1. Herringbone, printed in one job, already meshed.
Generator
A NEMA23 stepper run backwards: 0.318 V per rad/s from its own label, so 16 V peak per coil at 482 rpm
Why only speed buys watts
At 400 Hz the coil's reactance is 6.3 ohm against 0.9 ohm of resistance, so the current it can pass stays near 2.5 A at any speed. The torque is pinned, so the drive multiplies speed.
Predicted
10 W into the phone for 17.5 W at the hand at 90 rpm, about 19 N on the grip. 57 percent, hand to phone.
Electronics
Eight SB560 Schottkys in two bridges, a 1000 uF bus capacitor, a 7 to 30 V buck converter, a USB meter in the lead
Limit
Nothing measured yet. Iron loss is not modelled and the mesh efficiency is a guess, so the real number will be lower.
Test
60 s of cranking on film, the phone charging, the meter in shot, judged against the number written down beforehand. By 25 October 2026.
Render of the crank charger pulled apart along its axle: a black NEMA23 motor and its screws, a grey printed frame, an orange herringbone ring gear with three planets and a sun, three steel pins with washers, a grey spoked hand wheel with its two bearings and spacer, and the grip on its M6 bolt
Every part along the axle, from the motor behind the wall to the grip. Rendered from the part files; nothing measured yet.
Render of the gear cartridge pulled apart: an orange herringbone ring gear with three planets inside it, the small sun gear and three pin spacers to its left, six steel washers and three bearings in the air, and the orange three-armed spider with its three M8 pin bolts and the axle bolt to the right
The gear cartridge: ring, planets and sun printed in one job, the planets' bearings, pins and spacers, and the spider that carries them.

Cycloidal Arm

A five-axis robot arm on three printed 21:1 cycloidal joints, driven from a webcam

Drawn and checked, printing in progress: four of sixteen plates printed, nothing assembled or measured. The joint test, backlash and stall torque against a locked prediction, is due 30 November 2026.

A NEMA17 behind a printed cycloidal reducer: twenty-two steel dowel pins on a 72 mm circle, a 21-lobe disc running 1.0 mm off centre, a second disc 180 degrees round to cancel the wobble, six output dowels through oversized holes. Twenty-one to one in a single stage, and several lobes carry the load at once, which is why a printed disc can take what printed spur teeth would strip. Three identical joints, each on a 42 N cm NEMA17 with no balancer spring, are the yaw, shoulder and elbow of an arm with 150 mm links; two servos do wrist pitch and roll, and three two-joint fingers close on a 66 mm can. A laptop turns webcam pose into joint angles and an ESP32-S3 steps the motors. The question the build answers is not whether it turns but two numbers: backlash at the output and holding torque, measured against a prediction written down before the test.

Fusion 360, Blender, ngspice, C++ on ESP32-S3, Python, MediaPipe, PETG on a Bambu P1S

Joint
22 steel dowel pins on a 72 mm circle, a 21-lobe disc thrown 1.0 mm, two discs 180 degrees apart, six output dowels through 7.2 mm holes: 21 to 1 in one stage
Why cycloidal
Several lobes share the load, so PETG carries what printed spur teeth would strip. The price is backlash from the pin clearances, and that is what the test measures.
Predicted
4.28 N m stall per joint, from 0.34 N m x 21 x 0.60; the 0.60 is a guess the test replaces. Backlash 0.76 degrees from the drawn clearances, against a 0.9 degree gate.
Arm
Yaw, shoulder and elbow on three identical 21:1 joints, one 42 N cm NEMA17 each and no balancer spring; 150 mm links; wrist pitch and roll on hobby servos; three two-joint fingers rated 150 g on a 66 mm can
Control
Webcam pose through MediaPipe to joint angles on a laptop; step pulses from an ESP32-S3; no encoders, homed by hand
Checks
143 geometric checks on the joint and 144 on the arm, a collision scan over 82,485 poses, every print plate mesh-checked before slicing. Fits are estimates until the first joint is read.
Test
Backlash under 1 degree at the output, the arm holding 1 kg at 150 mm, and measured stall within 20 percent of the locked prediction, on film, by 30 November 2026
Render on a black studio floor of a grey printed robot arm standing on a dark square board: a round base with the yaw joint, an upright shoulder joint and an elbow joint, each a cylindrical drum with an orange ring, two flat links, a wrist block and three printed fingers closed round a satin steel can
The arm as drawn, holding a 66 mm can: three cycloidal joints with their orange ring housings, wrist servos and the three-finger gripper. Rendered from the part files; four plates printed, nothing assembled.

More work

Hardware

EMG front end

Surface-EMG amplifier and RP2040 firmware for proportional grip control

Board built, telemetry verified. No EMG recorded yet.

An instrumentation amplifier with driven-right-leg mains rejection feeds a Raspberry Pi Pico, which runs the whole loop: filtering, a safety state machine, and a map from contraction strength to grip. In a 10 s capture the link delivered 499 frames with no CRC errors and none dropped. The analog stage has not been powered, so nothing has been recorded from skin.

KiCad, C++, PlatformIO, Python

Render of the EMG front end board, rev E: a through-hole board with two amplifier chips, a socket for a Raspberry Pi Pico and the silkscreen warning BATTERY POWER ONLY
Rev E. KiCad render.

RL Car

Uncertainty-aware autonomous racing

Simulation only. The car is not built.

A racer meant to slow down when it stops trusting a sensor. The useful result was negative: an ensemble over the policy scored AUROC 0.127 on a blinded sensor, worse than chance, because steering has many right answers and disagreement between them means nothing. Estimating it on a forward model and isolating the faulty sensor, instead of braking, cut crashes from 155 to 2 across 192 held-out fault episodes at full speed. The body aerodynamics use a Navier-Stokes solver written from scratch and validated against published cylinder-flow benchmarks.

Python, NumPy, SciPy, OpenSCAD, FreeCAD, gmsh, CalculiX

Render of the RL car: a lofted blue body shell over a printed chassis with four treaded wheels, seen from the front left
150 by 90 by 46 mm. Rendered from the OpenSCAD model.

Photobioreactor controller

ESP32-S3 controller for a 1 L algae culture

Simulation only. Board designed, not fabricated.

A 2-layer board that reads optical density, pH and temperature and switches the lights, air and dosing. A fitted growth model chooses the light schedule. Across ten simulated runs with unknown parameters it grew a median of 21% more biomass than a fixed timer at equal energy, and never less.

KiCad, ngspice, CadQuery, Python, PlatformIO

Render of the photobioreactor controller board, rev B, with an ESP32-S3 module, a barrel jack and a row of white connectors
Rev B. KiCad render.

Software

Wave Lab

A real-time harmonic analyser that runs in the browser

Live at paingheinhtet.com since June 2026. Demo mode needs no microphone.

A single-page instrument that takes the microphone signal and shows what it is made of while it plays: each dominant frequency drawn as its own travelling sine wave with its note name, the spectrum with its peaks marked, the raw waveform, an X-Y phase scope, and the detected sines re-summed and laid over the real wave. The analysis runs on an 8,192-point FFT in the Web Audio API; the overlay uses a direct DFT at each detected frequency, so amplitude and phase are exact rather than read off a bin. Low-, high- and band-pass filters apply live, with optional monitoring. A YAMNet classifier runs in the browser through TensorFlow.js and names the sound among 521 classes; song recognition goes through the AudD API with the user's own token, which never leaves the browser.

JavaScript, Web Audio API, Canvas, TensorFlow.js

The Wave Lab instrument in demo mode: a dark dashboard with three travelling sine traces labelled 193 Hz G3, 393 Hz G4 and 586 Hz D5, an X-Y phase scope, a measurements table, a harmonics bar chart from H1 to H8, a spectrum with three marked peaks, a waveform, a Fourier synthesis overlay, a song recognition panel and a control column with power, range, channels, filter and cutoff
Demo mode, no microphone: a 193 Hz tone split into its three strongest components, their sum laid over the real waveform, and the H1 to H8 harmonics meter. Screenshot from the browser.

Watch Sentinel

Illness early-warning from Apple Watch data

Validated on synthetic data only.

Resting heart rate, heart rate variability, respiratory rate and wrist temperature are each scored against a personal 28-day baseline that never sees the future, and three of the four must agree before it alerts. A SwiftUI app exports the data from HealthKit. It compiles but has not yet run on a device.

Python, pandas, Swift, HealthKit

Two dark charts over 120 days. Top: a resting heart rate trace in white around 52 bpm with a grey trailing-median line and a shaded band, rising to 60 bpm at two dashed lines marked planted illness onset near days 45 and 95. Bottom: the daily risk score, flat at zero except two peaks to about 4.5 at the same days, with orange dots on the days above a dashed alert line at 1.75
The detector on its synthetic export: resting heart rate against a 28-day trailing baseline that ends yesterday, and the daily risk score. Two planted illnesses at days 45 and 95; alerts from days 43 and 93. No real watch data yet.

Gripper

Control software for a 4-DOF robot arm

100 unit tests pass. Not yet run on the arm.

Two modes, switched by a hand gesture: teleoperation that follows a tracked hand, and a grasp that aligns to an object by visual servoing. A Raspberry Pi 5 does perception and planning. An ESP32 does servo control and safety, so the arm stops if the Python side hangs or the cable is pulled.

Python, MediaPipe, C++, ESP32

A dark monospace telemetry page titled gripper, live telemetry: a green TELEOP state badge, bars for base 15.1 degrees, shoulder 30, elbow minus 60, wrist 14 and grip 68 percent, then latency p50 58 ms p95 95 ms, vbat 7.40 V, and the words no faults in green
The live telemetry page the package serves, here in its standalone demo with made-up joint angles. The arm is not attached yet.

Kaggriculture

Market-timing layers for Kaggle's two-farm simulation competition

Rank 339 of 10,246 on the public leaderboard at the close, 30 September 2026. Final standing settles in mid-October.

Two farms sell into one market where the price is a fixed function of stock and orders are served slot by slot, so the position of an order in the list is worth money. Most rivals in my band ran the same public engine, so I could predict their list, check that prediction every turn against their public money, and place each of my sales one slot ahead of theirs. When a rival buys a block of wheat, a layer buys alongside it and sells in the last slot of the same turn, taking the rise the rival's own purchase causes. Every build was replayed into my seat of a few hundred recorded ladder games and had to win at least as many; the farm itself is the public 2965 Master Engine (Apache-2.0), unchanged except three constants.

Python, NumPy, kaggle-environments

The competition's pixel-art visualiser at day 23 of a 30-day game: two fenced farms of ten by ten tiles either side of a town square with seven shops, crops and animals on both farms, farm hands walking the rows, and beneath them two player panels and a price board for eight products
Day 23 of 30 in one of the entry's ladder games on 30 September 2026, in the competition's own visualiser. Our farm is on the right.

Publication

Htet, P. H. (2026). Duplicate leakage in a public conjunctival pallor benchmark, and an honest baseline for image-based anaemia screening. Preprint, Zenodo. doi:10.5281/zenodo.22782147

Shows that a published clinical image dataset contains far fewer distinct images than records, that the duplicates carry conflicting labels, and that the usual site-grouped cross-validation does not remove the resulting inflation. Reports a corrected baseline and releases the detector.

Background

Tools and methods

Languages
Python, C, C++, MATLAB, SQL. Data structures and algorithms.
Evaluation
Bootstrap confidence intervals, DeLong test, calibration (Hosmer-Lemeshow, expected calibration error, Brier score), Bland-Altman agreement, decision curves, grouped cross-validation, leakage control
Machine learning
scikit-learn, PyTorch. Epistemic uncertainty with bootstrap ensembles and random Fourier features, out-of-distribution detection, reinforcement learning, gradient boosting
Vision
CNN, ViT, DETR, YOLO. OpenCV, ONNX Runtime, CoreML. Detection, tracking, face recognition
LLMs and agents
Anthropic API, tool use, MCP, multi-step agents, Hugging Face Transformers, Whisper
Signals and control
EMG, PPG and Wi-Fi channel-state processing. MuJoCo, domain randomisation
Electronics
2- and 4-layer PCB layout, analog front ends, power. KiCad, SKiDL, LTspice, ngspice. SMD soldering. ESP32-S3, RP2040
CAD and laboratory
Fusion 360, SolidWorks, CadQuery, 3D printing. Aseptic technique, cell passaging, Instron tensile testing