A kind of large birdcage for something unusual

Birdcages are not always for medical devices - case in point here was for an industrial customer

Birdcage FDM Workbench

A finite-difference playground for MRI-style birdcage coils
San Diego, CA, USA · gregory.durnan@gmail.com · durnan.org

Downloads

Birdcage FDM Workbench screenshot

This little workbench started life in the most dangerous of places: an Excel spreadsheet that “looked right” until the physics politely disagreed. What you’ll find here is the cleaned-up, Java-based evolution of that experiment: a finite-difference model of a 2D birdcage coil, solving for the magnetic vector potential and visualizing the resulting B fields in several ways.

From Spreadsheet to Workbench

The original model was a scalar-potential FDM in Excel. It was a great sandbox, but it quietly assumed an electrostatic world: charges, not currents; gradients, not curls. Once the goal shifted to modeling an MRI-style birdcage coil, the physics demanded an upgrade:

The result is this Birdcage FDM Workbench: a 1000×1000 grid, adjustable birdcage diameter and rung count, multiple visualizations, and just enough UI polish to make it fun to poke at.

Theoretical Background – Finite Differences in a Birdcage

1. The core PDEs

Electric (scalar) formulation:

∇²φ = -ρ / ε
E = -∇φ
  

Magnetic (vector) formulation (used here):

∇²A = -μ₀ J
B = ∇ × A
  

In this workbench we assume a 2D cross-section with currents flowing along z, so only Az(x, y) is non-zero. That collapses the vector Poisson equation into a scalar Poisson equation in Az, but the physics is still magnetic: the sources are currents, not charges, and the field we care about is B, not E.

2. Discretizing the Laplacian

On a uniform grid with spacing Δx = Δy = DX, the 2D Laplacian becomes:

∇²A_z(i,j) ≈ [A_z(i+1,j) + A_z(i-1,j) + A_z(i,j+1) + A_z(i,j-1) - 4 A_z(i,j)] / DX²
  

The discrete Poisson equation at each interior node is:

A_z(i+1,j) + A_z(i-1,j) + A_z(i,j+1) + A_z(i,j-1) - 4 A_z(i,j) = -μ₀ J_z(i,j) DX²
  

We solve this iteratively using SOR (Successive Over-Relaxation), updating Az until it settles into a self-consistent solution that satisfies the PDE and the boundary conditions.

3. From Az to B and |B|

With only Az non-zero, the magnetic field is:

B_x = ∂A_z / ∂y
B_y = -∂A_z / ∂x
  

Using central differences:

B_x(i,j) ≈ [A_z(i, j+1) - A_z(i, j-1)] / (2 DX)
B_y(i,j) ≈ -[A_z(i+1, j) - A_z(i-1, j)] / (2 DX)
|B|(i,j) = sqrt(B_x² + B_y²)
  

This is what you see in the |B| tab and the 3D |B| surface: the magnitude of the curl of Az, sampled across the grid.

Electric vs Magnetic FDM – What Really Changes?

Aspect Electric FDM (Scalar φ) Magnetic FDM (Vector A)
UnknownScalar potential φ(x, y)Vector potential A(x, y), here reduced to Az(x, y)
Source termCharge density ρCurrent density Jz along the rungs
Field recoveryE = -∇φ (gradient)B = ∇ × A (curl)
Typical boundariesDirichlet (fixed φ), Neumann (insulating)Neumann / absorbing (open space), sometimes Dirichlet on PECs
Geometry sensitivityCharges are points/volumesCurrents live on paths (rungs, loops)
Angular structureOften not criticalEssential – birdcage modes are cosine/sine around the ring
“Feels wrong” failure modePotential looks smooth but doesn’t match boundary physics|B| looks distorted by boundaries or wrong current phasing

Boundary Conditions, Nonlinearities, and “Why Is My Field So Weird?”

Neumann / ABC by folding the edges

A finite grid has edges; the real world doesn’t. If you simply clamp Az to zero at the boundary, you create an artificial conducting box that reflects fields back into the domain. The fix used here is a simple Neumann / absorbing boundary condition:

// top and bottom
Az[i][0] = Az[i][1];
Az[i][NY - 1] = Az[i][NY - 2];
// left and right
Az[0][j] = Az[1][j];
Az[NX - 1][j] = Az[NX - 2][j];
  

This “folds” the edges so the normal derivative is approximately zero, letting the field leave the domain without a dramatic bounce-back. It’s not a perfect ABC, but it’s simple, robust, and good enough for a birdcage playground.

Matrix size and the tyranny of boundaries

Early versions used a relatively small matrix. The birdcage looked fine, but the boundaries were so close that they warped the field in the center. The cure was simple but non-negotiable:

Once the coil is comfortably “inside” the domain, the center region behaves like free space and the |B| pattern finally looks like the physics textbooks promised.

Iterative solvers and the art of “try, fix, repeat”

The whole project is a nice reminder that finite-difference modeling is inherently iterative in two senses:

The first Excel version “worked” in the sense that it produced numbers and pretty colors. The Java workbench works in the sense that the fields are physically meaningful, stable, and interpretable. The gap between those two is where all the learning happened.

What the Workbench Shows You

You can change the number of rungs, adjust the birdcage diameter, switch color maps, export OFF geometry, and save PNGs of any view. Under the hood, it’s still just finite differences on a grid – but with enough knobs to make the physics visible and the trade-offs tangible.