OK so maybe it was IRIG madness… (not so much LCD madness)

I’ve been playing, on and off, with IRIG-B decoding – first, modifying NTP source code to continuously dump decoded data from what it reads on the audio input port… then extracting the IRIG-B decoding code to a stand-alone program which would read from the audio input port and output decoded data… then added unmodulated IRIG-B decoding (which was a challenge, due to audio bandpass limitations, but I made it work)…  then putting it to an LCD display, then another, then another with keypad…

Through it all, I struggled to find a practical way of making it useful.  After a discussion with Norbert of ERLPhase, I think maybe we came up with something.

Mobile Device Use?

Rather than expect someone to load up LINUX onto their laptop, drag the laptop to the site where the IRIG-B source is, and use a special cable to connect to the audio input port… why not use the mobile device that everyones seems to carry around with them?

I briefly tried to capture the IRIG-B signal (modulated and unmodulated) into a mobile device, without success 🙁    I tried both my Samsung Galaxy S5 (SM-G900T) and my Samsung Galaxy Tab S2.  No luck.  Maybe my physical setup might have been a bit precarious – I found out later that my audio jack connection may have been suspect – but, the result, even when it did seem to get signal, was not good.  A severely attenuated low frequency response (basically gone below about 100 Hz) made it almost impossible to decode the audio captured by either device.

Create a USB OTG Device?

Having used the Silicon LabsUniversal Bee EFM8UB2 processor last year while working at ERLPhase, and after talking to Norbert… why not capture the IRIG-B signal on the USB2’s analog input port, and then funnel it to any customer’s mobile device through the UB2’s well-integrated USB port?  After all, most modern Android devices support USB-on-the-go, where the mobile device can act like a USB host (similar to a computer) or a USB device (similar to a USB flash drive, camera, or MP3 player).

I thought maybe the EFM8 could do simple 8 ksamples/second signal acquisition (the sample rate used by NTP and later read_irig programs), then send packets of data to the mobile device, where it would be saved to a file that would be submitted for post-acquisition analysis.  This way, the burden of processing would be moved from real-time to remote post-acquisition, maximizing the likelihood of successful data capture.

Universal Bee Development Kit

I acquired the SLKSTK2001A Universal Bee EFM8 UB2 Development Kit and played with the examples.

Oscilloscope Example

The SLKSTK has a neat little graphical LCD display and a few buttons on it, and one example supplied was a simple oscilloscope program EFM8UB2_Oscilloscope which could acquire data on an analog input at 24 to 500 ksamples/second.  I created a custom version of this software locked at a sample rate of 8 ksamples/second with favourable amplitude and trigger settings.  I was readily able to see unmodulated IRIG-B waveforms!  Unfortunately, the EFM8 device only does unipolar conversions, and SLKSTK doesn’t have any circuitry to enable bipolar input – so modulated IRIG-B would only show half cycles.

I introduced a crude offset by wiring a 47k bias resistor to the analog input from the 3.3V supply bus.  Together with the 10k-22k-10k divider chain on the input, this gave a reasonable DC offset, so both modulated and unmodulated IRIG-B could be seen.

VCPXpress Echo

A second example supplied was a program to emulate a Silicon Labs CP210x serial port on the USB interface, EFM8UB2_VCPXpress_Echo, which performed a simple reflection echo of characters sent out.

To prove that it was working, and not just a local echo from minicom – ugh sometimes minicom frustrates me – I modified the Echo program to echo every character twice, then follow every character with an arbitrary string “Burp!” and carriage return.  It took a bit of doing, but it worked.

Oscilloscope with added VCPXpress USB Transmission – Failed

Well, I had the 8 kS/S data acquisition in my modified Oscilloscope project, so I mashed it together with the VCPXpress libraries… and got crap.  It seems as thought the whole thing messed up the link process so badly that symbols resolved, but overlapping memory areas caused unpredictable behaviour… and it would not run.  There was just too much gratuitous complexity in the Oscilloscope project.  So, I thought I would work the problem from the other end.

Starting with VCPXpress

I started with EFM8UB2_VCPXpress_Echo, putting out canned strings.  I wrote a simple Python script on my LINUX machine to accept the strings.  That worked.

