Blog Summary: 2020

You can’t make up results like this for a techie kind of blog:

Blog Top Post Summary - 2020-12-31
Blog Top Post Summary – 2020-12-31

Given my demographic cohort, bedbugs suddenly seemed downright friendly.

Overall, this blog had 109 k visitors and 204 k page views. The ratio of 1.8 pages / visitor has been roughly constant for the last few years, so I assume most folks find one more interesting post before wandering off.

My take from the increasing volume of ads WordPress shovels at those of you who (foolishly) aren’t using an ad blocker continues to fall:

Blog Ad Summary - 2020-12-31
Blog Ad Summary – 2020-12-31

The CPM graph scale seems deliberately scrunched, but the value now ticks along at 25¢ / thousand impressions, adding up to perhaps $250 over the full year. Obviously, I’m not in this for the money.

The ratio of five ads per page view remains more or less constant. Because Google continues to neuter Chrome’s ad blocking ability, I highly recommend using Firefox with uBlock Origin.

WordPress gives me no control over which ads they serve, nor where they put ads on the page. By paying WordPress about $50 / year I could turn off all their ads and convert the blog into a dead loss. I’m nearing their 3 GB limit for media files on a “free” blog, so the calculation may change late next year.

Onward, into Year Two …

Straightening Armature Wire

Although I was blithely unaware when I bought some useful-looking surplus, it turns out 1/16 inch armature wire works really well to seal our homebrew masks around our noses. Mary added a narrow passage along the top edge of her slightly reshaped Fu Mask pattern to retain the wire and I provided 4.5 inch lengths of straightened wire:

Armature wire - stock vs. straightened
Armature wire – stock vs. straightened

The wire comes off the roll in dead-soft condition, so I can straighten (and slightly harden) it by simply rolling each wire with eight fingertips across the battered cutting board. The slightly wavy wire shows its as-cut condition and the three straight ones are ready for their masks.

Although nearly pure aluminum wire doesn’t work-harden quickly, half a year of mask duty definitely takes its toll. This sample came from my biking mask after the edges wore out:

Armature wire - work-hardened
Armature wire – work-hardened

We initially thought using two wires would provide a better fit, but more metal just made adjusting the nose seal more difficult after each washing. The wire has work-hardened enough to make the sharper bends pretty much permanent; they can be further bent, but no longer roll out under finger pressure.

Although we’re not yet at the point where we must reuse wires, I took this as an opportunity to improve my annealing hand: heat the wire almost to its melting point, hold it there for a few seconds, then let it cool slowly. The usual technique involves covering the aluminum with something like hand soap or permanent marker ink, heat until the soap / marker burns away, then let it air-cool. Unlike steel, there’s no need for quenching or tempering.

Blue Sharpie worked surprisingly well with a propane torch:

Armature wire - annealed straightened
Armature wire – annealed straightened

As far as I can tell after a few attempts, the pigment vanishes just below the annealing temperature and requires another pass to reach the right temperature. Sweep the flame steadily, don’t pause, and don’t hold the wire over anything melt-able.

Those wires (I cut the doubled wire apart) aren’t quite as soft as the original stock, but they rolled straight and are certainly good enough for our simple needs; they’re back in the Basement Laboratory Warehouse for future (re)use.

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.

COVID-19: The New Face of Bicycling

Eastbound on the Walkway Over the Hudson, which asks everyone to mask up:

The New Face of Bicycling - Ed masked - 2020-05-21
The New Face of Bicycling – Ed masked – 2020-05-21

Homebrew cloth masks mostly protect you, not me, but they’re still a reasonable way to tamp down the infection rate.

You’d (well, I’d) like to know the population infection rate, but we don’t have enough random testing to justify a number. Current testing remains biased toward those most likely to be infected, so the 15% cumulative rate (total positive / total tested) is certainly a gross overestimate and the 4% daily rate (new positive today / tested today) is still biased upward..

We figure the real population rate is well under 4%, which means we don’t encounter many infected folks out there.

But even 4% means staying isolated is the only way to prevent another wave of infection and another 23,000 deaths (in NY). The Mid-Hudson region has yet to meet all the state criteria for “restarting”, although Dutchess County has recently become ready, so we’ll be continuing all our usual at-home activities.

