# Apple Watch estimates

In the Rumor Roundup segment of this week’s episode of Upgrade (starts about 32 minutes in), Jason and Myke talk about the temperature sensor that’s expected—according to Mark Gurman—to appear on the next generation of Apple Watches. The sensor isn’t going to take the temperature of the air; it’s going to take the temperature of you through contact with your wrist. According to Gurman,

The body-temperature feature won’t give you a specific reading—like with a forehead or wrist thermometer—but it should be able to tell if it believes you have a fever. It could then recommend talking to your doctor or using a dedicated thermometer.

Myke wasn’t happy with this. He wanted the actual temperature. Jason’s argument was that Apple wouldn’t want to give its temperature measurement because it probably wouldn’t match the temperature you’d get with an oral thermometer. Apple can avoid complaints that the Watch’s temperature values are inaccurate by never giving you a specific value, but still provide useful information by tracking your temperature over a period of time and putting up warning whenever is gets unusually high or low.

Jason’s argument is persuasive. It’s true that Apple already uses the Watch to provide estimated values for certain health data and doesn’t seem to worry about backlash. But there’s a reason for that.

Because I was out for a morning walk while listening to Upgrade, the estimated value that came to mind was VO₂ max, which you can see in the Cardio Fitness section of the Health app. VO₂ max is your maximum volume rate of oxygen intake, normalized by your body mass. It’s expressed in milliliters per minute per kilogram, and Apple gives you the value to the nearest tenth.

The proper measurement of VO₂ max involves putting you on a treadmill or stationary bike, covering your face with a mask and hose to measures your oxygen intake, and making you run or pedal at increasing speed until your oxygen intake maxes out. This is known as cardiopulmonary exercise testing, or CPET. Because the Apple Watch can’t do CPET, it estimates your VO₂ max by tracking your speed and heart rate (and possibly some other things) during an outdoor walk or run and then applying some formula to the sensor readings.

What formula? I don’t know. I’m pretty sure it isn’t one of the formulas described in the Wikipedia article on VO₂ max, because if it were, Apple wouldn’t have bothered publishing a paper on the study it ran to develop its estimate.

Basically, Apple gathered a group of about 500 people, tracked their exertion during outdoor walks and runs with an Apple Watch, and periodically measured their VO₂ max via CPET. From this, they came up with a formula that fit the sensor data to the CPET results. Apple’s paper doesn’t tell us the formula, but it does give us a graph that shows how good the fit is.

The graph should have a 1:1 ratio, but we’ll ignore that.

With the formula developed through those 500 people, Apple then tested another 200 people to make sure the formula wasn’t super-specific to the original group. The scatter plot for this validation group looks pretty much like the one for the design group.

Presumably, Apple could do—and probably has done—a similar study to correlate properly measured body temperatures with the readings from the upcoming Watch’s temperature sensor. It could use that study to provide an actual temperature value instead of just a high/low warning.

But look at the spread of the data in those graphs. Given the limited information it’s working from, the VO₂ max estimate looks decent as a population average, but for individuals, the spread can’t be ignored. My Watch tells me I’m at about 40 ml/min/kg, but these graphs say I could be ±10 from that. That’s huge.

Which fits in with Jason’s argument. Despite the spread, Apple’s not really inviting criticism by giving a specific value for VO₂ max—it’s an obscure measurement, hard to check, and the people who are interested in it know perfectly well that the elementary data available to the Watch can’t be expected to provide a highly accurate estimate. But body temperature is both familiar to everyone and easily checked. Imagine how many “Tempgate” YouTube videos would appear with young white men in backward baseball caps waving their Watches and thermometers to the camera. “Yo, check this out! Not even close! Hit that bell!”

The thought of it makes me glad my Apple Watch doesn’t monitor blood pressure.

# Tail I lose

I’ve been using the tail command for about 25 years, so you might think I’d know something about it. But last week, as I was putting together a short shell script (not this one), I opened the man page for tail and learned something new. Two things, actually, which surprised me, as tail doesn’t really do that much.

In the following, assume we have a file called lines.txt with 15 lines of text that look like this:

Line 01
Line 02
Line 03
Line 04
Line 05
Line 06
Line 07
Line 08
Line 09
Line 10
Line 11
Line 12
Line 13
Line 14
Line 15


The first thing I learned had to do with the -n option. I’ve known forever that

