Advertisements

Sharing the Lane on Burnett Blvd. at Rt 55

When we get to the end of Overocker Road, we occupy the entire left-and-straight lane, because we’re turning left onto Burnett Blvd and there’s no room for another vehicle beside us:

Burnett at Rt 55 - Right pass - 2017-05-23 - 1

Burnett at Rt 55 – Right pass – 2017-05-23 – 1

I’m towing a trailer of groceries.

On Burnett Blvd, we take the left side of the right lane (marked for left-and-right turns), because we’re turning left onto Rt 55, don’t want to get right-hooked by right-on-red traffic, and will be on the right side of the right lane of Rt 55 when we’re through the turn.

Without turn signals, it’s not clear whether the car following us from Overocker will turn left or right, but the driver is snuggling up next to Mary:

Burnett at Rt 55 - Right pass - 2017-05-23 - 2

Burnett at Rt 55 – Right pass – 2017-05-23 – 2

The driver’s window is sliding downward. Fortunately, we started moving before any comments were made. Perhaps he was going tell us we’re riding cool bikes?

Ah-ha! The driver is turning left and intending to pass me on the right while we’re in the intersection:

Burnett at Rt 55 - Right pass - 2017-05-23 - 3

Burnett at Rt 55 – Right pass – 2017-05-23 – 3

Helmet mirror FTW!

I’m moving rightward across the turning lane to end up on the right side of the Rt 55 lane, while not riding across the steel manhole cover at the car’s front wheel:

Burnett at Rt 55 - Right pass - 2017-05-23 - 4

Burnett at Rt 55 – Right pass – 2017-05-23 – 4

Mary doesn’t accelerate nearly as hard as I do; those pictures are one second apart.

I’m un-leaning from the turn into Rt 55, with the trailer still on my left and the driver accelerating toward me:

Burnett at Rt 55 - Right pass - 2017-05-23 - 5

Burnett at Rt 55 – Right pass – 2017-05-23 – 5

A close pass, but not too bad:

Burnett at Rt 55 - Right pass - 2017-05-23 - 6

Burnett at Rt 55 – Right pass – 2017-05-23 – 6

Most of the time, our rides aren’t this interesting, but I have plenty of examples showing how NYS DOT’s road designs ignore cyclists. The Burnett intersection signals still give us four seconds to clear the intersection.

Advertisements

Leave a comment

Arduino vs. Significant Figures: Preliminary 64-bit Fixed Point Exercise

Although it’s not advertised, the Arduino / AVR compiler mostly does the right thing with long long = uint64_t variables: add & subtract work fine, but multiplication & division discard anything that doesn’t fit into 64 bits. Fitting a 32 bit integer and a 32 bit fraction into such a thing should eliminate (most) problems with significant figures.

The general idea is to set up a struct giving access to the two 32 bit halves for direct manipulation, then overlay / union them with a single 64 bit integer for arithmetic purposes:

struct ll_s {
  uint32_t low;
  uint32_t high;
};

union ll_u {
  uint64_t ll_64;
  struct ll_s ll_32;
};

Of course, the integer part still falls one bit shy of holding 2³². At the cost of one bit’s worth of resolution, you can still compute 2³² / 125×10⁶ by pre-dividing each quantity by 2:

2^63 = [80000000 00000000]
2^63 / 125/2 M = [00000022 5c17d04d]

The low-order digit should be 0xe, not 0xd, but I think that’s survivable.

Unfortunately, printf doesn’t handle 64 bit quantities, necessitating some awkward conversion routines. “Printing” to a string seems the least awful method, as I’ll eventually squirt the strings to a display, not send them to the serial port:

void PrintFractionLL(char *pBuffer,uint64_t *pLL) {
  uint64_t Fraction;

  Fraction = (uint32_t)*pLL;                      // copy 32 fraction bits, high order = 0
  Fraction *= ONEGIG;                             // times 10^9 for conversion
  Fraction >>= 32;                                // align integer part in low long
  sprintf(pBuffer,"%09lu",(uint32_t)Fraction);    // convert low long to decimal
}

void PrintIntegerLL(char *pBuffer,uint64_t *pLL) {
  sprintf(pBuffer,"%lu",*((uint32_t *)pLL+1));
}

void PrintDecimalLL(char *pBuffer,uint64_t *pLL) {
  PrintIntegerLL(pBuffer,pLL);
  pBuffer += strlen(pBuffer);       // pointer to end of integer part
  *pBuffer++ = '.';                 // drop in the decimal point, tick pointer
  PrintFractionLL(pBuffer,pLL);
}

