Courses

Self-directed weekend courses aimed at one goal: becoming genuinely proficient, in both theory and practice, at digital signal processing for embedded software / firmware engineering. Course 1 is the mathematical foundation, worked by hand. Course 2 is the programming foundation, delivered as three 100-exercise GitHub repositories: modern embedded C for the firmware labs, modern C++ and CUDA for the rendering labs, and NumPy and PyTorch for the Python every lab prototypes in — solved one self-contained, test-checked file at a time. Course 3 is the bench: a fully lab-based course that spends that math and those languages building and measuring real-time DSP on real hardware; Course 1 is a mastered prerequisite for Course 3, its results applied there, never re-taught. Course 4 opens a second discipline on the same foundation: real-time rendering and GPU engineering — modern C++20, Vulkan, and Metal — taught the same way, fully lab-based, with Course 1’s mathematics applied rather than re-taught and a profiler open on every lab.

Weekend rhythm: Saturday = reading + handwritten derivations (Course 1), a chapter of exercises from one of the repositories (Course 2), or breadboard build + first measurements (Course 3). Sunday = deeper measurement/firmware + analysis + a staff-level note reconciling predicted vs. measured.

Note on AI use: The Course 3 and Course 4 lab write-ups and the Course 1 booklet’s teaching text are drafted with AI assistance so every page has a consistent structure. The substance is mine: every proof is worked by hand on paper first and converted to LaTeX/KaTeX using AI for typesetting only, and every circuit, measurement, and line of lab code is produced and debugged by me. The one disclosed exception is Course 2’s three exercise repositories, whose exercises are AI-drafted; I work through and correct them one at a time, with a dated status note in each README. The goal is to learn the material, which only happens by producing the proofs and building the labs myself.


Course 1 — Math Foundations for Signal Processing, Machine Learning, and Artificial Intelligence

A single self-contained booklet, Abridged Math Foundations for Signal Processing, Machine Learning, and Artificial Intelligence (337 pages): 70 lessons in 9 parts, dependency-ordered, the mathematical backbone under Course 3 and Course 4 — its final part is the rendering mathematics Course 4 applies; the applied signal-processing layer lives as theory sections inside the Course 3 labs. Each lesson: theory with definitions, theorems, and proofs; practice by hand on small examples; exercises tagged [Proof] and [Hand], worked by hand; and a deeper-reading pointer into the full textbooks, whose worked problem sets accumulate on the Books page.

→ Course page + booklet (PDF)

Part I · Lessons 1–7 — The Linear Algebra Core

Vectors and linear combinations; dot products, norms, and orthogonality; span, independence, basis, and dimension; matrices as linear maps; null space and rank; orthogonal projections and least squares; gradients.

Part II · Lessons 8–13 — Eigenstructure, the Spectral Theorem, the DFT, and the SVD

Complex vector spaces and complex exponentials; eigenvalues, eigenvectors, and diagonalization; self-adjoint operators and the spectral theorem; unitary matrices and the discrete Fourier transform; the singular value decomposition; determinants and trace.

Part III · Lessons 14–17 — The Probability Core

Probability models; counting — permutations, combinations, partitions; conditioning and Bayes’ rule; discrete and continuous random variables; functions of a random variable and the expected value rule; expectation and variance; joint distributions, functions of several random variables, and linearity of expectation; conditioning; the normal distribution.

Part IV · Lessons 18–23 — Random Vectors, Limit Theorems, and Stochastic Processes

Derived distributions, covariance, and correlation; conditional expectation and least-mean-squares estimation; random vectors and Gaussian vectors; limit theorems; the Bernoulli and Poisson processes; Markov chains.

Part V · Lessons 24–30 — The Signals-and-Systems Core

Signals and system properties; LTI systems and convolution; Fourier series; the continuous- and discrete-time Fourier transforms; frequency response and filtering; sampling and aliasing, and exact finite sampling of band-limited periodic signals by the DFT; Laplace and \(z\)-transforms.

Part VI · Lessons 31–43 — The Analysis Behind the Transforms

Sequences, series, and interchange of limits; metric spaces, continuity, and compactness; differentiation and the calculus theorems — the mean value theorem, L’Hôpital, Taylor — with the \(n\)-dimensional upgrade; the Riemann integral and the fundamental theorem of calculus; Lebesgue measure and integration and the swap theorems; Banach and Hilbert spaces, \(L^2\), and orthonormal bases; complex analysis — analytic functions, power series, and contour integrals, then zeros, poles, residues, and ROCs; the Fourier, Laplace, and \(z\)-transforms as operators, with the property tables proved; distributions and \(\delta\), Heisenberg’s inequality, and the Hilbert transform, the analytic signal, and causality; dual spaces, Riesz representation, and functional derivatives; numerical linear algebra — conditioning, stability, factorizations, and iteration; transforms of distributions — moment generating and characteristic functions, the Chernoff bound, and the central limit theorem with proof.

Part VII · Lessons 44–51 — Convex Optimization and Information Theory for ML, Signals, and Sensors