tail -n 6 lines.txt


would return the last six lines:

Line 10
Line 11
Line 12
Line 13
Line 14
Line 15


I’ve also known that, for historical reasons, this can be shortened to

tail -6 lines.txt


These are probably the most common ways people use tail and are analogous to the most common ways we use head to get the first bunch of lines. I learned about tail after learning head and sort of assumed that tail was—apart from its -f option for following log files—just as elementary.1

But tail has a trick up its sleeve: if you give the numerical argument to the -n option a leading + sign, the output will start that many lines from the beginning of the file and continue to the end. Like this:

tail -n +6 lines.txt


returns

Line 06
Line 07
Line 08
Line 09
Line 10
Line 11
Line 12
Line 13
Line 14
Line 15


This is really useful. If I wanted to process a file that had 5 lines of header information that I needed to skip over, tail -n +6 would be perfect as the first process in a pipeline. Too bad I didn’t know that a couple of decades ago.

How does tail works if -n is given a negative argument? Just as if the argument were unsigned.

tail -n -6 lines.txt


returns

Line 10
Line 11
Line 12
Line 13
Line 14
Line 15


just like

tail -n 6 lines.txt


This is mathematically perverse, but it fits well in the context of tail. The normal use is to count back from the end of the file, so that’s what an unsigned argument does. Putting a sign in front of the argument is a directional signal, and it makes sense to use + when counting from the beginning of a file and - when counting from the end.

The second thing I learned is the -r option. When used with no other options, it reverses the file.

tail -r lines.txt


returns

Line 15
Line 14
Line 13
Line 12
Line 11
Line 10
Line 09
Line 08
Line 07
Line 06
Line 05
Line 04
Line 03
Line 02
Line 01


which works more or less like the tac command.2 Since tac doesn’t come with macOS, you can use tail -r as a replacement. I wouldn’t normally do this, since I have tac installed on my system (it’s part of the coreutils bundle in Homebrew), but it’s handy to have when writing a shell script—or a Shortcut or Keyboard Maestro macro—for someone who doesn’t feel comfortable installing command line tools.

You can combine -r with -n like this:

tail -r -n 6 lines.txt


returns

Line 15
Line 14
Line 13
Line 12
Line 11
Line 10


As you can see, the reversal takes place on the 6 lines extracted from the end of the file. It doesn’t reverse the lines and then take the last 6 after the reversal.

What about using the + with -r?

tail -r -n +6 lines.txt


returns

Line 15
Line 14
Line 13
Line 12
Line 11


To me, this result makes no sense. For consistency with the previous, non-signed, command, I would expect it to extract from Line 6 through the end and then reverse them.

The manual says

Additionally, this option [-r] changes the meaning of the -b, -c and -n options. When the -r option is specified, these options specify the number of bytes, lines or 512-byte blocks to display, instead of the bytes, lines or blocks from the beginning or end of the input from which to begin the display.

OK. That suggests the sign doesn’t matter, but clearly the sign does matter because we got different output when we included the +. My takeaway is to avoid using -n with -r.

By the way, the GNU version of tail—which, like tac is part of the coreutils bundle—bypasses this mess by simply having no -r option. I’m going to use this as my excuse for not knowing about -r. My formative Unix years were with Linux, which uses GNU utilities like the -rless tail. Because OS X/macOS is a descendant of BSD, its utilities are just a little different.

1. I’m ignoring here the ways that both head and tail have options for counting by bytes or 512-byte blocks instead of lines. I’ve always known about those options but can’t think of any time I’ve used them.

2. tac is cat spelled backwards.

# BBEdit, Tail Mode, and bbtail

A new version of BBEdit, 14.5, was released a couple of days ago, and the feature that caught my eye was Tail Mode. It’s a way of viewing a log file in a way that persistently updates as new text is added to the file. Lots of processes send information (errors, connections, etc.) to log files, and when you’re debugging code, it’s often very useful to be able to see the log file update in real time. That’s what Tail Mode is for.

macOS has the Console app for doing this, but I’ve never liked Console. There’s also the old-school way of using the “follow” option to the tail command in a Terminal window:

tail -f /var/log/system.log


It is this use of tail that gives Tail Mode its name.

What I like about Tail Mode is that it works like tail -f but by doing so in a BBEdit window, all my ingrained habits for searching and copying text will work, which they don’t in Terminal or iTerm.

