diff --git a/IDEAS.md b/IDEAS.md index d705d5c..20fbb58 100644 --- a/IDEAS.md +++ b/IDEAS.md @@ -4,7 +4,7 @@ Working scratch list. Same format as the NLOS post: vanilla JS, 2D canvas, scene ## Electronics -- **How a transistor actually amplifies.** Draggable base current / gate voltage on a NMOS or NPN schematic, live I-V curve on the side, carrier flow animation in the channel or base region. Payoff: "small signal gain" stops being a formula and becomes something you can see. +- ~~**How a transistor actually amplifies.** Draggable base current / gate voltage on a NMOS or NPN schematic, live I-V curve on the side, carrier flow animation in the channel or base region. Payoff: "small signal gain" stops being a formula and becomes something you can see.~~ *Written 2026-04-23: [how-a-transistor-amplifies](/blog/how-a-transistor-amplifies/).* - **LC resonance from scratch.** Tank circuit with sliders for L, C, and drive frequency. Show the phasors rotating, impedance magnitude/phase sweeping, and a scope trace of voltage vs current. Payoff scene: pumping the tank at resonance and watching it ring. - **An oscillator starting up.** Colpitts or similar. Start from noise, show the limit cycle forming, let the reader nudge the loop gain and see it either die off or run away. - **Feedback loop stability.** Drag the poles and zeros around on the s-plane, watch the step response and the bode plot change. The moment a pole crosses into the right half plane and everything goes sideways. @@ -14,7 +14,7 @@ Working scratch list. Same format as the NLOS post: vanilla JS, 2D canvas, scene ## Computers / networking -- **A TCP connection, from the packets' perspective.** Client on the left, server on the right, sequence numbers and window sizes visible, user can introduce loss or latency and watch congestion control react. Slow start, fast recovery, the window collapsing on a single dropped packet. +- ~~**A TCP connection, from the packets' perspective.** Client on the left, server on the right, sequence numbers and window sizes visible, user can introduce loss or latency and watch congestion control react. Slow start, fast recovery, the window collapsing on a single dropped packet.~~ *Written 2026-04-27 (scheduled): [how-tcp-and-udp-work](/blog/how-tcp-and-udp-work/). Also covers UDP.* - **How DNS actually resolves a name.** Recursive resolver, root, TLD, authoritative, caching. User types a hostname, watches the queries fan out with their TTLs. - **What a CPU does per cycle.** A tiny toy ISA executing step by step. Pipeline stages, hazards, stalls. Adds a register renamer in a second scene and you get a decent intuition for why modern CPUs are fast. - **Cache coherence (MESI).** Two cores, a shared line of memory, user issues reads and writes, arrows show the invalidations flying around. The reason your "obviously correct" lock-free code isn't is usually on this graph somewhere. diff --git a/content/blog/how-a-transistor-amplifies.md b/content/blog/how-a-transistor-amplifies.md index aaba307..afb3573 100644 --- a/content/blog/how-a-transistor-amplifies.md +++ b/content/blog/how-a-transistor-amplifies.md @@ -20,7 +20,7 @@ A bipolar junction transistor is a three-terminal semiconductor device: a sandwi "N-type" and "p-type" are just two versions of silicon that have been doped with impurities to give them either a surplus of free electrons (n-type) or a surplus of the absence of free electrons, which solid-state physicists call *holes* and treat like positive charge carriers that move around independently. The *bipolar* in the name is an admission that both kinds of carriers end up doing useful work inside the device. Most semiconductor designs try to avoid that. The BJT embraces it. -The practical consequence is the behavior in the rest of this post: a small current flowing into the base lets a much larger current flow from the collector to the emitter. That is the whole trick, and once you accept that it happens, the amplifier parts follow. +The practical consequence is simple: a small current flowing into the base lets a much larger current flow from the collector to the emitter. That is the whole trick, and once you accept that it happens, the amplifier parts follow. ## A transistor is a valve @@ -76,7 +76,7 @@ The voltage gain of this common-emitter stage is then: A BJT biased at 2 mA with a 1 kΩ collector resistor has a transconductance of about 77 mA/V and a voltage gain of about 77. Run it at 5 mA and the gain climbs to around 190. Run it at 100 μA and you have a gain of about 4 and should probably consider a different amplifier topology. None of this depends on β, by the way, which is why a well-designed amplifier doesn't care very much that β varies from part to part. -Everything else, and there is a lot of *else*, is decoration on this core. Bypass capacitors, emitter degeneration, cascode stages, differential pairs, current mirrors, Darlingtons, bootstraps. They all exist to make the basic idea in this post more linear, more bandwidth-y, more stable with temperature, or less dependent on a specific transistor's specific quirks. But underneath the decoration there's still a valve controlling a current, and a resistor turning that current into a voltage, and the voltage is bigger than the one you started with. The rest is bookkeeping. +Everything else, and there is a lot of *else*, is decoration on this core. Bypass capacitors, emitter degeneration, cascode stages, differential pairs, current mirrors, Darlingtons, bootstraps. They all exist to make the basic idea above more linear, more bandwidth-y, more stable with temperature, or less dependent on a specific transistor's specific quirks. But underneath the decoration there's still a valve controlling a current, and a resistor turning that current into a voltage, and the voltage is bigger than the one you started with. The rest is bookkeeping. diff --git a/content/blog/how-tcp-and-udp-work.md b/content/blog/how-tcp-and-udp-work.md new file mode 100644 index 0000000..4f7873e --- /dev/null +++ b/content/blog/how-tcp-and-udp-work.md @@ -0,0 +1,79 @@ ++++ +title = "How TCP actually talks (and why UDP doesn't bother)" +date = 2026-04-27 +draft = false ++++ + + + +
+ +TCP and UDP are the two transport protocols that carry essentially all internet traffic that isn't doing something exotic. They live at the same layer, speak to the same lower-level IP plumbing, and have almost completely opposite personalities. + +TCP is a protocol that wants very badly to behave. It sets up connections, numbers every byte, acknowledges what it receives, retransmits what gets lost, slows down when the network complains, and eventually closes the connection neatly. If TCP were a person, it would arrive at meetings early and send a follow-up email. + +UDP is a protocol that has politely declined to do any of that. It takes a blob of data, wraps it in a tiny header, and throws it at the network. Whether it gets there is someone else's problem. If UDP were a person, it would be the one who texts "sent" without checking whether you got the message. + +Both are the right answer for different things, and the rest of what follows is an attempt to make it clear which is which, and why. + +## TCP opens with a handshake + +Before any data moves, TCP wants to establish that both ends exist, are talking to each other on purpose, and agree on where to start numbering. This takes three packets. + +
+ +The client sends a SYN with its chosen initial sequence number. The server replies with a SYN-ACK carrying its own sequence number and acknowledging the client's. The client sends one more ACK to confirm. Now both sides know each other is alive, and both sides know a starting byte number, and the connection is officially ESTABLISHED. If you have ever wondered why `curl` appears to hang for a beat before any bytes come back, this is part of what it's doing. + +Notice that no data moves during the handshake. These three packets are pure ceremony. That ceremony is also why TCP has measurable setup latency, which is a big deal if you're connecting to a server on the other side of the planet and your RTT is 300 ms. + +## Sequence numbers and ACKs keep things honest + +Once the connection is open, every byte sent over it has a sequence number. The receiver's job is to keep track of what it's got and tell the sender what it's expecting next. Those are the ACKs. If a segment gets lost, the receiver keeps asking for the byte it never saw, and the sender eventually figures out something is wrong and sends the missing segment again. + +
+ +Drag the slider through the loss scenarios. In the no-loss case ACKs march back one after another, each asking for the next byte. When a segment goes missing, the receiver keeps asking for the same byte over and over (duplicate ACKs), and the sender retransmits it. Cumulative ACKs mean a single "ack=5" implicitly confirms everything up to byte 4, which is why TCP can survive one lost ACK without restarting the world. + +The retransmission is how TCP keeps the "reliable" in "reliable byte stream." From the application's perspective, the bytes either show up in order or the connection dies. There is no "most of the bytes arrived." + +## A sliding window turns one pipe into many + +Sending one segment and then waiting for its ACK is absurdly slow over any network with real distance to cover. TCP instead allows multiple segments to be in flight at once, up to a window size, and only blocks when that window is full. + +
+ +Bigger window, more packets sitting on the wire at once, higher throughput. Halve the RTT and you halve the time to send a fixed amount of data even without changing the window. Double the window and you roughly double throughput, up to the point where some bottleneck in the network becomes the actual limit. The math here (throughput ≈ window / RTT) is the reason your 1 ms home LAN feels infinitely faster than your 150 ms satellite link, even though both technically support "gigabit." + +## Congestion control is TCP worrying about bandwidth + +TCP has no way of knowing, in advance, how much bandwidth is actually available on any given path. It finds out by experiment. It starts sending slowly, ramps up aggressively until something breaks, retreats, and then ramps up again. This cycle never stops for the life of the connection. + +
+ +The window grows exponentially during *slow start* (which despite the name is not slow, it's just starting small) until it reaches the *slow-start threshold*. After that it creeps up linearly, adding one segment per round trip. Eventually a packet gets dropped, which TCP interprets as the network saying "enough." The window is cut in half, the threshold is moved to the new value, and the cycle starts over. TCP is a protocol that lives its entire life anxious about whether it should be going faster. + +This is the source of the famous sawtooth pattern in any graph of TCP throughput over time. It is also why networks with high but variable delay (cellular, satellite, transoceanic) can be fairly miserable for TCP: every burst of delay looks like congestion, the window collapses, and throughput never really gets to stretch out. + +## UDP: the opposite approach + +Everything above exists to provide the illusion of a reliable, ordered byte stream on top of a network that guarantees neither. UDP exists for people who don't want that illusion, because they have a better idea of what to do with the occasional lost packet than the kernel does. + +
+ +Packets leave the sender. Some of them arrive. The ones that don't arrive are simply gone, and the sender has no idea anything went wrong. There are no ACKs, no retransmits, no sequence numbers that mean anything to the protocol itself, and no back-off. Applications that want any of those things build them on top. + +This is wonderful for the applications that benefit from not paying for TCP's services. Real-time voice and video are the classic cases: the receiver would rather glitch for 20 ms than hear a one-second gap while a lost packet gets retransmitted. DNS is another: the query and the response fit in single packets, timeouts are sub-second, and re-querying is cheaper than keeping a connection open. Game state updates are a third: a position that's a quarter-second late is worse than no position at all, because by the time it arrives it's wrong. + +## When you'd pick which + +**Reach for TCP when** you want bytes to arrive intact and in order, you can tolerate whatever latency that costs, and the application doesn't want to think about packets at all. HTTP, SMTP, SSH, file transfer, databases, most RPC frameworks. The default. + +**Reach for UDP when** late data is worse than lost data, when you care about the cost of a handshake, when you want to multicast to many recipients, or when you have a better reliability scheme than TCP's on top. Real-time media, DNS, NTP, SNMP, most online games, QUIC (which builds its own TCP-replacement on top of UDP specifically because UDP gets out of the way). + +Most of the modern protocols people hear about lately (HTTP/3, QUIC, WebRTC) are on UDP. That isn't because TCP has stopped being useful. It's because these protocols want control over exactly the parts of the stack that TCP does not let you touch: connection setup, head-of-line blocking, multiplexing. UDP is the way you get a blank sheet of paper where TCP would otherwise fill in the details for you. + +And if you find yourself staring at Wireshark wondering why a perfectly fine TCP connection is suddenly slow, there is a reasonable chance it is not slow at all, just anxiously deciding whether it should be going faster. + +
+ + diff --git a/content/blog/why-signals-bend.md b/content/blog/why-signals-bend.md index 6fb2481..b84fa96 100644 --- a/content/blog/why-signals-bend.md +++ b/content/blog/why-signals-bend.md @@ -20,7 +20,7 @@ Two antennas, flat ground, a hill in the middle. If the hill sticks above the li
-That model is how nearly every commercial point-to-point microwave link is designed. WISPs, utility SCADA, carrier backhaul, all of it. It hides two small lies that the rest of this post is mostly about. The Earth isn't flat, and the signal isn't a line. +That model is how nearly every commercial point-to-point microwave link is designed. WISPs, utility SCADA, carrier backhaul, all of it. It hides two small lies that the rest of what follows is mostly about. The Earth isn't flat, and the signal isn't a line. ## Earth gets in the way too @@ -72,9 +72,15 @@ The dashed line is the international standard atmosphere. Drag the slope and the A horizontal ray in a medium whose refractive index falls with altitude bends downward. The tighter the gradient, the tighter the curve. Under the standard atmosphere the bend is gentle, about a quarter of Earth's own curvature, and engineers handle this by quietly pretending the Earth is 4/3 its real size and the rays are straight. Nobody points out that this is a slightly strange thing to do. That's the familiar k = 4/3 factor. +The slider below is labeled **dN/dh**, which reads as "the change in N per unit of altitude." It's just the slope of the refractivity curve from the previous scene, in N-units per kilometer. If N drops from 315 at the surface to 275 at 1 km up, dN/dh is −40 N/km. That's the international standard atmosphere, and it's also the zero point for everything that follows. More negative numbers mean refractivity is falling *faster* with altitude, which is what bends rays harder: + +- **around −40 N/km**, standard. k ≈ 4/3, mildly bent rays, ordinary radio horizon. +- **below −79 N/km**, super-refraction. Rays bend meaningfully more than normal. A lot of VHF/UHF tropo propagation lives here. +- **below −157 N/km**, trapping. Rays curve tighter than the Earth itself curves away. The ray can't climb out anymore, and the atmosphere starts behaving less like an atmosphere and more like a waveguide. +
-Push the slope below −79 N/km and rays start bending faster than standard. A lot of VHF/UHF tropo propagation lives in that regime. Push below −157 N/km and rays curve tighter than the Earth curves away. The ray can't climb out anymore. +Drag dN/dh through those thresholds and watch the traced ray. Standard air, ray exits into space eventually. Super-refractive air, the ray stays close to the surface far longer. Trapping air, the ray never gets out at all, which is where the next scene picks up. ## The signal gets trapped diff --git a/static/js/tcpudp.js b/static/js/tcpudp.js new file mode 100644 index 0000000..b27a49c --- /dev/null +++ b/static/js/tcpudp.js @@ -0,0 +1,683 @@ +// TCP / UDP explainer. Vanilla JS + 2D canvas. +// Scoped to a single post via /