A CPU and its compiler from scratch, a fault controller taken to physical silicon, a neural network quantized onto an NPU and running on the mounted unit, an analog amplifier being linearized with a learned predistorter, and a web platform I run alone in production. Every figure on this page is measured, not estimated.

Work
application06 JanvaniTypeScript, PostgreSQL, CI, security review model05 Crop disease classifierTensorFlow, evaluation, 92% test acc. embedded04 Wildlife detection nodeYOLOv8 INT8 on Hailo NPU, systemd, 47 tests architecture03 RISC-V pipeline + compilercycle-accurate C model, gdb, 25-program suite RTL02 FaultLatchedPWMVerilog FSM, synthesis, board bring-up analog01 Amplifier linearizationLTspice, Python fit, SDR loop, in progress
Where each project sits. The two highlighted entries are current research at UBC.
  1. Analog.The bottom of the stack: a real amplifier with a real nonlinearity. Current research. The correction is modelled in LTspice and fit in Python, with an SDR closing the loop.
  2. RTL.One level up, logic described in Verilog and synthesized onto an FPGA. FaultLatchedPWM puts the safety envelope here, where firmware cannot reach it.
  3. Architecture.How instructions flow through a processor. A cycle-accurate five-stage RISC-V model in C, with the cross-compiler that feeds it, debugged in gdb against 25 programs.
  4. Embedded.Linux on a small board with an accelerator. The detection node: a quantized YOLOv8 model on a Hailo NPU, a self-recovering systemd service, and tests that run without the hardware.
  5. Model.The machine learning itself. A TensorFlow classifier taken to 92% test accuracy by reading the confusion matrix instead of guessing at hyperparameters.
  6. Application.The top: software people use. Janvani, a publishing platform on Next.js and PostgreSQL, run alone in production behind a 16-point security review.
01Analog signal path

Amplifier Linearization with Learned Predistortion

UBC undergraduate research · Sept 2026 to present · in progress, no measured results yet

Stage under testLTC6078 op amp, 10 V/V, diode clipped at ±1 V
Dominant distortioncubic (third harmonic)
Correctionpolynomial predistorter, coefficients fit in Python from DC sweeps
AdaptationSDR captures output, re-fits inverse model as temperature and load drift
Design targetthird-harmonic reduction of 10 dB
ToolsLTspice, Python, software-defined radio
x(t) predistortera1x + a3x³ amplifierLTC6078, clips loady(t)goal: y ≈ G·x further past the knee SDR capture re-fit coefficients
Fig. 1. Feed-forward inverse with a slow feedback re-fit. Dashed path is the adaptation loop.
  1. Input.The test signal, x(t). The amplifier's curve is measured first from DC sweep data, point by point, which is what the correction is fit against.
  2. Predistorter.A polynomial, a1x + a3x³, chosen to be the inverse of the amplifier's own curve. The coefficients are not derived by hand; they are fit in Python to the sweep data.
  3. Amplifier.An LTC6078 stage at 10 V/V, diode clipped at ±1 V. Past the knee it compresses, and the dominant error is the cubic term. The predistorter has already bent the input the other way.
  4. Output.y(t) should track G·x further into the knee than it would without correction. The design target is 10 dB less third harmonic. No measured number yet.
  5. SDR capture.A software-defined radio samples the real output, not the LTspice model. This is what makes the loop honest about temperature and load drift.
  6. Re-fit.The captured output goes back into the fitter, the coefficients update, and the predistorter tracks the amplifier as it drifts. This is the learned part.
Research log
  1. Project started. Amplifier stage chosen (LTC6078, 10 V/V, clipped at ±1 V). LTspice model built; DC sweep data collected; first polynomial fit in Python.
  2. SDR capture of the real output, then the re-fit loop. Third-harmonic measurement before and after correction goes here.

What this is. An amplifier is only linear up to a point. Push the input past that knee and the output no longer follows it, and the error shows up as harmonics, mostly the third. Predistortion means bending the input the opposite way first, so the amplifier's own curve straightens it back out. The interesting part is that the right bend changes as the amplifier warms up, so the correction has to be measured and re-fit rather than set once.

A diode-clipped op amp stage distorts once it passes its compression knee, and the dominant term is cubic. I am designing a polynomial predistortion stage that applies the inverse of that curve ahead of the amplifier so the chain stays linear further into the knee. The model lives in LTspice; the coefficients are fit in Python from DC sweep data rather than derived by hand.

Fixed coefficients drift with temperature and load, so the second half is an SDR feedback loop that captures the amplifier's actual output and re-fits the inverse with a learned predistorter. This entry gets numbers when the loop closes.

02Register transfer level

FaultLatchedPWM

Solo · 2026 · Verilog HDL on Tang Nano 20K FPGA