To turn on Tail Mode, you can choose the menu item or bring up the Text Options window and check the Tail Mode box.

You can also set a file’s language to Log File, which will turn Tail Mode on without any other action from you. By default, files with a .log extension are opened with their language set to Log File and Tail Mode on.

Yesterday, Mark Gardner had a great idea:

Already emailed asking for a bbedit -f or bbtail command

Although I have a feeling Rich Siegel will soon have a bbtail command to go along with bbdiff and bbfind, I couldn’t wait. Here’s my combination shell script/AppleScript:

bash:
1:  #!/bin/zsh
2:
3:  # Get the absolute path to the file argument.
4:  f="$1:a" 5: 6: # Open the file in BBEdit and go to the end. By setting the source 7: # language to Log File, the Text Display will be set to Tail Mode. 8: # This works for BBEdit 14.5 and later. 9: osascript << OSAEND 10: tell application "BBEdit" 11: activate 12: open "$f"
13:    tell front text window
14:      set source language to "Log File"
15:      set lastChar to length of contents
16:      select character (lastChar + 1)
17:    end tell
18:  end tell
19:  OSAEND


I think the comments explain everything reasonably well. I’ll just link to the parts of the zsh user manual that cover the :a modifier used in Line 4 to expand the filename argument to its full absolute path and the << redirection that creates a here-document out of the AppleScript code between the OSAEND strings and feeds it to the osascript command.

As far as I can tell, BBEdit doesn’t have an AppleScript for setting Tail Mode directly, but by setting the language to Log File in Line 14, I achieve the same result.

I suppose I could have done this entirely in AppleScript with an on run routine, but I don’t know how to get an absolute path from a partial path in AppleScript.

# Watches and stages

Two announcements at WWDC are strongly connected in my mind: watchOS 9 not being available for the Series 3 Apple Watch and Stage Manager not being available for non-M1 iPads. The former got a raised eyebrow from most Apple pundits—after all, the Series 3 is currently for sale—but the consensus was “At least this will force Apple to pull the damned thing.” The latter has caused quite a ruckus, forcing Craig Federighi to go out and give interviews explaining Apple’s reasoning to angry customers with relatively new iPads.

From the start, the iPad has always maintained this extremely high standard for responsiveness and interactivity. That directness of interaction in that every app can respond to every touch instantaneously, as if you are touching the real thing underneath the screen.

This explanation—pre-M1 iPads just wouldn’t provide the wonderful touch experience Apple insists on and its customers expect—has not been accepted calmly. The best summary of opinions on the topic has been collected by Michael Tsai.1

At first glance, Apple’s exclusion of of Stage Manager from pre-M1 iPads seems consistent with its exclusion of watchOS 9 from Series 3 watches. I don’t think anyone asked Federighi about the Series 3 because it’s obvious to everyone that it’s just too old and too underpowered to keep up with watchOS 9.

But if I had been interviewing Federighi and he started going on about extremely high standards for responsiveness and interactivity, I would have held out my left arm and asked him about the responsiveness and interactivity of the Series 3 on my wrist. “Does this,” I would ask, “respond to every touch instantaneously, as if you are touching the real thing underneath the screen?”

You see, things have changed since my defense of the Series 3 back in September. I was still running watchOS 7 then and the experience—apart from OS updates—was perfectly fine. But a couple of months ago, I bit the bullet and went through the multi-hour experience to update to watchOS 8. I had read that watchOS 8 would make the pain of updates a thing of the past. What I had not read was that the occasional pain of long updates would be replaced by the daily pain of a watch that commonly takes a second or two to respond to taps and swipes—if it responds at all.2

So watchOS 8 basically did to my Apple Watch what Federighi says Stage Manager will do to older iPads. I guess that means I’m defending Apple’s Stage Manager decision. But it also means that stuff about extremely high standards for responsiveness is bullshit.

1. I could add that sentence to any post about a current Apple topic. But in this case Michael has exceeded his usual high standard.

2. There are some nice things about watchOS 8. Entering my passcode is actually faster than it used to be because that screen is as responsive as ever, and Apple finally realized there’s no need for an OK button; it can just log me in when I’ve tapped the last key of my passcode. It’s things like that that have kept me from scouring the internet for a way to revert to watchOS 7. But it’s a close balance.