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