The result seems nearly indistinguishable from the Right Answer:

Integer:  34
Fraction: 359738367
Decimal: 34.359738367

This whole mess has a bunch of rough edges, but it looks promising. The code coalesced while fiddling around, so the union notation didn’t get much love at first.

The Arduino source code as a GitHub Gist:

,

2 Comments

Arduino vs Significant Figures: Floating Point Calculations

Herewith, to nail down the reasons why you can’t (or, perhaps, shouldn’t) use Arduino float variables, a small collection of DDS-oid calculations.

Remember that float and double variable are both IEEE 754 single-precision floating point numbers:

Size of float: 4
       double: 4

The Arduino floating-point formatter gags on some values, although they calculate correctly:

2^24: 16777216.000
printf:        ?
2^32: ovf or ovf
2^32: ovf
2^32 / 256: 16777216.000

Don’t add values differing by more than seven orders of magnitude and suspect any results beyond the first half-dozen significant figures:

Oscillator steps: HzPerCt
 Oscillator: 125000000.00
 -25 -> 0.02910382461
 -24 -> 0.02910382461
 -23 -> 0.02910382461
 -22 -> 0.02910382461
 -21 -> 0.02910382461
 -20 -> 0.02910382747
 -19 -> 0.02910382747
 -18 -> 0.02910382747
 -17 -> 0.02910382747
 -16 -> 0.02910382747
 -15 -> 0.02910382747
 -14 -> 0.02910382747
 -13 -> 0.02910382747
 -12 -> 0.02910382747
 -11 -> 0.02910382747
 -10 -> 0.02910382747
  -9 -> 0.02910382747
  -8 -> 0.02910382747
  -7 -> 0.02910382747
  -6 -> 0.02910382747
  -5 -> 0.02910382747
  -4 -> 0.02910383033
  -3 -> 0.02910383033
  -2 -> 0.02910383033
  -1 -> 0.02910383033
  +0 -> 0.02910383033

The Arduino source code as a GitHub Gist:

,

3 Comments

DDS Musings: Arithmetic with 32-bit Fixed Point Numbers

Spoiler alert: having spent a while trying to fit the DDS calculations into fixed-point numbers stuffed into a single 32 bit unsigned long value, it’s just a whole bunch of nope.

The basic problem, as alluded to earlier, comes from calculations on numbers near 32768.0 and 60000.0 Hz, which require at least 6 significant digits. Indeed, 0.1 Hz at 60 kHz works out to 1.7 ppm, so anything around 0.05 Hz requires seven digits.

The motivation for fixed-point arithmetic, as alluded to earlier, comes from the amount of program memory and RAM blotted up by the BigNumber arbitrary precision arithmetic library, which seems like a much bigger hammer than necessary for this problem.

So, we begin.

Because the basic tuning increment works out to 0.0291 Hz, you can’t adjust the output frequency in nice, clean 0.01 Hz clicks. That doesn’t matter, as long as you know the actual frequency with some accuracy.

Setting up the DDS requires calculations involving numbers near 125.000000 MHz and 2³², both of which sport nine or ten significant figures, depending on how fussy you are about calibrating the actual oscillator frequency and how you go about doing it. Based on a sample of one AD8950 DDS board, the 125 MHz oscillator runs 300 to 400 Hz below its nominal 125 MHz: about 3 ppm low, with a -2.3 Hz/°C tempco responding to a breath. It’s obviously not stable enough for precise calibration, but even 1 ppm = 125 Hz chunks seem awkwardly large.

Many of the doodles below explore various ways to fit integer values up to 125 MHz and fractions down to 0.0291 Hz/count into fixed point numbers with 24 integer bits + 8 fraction bits, perhaps squeezed a few bits either way. Fairly obviously, at least in retrospect, it can’t possibly work: 125×10⁶ requires 28 bits. Worse, 8 fraction bits yield steps of 0.0039, so you start with crappy resolution.

The DDS tuning word is about 2×10⁶ for outputs around 60 kHz, barely covered by 21 bits. You really need at least seven significant figures = 0.1 ppm for those computations, which means the 125 MHz / 2³² ratio must carry seven significant figures, which means eight decimal places: 0.02910383 and not a digit less.

En passant, it’s disturbing how many Arduino DDS libraries declare all their variables as double and move on as if the quantities were thereby encoded in 64 bit floating point numbers. Were that the case, I’d agree 125e6 / pow(2.0,32) actually meant something, but it ain’t so.

The original non-linear doodles, which, despite containing some values useful in later computations, probably aren’t worth your scrutiny:

