The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Science

If you measure something often enough, it becomes science

  • NPN RGB Astable Multivibrator Timing Adjustment

    NPN RGB Astable Multivibrator Timing Adjustment

    Back in the beginning of July, I replaced the NP-BX1 battery in the RGB Piranha astable multivibrator with a 18650 lithium cell and a USB charge controller, then watched it blink for the next two weeks on the first charge:

    Astable - 10 11 12 uF tweak - 027
    Astable – 10 11 12 uF tweak – 027

    However, the blinks looked … odd and some poking around with a Tek current probe showed the red and blue astables had locked together, so they blinked in quick succession. Alas, I don’t have a scope shot to prove it.

    I built all three astables with the same parts, figuring the normal tolerance of electrolytic caps would make the astables run at slightly different rates, which they did at first.

    This being a prototype, I just soldered a 1 µF cap onto the blue channel’s existing 10 µF cap:

    Astable - 11 uF cap - detail
    Astable – 11 uF cap – detail

    You can barely make out the top of the additional 2.2 µF cap on the red channel, through the maze of components; now, they definitely have different periods.

    Aaaand the scope shot to prove it:

    Astable NPN - 10 11 12 uF tweak - 10 mA-div
    Astable NPN – 10 11 12 uF tweak – 10 mA-div

    The bottom trace shows the battery current at 10 mA/div. The first pulse, over on the left, has the red and blue LEDs firing in quick succession with some overlap, but they separate cleanly for their next pulses.

    You don’t want to build a battery-powered astable from NPN transistors, because the 8 mA current between blinks is murderously high. In round numbers, each of the three LEDs blinks twice a second for 30 ms at 20 mA, so they average 3.6 mA, less than half the current required to keep the astables running between blinks. Over the course of 14 days, the circuit drew 11.6 mA × 336 hr = 3900 mA·h until the protection circuit shut it down.

    The lead photo shows a harvested 18650 cell, but I started with a known-good Samsung 18650 cell rated at 2600 mA·h at a 0.2C = 520 mA rate to 2.75 V. It’s comforting to see more energy trickling out at a 0.005C rate!

    I must conjure a holder with contacts for an 18650 cell, support for a trio of 2N7000 MOSFET astables, and some kind of weird spider with the RGB Piranha LED on the top. Even a harvested 18650 cell should last a couple of months with a much longer blink period (500 ms is much too fast), less LED current (this one is shatteringly bright), and a lower average current.

    And, yeah, I’ve been misspelling “Piranha” for a while.

  • Quilting Hexagon Template Generator

    Quilting Hexagon Template Generator

    Mary took on the task of finishing a hexagonal quilt from pieced strips, only to discover she’ll need several more strips and the myriad triangles required to turn hexagons into strips. The as-built strips do not match any of the standard pattern sizes, which meant ordinary templates were unavailing. I offered to build a template matching the (average) as-built hexagons, plus a triangle template based on those dimensions.

    Wikipedia has useful summaries of hexagon and equilateral triangle geometry and equations.

    Quilters measure hexes based on their finished side length, so a “1 inch hex” has sides measuring 1 inch, with the seam allowance extending ¼ inch beyond the sides. It’s difficult to measure finished sides with sufficient accuracy, so we averaged the side-to-side distance across several hexes.

    Some thrashing around produced a quick-and-dirty check piece that matched (most of) the stack of un-sewn hexes:

    Quilting Hexagon Cutting Template
    Quilting Hexagon Cutting Template

    That one came from a knockoff of the circle template, after some cleanup & tweakage, but failed user testing for not withstanding the side force from the rotary cutter blade. The inside and outside dimensions were correct, however, so I could proceed with some confidence I understood the geometry.

    Both the pattern width (the side-to-side distance across the inside of the hex) and the seam allowance appearing in the Customizer appear in inches, because that’s how things get measured outside the Basement Laboratory & Fabrication Facility:

    FinishedWidthInch = 2.75;
    FinishedWidth = FinishedWidthInch * inch;
    
    SeamAllowanceInch = 0.25;
    SeamAllowance = SeamAllowanceInch * inch;

    You feed in one side-to-side measurement and all other hex dimensions get calculated from that number; quilters default to a ¼ inch seam allowance. Remember, standard quilt hexes are measured by their side length, so just buy some standard templates.

    This is one of the few times I’ve needed triangle graph paper:

    Hex Quilting Template - geometry doodles
    Hex Quilting Template – geometry doodles

    After I gave up trying to get it right on square-grid paper, of course.

    Solidifying those relations:

    Quilting Hex Template - build layout
    Quilting Hex Template – build layout

    Then math got real:

    Hex Quilting Templates - on strips
    Hex Quilting Templates – on strips

    Both templates have non-skid strips to keep the fabric in place while cutting:

    Hex Quilting Template - grip strips
    Hex Quilting Template – grip strips

    I should have embossed the size on each template, but this feels like a one-off project and YAGNI. Of course, that’s how I felt about the circle templates, so maybe next time I’ll get it right.

    As it turned out, Mary realized she needed a template for the two half-triangles at the end of each row:

    Quilting Hex Template - half-triangle
    Quilting Hex Template – half-triangle

    It’s half of the finished size of the equilateral triangle on the right, with seam allowance added all around. The test scrap of fabric on the left shows the stitching along the hypotenuse of the half-triangle, where it joins to the end-of-row hexagon. Ideally, you need two half-triangle templates, but Mary says it’s easier to cut the fabric from the back side than to keep track of two templates.

    The family portrait now has three members:

    Quilting Hex Template - family
    Quilting Hex Template – family

    The OpenSCAD source code as a GitHub Gist:

    // Quilting – Hexagon Templates
    // Ed Nisley KE4ZNU – July 2020
    // Reverse-engineered to repair a not-quite-standard hexagon quilt
    // Useful geometry:
    // https://en.wikipedia.org/wiki/Hexagon
    /* [Layout Options] */
    Layout = "Build"; // [Build, HexBuild, HexPlate, TriBuild, TriPlate, EndBuild, EndPlate]
    //——-
    //- Extrusion parameters must match reality!
    // Print with 2 shells
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleFinagle = 0.2;
    HoleFudge = 1.00;
    function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle;
    Protrusion = 0.1; // make holes end cleanly
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    inch = 25.4;
    //——-
    // Dimensions
    /* [Layout Options] */
    FinishedWidthInch = 2.75;
    FinishedWidth = FinishedWidthInch * inch;
    SeamAllowanceInch = 0.25;
    SeamAllowance = SeamAllowanceInch * inch;
    TemplateThick = 3.0;
    TriKnob = true;
    EndKnob = false;
    /* [Hidden] */
    FinishedSideInch = FinishedWidthInch/sqrt(3);
    FinishedSide = FinishedSideInch * inch;
    echo(str("Finished side: ",FinishedSideInch," inch"));
    CutWidth = FinishedWidth + 2*SeamAllowance;
    CutSide = CutWidth/sqrt(3);
    echo(str("Cut side: ",CutSide / inch," inch"));
    // Make polygon-circles circumscribe the target widths
    TemplateID = FinishedWidth / cos(180/6);
    TemplateOD = CutWidth / cos(180/6);
    /* [Hidden] */
    TriRadius = FinishedSide/sqrt(3);
    TriPoints = [[TriRadius,0],
    [TriRadius*cos(120),TriRadius*sin(120)],
    [TriRadius*cos(240),TriRadius*sin(240)]
    ];
    echo(str("TriPoints: ",TriPoints));
    EndPoints = [[TriRadius,0],
    [TriRadius*cos(120),TriRadius*sin(120)],
    [TriRadius*cos(120),0]
    ];
    echo(str("EndPoints: ",EndPoints));
    TipCutRadius = 2*(TriRadius + SeamAllowance); // circumscribing radius of tip cutter
    TipPoints = [[TipCutRadius,0],
    [TipCutRadius*cos(120),TipCutRadius*sin(120)],
    [TipCutRadius*cos(240),TipCutRadius*sin(240)]
    ];
    HandleHeight = 1 * inch;
    HandleLength = (TemplateID + TemplateOD)/2;
    HandleThick = IntegerMultiple(3.0,ThreadWidth);
    HandleSides = 12*4;
    StringDia = 4.0;
    StringHeight = 0.6*HandleHeight;
    DentDepth = HandleThick/4;
    DentDia = 15 * DentDepth;
    DentSphereRadius = (pow(DentDepth,2) + pow(DentDia,2)/4)/(2*DentDepth);
    KnobOD = 15.0; // Triangle handle
    KnobHeight = 20.0;
    //——-
    module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
    Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
    FixDia = Dia / cos(180/Sides);
    cylinder(r=HoleAdjust(FixDia)/2,h=Height,$fn=Sides);
    }
    //——-
    // Hex template
    module HexPlate() {
    difference() {
    cylinder(r=TemplateOD/2,h=TemplateThick,$fn=6);
    translate([0,0,-Protrusion])
    cylinder(r=TemplateID/2,h=(TemplateThick + 2*Protrusion),$fn=6);
    }
    for (i=[1:6/2])
    rotate(i*60)
    translate([0,0,TemplateThick/2])
    cube([HandleLength,HandleThick,TemplateThick],center=true);
    }
    module HexHandle() {
    difference() {
    rotate([90,0,0])
    scale([1,HandleHeight/(TemplateOD/2),1])
    rotate(180/HandleSides)
    cylinder(d=HandleLength,h=HandleThick,center=true,$fn=HandleSides);
    translate([0,0,-HandleHeight])
    cube([2*TemplateOD,2*TemplateOD,2*HandleHeight],center=true);
    translate([0,HandleThick,StringHeight])
    rotate([90,090,0])
    rotate(180/8)
    PolyCyl(StringDia,2*HandleThick,8);
    for (j=[-1,1]) {
    translate([0,j*(DentSphereRadius + HandleThick/2 – DentDepth),StringHeight])
    rotate(180/48)
    sphere(r=DentSphereRadius,$fn=48);
    }
    }
    }
    module HexTemplate() {
    HexPlate();
    HexHandle();
    }
    //——-
    // Triangle template
    module TriPlate() {
    linear_extrude(height=TemplateThick)
    intersection() {
    offset(delta=SeamAllowance) // basic cutting outline
    polygon(points=TriPoints);
    rotate(180)
    polygon(points=TipPoints);
    }
    }
    module TriTemplate() {
    union() {
    if (TriKnob)
    cylinder(d=KnobOD,h=KnobHeight,$fn=HandleSides);
    TriPlate();
    }
    }
    //——-
    // End piece template
    module EndPlate() {
    linear_extrude(height=TemplateThick)
    intersection() {
    offset(delta=SeamAllowance) // basic cutting outline
    polygon(points=EndPoints);
    rotate(180)
    polygon(points=TipPoints);
    }
    }
    module EndTemplate() {
    union() {
    if (EndKnob)
    translate([0,(TriRadius/2)*sin(30),0])
    cylinder(d=KnobOD,h=KnobHeight,$fn=HandleSides);
    EndPlate();
    }
    }
    //——-
    // Build it!
    if (Layout == "HexPlate")
    HexPlate();
    if (Layout == "HexBuild")
    HexTemplate();
    if (Layout == "TriPlate")
    TriPlate();
    if (Layout == "TriBuild")
    TriTemplate();
    if (Layout == "EndPlate")
    EndPlate();
    if (Layout == "EndBuild")
    EndTemplate();
    if (Layout == "Build") {
    translate([1.5*TriRadius,-TriRadius,0])
    rotate(180/6)
    TriTemplate();
    translate([-1.5*TriRadius,-TriRadius,0])
    rotate(180/6)
    EndTemplate();
    translate([0,TemplateOD/2,0])
    HexTemplate();
    }

  • Medium Turtle Teleportation: Rail Trail

    Medium Turtle Teleportation: Rail Trail

    Perhaps this is a relative of the tiny turtle I teleported two years ago in the same section of the Dutchess Rail Trail:

    Turtle Teleportation - DCRT near Lagrange Trailhead - 2020-06-19
    Turtle Teleportation – DCRT near Lagrange Trailhead – 2020-06-19

    Such fancy patterns!

    I’m pretty sure box turtles don’t grow fast enough for this to be the same one …

  • OXO Pepper Grinder: Inadvertent Abuse

    OXO Pepper Grinder: Inadvertent Abuse

    Being that type of guy, I’m reasonably sure I would not have bought what’s now clearly labeled as an OXO Radial Pepper Grinder for use as a salt mill:

    OXO Salt Mill - corrosion
    OXO Salt Mill – corrosion

    Mary recalls we got it at Target, back when one could go places and buy things, and I vaguely recall contemplating a wall of OXO gadgets. It’s been a while and I neglected to save the packaging for future reference.

    Obviously not stainless steel, but not lethal, so we’ll continue abusing it.

  • Spiders Discover Radio Astronomy

    Spiders Discover Radio Astronomy

    A view of the middle of the Very Large Array of the National Radio Astronomy Observatory:

    A view of our back yard, one foggy morning:

    Sheet spider webs on lawn - 2020-06-29
    Sheet spider webs on lawn – 2020-06-29

    Coincidence? Ha!

  • Maple Samaras

    Maple Samaras

    Today I Learned that maple seed spinners are properly called samaras:

    Triple and Quad Maple Seeds
    Triple and Quad Maple Seeds

    The Norway Maple near the road produced a bumper crop of triples this year, along with the first quad spinner samara I’ve ever seen.

    Looks like the odds are ever in my favor

  • Monthly Science: COVID-19 Lagged CFR

    Monthly Science: COVID-19 Lagged CFR

    In round numbers, a nasty COVID-19 infection ramps up for a week before you develop enough symptoms to finally get tested. Various states report various combinations of test results as confirmed / probable / tested “cases”, with “tested” including any possible combination (or lack thereof) of viral / antibody presence. As a result, the number of “daily cases” doesn’t mean much, but it’s the only number we’re likely to get. With that in mind, about 6% of those tested have a positive result for whatever they’re being tested for. Got that?

    At some point within a week or two of being infected, tested, and found positive, about 2.8% of all cases will be hospitalized. That’s 2.4% of cases in the 18-49 age bracket and 4.3% of my decade (64-75):

    COVID-19-NET_Image - Weekly Hospitalizations - 2020-06-24
    COVID-19-NET_Image – Weekly Hospitalizations – 2020-06-24

    You get the Weekly Rate chart from the CDC’s weekly data by drilling into the Hospitalization block to reach the summary chart (through Additional Rate Data), dinking with the controls to show the Weekly Rate and COVID-NET Surveillance Area, then turning off the overlapping age ranges. Most of us seem to have an Underlying Medical Condition or two affecting the outcome.

    Roughly a week (more or less, kinda-sorta) after hospitalization, 15% of all patients and 28% of those over 65 will die:

    COVID-19 - Weekly Hospitalization Outcomes by Age - 2020-06-24
    COVID-19 – Weekly Hospitalization Outcomes by Age – 2020-06-24

    You get that chart from the Lab-Confirmed Hospitalizations page by dinking around with the controls for the lower-right pane. The Overall column represent 5800 patients and, as it happens, each column represents about 2000 patients.

    Because it takes about three weeks to go from “infected” to “dead”, the ratio of [daily deaths today] to [daily positive test results from three weeks earlier] gives (In My Opinion) a better indication of the expected outcome than the simpler ratio of [today’s deaths] to [today’s test positives]. Because the news headlines always feature cumulative numbers, these numbers aren’t at the tip of anyone’s awareness.

    Fetch the daily data as a CSV from the COVID Tracking Project’s Historical Data, compute the day-to-day values from the appropriate columns, then slam the columns into a graph:

    COVID-19 - Lagged Daily CFR - 2020-06-23
    COVID-19 – Lagged Daily CFR – 2020-06-23

    The strong weekly component is surely a combination of data aggregation (no weekend reports?) and actual death events (nobody dies on Sunday?), but there’s no way to know from here. There’s plenty of noise in April which I decided to completely ignore; consult the raw data and draw your own conclusion.

    Eyeballometrically, the lagged CFR has been declining linearly by 1% every 3 weeks since mid-May and should be around 2% in July. If you’re under 50 and in reasonable health, the news is even better, because you’re very unlikely to either need hospitalization or die from it. Again, work the numbers out for yourself from the raw data.

    However, AFAICT, those results depend on a relatively unloaded healthcare system, because little of the US has (yet) to experience the catastrophic overload seen during the early onset in Washington state and NYC. This chart of ICU occupancy suggests the worst is yet to come for folks in states where expectations don’t match up to the reality of exponential growth:

    COVID-19 - All-patient ICU occupancy - 2020-06-23
    COVID-19 – All-patient ICU occupancy – 2020-06-23

    It seems having the ICUs tick along at 50% occupancy is about right, so the states with 70+% occupancy don’t have much surge margin.

    Right now, COVID-19 is burning through the US population at about 30,000 confirmed new cases per day, which means 840 people will require hospitalization every day next week (in addition to all the usual hospitalizations for other causes) and, in another week, 126 people will die every day. Maybe 40 people under age 50 will die, so the human herd will develop immunity by killing off we Olde Fartes.

    After I ran those numbers, the rate passed 40,000 cases per day, with no sign of slowing down and indications it’s getting worse faster. Scale my numbers up by 30%: 1100 hospitalizations and 170 deaths per day in a few weeks.

    However, if you live in one of those dark purple states already showing 70+% ICU utilization, don’t do anything starting with “Hold my beer. Watch this!” because you will not get a welcoming Emergency Room reception. The CNN synoptic view of new cases continues to be informative.

    One of Mary’s cronies is married to a guy who knows this whole COVID-19 thing is a hoax: “They’d all have died of something else, anyway.” Plotting all-cause fatalities vs. age (2020 in red, last five years in gray) shows tens of thousands of people are dying from something new this year:

    All-cause deaths by age - current vs historical - 2020-06-26
    All-cause deaths by age – current vs historical – 2020-06-26

    Before you do the happy dance about the downward slope toward the right, read the disclaimer:

    Data are incomplete because of the lag in time between when the death occurred and when the death certificate is completed, submitted to NCHS and processed for reporting purposes. This delay can range from 1 week to 8 weeks or more, depending on the jurisdiction and cause of death.

    Some of the decline is real, because NYC hospitals aren’t running out of body bags nowadays, but much of it seems due to the paperwork not catching up with reality.

    Judging from the slope of the Johns Hopkins summary of daily cases in the US, corroborated by the CNN projections, the doubling time (before the most recent increases) runs around four weeks: five million cases by the end of July and ten million by the end of August. Later this year, we’ll know how well saying “It’ll be gone by April summer Election Day 2021″ without doing anything has worked out for us.

    The overall death rate should decline in a few years, because those (of us?) who died early will reduce the later rate, but it’s not something to look forward to.

    Back to the Basement Laboratory … and, on good days, the rail trail.