I added framing and a packet structure to the strings, and decoding into the Python script.  That worked too.

I had thought that I’d send the full 10 bit ADC values, packing them as needed into the serial stream.  However, the nominal line rate is 115 kbaud, or about 11,500 characters per second.  Sending 8 kS/S of 10 bit data would take 10,000 bytes per second.  With 5 bytes of overhead per packet,  and 50 bytes of data per packet, then this 10% overhead would result in 11,000 bytes per second, not enough margin to make me feel comfortable that it would be a robust transfer.

In fact, I decided to add 2 more bytes of overhead per packet – a running binary sample count, to tell if overflow or underflow had occurred – so the overhead is now 14%.

Now, the original NTP code only used 8 bit samples, and seemed to work just fine.  So, why not reduce the data size to 8 bits per sample?  Then 8 kS/S of data would be 8,000 bytes per second, and with 14% overhead, still “only” 9,120 bytes per second.

It turns out that the 115 kbaud line rate is conservative, and really only even supported to make legacy software happy – the USB connection is far faster than this, and will transfer much more data than the stated.  So, in the end, with 8 bits per sample, the link is very solid.

Here’s the packet format:

00 --------- SOH
01 --------- TYPE - Echo of Command (presently fixed)
02 --------- DATLEN - Data Length (binary)
03 -------+
 .        +- DATLEN bytes of binary data
 .        |
DATLEN+3 --- CKSUM - sum TYPE to CKSUM (inclusive) is zero
DATLEN+4 --- EM - end marker - end of frame

The binary data that I typically send is 52 bytes total, including 50 bytes of analog data:

00 --------- Acquisition Count High Byte
01 --------- Acquisition Count Low  Byte
02 --------- First Data Sample
DATLEN-1 --- DATLEN-2th Data Sample

Data Acquisition and Transmission

I added data code to make the 8 kS/S ADC acquisition, directly timer driven for jitter reduction, interrupt at the end for buffer stuffing.  The data was reduced from 10 bits to 8 bits at interrupt level.  Two swing buffers were employed, with main line code creating the packet and firing it off to the VCPXpress code for transmission.

Python Processing

Data Reception and Processing

I modified the Python script to receive the analog samples and stuff them into a list, keeping track of whether packets were valid and all samples were present, then writing them to a CSV for processing in a spreadsheet.  I was able to verify that the data was transferred intact and complete, with reasonable fidelity.

I then proceeded to decode the unmodulated IRIG-B signal bits as (0/1/Position Indicator/Invalid), and add them to the CSV file output.  Then, I decoded the signal bits and compose a string of characters to represent each one-second frame of IRIG-B data.  Lastly, if the frame met proper format criteria (PIs in the right places, 1/0s in the right places, not too many bits), I pulled the data out and performed full decoding just as I had done with read_irig in the past.  I also added this to the CSV file output.

I actually created three CSV file outputs:

  • Raw data sample file – with extended columns for bit decode internal data
  • Bit decode sample file – each bit as it was decoded – with extended column for full decode output when successfully performed
  • Full decode file – a bit string for each one-second frame, plus fully decoded data

Threshold Detection

It was difficult to consistently get good thresholds for decoding, so I added rescaling.  The maximum and minimum values of signal in the file are calculated.  An offset is subtracted to centre the signal around zero, then a gain is multiplied to make the signal approximately -3 dB of full scale, or about +/-25,000 counts.

Modulated IRIG-B Processing

It was difficult to decide how to work with modulated IRIG-B.  The original NTP code did a kind of phase-locked loop decode on the signal, so it could recover the bit stream, but also the precise zero cross time, so the local clock could be time sync’d to the IRIG-B signal.  I didn’t want to do this.  The code is hard to understand, we don’t need time sync for post processing, and I’d rather not incorporate someone else’s code if I don’t have to.

Instead, I went back to the way that Filipe and I designed modulated IRIG-B processing so many years ago: watching for positive side pulses due to the sinusoid going above zero (Polarity), and also for “high” level amplitude by positive side pulses due to the sinusoid going above a threshold (Peaks).  Polarity without Peak means low level cycle, Polarity with Peak means high level cycle.