A number of state are now “opening up” without worrying about the details. Because exponential growth starts very slowly and the dying begins three weeks after the infections, the CNN charts (near the bottom of the page) will be revealing; we’ll witness several large-scale epidemiology experiments in real time over the next few months.

We have enough data to know anybody in and beyond our age bracket has plenty to worry about.

I think if any single action other than a virus killed 100,000 US citizens in three months, there wouldn’t be nearly as much discussion about the correct response. On the other paw, COVID-19 still runs a little under the rate for heart disease, so it seems we can get used to dying, even in bulk, when we do it long enough.

Gosling Time

The Dutchess Rail Trail has gotten far more use in recent months than ever before, with entire families walking along the path:

Canada Geese Families on the Rail Trail - 2020-05-08
Canada Geese Families on the Rail Trail – 2020-05-08

Almost by definition, though, goslings don’t practice social distancing …

COVID-19: Elephant Tracks

Getting a post mentioned on Reddit causes a traffic spike:

Elephant Sighting - Reddit traffic spike
Elephant Sighting – Reddit traffic spike

It’s nothing like the bedbug impulse, though …

The bulk of the subsequent increase comes from the Fu Mask Templates, although I suspect folks aren’t looking for 3D printed stuff.

As far as my original predictions go, I’m pleased to be somewhat wrong, as the most recent data shows the effect of handwashing, distancing, and general paranoia:

COVID-19 - USA Total Cases and Total Deaths - 2020-04-08
COVID-19 – USA Total Cases and Total Deaths – 2020-04-08

The lowered slope in the Total Cases curve means the cases now increase by a factor of ten every 20 days, rather than every eight, which is a major improvement. Still, it implies whatever seems bad right now will be only 10% of the badness in three weeks.

Folks with better models than my ruler make better predictions:

They assume “full social distancing through May 2020” and, apparently, the virus vanishing thereafter.

The colored area represents the 95% uncertainty range. Among other things, we don’t know what will happen when the (unknown number of) currently infected people need (far) more medical care / equipment / resources than we have available (“open image in new tab” for more dots):

Hospital Resources - healthdata.org projection - 2020-04-09
Hospital Resources – healthdata.org projection – 2020-04-09

Given our somewhat … erratic … national leadership, keeping everybody tucked in and the economy turned off for any substantial duration seems unlikely, but there’s no other way to reduce the death toll. The vast majority of the population will not have been exposed to COVID-19 and will, therefore, remain vulnerable to any (infected-but-asymptomatic, thus untested) people arriving from other counties / states / countries.

You know what to do: stay home and wash your hands. You’re buying time for the medical folks to catch up with the situation.

Fu Mask Cutting Templates

A local hospital contacted Mary’s quilting group to sew up cloth covers to prolong the life of their medical-grade N95 masks. Their recommended pattern, the Fu Face Mask from the FreeSewing group, comes in three sizes:

Freesewing - Fu Mask
Freesewing – Fu Mask

N.B.: Use their original PDF, because a JPG picture probably won’t come out at the right size.

Also N.B.: Used by itself, this is not a medical-grade filter mask.

The patterns do not include the usual 1/4 inch seam allowance around the outside, so I cranked out 3D printed plastic cutting templates.

If you’re not interested in 3D printing, 2D print the PDF file on cardboard, sketch a seam allowance, and cut it out, as quilters have been doing since slightly after home printers happened.

The plan of attack:

  • Convert mask outlines into a bitmap image (GIMP)
  • Create Bezier curves by tracing outlines (Inkscape)
  • Save curves as SVG files
  • Convert SVG into solid model (OpenSCAD)
  • Add stiffening ribs &c
  • Save as STL solid model
  • Slice into G-Code file (Slic3r)
  • Fire the M2!

So, we begin …

Import the PDF into The GIMP, delete the text & suchlike, convert to monochrome, and save the pattern outlines as a PNG file:

Fu Facemask - outlines
Fu Facemask – outlines

It turns out Inkscape can directly import the PDF, but it valiantly tries to convert all the text and the incidental graphic elements, none of which will be useful in this situation. It’s easier to delete them in The GIMP and make a bank shot off a PNG file.

Update: Scruss’s comment provides a much simpler workflow!

Import the PNG into Inkscape and trace one outline with the Bezier curve tool:

Fu Mask - Inkscape Bezier trace
Fu Mask – Inkscape Bezier trace