AD9850 DDS Fixed-point Number Doodles - 1

AD9850 DDS Fixed-point Number Doodles – 1

AD9850 DDS Fixed-point Number Doodles - 2

AD9850 DDS Fixed-point Number Doodles – 2

AD9850 DDS Fixed-point Number Doodles - 3

AD9850 DDS Fixed-point Number Doodles – 3

AD9850 DDS Fixed-point Number Doodles - 4

AD9850 DDS Fixed-point Number Doodles – 4

AD9850 DDS Fixed-point Number Doodles - 5

AD9850 DDS Fixed-point Number Doodles – 5

AD9850 DDS Fixed-point Number Doodles - 6

AD9850 DDS Fixed-point Number Doodles – 6

AD9850 DDS Fixed-point Number Doodles - 7

AD9850 DDS Fixed-point Number Doodles – 7

AD9850 DDS Fixed-point Number Doodles - 8

AD9850 DDS Fixed-point Number Doodles – 8

,

11 Comments

Beckman DM73 Circuitmate: RIP

I’d added Mad Phil’s trusty Circuitmate to the tool kit I carry along to Squidwrench:

Beckman DM73 - new ground clip

Beckman DM73 – new ground clip

Over the last few months it became increasingly erratic, eventually got to the point where slight pressure on the case would blank the display, and finally didn’t turn on at all. Yes, I replaced the batteries.

So I took it apart:

Beckman DM73 Circuitmate - case open

Beckman DM73 Circuitmate – case open

Nothing seemed particularly broken and, even after resoldering all the joints, it continued to not work at all:

Beckman DM73 Circuitmate - PCB

Beckman DM73 Circuitmate – PCB

If you want to try your hand at instrument rehabilitation, let me know.

11 Comments

Mystery Pigeon

Mary spotted this critter atop the roof and, much to my surprise, it waited courteously until I deployed the camera:

Mystery Pigeon - on roof ridge

Mystery Pigeon – on roof ridge

It looks, walks, and acts just like a pigeon:

Mystery Pigeon - walking on roof ridge

Mystery Pigeon – walking on roof ridge

… but we’ve never seen one with those feather patterns & colors. It’s not in any of our books, so it may be an escaped domestic pigeon.

Those feathers require plenty of body maintenance:

Mystery Pigeon - body maintenance

Mystery Pigeon – body maintenance

As nearly as we can tell, it’s wearing a green leg band with three digits that might be 904:

Mystery Pigeon - leg band composite

Mystery Pigeon – leg band composite

If this was your bird, it flew through Red Oaks Mill NY just after noon on 1 May 2017 …

1 Comment

Copying Video Files From Action Cameras to a NAS Drive

For unknown reasons, a recent VLC update caused it to ignore uppercase file extensions: MP4 and AVI files no longer appear in its directory listings, while mp4 and avi files do. The least-awful solution involved renaming the files after copying them:

find /mnt/video -name \*AVI -print0 | xargs -0 rename -v -f 's/AVI/avi/'
find /mnt/video -name \*MP4 -print0 | xargs -0 rename -v -f 's/MP4/mp4/'
find /mnt/video -name \*THM -print0 | xargs -0 rename -v -f 's/THM/thm/'

Yup, that scans the whole drive every time, which takes care of stray files, manual tweaks, and suchlike. The THM files are useless thumbnails; I should just delete them.

While I had the hood up, I listed the remaining space on the NAS drive and cleaned up a few misfeatures. I manually delete old video files / directories as needed, usually immediately after the script crashes for lack of room.

The Sony HDR-AS30V can act as a USB memory device, but it dependably segfaults the ExFAT driver; I now transfer its MicroSD card to an adapter and jam it into the media slot on the monitor, where it works fine.

Protip: always turn the AS30V on to verify the MicroSD card has seated correctly in its socket. Unfortunately, the socket can also hold Sony’s proprietary Memory Stick Micro cards (32 GB maximum capacity = roadkill), but the dual-use / dual-direction socket isn’t a snug fit around MicroSD cards. You (well, I) can insert a card so it looks fine, while sitting slightly canted and not making proper contact. The camera will kvetch about that and it’s easier to fix with the camera in hand.

I’ve disabled USB device automounting, as I vastly prefer to handle them manually, so the script asks for permission in order to mount the drives. The transfer requires about an hour, so I’ve extended the time the sudo password remains active.

The script lets both cards transfer data simultaneously; the Fly6 generally finishes first because it produces less data. That produces a jumbled progress display and the script waits for both drives to finish before continuing.

The Bash source code as a GitHub Gist:

4 Comments