One problem was an unknown baseline.  As mentioned, an arbitrary offset had been applied.  The maximum and minimum values of signal in the file are calculated.  Zero cross was assumed to be at the halfway point – the median – the average of maximum and minimum – this gives Polarity.

The amplitude of a low level cycle is defined as 1/3 the amplitude of a high level cycle.  The threshold would be halfway between these two levels, or 2/3 the amplitude of a high level cycle, or 5/6 of the way to maximum level –
minimum + (5/6 x (maximum – minimum))

Now, I tracked how many high level cycles in a row happened before low level cycles resumed.  This would determine whether a bit was a 0/1/Position Indicator.

Tarball and Steganography

I added a feature to roll the three CSV files up into a GZIPped tarball.  Because the files are ASCII, they compress well.  Then the original CSV files are deleted.  A tarball is easier to transfer for post processing.

A tarball might not pass E-mail inspection, so I added a steganography library to encode the tarball into an arbitrary JPEG image.  The JPEG image would likely get through the E-mail system more easily.  However, this processing took a very long time (over 10 minutes) and created a huge image file (original 100k, over 5 Meg afterwards), so this was abandoned.


Automatic Gain Control

By putting the EFM8 MCU’s VREF on an RC-integrated PWM output, and using the same signal as a DC bias offset on the analog input, I could change the bias and the ADC span under program control.

I added code to the EFM8 to track the maximum and minimum ADC input levels (single ended) and calculate whether the system gain should be increased or decreased to make the span approximately 128 counts, or about half scale.  Margin is maintained, but gain is maximized.  The system is designed to track within a second or two of amplitude change.

Building it Onto a Beadboard

The analog circuitry was put onto a breadboard and wired to the EFM8 MCU on the development kit.

Silicon Labs SLKSTK2001A EFM8 UB2 Universal Bee Demonstration Board with Simple Analog Front End
Silicon Labs SLKSTK2001A EFM8 UB2 Universal Bee Development Kit with Simple Analog Front End

Next Up

Next, to connect this to a mobile device, invoke a serial port driver, and capture the data there for post processing analysis.  That’s easier said than done!



The LCD Madness Continues

I purchased a Crystalfontz CFA635-YYK-KU 4 line LCD display with integrated USB interface, 4 bicolour LEDs and 6 button keypad, then proceeded to modify the read_irig program to talk to it.

CFA635 Display Showing IRIG-B
Integrated Display with LEDs and Keypad showing IRIG-B

I’ve modified the keyboard interface a bit as well.  Keys now supported:

a - Change backlight intensity (CFA635 only)
d / keypad "DOWN" - Change display format: DECODED, RAW, TITLED
h / keypad "CHECKMARK" - Hold/unhold display
u / keypad "UP" - Reverse RAW or TITLED display order MSbit <>LSbit
r / keypad "RIGHT" - Shift display data right
l / keypad "LEFT" - Shift display data left
v - Diagnostic dump of display data to terminal
f - Change format of terminal displayed data: RAW+DECODED, DECODED only, RAW only
q / keypad "X CANCEL" twice consecutively - Exit program

I’ve also made the top LED blink green bright and dim, each time it gets a time update, solid red when IRIG input fails and a timeout is declared, and blink orange bright and dim slowly, when display is in hold mode.


Decoded Time Display

Well, I did it – what I’ve been trying to accomplish for some time now.  I have a “live” decode of IRIG-B to my little 5×7-character-based LCD display.

Pulling Threads

I created two new threads in my read_irig program.

One thread reads the keyboard, looking for single character commands:

  • q: quit read_irig
  • d: show decoded data
  • r: show raw data 3 lines at a time (60 bits at a time), and if raw data already showing, reverse the bit sequence
  • t: show raw data 1 line at a time (20 bits at a time) with header, and if already showing, reverse the bit sequence
  • u/l: move between windows of present format up/down (e.g. show next or previous 20 bits of raw data)
  • h: freeze the display at the present time

The second thread takes a full structure of present time data and displays it on the screen, in accordance with the present format and situation.

Displayed Output

Decoded Display

Decoded Time Display, showing decoded date, day of year, time of day (HH:MM:SS and straight binary seconds in hex)
Decoded Data Second Page, showing format, gain and amplitude of signal