Convex sets, functions, and problems; regularized fitting and inverse problems; duality, KKT conditions, and certificates; gradient, Newton, and proximal algorithms; entropy, KL divergence, and mutual information; the asymptotic equipartition property and lossless compression; hypothesis testing, channels, and sensor information; rate–distortion, compression, and representation learning.

Part VIII · Lessons 52–62 — Neural Networks and Deep Learning

Feedforward networks, activations, and what depth buys; logits, softmax, and the losses maximum likelihood forces; logistic regression and kernel methods; the matrix and tensor calculus behind the derivations — outer products, Kronecker products, traces, and index notation; Jacobians, the chain rule, and backpropagation; vanishing and exploding gradients, initialization, normalization, and residual connections; convolutional networks — equivariance, receptive fields, and parameter sharing; recurrence, gating, and attention; autoencoders, variational autoencoders, and adversarial networks; risk, the bias–variance decomposition, and cross-validation; Monte Carlo, Metropolis–Hastings, and Gibbs sampling.

Part IX · Lessons 63–70 — The Mathematics of Real-Time Rendering

Points, vectors, and homogeneous coordinates — affine maps, the view matrix, perspective projection and its hyperbolic depth, reverse-Z; rotations — \(SO(3)\), Rodrigues’ formula, Euler angles and gimbal lock, quaternions and slerp; triangles, planes, and frusta — barycentric coordinates, edge functions, perspective-correct interpolation, frustum-plane extraction and culling, the geometry of shadow maps; radiometry and the rendering equation — the Lambertian \(1/\pi\), Blinn–Phong, Fresnel, and the Cook–Torrance microfacet model with GGX; integrating light — Monte Carlo shading, cosine and GGX importance sampling, the split sum, spherical harmonics, mipmapping as prefiltering; color — spectra as vectors, metamers, sRGB, high dynamic range, and tone mapping; Gaussian splatting — anisotropic Gaussians, their linearized projection, and alpha compositing; Fourier analysis in two dimensions — spatial frequency, the stretch theorem, sampling on a lattice and the dual lattice, when a texture lookup aliases, the 2-D DFT, and the projection–slice theorem.


Course 2 — Programming Foundations: Modern Embedded C, Modern C++ & CUDA, and NumPy & PyTorch

The programming prerequisite for the labs, delivered as three 100-exercise repositories on GitHub, each in the format of Mainmatter’s 100 exercises to learn Rust: one self-contained file per exercise that states a problem and tests the answer, a next command that runs the first unfinished exercise, and a reference solution to diff against. Each repository maps to the track that spends it — modern embedded C for Course 3’s firmware, modern C++ and CUDA for Course 4’s engine and kernels, NumPy and PyTorch for the Python every lab prototypes in. For these repositories only, the exercises are AI-generated; each README opens with a dated status note recording how much has been through my own hands.

→ Course page + repositories

100 exercises to learn modern embedded C

C17, the C of shipping firmware: 100 host exercises across fifteen chapters — objects and types, integers and bits, pointers and arrays, strings and memory, structs and unions, storage and linkage, the preprocessor, memory without malloc, errors and APIs, modules and test doubles, volatile and MMIO, interrupts and C11 atomics, state machines and time, and a capstone — run on the Mac under the sanitizers with an MCU’s budgets, then 15 more on the NUCLEO-L476RG’s bare metal, from linker script and startup code to interrupt-driven UART, ADC, DMA, and a watchdog soak test.

100 exercises to learn modern C++

C++20 in 100 exercises across thirteen chapters — ownership and RAII, classes and polymorphism, errors with optional and variant, containers, algorithms and ranges, templates and concepts, lambdas, concurrency with jthread and atomics, coroutines, and the modern standard library — then 25 more on modern CUDA C++: kernels, streams, coalescing, shared-memory tiling, warp shuffles, occupancy, Thrust/CUB/libcu++, CUDA graphs, and Nsight profiling on the RTX 4090 Linux desktop that Course 4 uses.

100 exercises to learn modern NumPy and PyTorch

NumPy 2 and PyTorch 2 in 100 exercises across fourteen chapters — arrays, broadcasting, views and memory, linear algebra and random numbers, structured data and I/O, the 1.x to 2.x migration, tensors, autograd, modules and the training loop, datasets and loaders, torch.compile and the profiler, debugging and testing, and a capstone character-level transformer — every test running on the CPU.


Course 3 — Embedded DSP: From the Bench to Real-Time Firmware

A fully lab-based course connecting the mathematics of Course 1 to working firmware and a real bench. Eight core modules plus two bonus modules (~46 labs), each predicted by hand, built on a breadboard, measured on real instruments (WANPTEK PSU, Fluke 117, Siglent 100 MHz scope, FNIRSI LCR meter, Saleae Logic 8), and driven from an STM32 Cortex-M4F.

→ Full Syllabus

Modules 0–2 · Bench, Scope, and Digital Timing

