154359Sroberto# awk program to scan clockstat files and report errors/statistics 254359Sroberto# 354359Sroberto# usage: awk -f check.awk clockstats 454359Sroberto# 554359Sroberto# This program works for the following radios: 654359Sroberto# PST/Traconex 1020 WWV reciever 754359Sroberto# Arbiter 1088 GPS receiver 854359Sroberto# Spectracom 8170/Netclock-2 WWVB receiver 954359Sroberto# IRIG audio decoder 1054359Sroberto# Austron 2200A/2201A GPS receiver (see README.austron file) 1154359Sroberto# 1254359SrobertoBEGIN { 1354359Sroberto etf_min = osc_vmin = osc_tmin = 1e9 1454359Sroberto etf_max = osc_vmax = osc_tmax = -1e9 1554359Sroberto} 1654359Sroberto# 1754359Sroberto# scan all records in file 1854359Sroberto# 1954359Sroberto{ 2054359Sroberto # 2154359Sroberto # select PST/Traconex WWV records 2254359Sroberto # 00:00:37.234 96/07/08/190 O6@0:5281825C07510394 2354359Sroberto # 2454359Sroberto if (NF >= 4 && $3 == "127.127.3.1") { 2554359Sroberto if (substr($6, 14, 4) > "0010") 2654359Sroberto wwv_sync++ 2754359Sroberto if (substr($6, 13, 1) == "C") 2854359Sroberto wwv_wwv++ 2954359Sroberto if (substr($6, 13, 1) == "H") 3054359Sroberto wwv_wwvh++ 3154359Sroberto x = substr($6, 12, 1) 3254359Sroberto if (x == "1") 3354359Sroberto wwv_2.5++ 3454359Sroberto else if (x == "2") 3554359Sroberto wwv_5++ 3654359Sroberto else if (x == "3") 3754359Sroberto wwv_10++ 3854359Sroberto else if (x == "4") 3954359Sroberto wwv_15++ 4054359Sroberto else if (x == "5") 4154359Sroberto wwv_20++ 4254359Sroberto continue 4354359Sroberto } 4454359Sroberto # 4554359Sroberto # select Arbiter GPS records 4654359Sroberto # 96 190 00:00:37.000 0 V=08 S=44 T=3 P=10.6 E=00 4754359Sroberto # N39:42:00.951 W075:46:54.880 210.55 2.50 0.00 4854359Sroberto # 4954359Sroberto if (NF >= 4 && $3 == "127.127.11.1") { 5054359Sroberto if (NF > 8) { 5154359Sroberto arb_count++ 5254359Sroberto if ($7 != 0) 5354359Sroberto arb_sync++ 5454359Sroberto x = substr($10, 3, 1) 5554359Sroberto if (x == "0") 5654359Sroberto arb_0++ 5754359Sroberto else if (x == "1") 5854359Sroberto arb_1++ 5954359Sroberto else if (x == "2") 6054359Sroberto arb_2++ 6154359Sroberto else if (x == "3") 6254359Sroberto arb_3++ 6354359Sroberto else if (x == "4") 6454359Sroberto arb_4++ 6554359Sroberto else if (x == "5") 6654359Sroberto arb_5++ 6754359Sroberto else if (x == "6") 6854359Sroberto arb_6++ 6954359Sroberto } else if (NF == 8) { 7054359Sroberto arbn++ 7154359Sroberto arb_mean += $7 7254359Sroberto arb_rms += $7 * $7 7354359Sroberto if (arbn > 0) { 7454359Sroberto x = $7 - arb_val 7554359Sroberto arb_var += x * x 7654359Sroberto } 7754359Sroberto arb_val = $7 7854359Sroberto } 7954359Sroberto continue 8054359Sroberto } 8154359Sroberto # 8254359Sroberto # select Spectracom WWVB records 8354359Sroberto # see summary for decode 8454359Sroberto # 96 189 23:59:32.248 D 8554359Sroberto # 8654359Sroberto if (NF >= 4 && $3 == "127.127.4.1") { 8754359Sroberto if ($4 == "SIGNAL" || NF > 7) 8854359Sroberto printf "%s\n", $0 8954359Sroberto else { 9054359Sroberto wwvb_count++ 9154359Sroberto if ($4 ~ /\?/) 9254359Sroberto wwvb_x++ 9354359Sroberto else if ($4 ~ /A/) 9454359Sroberto wwvb_a++ 9554359Sroberto else if ($4 ~ /B/) 9654359Sroberto wwvb_b++ 9754359Sroberto else if ($4 ~ /C/) 9854359Sroberto wwvb_c++ 9954359Sroberto else if ($4 ~ /D/) 10054359Sroberto wwvb_d++ 10154359Sroberto } 10254359Sroberto continue 10354359Sroberto } 10454359Sroberto # 10554359Sroberto # select IRIG audio decoder records 10654359Sroberto # see summary for decode 10754359Sroberto # 10854359Sroberto if (NF >= 4 && $3 == "127.127.6.0") { 10954359Sroberto irig_count++ 11054359Sroberto if ($5 ~ /\?/) 11154359Sroberto irig_error++ 11254359Sroberto continue 11354359Sroberto } 11454359Sroberto # 11554359Sroberto # select Austron GPS LORAN ENSEMBLE records 11654359Sroberto # see summary for decode 11754359Sroberto # 11854359Sroberto else if (NF >= 13 && $6 == "ENSEMBLE") { 11954359Sroberto ensemble_count++ 12054359Sroberto if ($9 <= 0) 12154359Sroberto ensemble_badgps++ 12254359Sroberto else if ($12 <= 0) 12354359Sroberto ensemble_badloran++ 12454359Sroberto else { 12554359Sroberto if ($13 > 200e-9 || $13 < -200e-9) 12654359Sroberto ensemble_200++ 12754359Sroberto else if ($13 > 100e-9 || $13 < -100e-9) 12854359Sroberto ensemble_100++ 12954359Sroberto ensemble_mean += $13 13054359Sroberto ensemble_rms += $13 * $13 13154359Sroberto } 13254359Sroberto continue 13354359Sroberto } 13454359Sroberto # 13554359Sroberto # select Austron LORAN TDATA records 13654359Sroberto # see summary for decode; note that signal quality log is simply 13754359Sroberto # copied to output 13854359Sroberto # 13954359Sroberto else if (NF >= 7 && $6 == "TDATA") { 14054359Sroberto tdata_count++ 14154359Sroberto for (i = 7; i < NF; i++) { 14254359Sroberto if ($i == "M" && $(i+1) == "OK") { 14354359Sroberto i += 5 14454359Sroberto m += $i 14554359Sroberto tdata_m++ 14654359Sroberto } 14754359Sroberto else if ($i == "W" && $(i+1) == "OK") { 14854359Sroberto i += 5 14954359Sroberto w += $i 15054359Sroberto tdata_w++ 15154359Sroberto } 15254359Sroberto else if ($i == "X" && $(i+1) == "OK") { 15354359Sroberto i += 5 15454359Sroberto x += $i 15554359Sroberto tdata_x++ 15654359Sroberto } 15754359Sroberto else if ($i == "Y" && $(i+1) == "OK") { 15854359Sroberto i += 5 15954359Sroberto y += $i 16054359Sroberto tdata_y++ 16154359Sroberto } 16254359Sroberto else if ($i == "Z" && $(i+1) == "OK") { 16354359Sroberto i += 5 16454359Sroberto z += $i 16554359Sroberto tdata_z++ 16654359Sroberto } 16754359Sroberto } 16854359Sroberto continue 16954359Sroberto } 17054359Sroberto # 17154359Sroberto # select Austron ITF records 17254359Sroberto # see summary for decode 17354359Sroberto # 17454359Sroberto else if (NF >= 13 && $5 == "ITF" && $12 >= 100) { 17554359Sroberto itf_count++ 17654359Sroberto if ($9 > 200e-9 || $9 < -200e-9) 17754359Sroberto itf_200++ 17854359Sroberto else if ($9 > 100e-9 || $9 < -100e-9) 17954359Sroberto itf_100++ 18054359Sroberto itf_mean += $9 18154359Sroberto itf_rms += $9 * $9 18254359Sroberto itf_var += $10 * $10 18354359Sroberto continue 18454359Sroberto } 18554359Sroberto # 18654359Sroberto # select Austron ETF records 18754359Sroberto # see summary for decode 18854359Sroberto # 18954359Sroberto else if (NF >= 13 && $5 == "ETF" && $13 >= 100) { 19054359Sroberto etf_count++ 19154359Sroberto if ($6 > etf_max) 19254359Sroberto etf_max = $6 19354359Sroberto else if ($6 < etf_min) 19454359Sroberto etf_min = $6 19554359Sroberto etf_mean += $6 19654359Sroberto etf_rms += $6 * $6 19754359Sroberto etf_var += $9 * $9 19854359Sroberto continue 19954359Sroberto } 20054359Sroberto # 20154359Sroberto # select Austron TRSTAT records 20254359Sroberto # see summary for decode 20354359Sroberto # 20454359Sroberto else if (NF >= 5 && $5 == "TRSTAT") { 20554359Sroberto trstat_count++ 20654359Sroberto j = 0 20754359Sroberto for (i = 6; i <= NF; i++) 20854359Sroberto if ($i == "T") 20954359Sroberto j++ 21054359Sroberto trstat_sat[j]++ 21154359Sroberto continue 21254359Sroberto } 21354359Sroberto # 21454359Sroberto # select Austron ID;OPT;VER records 21554359Sroberto # 21654359Sroberto # config GPS 2201A TTY1 TC1 LORAN IN OUT1 B.00 B.00 28-Apr-93 21754359Sroberto # 21854359Sroberto # GPS 2201A receiver model 21954359Sroberto # TTY1 rs232 moduel 22054359Sroberto # TC1 IRIG module 22154359Sroberto # LORAN LORAN assist module 22254359Sroberto # IN input module 22354359Sroberto # OUT1 output module 22454359Sroberto # B.00 B.00 firmware revision 22554359Sroberto # 28-Apr-9 firmware date3 22654359Sroberto # 22754359Sroberto else if (NF >= 5 && $5 == "ID;OPT;VER") { 22854359Sroberto id_count++ 22954359Sroberto id_temp = "" 23054359Sroberto for (i = 6; i <= NF; i++) 23154359Sroberto id_temp = id_temp " " $i 23254359Sroberto if (id_string != id_temp) 23354359Sroberto printf "config%s\n", id_temp 23454359Sroberto id_string = id_temp 23554359Sroberto continue 23654359Sroberto } 23754359Sroberto # 23854359Sroberto # select Austron POS;PPS;PPSOFF records 23954359Sroberto # 24054359Sroberto # position +39:40:48.425 -075:45:02.392 +74.09 Stored UTC 0 200 0 24154359Sroberto # 24254359Sroberto # +39:40:48.425 position north latitude 24354359Sroberto # -075:45:02.392 position east longitude 24454359Sroberto # +74.09 elevation (meters) 24554359Sroberto # Stored position is stored 24654359Sroberto # UTC time is relative to UTC 24754359Sroberto # 0 200 0 PPS offsets 24854359Sroberto # 24954359Sroberto else if (NF >= 5 && $5 == "POS;PPS;PPSOFF") { 25054359Sroberto pos_count++ 25154359Sroberto pos_temp = "" 25254359Sroberto for (i = 6; i <= NF; i++) 25354359Sroberto pos_temp = pos_temp " " $i 25454359Sroberto if (pos_string != pos_temp) 25554359Sroberto printf "position%s\n", pos_temp 25654359Sroberto pos_string = pos_temp 25754359Sroberto continue 25854359Sroberto } 25954359Sroberto # 26054359Sroberto # select Austron OSC;ET;TEMP records 26154359Sroberto # 26254359Sroberto # loop 1121 Software Control Locked 26354359Sroberto # 26454359Sroberto # 1121 oscillator type 26554359Sroberto # Software Control loop is under software control 26654359Sroberto # Locked loop is locked 26754359Sroberto # 26854359Sroberto else if (NF >= 5 && $5 == "OSC;ET;TEMP") { 26954359Sroberto osc_count++ 27054359Sroberto osc_temp = $6 " " $7 " " $8 " " $9 27154359Sroberto if (osc_status != osc_temp) 27254359Sroberto printf "loop %s\n", osc_temp 27354359Sroberto osc_status = osc_temp 27454359Sroberto if ($10 > osc_vmax) 27554359Sroberto osc_vmax = $10 27654359Sroberto if ($10 < osc_vmin) 27754359Sroberto osc_vmin = $10 27854359Sroberto if ($11 > osc_tmax) 27954359Sroberto osc_tmax = $11 28054359Sroberto if ($11 < osc_tmin) 28154359Sroberto osc_tmin = $11 28254359Sroberto continue 28354359Sroberto } 28454359Sroberto # 28554359Sroberto # select Austron UTC records 28654359Sroberto # these ain't ready yet 28754359Sroberto # 28854359Sroberto else if (NF >= 5 && $5 == "UTC") { 28954359Sroberto utc_count++ 29054359Sroberto utc_temp = "" 29154359Sroberto for (i = 6; i <= NF; i++) 29254359Sroberto utc_temp = utc_temp " " $i 29354359Sroberto if (utc_string != utc_temp) 29454359Sroberto# printf "utc%s\n", utc_temp 29554359Sroberto utc_string = utc_temp 29654359Sroberto continue 29754359Sroberto } 29854359Sroberto} END { 29954359Sroberto# 30054359Sroberto# PST/Traconex WWV summary data 30154359Sroberto# 30254359Sroberto if (wwv_wwv + wwv_wwvh > 0) 30354359Sroberto printf "wwv %d, wwvh %d, err %d, MHz (2.5) %d, (5) %d, (10) %d, (15) %d, (20) %d\n", wwv_wwv, wwv_wwvh, wwv_sync, wwv_2.5, wwv_5, wwv_10, wwv_15, wwv_20 30454359Sroberto# 30554359Sroberto# Arbiter 1088 summary data 30654359Sroberto# 30754359Sroberto# gps record count 30854359Sroberto# err error count 30954359Sroberto# sats(0-6) satellites tracked 31054359Sroberto# mean 1 PPS mean (us) 31154359Sroberto# rms 1 PPS rms error (us) 31254359Sroberto# var 1 PPS Allan variance 31354359Sroberto# 31454359Sroberto if (arb_count > 0) { 31554359Sroberto printf "gps %d, err %d, sats(0-6) %d %d %d %d %d %d %d", arb_count, arb_sync, arb_0, arb_1, arb_2, arb_3, arb_4, arb_5, arb_6 31654359Sroberto if (arbn > 1) { 31754359Sroberto arb_mean /= arbn 31854359Sroberto arb_rms = sqrt(arb_rms / arbn - arb_mean * arb_mean) 31954359Sroberto arb_var = sqrt(arb_var / (2 * (arbn - 1))) 32054359Sroberto printf ", mean %.2f, rms %.2f, var %.2e\n", arb_mean, arb_rms, arb_var * 1e-6 32154359Sroberto } else { 32254359Sroberto printf "\n" 32354359Sroberto } 32454359Sroberto } 32554359Sroberto# 32654359Sroberto# ensemble summary data 32754359Sroberto# 32854359Sroberto# ensemble record count 32954359Sroberto# badgps gps data unavailable 33054359Sroberto# badloran loran data unavailable 33154359Sroberto# rms ensemble rms error (ns) 33254359Sroberto# >200 ensemble error >200 ns 33354359Sroberto# >100 100 ns < ensemble error < 200 ns 33454359Sroberto# 33554359Sroberto if (ensemble_count > 0) { 33654359Sroberto ensemble_mean /= ensemble_count 33754359Sroberto ensemble_rms = sqrt(ensemble_rms / ensemble_count - ensemble_mean * ensemble_mean) * 1e9 33854359Sroberto printf "ensemble %d, badgps %d, badloran %d, rms %.1f, >200 %d, >100 %d\n", ensemble_count, ensemble_badgps, ensemble_badloran, ensemble_rms, ensemble_200, ensemble_100 33954359Sroberto } 34054359Sroberto# 34154359Sroberto# wwvb summary data 34254359Sroberto# 34354359Sroberto# wwvb record count 34454359Sroberto# ? unsynchronized 34554359Sroberto# >1 error > 1 ms 34654359Sroberto# >10 error > 10 ms 34754359Sroberto# >100 error > 100 ms 34854359Sroberto# >500 error > 500 ms 34954359Sroberto# 35054359Sroberto if (wwvb_count > 0) 35154359Sroberto printf "wwvb %d, ? %d, >1 %d, >10 %d, >100 %d, >500 %d\n", wwvb_count, wwvb_x, wwvb_a, wwvb_b, wwvb_c, wwvb_d 35254359Sroberto# 35354359Sroberto# irig summary data 35454359Sroberto# 35554359Sroberto# irig record count 35654359Sroberto# err error count 35754359Sroberto# 35854359Sroberto if (irig_count > 0) 35954359Sroberto printf "irig %d, err %d\n", irig_count, irig_error 36054359Sroberto# 36154359Sroberto# tdata summary data 36254359Sroberto# 36354359Sroberto# tdata record count 36454359Sroberto# m M master OK-count, mean level (dB) 36554359Sroberto# w W slave OK-count, mean level (dB) 36654359Sroberto# x X slave OK-count, mean level (dB) 36754359Sroberto# y Y slave OK-count, mean level (dB) 36854359Sroberto# z Z slave OK-count, mean level (dB) 36954359Sroberto# 37054359Sroberto if (tdata_count > 0 ) { 37154359Sroberto if (tdata_m > 0) 37254359Sroberto m /= tdata_count 37354359Sroberto if (tdata_x > 0) 37454359Sroberto w /= tdata_count 37554359Sroberto if (tdata_x > 0) 37654359Sroberto x /= tdata_count 37754359Sroberto if (tdata_y > 0) 37854359Sroberto y /= tdata_count 37954359Sroberto if (tdata_z > 0) 38054359Sroberto z /= tdata_count 38154359Sroberto printf "tdata %d, m %d %.1f, w %d %.1f, x %d %.1f, y %d %.1f, z %d %.1f\n", tdata_count, tdata_m, m, tdata_w, w, tdata_x, x, tdata_y, y, tdata_z, z 38254359Sroberto } 38354359Sroberto# 38454359Sroberto# itf summary data 38554359Sroberto# 38654359Sroberto# itf record count 38754359Sroberto# rms itf rms error (ns) 38854359Sroberto# >200 itf error > 200 ns 38954359Sroberto# >100 itf error > 100 ns 39054359Sroberto# var Allan variance 39154359Sroberto# 39254359Sroberto if (itf_count > 1) { 39354359Sroberto itf_mean /= itf_count 39454359Sroberto itf_rms = sqrt(itf_rms / itf_count - itf_mean * itf_mean) * 1e9 39554359Sroberto itf_var = sqrt(itf_var / (2 * (itf_count - 1))) 39654359Sroberto printf "itf %d, rms %.1f, >200 %d, >100 %d, var %.2e\n", itf_count, itf_rms, itf_200, itf_100, itf_var 39754359Sroberto } 39854359Sroberto# 39954359Sroberto# etf summary data 40054359Sroberto# 40154359Sroberto# etf record count 40254359Sroberto# mean etf mean (ns) 40354359Sroberto# rms etf rms error (ns) 40454359Sroberto# max etf maximum (ns) 40554359Sroberto# min etf minimum (ns) 40654359Sroberto# var Allan variance 40754359Sroberto# 40854359Sroberto if (etf_count > 0) { 40954359Sroberto etf_mean /= etf_count 41054359Sroberto etf_rms = sqrt(etf_rms / etf_count - etf_mean * etf_mean) 41154359Sroberto etf_var = sqrt(etf_var / (2 * (etf_count - 1))) 41254359Sroberto printf "etf %d, mean %.1f, rms %.1f, max %d, min %d, var %.2e\n", etf_count, etf_mean, etf_rms, etf_max, etf_min, etf_var 41354359Sroberto } 41454359Sroberto# 41554359Sroberto# trstat summary data 41654359Sroberto# 41754359Sroberto# trstat record count 41854359Sroberto# sat histogram of tracked satellites (0 - 7) 41954359Sroberto# 42054359Sroberto if (trstat_count > 0) 42154359Sroberto printf "trstat %d, sat %d %d %d %d %d %d %d %d\n", trstat_count, trstat_sat[0], trstat_sat[1], trstat_sat[2], trstat_sat[2], trstat_sat[3], trstat_sat[4], trstat_sat[5], trstat_sat[6], trstat_sat[7] 42254359Sroberto# 42354359Sroberto# osc summary data 42454359Sroberto# 42554359Sroberto# osc record count 42654359Sroberto# control control midrange (V) +/- deviation (mV) 42754359Sroberto# temp oven temperature midrange +/- deviation (deg C) 42854359Sroberto# 42954359Sroberto if (osc_count > 0) 43054359Sroberto printf "osc %d, control %.3f+/-%.3f, temp %.1f+/-%.2f\n", osc_count, (osc_vmax + osc_vmin) / 2, (osc_vmax - osc_vmin) / 2 * 1e3, (osc_tmax + osc_tmin) / 2, (osc_tmax - osc_tmin) / 2 43154359Sroberto} 432