Raw Display

Raw Data, showing chips 0 to 59
Raw Data Second Page, showing chips 40 to 99

Reversed Raw Display

Reversed raw display is convenient because the bits are arranged from most significant (MSB) to least significant (LSB) from left to right, which is convenient for most people to read.

Reversed Raw Data, showing chips 99 to 40
Reversed Raw Data Second Page, showing chips 59 to 0

Timeout/Searching for Signal Display

Timeout Indication, showing blanked out data, presently searched-for signal type, gain and amplitude of signal

What’s Next?

I was thinking that I might introduce a third display mode, that of raw data with headers, more like the console output of read_irig:

#           Normal Unmodulated IRIG-B Raw  (noninv audio)  (Gain  93 giving  +1.0 dB)              ||   Normal Unmodulated IRIG-B (noninv, gain  93 ->  +1.0 dB) |
# StrtBinSecs (SBS) |    Control Bits   |   Year  |    Day of Year    |  Hours  | Minutes |Seconds ||Day|   Date and Time    |SBS hex|Leap| DST |Offset|Qual|Par |
# ........ .........|......... .........|.... ....|       .. .... ....|  .. ....| ... ....|........||...|.... .. .. .. .. .. | . ....|....|.....|......|  ..|....|
#                   |                   |         |                   |         |         |        ||   |                    |       |    |     |      |    |    |
.001010101.010111101.000100000.010111000.000101001.000000001.010000000.000100010.000001000.01001001. 140 2019-05-20 12:08:29   0_AABD !lsp  DST  UTC-05   00 1 ok 
.001010101.010111110.000000000.010111000.000101001.000000001.010000000.000100010.000001000.01100000. 140 2019-05-20 12:08:30   0_AABE !lsp  DST  UTC-05   00 0 ok

And Then, and Then!?!

You think that would be enough for me?  Well, apparently not!  read_irig takes very little computing power, so it could easily run on a smaller processor…  say, an ARM… on a Raspberry Pi, or a Beagleboard – then it could be made portable.  I have two Beagleboard Blacks and like them.  The problem here is that none of these boards have easy audio input ports, like my laptop.  Some do have ADC inputs, but they need to be protected, amplified, provided with a jack, etc.  Hmm, have to think about this.

Almost every device these days has an I2C port, so there shouldn’t be much trouble there.

That’s *Mister* IRIG to you, sir…

I’m a bit of a time-nut…  well, not quite as adamant as some of those on that list  ( Allen deviations?   Seriously?   Who would talk about Allen that way?!? ), but I am crazy about keeping time, accurate time (well to within the millisecond or so, anyway), and distributing time.

IRIG-B Decoder Box

Since my first encounter with IRIG-B in, oh, was that 1988 (?), doing an IRIG-B decoder box at Vansco, on contract for Manitoba Hydro, I’ve been fascinated by the IRIG-B time code.  Here’s the official specification, and an unofficial site by someone trying to sell you something.  Truth be told, the original MC68xx (might have been MC68701 because it had both accumulators and more than one TCAP pin) IRIG-B decoder firmware was written by Filipe Fernandes…   then I took it from there, as Filipe got gobbled up by all the other stuff going on at Vansco 🙂  That decoder box took in modulated IRIG-B only, put out a contact for when it was valid or invalid, and had an RS-232 interface for another device to tell it the IRIG-B time.  What fun!


Then came the IEEE 1344 extensions, which defined a use for the extra IRIG-B undefined bits, giving more information that originally intended.  The original IRIG-B decoder box did not support these extensions, but our next product did.

APT Power Technologies had IRIG-B

Anyways, while tangled up in all the other matters during development of the APT relay, like running the APT division, hiring staff, arranging trade shows, and designing the entire data acquisition system, I designed the hardware and ported & upgraded the firmware for the on-board MC68711 IRIG-B decoder.  Oh yes, and designed the time coordination system between the multiple processors in the system, which one had the master time and when, etc.  Very interesting.  During that time, we added unmodulated IRIG-B input as well.  The unit cycles between searching for valid modulated IRIG-B and unmodulated IRIG-B.