Power supplies, multimeters, and LCR measurement done safely and correctly. The oscilloscope: probe compensation, DC/ripple, and a first RC filter. Digital I/O and timing on the STM32: GPIO timing, timer-interrupt jitter, and UART decoding, all captured on the Saleae logic analyzer.

Modules 3–4 · Mixed-Signal I/O and Analog Conditioning

I²C bus bring-up, the MCP4725 DAC (voltage and waveform generation), the ADS1115 16-bit ADC, and safe 3.3 V ↔︎ 5 V level shifting. Then analog signal conditioning with the MCP6002 op-amp: voltage followers, non-inverting gain, clipping, and an active anti-alias low-pass filter.

Modules 5–7 · Acquisition, Real-Time DSP, and Robust Firmware

STM32 data acquisition: single-sample, timer-triggered, and DMA circular-buffer sampling, plus a live aliasing demonstration. Real-time DSP on the Cortex-M4F: FIR and IIR filters (with fixed-point stability), the FFT spectrum analyzer, PSD/noise-floor estimation, and Goertzel tone detection. Robust firmware: watchdog and fault handling, a FreeRTOS pipeline, and an end-to-end capstone.

Bonus Module 8 · Edge ML Signal Processing

The modern differentiator: learned DSP on edge accelerators. Real-time GPU spectrograms on the Jetson Orin Nano, an on-device keyword/tone classifier, a learned denoiser compared to the classical Wiener filter, vibration anomaly detection, and a latency/power benchmark across STM32 vs. Raspberry Pi 5 vs. Jetson.

Bonus Module 9 · Host-in-the-Loop Audio, Image & Video Processing

Real media, real files, verifiable results. The laptop streams a real audio/image/video file to the embedded target, which processes it in real time and streams it back for verification against a reference implementation: a WAV round-trip harness, streamed real-time audio filtering, STFT overlap-add effects, 2-D image convolution (blur/Sobel), and a real-time video-frame pipeline on the Pi 5 / Jetson.



Course 4 — Real-Time Rendering & GPU Engineering: Vulkan & Metal in Modern C++

A fully lab-based course (28 labs across 7 modules) that turns Course 1’s mathematics toward a second craft: real-time 3D rendering and GPU computing. Everything is built in modern C++20 with CMake and measured in a profiler: the graphics pipeline learned twice — every scene rendered through both Vulkan (C++) and Metal (Swift, then metal-cpp), on a Mac and a Linux desktop’s RTX 4090 (the CUDA compute foundations are worked beforehand in Course 2’s C++ repository) — an engine that grows from a cleared swapchain to a render graph with multithreaded command recording, the techniques modern renderers are made of (cascaded shadows, deferred shading on tile-based GPUs, terrain LOD and streaming, GPU-driven rendering, Gaussian splatting), and a dedicated performance-engineering module built on Tracy, Xcode GPU capture, RenderDoc, and Nsight. Capstone: a streaming 3D world viewer on two APIs and two GPUs, with a staff-level performance report.

→ Full Syllabus

Module 0 · Toolchain & GPU Bring-Up

A C++20/CMake project skeleton with profiling, benchmarks, and sanitizers wired in from the first commit; Vulkan and Metal brought up side by side to a cleared, animated swapchain — validation layers and a first GPU capture included. The GPU-compute foundations (CUDA kernels, the memory hierarchy, reductions and scans, streams, occupancy and the roofline) are assumed from Course 2’s C++ repository, not re-taught here.

Modules 2–3 · The Raster Pipeline & Shading

The graphics pipeline proper, every lab built twice — Vulkan/GLSL and Metal/MSL: pipelines and vertex input, transforms, depth and the camera (the coordinate-system differences worked, not footnoted), textures, samplers and mipmaps as applied sampling theory, and real glTF assets with honest alpha blending. Then the fragment shader earns its keep: Blinn–Phong in linear space, tangent-space normal mapping, physically based rendering with image-based lighting, and an HDR post stack — tone mapping and separable-Gaussian bloom.

Modules 4–5 · Engine Architecture & Advanced Techniques

From “a program that draws” to “an engine”: RAII resource lifetimes keyed to frames in flight, a minimal render graph that emits the barriers, a C++20 job system feeding multithreaded command recording, and a culled, instanced scene — one C++ core driving both APIs, with metal-cpp arriving as the second backend. Then the techniques a modern renderer is made of: cascaded shadow maps, deferred shading and its tile-memory variant on Apple GPUs, quadtree terrain with streaming and reverse-Z, GPU-driven culling with indirect draws, and a Gaussian-splat point renderer.

Modules 6–7 · Performance Engineering & the Capstone

The profilers become the subject: Tracy fluency and honest benchmarking, frame pacing, Metal GPU capture and counter-based limiter analysis, RenderDoc and timestamp queries on the Vulkan side, then a disciplined optimization ladder — overdraw, bandwidth, texture compression, perf-per-watt — run with before/after evidence. The capstone converges everything: a streaming 3D world viewer on two APIs and two GPUs, benchmarked on a deterministic flight path, closed out with a staff-level performance report in which every claim traces to a capture.