## Character-string Histogram

I’m in the midst of counting glitches on a WWVB receiver, a glitch being any pulse with a duration that isn’t close to 200, 500, or 800 ms. It’s useful to know the pulse width distribution, which is what a histogram does for a living.

Rather than a graphic histogram, though, I’ve been using a character array (a string!) with one character for each possible pulse duration, measured in units of 20 ms. The value of each character indicates the number of pulses having that duration during the previous minute.

The counting sequence goes like this:

• No counts: . (a period)
• 1 to 9 counts: 1 .. 9
• 10 to 35 counts: A .. Z
• 36 to 61 counts: a .. z
• More than 61 counts: !

So a minute with no glitches (and a valid WWVB time code frame) looks like this:

```.........4S9............462............322.........
```

The three clusters show the three valid pulse widths. The pulse widths from the receiver have an inherent jitter, plus the usual ±1 jitter you get for free when you digitize something, plus (this being RF from half a continent away) whatever the Lords of Cosmic Jest do to the signal. So each width usually occupies two or three cells.

• The 200 ms binary zero pulses form the cluster on the left: that “S” is equivalent to 10 + 18 = 28 counts. Add in the 4 and 9 on either side and you get 41 binary zero pulses.
• The middle cluster has the 500 ms binary 1 pulses: 4 + 6 + 2 = 12.
• Each WWVB time code frame has exactly seven 800 ms frame markers, which form the cluster on the right end: 3+2+2 = 7.

Add them up: 41 + 12 + 7 = 60. That’s exactly the right number of pulses in a minute. What a pleasant surprise!

A minute with three out-of-spec glitches looks like this:

```1...1....6NC2............82.......1.....51.........
```

And a minute with very high noise that pretty much obliterates the WWVB signal:

```f!!jHC6AB746312.2121..2.1..........................
```

Here’s how all that works…

The histogram counters form a character array that’s also a string. There are 50 20-ms Jiffies in each second (given by the obvious constant), so the histogram has 52 entries: 50 valid counts (0-49), 1 for “more than that”, and 1 for the null byte at the end of the string.

```char    Durations[JIFFIES_PER_SECOND + 2];
```

Initialize each counter (character) with the starting value and jam a binary zero at the end:

```memset(Durations,'.',sizeof(Durations)-1);
Durations[sizeof(Durations) - 1] = 0;
```

And then tick the appropriate counter as each pulse arrives:

```Index = min(PWM_Width,sizeof(Durations)-2);

switch (Durations[Index]) {
case '.' :
Durations[Index] = '1';
break;
case '9' :
Durations[Index] = 'A';
break;
case 'Z' :
Durations[Index] = 'a';
break;
case 'z' :
Durations[Index] = '!';
break;
case '!' :
break;
default :
Durations[Index]++;
}
```

The switch statement maneuvers the counting sequence through the digits, uppercase and lowercase alphabet, then enforces a stall at the maximum count value of “!”. You can’t just increment each element without some checking, because you do not want unprintable control characters in the string.

Then you print the histogram as you would any ordinary string. If you’re using an Arduino, as I am, this will suffice:

```Serial.println(Durations);
```

All this depends on the ASCII character set’s numerical sequence. Ponder the charts there and all should become clear.

Here are the histograms from an hour of WWVB reception during the late afternoon of New Year’s Day: watch the noise floor rise up and eat the WWVB signal…

```
.........7OD............36............133..........
.........BID1...........37.............6.1.........
.1.......9O91..........262.............43..........
........27V2............272............421.........
.........4Y41...........46............124.........2
.........AP71...........2811..........123.........2
.........AN9............731...........1.6..........
12.111..28IB11.........1623.......2..1.42.....2....
1412...125Q911..........461.....1......41..........
1........8Q81..........137...1.........15..........
.12....119N912.........116..........1.132..........
1521..1.17O931...1......27...........1..5..........
.12....12BKB2...........332....1......132.......2..
25211.1.3AHB5......1...1143........1...14.........3
45412...4BDA4..12.......25111..1.....1..22.........
6A44322.26CI53.2.1...1..343...1.......1.11.........
5D75531113FG511...12..212313.1........1.2..1.......
1432.1.119GB41..........262.1...11.....14..........
.5211..115MB4...........441............14.2........
.4.1....25JB6...........442.........1..231.........
6B443...27I772..........2322.....1.....1221......2.
4555411.27HA321........3232......1....114..........
3232.1.129GI1...1.......4321...1.1.1...111.........
...1..1.19O8..1....11...262............24..........
11......2AN62...........622...........124..........
111.....2BJ551..1......1522........3..141........21
1421....29N611.......1.136............1231........2
1.12.....AIB3........1..38...1........312..........
7F42..1.28FE341.1.1.....351........1...12...1.....2
.23......8GG2....11....2423............33..........
112..13.1AK931.....2....142....2.11.1..3.1........2
423111..44JD4.2..1.....1433........11111...........
1413..1.3CL812..11......242..1....11...21.........2
474112.34AI84.2...3.1...16.2.....1...1.11..........
8LHC734657D857411..11...131......1..1.1...........2
JuSFDCCDDCD662412...1..............................
VmG376788AC8671.21.1..3.......1....................
IlCB4576CFE532131.11.1..1.1........................
KxN798EB98A7422...2.1...1..........................
AYL96853CF7742121311.13..21....1...................
8TDEB6649A7952..32.41..124.....1.....1............2
DeO78638C9GA6142.15111..........1........2.....2...
AcPC83426BD4823.122..11132.1.......................
7SF31121AHFB73..2.111...321..1.1...................
7F3221414GG5411.111121.133...1.1.1.................
6RD9669647F7361.31.2..1212...1.....................
6L71.2444ALB21...221.212321..2...1...1.............
4LHFD7638C9B12.31341.22113...2..........1..........
264321112EFA5.112.22.2.14111..1.....1...1.........2
235511445BEC3.12..1131.131..1.1........11..........
7UC741635AAC442.1..112.1..11311.......1.1.........2
EVLCAB3598E752252133.111.1.1..........1...........2
JnTE9913A59A452331.13..1222.............1..........
f!!jHC6AB746312.2121..2.1..........................
!!!iMB772.4532..1.1.1.1..1.........................
```