Getting IRIG-B for Testing

The only way that we had to generate IRIG-B was with an Arbiter 1084 satellite clock.  It would put out a modulated IRIG-B stream, and an unmodulated IRIG-B stream (TTL level), and a 1 pulse-per-second (generally referred to as 1 PPS or just “PPS”) (also TTL level).  There was also a serial interface – reminiscent of what we did in the original IRIG-B decoder box – but we rarely used it.  It could change settings on the IRIG-B interface signal, but we generally had models with the front panel buttons and display, so we changed parameters using that.

Satellite clocks were expensive back then.  Well, industrial grade ones still are – but we needed IRIG-B signals for testing – in product development, but also in manufacturing test.  So, we had one central satellite clock, and distributed IRIG-B through the building using CAT5 twisted pair, with specially marked RJ45 drops at developer’s desks, in production, in customer support, etc.

Experimenting with various formats was a pain.  We had to get access to the satellite clock (it was in the locked server room), change the settings, then get other users’ acceptance of the change…  oops, did I get that out of sequence?  Ha ha, I did get that out of sequence several times.  It turned out that most locations only had a single drop, so if I changed from unmodulated to modulated when users weren’t expecting it, ugh it caused us some heartache.  To the point where production got two separate direct wire drops.  Then, we had loading issues, so production got its own clock.  It didn’t have to be accurate, just functional, so I’m not sure that it was even always satellite locked.

Rudimentary Test Recordings

Sometimes, we recorded IRIG-B signals and just played them back.  After all, modulated IRIG-B was developed in the 50s (or was it 60s?) and was intended to be recorded on multi-track audio recorders and strip chart recorders for the telemetry of various military tests (think nuclear weapons testing).  I experimented with cassette tape recorderings in the early days, then with MP3 players like my little Samsung YP-U3 that we used on our trip to England & Scotland in 2005.  It had mixed results.  Modulated worked quite well, but unmodulated was unreliable – since it’s not really audio, and requires DC offset to be maintained, or restored, or something.

Enter tg

Around 2005, I found out that the NTP project had a program called tg in its “utils” subdirectory.   tg stands for “Timecode Generator”, and it was designed to put out modulated simulated IRIG-B or WWV through the audio output port of a Sun workstation computer (I suspect that this was the original target for the NTP executable).  I could be wrong, maybe it was a different *NIX system, but anyway, it didn’t work on the LINUX that I was running at the time, probably Mandrake LINUX.  So, I hacked it to use OSS to make it run on my computer.  What fun!

tg isn’t good enough for really accurate time sync!  It’s just good enough to test the decoder, test edge cases, etc.

Deano went a-hacking

Of course, I couldn’t leave well enough alone, so I Weiten-ified it, as Michael Miller used to say.  I added a slew of options and tweaks.  I added optional unmodulated IRIG-B output, tweaked its time code generation, added IEEE 1344 extension support, added the ability to start at an arbitrary specified time & date, added the ability to insert and remove leap seconds on demand, and much more.  I found that the audio card output sample rate wasn’t quite good enough over long term testing to keep accurate time – the output sample rate of 8,000 samples per second and the sinewaves were precisely, you know, 8 samples or 80 samples (IRIG or WWV) per cycle, so if the output sample rate were off by 0.1%, the frequency was off by 0.1%, and this would accumulate to eventually cause time drift.

So, I arranged to insert or remove a single cycle (1 mSec or 10 mSec) at what I decided was an innocuous part of the time code – at least for my decoders, heh heh.  The program compared the time to the LINUX real-time clock (which often is sync’d to global standard using NTP, how cool is that), and if the amount became detectable, it would slip in an extra cycle, or remove an extra cycle per second, to get back in sync.

I also added options to create file output instead of audio, so could be played back later (through audio port, as before, or through an Arbitrary Waveform Generator).

The Fork Less Travelled

So anyways, when I was done, I was quite proud of my work, so I sent it back to the NTP project – specifically to Dr. David Mills, chief NTP guy , and author of the book on network time sync – and I’m sure he was absolutely horrified at what I had done to the program.  In retrospect, I didn’t read nor respect the code formatting guidelines, I hacked and slashed the original audio driver code, yikes.  Dr. Mills was very polite, but wouldn’t accept my changes to tg on top of tg itself, but instead called it tg2.  If you download NTP today, you will see util/tg2 in there, waiting to be hacked some more 🙂