Functiondeterministic PWM motor controller with latched fault handling
State machineINIT, IDLE, RUN, FAULT, SAFE
Fault responseoutput held low, latched until operator reset
Config guardseparate module rejects out-of-range parameters at load
Flow completedsimulation, synthesis, place-and-route, physical board
INIT IDLE RUNany fault, 1 clk FAULToutput held low, latched operator reset onlySAFE
Fig. 2. No path returns from FAULT without an external reset; a transient cannot re-enable the drive.
  1. INIT.Power-up state. Registers load their defaults and the output is forced low before anything else runs.
  2. IDLE.Waiting for a valid configuration. A separate validation module checks period and duty against their ranges and refuses anything out of bounds, so bad settings never reach the driver.
  3. RUN.PWM is driving the motor. A combinational guard re-checks the parameters every clock cycle; this is the only state where the output can be high.
  4. FAULT.Any violation moves here on the next clock edge, one cycle. The output drops low and the state latches. There is no transition out of FAULT that firmware can trigger, because none was built.
  5. SAFE.Reached only after an external operator reset sequence. Verified in simulation, then in synthesis and place-and-route, then on the Tang Nano 20K board.

What this is. A PWM signal sets how hard a motor is driven. Most controllers check for faults in firmware, which is fine until the firmware itself is the thing that has gone wrong. Here the fault logic is in the FPGA fabric, one clock cycle from the output, and once it latches there is no software path to unlatch it. The point was to build the safety envelope in a place a bug cannot reach.

When a fault asserts, the output drops to a safe state and stays there until an operator resets it, so a transient glitch cannot quietly put the drive back in motion. A separate configuration-validation module rejects out-of-range parameters at load time rather than letting bad settings reach the driver stage. Carried through the complete flow, from simulation to a physical board.

Source →

03Architecture & toolchain

RISC-V Toolchain to Hardware Emulation Pipeline

Solo · 2025 · Bare-metal C, RISC-V assembly, gdb

Componentscross-compiler, bare-metal startup, cycle-accurate emulator
Pipeline5 stage, IF/ID/EX/MEM/WB, forwarding and stalling as separate modules
Throughput~1.0 IPC after hazard debugging
Validation25-program regression suite, C and assembly
Built inC

What this is. A processor pipeline works on several instructions at once, one per stage. That breaks when an instruction needs a value the previous one has not finished producing, called a hazard. Forwarding hands the value across early; stalling waits. I wrote the model in C so I could watch every stage every cycle, and wrote the compiler that feeds it so the test programs were real C, not hand-picked assembly.

Most of the work was hazard debugging, tracing execution cycle by cycle in gdb and comparing register state by hand, because a wrong value three instructions later usually originates several cycles earlier.

Source →

04Embedded & edge ML

Wildlife-Vehicle Collision Early Warning System

UBC undergraduate research · May 2026 to present · Python, YOLOv8, Raspberry Pi 5, Hailo-8L NPU

ModelYOLOv8n, fine-tuned; mAP50 0.823, mAP50-95 0.638
Dataset7 classes, 3,015 sourced, 2,860 after filtering, fixed-seed split
QuantizationINT8, 2,001-image calibration set, quantization-aware fine-tuning
Camera calibrationOpenCV checkerboard on the mounted unit, 1.34 px reprojection error
Range estimatethin-lens geometry fused with time-to-contact optical expansion
Deploymentsystemd service, self-recovering; cold boot to first detection ~45 s
Tests47 unit tests, run without hardware via simulation backend
cameraOpenCV calibrated YOLOv8n INT8 / Hailo-8L range estimatethin lens + time to contact alertGPIO / display systemdself-recovering
Fig. 3. Everything runs on the Pi. No cloud dependency.
  1. Camera.Mounted on the unit and calibrated in place with an OpenCV checkerboard: 1.34 px reprojection error. This replaced a placeholder focal length that every earlier distance number had silently depended on.
  2. Detector.YOLOv8n fine-tuned on a 7-class dataset I built (2,860 images after filtering), then quantized to INT8 with a 2,001-image calibration set and quantization-aware fine-tuning. The Hailo compiler refused the first export; the fix was explicit end-node parsing and a custom NMS config.
  3. Range.Two estimates fused conservatively: thin-lens geometry from the calibrated focal length, and time-to-contact from how fast the box grows frame to frame.
  4. Alert.Drives the warning output over GPIO and the I2C display. The display driver got retry and graceful degradation after the connector proved flaky.
  5. Service.The whole pipeline runs as a systemd unit that restarts itself. Verified by cold boot, detecting about 45 s after power-on with no manual steps. 47 unit tests run without the hardware through a simulation backend.

