Really tired today, not counting as an official devlog. Just ran a bunch of tests today and got a bunch of values ill sort through tomorrow.
Really tired today, not counting as an official devlog. Just ran a bunch of tests today and got a bunch of values ill sort through tomorrow.
Devlog #7
Since my last devlog I have been teaching DEVSIM to run the same physics my own solver runs. Before this it was on a stripped down model set, so the two codes had similar geometry and nothing about mobility. Now it runs the real thing: doping dependent mobility, surface scattering at the oxide, velocity saturation, and proper Fermi-Dirac statistics.
Getting there meant three more small lies.
DEVSIM will easily chain a derivative through one kind of model and silently return zero for another. No error, no warning. My solver just diverged on the first step. It took a dump of every derivative on the device to see a column of exact zeros where numbers should have been.
Then a field magnitude written as a square root of a square. Mathematically, sounds good but numerically it produces a nan wherever the field is exactly zero, which in a neutral chunk of silicon is nearly every edge.
Then the surface mobility. I was refreshing it on every pass, forever. That is not a converging loop, that is two numbers chasing each other. The gate walk climbed to 0.50 V and then refused 0.55 V at every step size I gave it, down to a tenth of a millivolt. A failure that ignores step size is not a step size problem. I gave the refresh a stopping rule and re-ran it. Same answer to the last digit, just reachable now.
The 1 micron device now agrees between the two codes to under 3.3 percent at low drain and under 1.3 percent at high drain, across four decades of current.
The remaining blocker is not code. My browser is holding 15 of the machine’s 16 GB.
Devlog #6
Im not going to say much this devlog. I hate Github CI errors with a passion and everybody that creates software relates.
Devlog #5
Since the license was added, all my time has gone into one stubborn thing, that is getting DEVSIM simulator, to produce trustworthy MOSFET curves.
It has been a long journey of small lies the application tells you. DEVSIM’s solve doesn’t take a device argument, so it solves everything you’ve ever built in that process at once. I was building one device per curve and leaving them around, so the second curve was dragging a finished device along with it and ruining the shared error check. Deleting each device when its curve finishes fixed a whole family of weird failures.
Then I found the equilibrium solve was starting from all zeros, which on this device is 0.6 V off. I supply it from charge neutrality now. Same final output but far less trouble getting there.
2 of my own ideas turned out wrong and got reverted, but I wrote the measurements rather than dropping them. Capping the solver’s pass budget moved the current by 0.4%. Pinning the math library to one thread made a four second step take three minutes. Big Ouch.
Currently, the 1 micron transfer curve at 50 mV of drain runs end to end and confirms with my simulator to within 0.23% above threshold. The 1 V curve still stalls at 0.4 V of gate, and I checked it properly rather than simply loosening the tolerance, because it turns out DEVSIM isn’t converging there at all.
My own code, for contrast, does the same curve in 4.6 seconds.
Dev log #4
After the last devlog I pushed and CI went red on all three Python versions. One test, one solver that would not converge.
I guessed this before and fixed the wrong line. Last time I saw the residual and assumed a gate step was missing the convergence basin, so I put continuation on the gate ramp. That was a real improvement, just not this bug. This time I actually read the CI log
The failing solve was the one before the ramp even starts. Gate at zero, drain already at 1 V, starting from a cold guess. So I measured it instead of guessing. Cold at 0 V drain takes 1 step. At 1 V it takes 22, and 12 of those get clipped by the step limiter, which means the solver is being dragged the whole way instead of converging properly
The fix walks the bias in from zero using the continuation I already had. I regenerated the whole roll-off table through the new path and every digit came out identical. Only the path changed, not the answer.
Also added the Open-Source MIT license, and cleaned the commit history.
Dev log #3
I found a bug that made every 2D current in the simulator wrong by a factor of about 245, WAY too big.
The cause, i believe, was one missing conversion. The code turns an internal number into a real current, and in 2D that conversion needs an extra length factor that I never included. In 1D it happened to be right, which is why it went un-noticed.
I fixed it and then wrote a test that compares a 2D current against Ohm’s law, worked out by hand with no solver involved. This test was missing before.
The reassuring part: I measure the turn-on voltage two completely different ways. They used to differ by 180 mV, which I didnt pay much attention to previously. After the fix they agree to about 2 mV. I did not tune anything to make that happen, so I might have to start believing in miracles.
I also fixed two divide-by-zero crashes in the surface mobility code that were blocking a whole test combination.
Also updated the README numbers and the decisions log. The full test suite is still running, and I will push to github once done.
Devlog #2
Two things this stretch, and both started as “that’s odd” rather than “that’s broken.”
First, the solver was crawling. Every step up in voltage cost more than the last, and past a point it just gave up. I traced it back to the starting guess, which was asking what makes glass electrically neutral. That question has no answer, because glass has no charges to balance in the first place. The solver was grinding away at something stupid before it ever got to the real problem. I gave it a proper starting answer instead, and the slowdown disappeared entirely.
Second, I stopped trusting my tests and went to check them. I broke my own code ten different ways on purpose, one at a time, and watched to see which breakages the suite would catch. 9/10 failed, which is what I wanted. 1 slipped through clean, and that is the interesting one, because a test that cannot fail is not a test.
Chasing the one that got away turned up a real bug hiding underneath it. Setting the voltage on the bottom contact was silently doing nothing at all. The code ran, reported success, and ignored the value. One line to fix, and it would have been very hard to find any other way, since nothing about the output looked wrong.
Heads up! Light AI usage to debug the tests and break code to find errors
This is a 6-key macropad arranged in a 2x3 matrix, with a rotary encoder for analog-style control and a 0.91” OLED for live feedback. It is built on a custom PCB, with the Seeeduino XIAO RP2040 socketed on top. It runs QMK, so every key, layer, and encoder action is fully remappable, and you get access to the entire QMK feature set (layers, tap-dance, macros, combos.The whole thing is housed in a 3D printed case designed to hold the PCB, switches, encoder, OLED, and XIAO board in place.
DEVLOG : 7?
Since that last update, the cleanup turned into actual features.
I finished the frontend narrator pass. Every disclosure string, every physics note, every view intro is now plain prose instead of the app talking about itself in first person.
Then I went after the parts of the app that were just annoying to use.
Plots are zoomable now. Wheel to zoom, drag to pan, on all five analytic views. I also built a small notation layer so the ASCII the engine emits gets typeset properly at render time, subscripts and superscripts where they belong, without dragging in a whole math library.
The big one was mobile. The app used to just refuse to render below a certain width. Now it works down to 320px: a proper mobile shell, view tabs instead of a sidebar list, controls that collapse, and per-view width floors so nothing spills sideways. That took a lot of small fixes I did not expect, a fixed SVG viewBox that hid fixed-width text, and an overflow rule that was already scrolling the page sideways before I touched anything.
After that, the URL got a real history. Back and Forward actually work now, and moving between orbitals pushes a history entry while flipping a display toggle just replaces one. Added a copy-link button and keyboard shortcuts for stepping through n, l, m and switching views.
Last thing, the title is now just AtomSim. The tagline was doing nothing for anyone.
Devlog #5 or 6???
Since the site went live, most of the work has been cleanup rather than new physics.
The whole app used to talk in first person. Every explanation said “I compute this” or “what I’m showing you.” It read like the code was narrating itself, which was odd. So I went through the entire Python engine module by module and rewrote it in plain technical prose. That’s done.
Then I started on the frontend, which had way more of it. The disclosure text, the physics notes under each equation, the view intros. That’s still in progress.
there were 2 things I had to be extra careful about. Some of those strings are checked word-for-word by tests, so rewording one has potential to break complete the build by itself.
In addition, I also tidied the repo layout for public viewing, fixed a deploy pipeline failure, and added privacy-safe visitor counting.
Right now i’m cutting padding, and pitching it so a high schooler can follow it without boring a physics grad.
I think everything is ready to ship. I changed up a lot of things but i couldn’t record around 3 hours of it but that’s alright cause there were some recent hackatime issues.
Changed up the CAD and the whole BOM. I also added a 0-36V buck-boost converter for a variable voltage/current supply which I am pretty sure will be incredibly helpful with my bionic projects
Sourcing the CAD Files & Building the BOM
This stage was mostly about getting the physical side of RePSU figured out before moving further into the build.
I started by sourcing the CAD files for the enclosure and checking the different views to understand how everything would fit together. Having the enclosure laid out made it much easier to plan where the displays, banana sockets, buttons and other components would go.
Once the enclosure was taking shape, I started putting together the Bill of Materials (BOM). I went through each component needed for the build, recorded the quantity, found suitable parts, and added the approximate prices and purchase links. The current BOM includes the displays, banana sockets, fuses, buttons, fans, MOSFETs, and the 85W USB charger.
The estimated cost is around $35 USD, excluding the original ATX PSU and miscellaneous hardware.
This gives me a much clearer idea of what I actually need to source before starting the physical assembly.
I’m building a chip simulator from scratch. Today I got it to simulate a MOS capacitor, a silicon slab with a thin glass layer and a metal plate on top. It’s the heart of every transistor ever made.
What I built:
I stacked two grids together: a fine one near the silicon surface where all the action is, and a coarse one for the glass where nothing happens. Then I wrote one function that builds the whole sandwich.
I wrote every test before the code. This kind of maths loves to give you wrong answers that look perfectly reasonable, so I only trust it when it matches something I can work out on paper.
I’m happy that the “flatband” voltage came out exact to 15 decimal places. The threshold voltage matched the textbook to 0.13 millivolts, 50 times better than I needed.
I also identified a few problems; the solver was getting slower and slower at high voltage, then giving up. The starting guess was asking “what makes glass electrically neutral?”, a meaningless question, since glass has no charges. I gave it a proper answer instead and the slowdown vanished completely.
Then I deliberately broke my own code ten ways to check the tests would catch it. Nine got caught. One didn’t. Chasing that turned up a real bug: the bottom-contact voltage setting was silently doing nothing. One line to fix.
Current Position: 1339 tests passing, everything clean, C-V curve working across all three regimes.
Decided to build my own custom RP2040 board to learn hardware design. The RP2040 is awesome for this because it has incredible documentation.
I started by blocking out the schematic into logical chunks. The power supply needs to deliver both 3.3V and 1.1V, so I used an MCP1700 regulator and stacked up a dense bank of 0.1uF and 1uF decoupling capacitors to keep the power rails stable. For storage, I connected a 128Mb flash chip. I also integrated a USB-C connector and wired up a standard 12MHz crystal oscillator circuit to handle the clocking.
Moving from the schematic to the layout sort of tricky but we got there.
Hopefully everything runs
Dev log #5??
Ran a 20-item polish checklist over the site. Ten things were already fine: links all work, buttons all do something, the 404 page is real, errors show up properly.
Six items from the checklist were missing, so I built them.
Fixed the page titles. Every page was showing the same title because nothing reloads in a single-page app. Now a part page names the part, a search names what you searched.
Put a year in the footer, read live so it never goes stale. Dropped the “404 demo” link, that was a leftover dev thing sitting next to real links.
Then two actual bugs I only found by measuring in a browser at phone size. The home page really was scrolling sideways: a card grid was asking for 400px inside a 319px space. About had the same thing at 340px. Fixed both.
The header was the other one. It needed 390px of room for the logo and five links on a 375px phone. It had been wrapping onto three rows and leaving Contact stranded alone. Now the links tuck behind a menu button below 640px. Header went from 281px tall to 69px.
Last thing: the pages were too narrow and floated in empty space. Widened them a lot, 1600px for the main shell and 1400px for the text pages. Width alone would’ve just made long ugly lines, so the card grids reshaped too. FAQ goes two across, the three how-it-works steps share a row, the four-card grids go four across and step down cleanly.
Plus a few more minor changes, The project is built enough to be shipped!
Dev log #3 or #4??
After the site went multi-distributor, I kept going.
I added a contact page with my email, Instagram and GitHub, dropped GitHub out of the header, gave the footer real columns with links that work, moved the data source note over to the About page and wrote more there. The front page got more to read too, and the About cards now sit in a clean 2x2 grid.
Then I did a proper security pass. I added a middleware that stamps security headers on every API response, including CSP, frame options and HSTS. Wrote a rate limiter that reads the client IP from headers the platform actually writes, never the one a caller can fake, and capped its key table so the limiter itself cannot be turned into the attack. Added input caps: query at 200 characters, page at 50, part key at 128, all refused early so nobody can burn my distributor quota. Added a body size ceiling and tightened CORS.
The static site got its own CSP through vercel.json, checked against the real built bundle.
I also wrote guard tests: they fail if a stray .env gets committed, if a credential literal shows up in source, if SQL starts joining values instead of using placeholders, or if a Set-Cookie ever appears. Then I documented the whole posture in the backend README, including what I deliberately left out and why.
Started with a simple annoyance: finding a part that is actually in stock means opening six distributor tabs per line of a BOM. Wrote a throwaway script to poke at the free jlcsearch API and see what the data really looked like. Turned out it has no brand and no datasheet. Decided early to show that as blank rather than show wrong results.
Also built the backend. FastAPI, a swappable data source so the real LCSC API can drop in later.
Also tweaked the frontend a bit. React, inline styles, a loud yellow-and-black look. Then deploy configs, and the site went live on Render.
Implemented a price history recorder, so the data is there later even if nothing reads it yet.
The big addition. The site finally became multi-distributor: Mouser and DigiKey alongside LCSC. Every part now carries a list of offers, one per distributor, and a per-source status so a partial failure shows as a partial answer rather than an error.