Oh, and I have hacked it some more.    Source code in tarball with RCS tracking available online.  I am trying to be more respectful of code formatting guidelines, and maintaining backward compatibility these days.

tg2‘s Greatest Hits?

Around 2006, I re-mastered a Knoppix CD with tg2 built in, so I could demo all its features on a live CD.  At the time, Jason Fuith and I were operating our own business called Elecsys Solutions (and starving, at least financially, while doing it), and we wanted to maybe sell it to folks like Krish Narendra, who was now in charge of Product Development at ERLPhase, and still faced all the problems of satellite clocks, IRIG-B distribution etc.

The idea that we had wasn’t necessarily to sell the code, but to sell support of it – maybe install it on custom embedded hardware, or put in specific customization, etc.

tg2 + Knoppix = NAN

Although interesting, it didn’t sweep Krish off his feet, and even at a modest cost, he could not justify the expenditure.  Well, I gave him the CD anyway, and I don’t think it went any further.

After Krish left ERLPhase, I worked out of his office for a while in 2018, and I stumbled across that CD, heh heh.  I gave it to Mark Poole, as he is now ERLPhase’s IRIG-B guy – and he was quite interested.  Mark and I had a long chat, and my next “hobby” project was born!  More on that later.

Meanwhile, Back doing Real Work

I tinkered with tg2 from time to time, per above, but didn’t do much with it.  In the meantime, Elecsys was purchased by Norscan Instruments and I went to work there as Product Development Manager for 3-1/2 years.  They didn’t have any specific interest in IRIG-B, NTP, or tg2 – they needed to make some money to pay our wages, imagine that!

Then back to ERLPhase for a bit, a great year at GE Multilin in Markham, back in Winnipeg for a short time, and off to Phoenix to work for Alstom Grid Digital Instrument Transformers, or Alstom Grid DIT (now GE Grid Solutions DIT).

Optical IRIG

Now, at DIT, they used satellite clocks all right – Arbiter 1084s, in fact, among others (like Reason, now GE, ones).  There was one important difference though – DIT used the now-standard orange 62.5/125 multimode fibre with 820 nm pulsed light (using the Avago/Broadcom HFPL1414TZ transmitter).  On the Arbiter 1084, this option is called “option 20”, and the single ST output can be configured to output IRIG-B unmodulated (of course 🙂 ), IRIG-B modified manchester coding, or 1 PPS.  DIT used the 1 PPS, because its primary use was to synchronize sampling / output of its product – what’s now known in the industry as a “primary converter merging unit” – so that it can be synchronized in time to other merging units in the system.

We did switch our satellite clocks back and forth between 1 PPS and IRIG-B unmodulated, when we were synchronizing with Reason (now GE) merging units.  I was intrigued.

Dean Scores!  ( an Arbiter 1084C satellite clock )

I always wanted a satellite clock, but, as I said before, they are expensive.  I started trolling for one in late 2015.  They are still expensive – generally selling for US700 used, and up to US2100 if new in box.  I just happened to find one selling at BMI Surplus for something like US250, talked them down to US236 inc shipping and tax, and it was mine, yay!  As a bonus, it was the Arbiter 1084C model, which has the big seven segment LED display on the front, way cool 🙂

Satellite Clock
Arbiter 1084C Satellite Clock

It didn’t come with option 20, so I (carefully!) disassembled one of DIT’s 1084 clocks, made a parts list and took pictures, ordered what I needed, and installed them in my clock.  Now I have option 20, heh heh heh.

This came in handy for testing of the Reason merging unit with RogoFlex at PowerTech in Vancouver in August 2017, when I took my own 1084 clock to sync the systems together.

What to Do with a Satellite Clock?

My satellite clock didn’t come with a GPS antenna, so I got one through Amazon, of course, put that up with the many other antennas above my house, and got the clock working.

I had a lot of fun with the Arbiter 1084C and my oscilloscope – marvelling at the time code, watching the different signals, cross referencing the different formats (yes, I am that weird).