If you squint really carefully, you’ll see Bezier control handles sticking out of the nodes. I laid three nodes along the top arc and four along the right side, but do what’cha like; the Insert key or Shift+I inserts and Delete removes nodes. It’s easier to center a node in the middle of the PNG line with snapping turned off: Shift+drag while mousing or globally with #.

You could unleash the bitmap auto-tracer, but it generates a bazillion uselessly tiny Bezier curves.

When you’re happy, select and copy the path with Ctrl+C, paste it into a shiny new Inkscape document (Ctrl+N) with Ctrl-V, save it with a catchy file name like Fu Mask - Small - nominal.svg, and close that document to return to the document with the PNG outlines and the original path.

Select the original path again, create a dynamic offset with Ctrl+J, open the XML editor with Ctrl+Shift+X (which automagically selects the proper SVG element), and change the inkscape:radius value from 0 to 6.35 (mm, which everyone should use) to get a 1/4 inch seam allowance:

Fu Mask - Inkscape XML Editor - Offset radius
Fu Mask – Inkscape XML Editor – Offset radius

The path will puff out with curved corners:

Fu Mask - Inkscape offset
Fu Mask – Inkscape offset

Copy into a new document, save as Fu Mask - Small - seam allowance.svg, and close.

Repeat that process for each of the three mask sizes to create three pairs of SVG files: the nominal mask outline and the corresponding seam allowance outline for each size.

The OpenSCAD program imports the SVG files, removes the nominal outline from within the seam allowance to leave the outline, adds stiffening ribs, and stamps an ID letter on both sides of the central button:

Fu Mask Cutting Template - Small - solid model
Fu Mask Cutting Template – Small – solid model

Choose one of the three sizes with the OpenSCAD customizer, save the resulting model as an STL file, repeat for the three sizes, and you’re done.

This process can convert any outline paths in SVG files into cutting templates, so, should the Fu Mask not suit your fancy, Use The Source.

For convenience, the STL files are on Thingiverse.

From the comments, a Washington hospital uses a similar pattern: their PDF with assembly instructions.

The OpenSCAD source code as a GitHub Gist:

// Fu Mask cutting templates
// Ed Nisley - KE4ZNU - 2020-03
// Mask patterns from:
// https://freesewing.org/blog/facemask-frenzy/
// More info on my blog:
// https://softsolder.com/2020/03/29/fu-mask-cutting-templates/
/* [Mask Size] */
Name = "Small"; // [Small, Medium, Large, Test]
/* [Hidden] */
Templates = [ // center ID letter and file name
["S","Small"],
["M","Medium"],
["L","Large"],
["T","Test"], // for whatever you like
];
T_ID = 0; // Template indexes
T_NAME = 1;
BarThick = 4.0; // template thickness
HubOD = 20.0; // center button diameter
// These should match slicer values
ThreadThick = 0.25;
ThreadWidth = 0.40;
Protrusion = 0.1; // make clean holes
//--- Build it
t = Templates[search([Name],Templates,1,1)[0]]; // find template index
Dir = "./";
FnOuter = str(Dir,"Fu Facemask - ",t[T_NAME]," - seam allowance.svg");
FnInner = str(Dir,"Fu Facemask - ",t[T_NAME]," - nominal.svg");
difference() {
linear_extrude(BarThick,convexity=5) {
intersection() {
import(FnOuter,center=true);
union() {
square([200.0,5.0],center=true); // horizontal bar
square([5.0,200.0],center=true); // vertical bar
}
}
circle(d=HubOD); // central button
difference() { // cutting template!
import(FnOuter,center=true);
import(FnInner,center=true);
}
}
translate([0,0,BarThick - ThreadThick]) // top ID recess
cylinder(d=HubOD - 6*ThreadWidth,h=ThreadThick + Protrusion);
translate([0,0,-Protrusion]) // bottom ID recess
cylinder(d=HubOD - 6*ThreadWidth,h=ThreadThick + Protrusion);
}
translate([0,0,2*BarThick/3]) // top ID
linear_extrude(height=BarThick/3,convexity=2)
text(text=t[T_ID],size=10,
font="Arial:style:Bold",halign="center",valign="center");
mirror([1,0,0]) // bottom ID
linear_extrude(height=BarThick/3,convexity=2)
text(text=t[T_ID],size=10,
font="Arial:style:Bold",halign="center",valign="center");

Verily, there’s nothing like a good new problem to take your mind off all your old problems …