/contrib/ntp/scripts/stats/clock.awk

https://bitbucket.org/freebsd/freebsd-head/ · AWK · 431 lines · 257 code · 0 blank · 174 comment · 187 complexity · bd4ebb0b8cd436341b5cd1795f5e5323 MD5 · raw file

  1. # awk program to scan clockstat files and report errors/statistics
  2. #
  3. # usage: awk -f check.awk clockstats
  4. #
  5. # This program works for the following radios:
  6. # PST/Traconex 1020 WWV reciever
  7. # Arbiter 1088 GPS receiver
  8. # Spectracom 8170/Netclock-2 WWVB receiver
  9. # IRIG audio decoder
  10. # Austron 2200A/2201A GPS receiver (see README.austron file)
  11. #
  12. BEGIN {
  13. etf_min = osc_vmin = osc_tmin = 1e9
  14. etf_max = osc_vmax = osc_tmax = -1e9
  15. }
  16. #
  17. # scan all records in file
  18. #
  19. {
  20. #
  21. # select PST/Traconex WWV records
  22. # 00:00:37.234 96/07/08/190 O6@0:5281825C07510394
  23. #
  24. if (NF >= 4 && $3 == "127.127.3.1") {
  25. if (substr($6, 14, 4) > "0010")
  26. wwv_sync++
  27. if (substr($6, 13, 1) == "C")
  28. wwv_wwv++
  29. if (substr($6, 13, 1) == "H")
  30. wwv_wwvh++
  31. x = substr($6, 12, 1)
  32. if (x == "1")
  33. wwv_2.5++
  34. else if (x == "2")
  35. wwv_5++
  36. else if (x == "3")
  37. wwv_10++
  38. else if (x == "4")
  39. wwv_15++
  40. else if (x == "5")
  41. wwv_20++
  42. continue
  43. }
  44. #
  45. # select Arbiter GPS records
  46. # 96 190 00:00:37.000 0 V=08 S=44 T=3 P=10.6 E=00
  47. # N39:42:00.951 W075:46:54.880 210.55 2.50 0.00
  48. #
  49. if (NF >= 4 && $3 == "127.127.11.1") {
  50. if (NF > 8) {
  51. arb_count++
  52. if ($7 != 0)
  53. arb_sync++
  54. x = substr($10, 3, 1)
  55. if (x == "0")
  56. arb_0++
  57. else if (x == "1")
  58. arb_1++
  59. else if (x == "2")
  60. arb_2++
  61. else if (x == "3")
  62. arb_3++
  63. else if (x == "4")
  64. arb_4++
  65. else if (x == "5")
  66. arb_5++
  67. else if (x == "6")
  68. arb_6++
  69. } else if (NF == 8) {
  70. arbn++
  71. arb_mean += $7
  72. arb_rms += $7 * $7
  73. if (arbn > 0) {
  74. x = $7 - arb_val
  75. arb_var += x * x
  76. }
  77. arb_val = $7
  78. }
  79. continue
  80. }
  81. #
  82. # select Spectracom WWVB records
  83. # see summary for decode
  84. # 96 189 23:59:32.248 D
  85. #
  86. if (NF >= 4 && $3 == "127.127.4.1") {
  87. if ($4 == "SIGNAL" || NF > 7)
  88. printf "%s\n", $0
  89. else {
  90. wwvb_count++
  91. if ($4 ~ /\?/)
  92. wwvb_x++
  93. else if ($4 ~ /A/)
  94. wwvb_a++
  95. else if ($4 ~ /B/)
  96. wwvb_b++
  97. else if ($4 ~ /C/)
  98. wwvb_c++
  99. else if ($4 ~ /D/)
  100. wwvb_d++
  101. }
  102. continue
  103. }
  104. #
  105. # select IRIG audio decoder records
  106. # see summary for decode
  107. #
  108. if (NF >= 4 && $3 == "127.127.6.0") {
  109. irig_count++
  110. if ($5 ~ /\?/)
  111. irig_error++
  112. continue
  113. }
  114. #
  115. # select Austron GPS LORAN ENSEMBLE records
  116. # see summary for decode
  117. #
  118. else if (NF >= 13 && $6 == "ENSEMBLE") {
  119. ensemble_count++
  120. if ($9 <= 0)
  121. ensemble_badgps++
  122. else if ($12 <= 0)
  123. ensemble_badloran++
  124. else {
  125. if ($13 > 200e-9 || $13 < -200e-9)
  126. ensemble_200++
  127. else if ($13 > 100e-9 || $13 < -100e-9)
  128. ensemble_100++
  129. ensemble_mean += $13
  130. ensemble_rms += $13 * $13
  131. }
  132. continue
  133. }
  134. #
  135. # select Austron LORAN TDATA records
  136. # see summary for decode; note that signal quality log is simply
  137. # copied to output
  138. #
  139. else if (NF >= 7 && $6 == "TDATA") {
  140. tdata_count++
  141. for (i = 7; i < NF; i++) {
  142. if ($i == "M" && $(i+1) == "OK") {
  143. i += 5
  144. m += $i
  145. tdata_m++
  146. }
  147. else if ($i == "W" && $(i+1) == "OK") {
  148. i += 5
  149. w += $i
  150. tdata_w++
  151. }
  152. else if ($i == "X" && $(i+1) == "OK") {
  153. i += 5
  154. x += $i
  155. tdata_x++
  156. }
  157. else if ($i == "Y" && $(i+1) == "OK") {
  158. i += 5
  159. y += $i
  160. tdata_y++
  161. }
  162. else if ($i == "Z" && $(i+1) == "OK") {
  163. i += 5
  164. z += $i
  165. tdata_z++
  166. }
  167. }
  168. continue
  169. }
  170. #
  171. # select Austron ITF records
  172. # see summary for decode
  173. #
  174. else if (NF >= 13 && $5 == "ITF" && $12 >= 100) {
  175. itf_count++
  176. if ($9 > 200e-9 || $9 < -200e-9)
  177. itf_200++
  178. else if ($9 > 100e-9 || $9 < -100e-9)
  179. itf_100++
  180. itf_mean += $9
  181. itf_rms += $9 * $9
  182. itf_var += $10 * $10
  183. continue
  184. }
  185. #
  186. # select Austron ETF records
  187. # see summary for decode
  188. #
  189. else if (NF >= 13 && $5 == "ETF" && $13 >= 100) {
  190. etf_count++
  191. if ($6 > etf_max)
  192. etf_max = $6
  193. else if ($6 < etf_min)
  194. etf_min = $6
  195. etf_mean += $6
  196. etf_rms += $6 * $6
  197. etf_var += $9 * $9
  198. continue
  199. }
  200. #
  201. # select Austron TRSTAT records
  202. # see summary for decode
  203. #
  204. else if (NF >= 5 && $5 == "TRSTAT") {
  205. trstat_count++
  206. j = 0
  207. for (i = 6; i <= NF; i++)
  208. if ($i == "T")
  209. j++
  210. trstat_sat[j]++
  211. continue
  212. }
  213. #
  214. # select Austron ID;OPT;VER records
  215. #
  216. # config GPS 2201A TTY1 TC1 LORAN IN OUT1 B.00 B.00 28-Apr-93
  217. #
  218. # GPS 2201A receiver model
  219. # TTY1 rs232 moduel
  220. # TC1 IRIG module
  221. # LORAN LORAN assist module
  222. # IN input module
  223. # OUT1 output module
  224. # B.00 B.00 firmware revision
  225. # 28-Apr-9 firmware date3
  226. #
  227. else if (NF >= 5 && $5 == "ID;OPT;VER") {
  228. id_count++
  229. id_temp = ""
  230. for (i = 6; i <= NF; i++)
  231. id_temp = id_temp " " $i
  232. if (id_string != id_temp)
  233. printf "config%s\n", id_temp
  234. id_string = id_temp
  235. continue
  236. }
  237. #
  238. # select Austron POS;PPS;PPSOFF records
  239. #
  240. # position +39:40:48.425 -075:45:02.392 +74.09 Stored UTC 0 200 0
  241. #
  242. # +39:40:48.425 position north latitude
  243. # -075:45:02.392 position east longitude
  244. # +74.09 elevation (meters)
  245. # Stored position is stored
  246. # UTC time is relative to UTC
  247. # 0 200 0 PPS offsets
  248. #
  249. else if (NF >= 5 && $5 == "POS;PPS;PPSOFF") {
  250. pos_count++
  251. pos_temp = ""
  252. for (i = 6; i <= NF; i++)
  253. pos_temp = pos_temp " " $i
  254. if (pos_string != pos_temp)
  255. printf "position%s\n", pos_temp
  256. pos_string = pos_temp
  257. continue
  258. }
  259. #
  260. # select Austron OSC;ET;TEMP records
  261. #
  262. # loop 1121 Software Control Locked
  263. #
  264. # 1121 oscillator type
  265. # Software Control loop is under software control
  266. # Locked loop is locked
  267. #
  268. else if (NF >= 5 && $5 == "OSC;ET;TEMP") {
  269. osc_count++
  270. osc_temp = $6 " " $7 " " $8 " " $9
  271. if (osc_status != osc_temp)
  272. printf "loop %s\n", osc_temp
  273. osc_status = osc_temp
  274. if ($10 > osc_vmax)
  275. osc_vmax = $10
  276. if ($10 < osc_vmin)
  277. osc_vmin = $10
  278. if ($11 > osc_tmax)
  279. osc_tmax = $11
  280. if ($11 < osc_tmin)
  281. osc_tmin = $11
  282. continue
  283. }
  284. #
  285. # select Austron UTC records
  286. # these ain't ready yet
  287. #
  288. else if (NF >= 5 && $5 == "UTC") {
  289. utc_count++
  290. utc_temp = ""
  291. for (i = 6; i <= NF; i++)
  292. utc_temp = utc_temp " " $i
  293. if (utc_string != utc_temp)
  294. # printf "utc%s\n", utc_temp
  295. utc_string = utc_temp
  296. continue
  297. }
  298. } END {
  299. #
  300. # PST/Traconex WWV summary data
  301. #
  302. if (wwv_wwv + wwv_wwvh > 0)
  303. 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
  304. #
  305. # Arbiter 1088 summary data
  306. #
  307. # gps record count
  308. # err error count
  309. # sats(0-6) satellites tracked
  310. # mean 1 PPS mean (us)
  311. # rms 1 PPS rms error (us)
  312. # var 1 PPS Allan variance
  313. #
  314. if (arb_count > 0) {
  315. 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
  316. if (arbn > 1) {
  317. arb_mean /= arbn
  318. arb_rms = sqrt(arb_rms / arbn - arb_mean * arb_mean)
  319. arb_var = sqrt(arb_var / (2 * (arbn - 1)))
  320. printf ", mean %.2f, rms %.2f, var %.2e\n", arb_mean, arb_rms, arb_var * 1e-6
  321. } else {
  322. printf "\n"
  323. }
  324. }
  325. #
  326. # ensemble summary data
  327. #
  328. # ensemble record count
  329. # badgps gps data unavailable
  330. # badloran loran data unavailable
  331. # rms ensemble rms error (ns)
  332. # >200 ensemble error >200 ns
  333. # >100 100 ns < ensemble error < 200 ns
  334. #
  335. if (ensemble_count > 0) {
  336. ensemble_mean /= ensemble_count
  337. ensemble_rms = sqrt(ensemble_rms / ensemble_count - ensemble_mean * ensemble_mean) * 1e9
  338. 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
  339. }
  340. #
  341. # wwvb summary data
  342. #
  343. # wwvb record count
  344. # ? unsynchronized
  345. # >1 error > 1 ms
  346. # >10 error > 10 ms
  347. # >100 error > 100 ms
  348. # >500 error > 500 ms
  349. #
  350. if (wwvb_count > 0)
  351. 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
  352. #
  353. # irig summary data
  354. #
  355. # irig record count
  356. # err error count
  357. #
  358. if (irig_count > 0)
  359. printf "irig %d, err %d\n", irig_count, irig_error
  360. #
  361. # tdata summary data
  362. #
  363. # tdata record count
  364. # m M master OK-count, mean level (dB)
  365. # w W slave OK-count, mean level (dB)
  366. # x X slave OK-count, mean level (dB)
  367. # y Y slave OK-count, mean level (dB)
  368. # z Z slave OK-count, mean level (dB)
  369. #
  370. if (tdata_count > 0 ) {
  371. if (tdata_m > 0)
  372. m /= tdata_count
  373. if (tdata_x > 0)
  374. w /= tdata_count
  375. if (tdata_x > 0)
  376. x /= tdata_count
  377. if (tdata_y > 0)
  378. y /= tdata_count
  379. if (tdata_z > 0)
  380. z /= tdata_count
  381. 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
  382. }
  383. #
  384. # itf summary data
  385. #
  386. # itf record count
  387. # rms itf rms error (ns)
  388. # >200 itf error > 200 ns
  389. # >100 itf error > 100 ns
  390. # var Allan variance
  391. #
  392. if (itf_count > 1) {
  393. itf_mean /= itf_count
  394. itf_rms = sqrt(itf_rms / itf_count - itf_mean * itf_mean) * 1e9
  395. itf_var = sqrt(itf_var / (2 * (itf_count - 1)))
  396. printf "itf %d, rms %.1f, >200 %d, >100 %d, var %.2e\n", itf_count, itf_rms, itf_200, itf_100, itf_var
  397. }
  398. #
  399. # etf summary data
  400. #
  401. # etf record count
  402. # mean etf mean (ns)
  403. # rms etf rms error (ns)
  404. # max etf maximum (ns)
  405. # min etf minimum (ns)
  406. # var Allan variance
  407. #
  408. if (etf_count > 0) {
  409. etf_mean /= etf_count
  410. etf_rms = sqrt(etf_rms / etf_count - etf_mean * etf_mean)
  411. etf_var = sqrt(etf_var / (2 * (etf_count - 1)))
  412. 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
  413. }
  414. #
  415. # trstat summary data
  416. #
  417. # trstat record count
  418. # sat histogram of tracked satellites (0 - 7)
  419. #
  420. if (trstat_count > 0)
  421. 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]
  422. #
  423. # osc summary data
  424. #
  425. # osc record count
  426. # control control midrange (V) +/- deviation (mV)
  427. # temp oven temperature midrange +/- deviation (deg C)
  428. #
  429. if (osc_count > 0)
  430. 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
  431. }