The clock was affected by a rollover bug.  I ordered new EPROMs for US$60 from Arbiter.  Easy peasy, replaced those, just like in my early days.

GPS Module Troubles

At one point, the clock stopped working properly.  Sad day!  The GPS module had died.  It seems that it’s writing something to the flash on the GPS module constantly, and it just wore out.

The module, an old Motorola OnCore unit, is of course obsolete.  There are non-drop-in replacements, but they aren’t binary compatible.  Arbiter will upgrade your unit – as I recall, it’s about US$300 – more than I paid for the satellite clock in the first place!  Now that was a very sad day.

I bought a SMT soldering/desoldering station, flash programmer and some spare flash parts, pulled the old flash off the board and rolled it out to disk… programmed the new part, but could not get it installed back on the board properly.  Seems as though I damaged the board removing the parts, so sad.

Fortunately, I found a (less) used GPS module of the exact same model, at some place in the far east.  I received it, plugged it in, and was back in business.

Oh, and the backup battery had of course died – being nickel-cadmium and probably 25 years old!  But, it had also corroded its connections badly.  I repaired the board and replaced the battery, and all is good again.   The battery is actually optional, probably should have just left it off.

Now What to do with a Satellite Clock?

The satellite clock sat running on my shelf for a year or so, before I got to thinking that I should use the IRIG-B signal output.  At first, I wanted to time sync a local computer and create my own (effectively) stratum 1 NTP time reference.  I don’t recall, I might have even had it working briefly, but what do I need a stratum 1 NTP time reference for?  That’s kind of a dead-end project, at least for me.

If You Can’t Generate ‘Em, Decode ‘Em?

Back to that conversation with Mark Poole, he mused that it would be nice to have a tool that could display the details of IRIG-B signals, so Customer Service, Applications and Product Development personnel, could trouble shoot issues, including various clocks that apparently give wrong or conflicting information, get the parity wrong, use reversed time zone-to-UTC offset etc.

So I started playing with NTP’s refclock_irig, not to sync my computer’s clock (in fact, I neutered it, so it would not), but to fully decode and display the signal.  Along the way, I added support for unmodulated IRIG-B as well – that was a challenge, since an audio input port is used to read the signal, and it does not maintain DC levels.  In fact, I did a lot of work on DC restoration à la NTSC TV signal recovery, back in the day.  That was fraught with peril, eventually causing a numerical overflow or a drifting DC baseline, so I eventually settled on a much simpler “look for fast shifts” solution, and that worked well.  I made the printout of the time code optional, using “fudge” tweak configuration bits already in the code, to dump output to the existing log, then tail -f in a separate console to display them.  I also generated some (huge) CSVs from time to time, both raw analog data (do you see what I see?) and various decode internals (do you decode what I decode?).  A lot of work to keep putting debug in, take it out, etc.  There are only 4 fudge tweak bits, and 3 of them are already in use… I pulled one back, so I could use 2, but still, too much hassle to tweak it inside the NTP framework.

Stand-Alone Decoder Program

Eventually, I undertook an effort to break my refclock_irig code away from NTP, creating read_irig.  This program stands alone, and supports too many options:

Read and decode modulated/unmodulated IRIG-B/modulated IRIG-E from audio signal, v0.43, 2019-05-08 dmw

RCS Info:
  Header: /home/dmw/src/ntp/refclock_irig/RCS/read_irig.c,v 1.57 2019/05/08 06:07:07 dmw Exp

Usage: read_irig [option]*