What this is. A camera on a roadside unit watches for animals and warns drivers. It has to run on a small board with no network, so the detection model is shrunk from floating point to 8-bit integers and moved onto a dedicated accelerator. Shrinking a model loses accuracy unless it is done carefully, which is what the calibration set and the quantization-aware fine-tuning are for. The rest of the work was making it survive real hardware: a service that comes back on its own after a power cut, and tests that run without the board attached.

The Hailo compiler refused the model. I traced it to an incompatible automatic postprocess-extraction step and rebuilt the export path with explicit end-node parsing and a custom NMS configuration rather than working around it. The camera calibration replaced a placeholder focal length that every prior distance measurement had silently depended on.

Bugs fixed on the real unit: a SIGTERM handler bypassed by a vendored library, a non-daemon thread that hung shutdown, a race between the alert thread and hardware cleanup (confirmed with a 20-trial stress test, fixed with a lock and idempotent teardown), a flaky I2C connector, and an apparent startup hang that was stdout block-buffering.

05Applied machine learning

AI-in-Farming: Crop Disease Classifier

Solo · 2025 · Python, TensorFlow, NumPy, pandas

What this is. A convolutional network that looks at a photo of a leaf and names the disease. The number that matters is test accuracy on images the model has never seen. Getting it up meant reading the confusion matrix to see which diseases the model mixed up and why, then changing the network in response, rather than re-running training with different knobs and hoping.

Taskcrop disease from leaf imagery, convolutional classifier
Dataset~15,000 images
Test accuracy92%
Methodconfusion analysis drove architecture changes, not blind hyperparameter search

Source →

06Production application

Janvani, Citizen Journalism Platform

Solo, live in production · 2026 to present · Next.js, TypeScript, Node.js, PostgreSQL, Redis

What it isverified student journalists publish, the public comments
StackReact and Next.js in TypeScript; REST on Node.js; PostgreSQL schema I designed and migrate; Redis
Security review16 points before launch; access-control flaw and stored secrets found and fixed
Rate limitingRedis-backed, built from the same review to close the class of problem
DeliveryGitHub Actions CI, Sentry in production
Team1

What this is. A publishing platform for verified student journalists, built and run by one person. The part I would point a reviewer at is not the feature list but the security review: before launch I went through sixteen ways the site could be abused and found two real ones. Fixing the instance is easy; the rate limiter exists because I wanted the whole category closed.

The access-control flaw let a signed-in user reach another user's records through a predictable API route. An LLM API is integrated as a production feature, not a demo. When something breaks I read the logs, reproduce it, and write the test that should have caught it.

Live site →

Experience
May 2026 to present

Undergraduate Research Assistant

University of British Columbia · Kelowna, BC

Two projects under the same supervisor. First, an edge ML detection pipeline owned end to end, from dataset construction through INT8 deployment on an NPU to a self-recovering unit. Second, from September 2026, analog amplifier linearization: a polynomial predistortion stage modelled in LTspice with coefficients fit in Python, and an SDR feedback loop with a learned predistorter that tracks drift.

2026 to present

Founder and Sole Developer

Janvani · live in production

Design, build, secure, deploy, and support a production web platform without a team. Every issue that surfaces in production escalates to me.

Jul 2025 to present

Sales Advisor

Best Buy Canada · Kelowna, BC

Diagnose customer hardware and software problems across 20+ consultations a day and explain cause and fix in plain language to people with no technical background.

Nov 2023 to Dec 2024

Founder

The StoreNinja · New Delhi, India

Ran an e-commerce operation across 200+ products solo for 14 months, coordinating vendors and delivery timelines and setting prices from margin data.

Toolkit
Languages
C, Python, TypeScript, JavaScript, Java, SQL, Bash, Verilog HDL, RISC-V assembly
Systems, hardware
Embedded Linux, systemd, UART / I2C / SPI / GPIO, FPGA design flow, LTspice, software-defined radio, Raspberry Pi, Arduino, gdb, GCC cross-compiler
Machine learning
TensorFlow, YOLOv8, OpenCV, INT8 quantization, Hailo Dataflow Compiler, model evaluation, LLM API integration
Web, data
React, Next.js, Node.js, Flask, REST APIs, PostgreSQL, Redis, schema design and migrations
Practice
Git, GitHub Actions CI/CD, automated testing with simulation backends, security review, root cause analysis, technical documentation, Claude Code and Copilot as daily coding agents
Education
B.A.Sc. Computer Engineering, UBC, expected May 2029. Fall 2026: Microcomputer Engineering, Microelectronics I, Linear Circuit Theory, Industrial Automation. Data Structures and Algorithms in Java. OpenCV University certificate, 2026.
Contact

Looking for co-op terms starting January 2027, 4 to 16 months, anywhere in Canada. Embedded, firmware, test and verification, edge ML, or full-stack. Canadian permanent resident. I reply within two days.

Email me Resume (PDF)