Options: -b                             Disable automatic input gain control
         -c <csv_output_filename>       Put out CSV file of bunch of internal values for portion of time
         -e <lines_between_headers>     Repeat full header every this many lines (default 20)
         -f <format_type>               Force only format:
                                             0 = Any (default)
                                             1 = Normal Modulated
                                             2 = Normal Unmodulated
                                             3 = Inverted Unmodulated
                                             4 = Normal or Inverted Unmodulated
         -g <initial_gain>              Initial gain setting (default 50), from 10 to 100
         -i <input_file>                Input file instead of audio input
         -j <csv_output_delay_samples>  Delay in samples for "-c" CSV output after startup (default 8000)
         -m                             Enable IRIG-B modulated bandpass filter
         -n                             Non-inverting input stream (normally input is inverted)
         -o <raw_signal_csv_out>        Put out CSV file of just raw input for as long as program runs
         -r <bitmap_of_outputs>         Bitmap of outputs:
                                             bit 0 = decoded data
                                             bit 1 = raw data
                                             bit 2 = do not repeat full header while in low verbosity
                                             bit 3 = 8 lines x 16 chars/line flat panel display output (disables all others)
                                             (default value shows raw and decoded data, and repeats full header periodically)
         -s <seconds_to_run>            Run this many seconds then exit (default forever), must be greater than 7
         -t <timeout_seconds>           Change timeout on successful decode, must be greater than 4.0 sec
         -v                             Increase verbosity of output
         -x                             Use 2nd stream (right? left?) instead of 1st
         -y                             Invert raw_signal_csv_out from "-o" option
         -z <threshold_amount>          Unmodulated edge detect threshold amount (default +/-0.20) in +/- amount of max

Notes: 1. Starting with "  Normal Unmodulated" format, default time out after about 64,000 samples
          (about 8.0 sec) without successful decode, then will cycle through "  Normal   Modulated",
          "  Normal Unmodulated", and "Inverted Unmodulated", with about 8.0 sec timeout on each format.
       2. Setting timeout on successful decode to less than about 8 sec may produce intermittent lock or
          failure to lock on modulated IRIG carrier.
       3. It can take a few seconds to lock onto a signal, so output may not be <seconds_to_run> frames.
       4. Modulated bandpass filter for IRIG-B tends to "shmoosh" the input signal and make it difficult
          to decode, and most IRIG-B signals are very clean, so it's not generally necessary.
       5. Default outputs include both raw and decoded data.  If both are turned off using "-r" option,
          decoded data is turned on alone.

This software licenced under the GPL, derived from refclock_irig, changes made 2018, 2019 by Dean Weiten
Contact: Dean Weiten, Winnipeg, MB, Canada, ph (204)-888-1334, E-mail dmw@weiten.com

The output, I think, is way cool:

#         Inverted Unmodulated IRIG-B Raw (inverted audio) (Gain 100 giving -12.9 dB)              || Inverted Unmodulated IRIG-B (inv   , gain 100 -> -12.9 dB) |
# StrtBinSecs (SBS) |    Control Bits   |   Year  |    Day of Year    |  Hours  | Minutes |Seconds ||Day|   Date and Time    |SBS hex|Leap| DST |Offset|Qual|Par |
# ........ .........|......... .........|.... ....|       .. .... ....|  .. ....| ... ....|........||...|.... .. .. .. .. .. | . ....|....|.....|......|  ..|....|
#                   |                   |         |                   |         |         |        ||   |                    |       |    |     |      |    |    |
.001010000.000011001.000100000.010111000.000101001.000000001.001100000.000100001.001000011.00000101. 130 2019-05-10 11:23:05   0_A019 !lsp  DST  UTC-05   00 1 ok 
.001010000.000011010.000100000.010111000.000101001.000000001.001100000.000100001.001000011.00000110. 130 2019-05-10 11:23:06   0_A01A !lsp  DST  UTC-05   00 1 ok 
.001010000.000011011.000000000.010111000.000101001.000000001.001100000.000100001.001000011.00000111. 130 2019-05-10 11:23:07   0_A01B !lsp  DST  UTC-05   00 0 ok 
.001010000.000011100.000000000.010111000.000101001.000000001.001100000.000100001.001000011.00001000. 130 2019-05-10 11:23:08   0_A01C !lsp  DST  UTC-05   00 0 ok 

The raw and inverted decode sections can be enabled independently, and the program can auto-detect (slowly, mind you) modulated IRIG, unmodulated IRIG, and inverted unmodulated IRIG.

I’m still a sad case… I can sit and watch the codes go by, constantly.  It turns in a separate TTY on my computer, in the background, all the time.  Heh heh heh.

Source code in tarball with RCS tracking available online.

What Now?

In keeping with How Could They Possibly Improve Upon That?, you have to wonder where I could go from there.  Stay tuned! 🙂