PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/ntpd/refclock_wwv.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2709 lines | 1594 code | 204 blank | 911 comment | 264 complexity | d5531729a944f68437d2d9bd4047b8da MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. /*
  2. * refclock_wwv - clock driver for NIST WWV/H time/frequency station
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. #include <config.h>
  6. #endif
  7. #if defined(REFCLOCK) && defined(CLOCK_WWV)
  8. #include "ntpd.h"
  9. #include "ntp_io.h"
  10. #include "ntp_refclock.h"
  11. #include "ntp_calendar.h"
  12. #include "ntp_stdlib.h"
  13. #include "audio.h"
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <math.h>
  17. #ifdef HAVE_SYS_IOCTL_H
  18. # include <sys/ioctl.h>
  19. #endif /* HAVE_SYS_IOCTL_H */
  20. #define ICOM 1
  21. #ifdef ICOM
  22. #include "icom.h"
  23. #endif /* ICOM */
  24. /*
  25. * Audio WWV/H demodulator/decoder
  26. *
  27. * This driver synchronizes the computer time using data encoded in
  28. * radio transmissions from NIST time/frequency stations WWV in Boulder,
  29. * CO, and WWVH in Kauai, HI. Transmissions are made continuously on
  30. * 2.5, 5, 10 and 15 MHz from WWV and WWVH, and 20 MHz from WWV. An
  31. * ordinary AM shortwave receiver can be tuned manually to one of these
  32. * frequencies or, in the case of ICOM receivers, the receiver can be
  33. * tuned automatically using this program as propagation conditions
  34. * change throughout the weasons, both day and night.
  35. *
  36. * The driver receives, demodulates and decodes the radio signals when
  37. * connected to the audio codec of a workstation running Solaris, SunOS
  38. * FreeBSD or Linux, and with a little help, other workstations with
  39. * similar codecs or sound cards. In this implementation, only one audio
  40. * driver and codec can be supported on a single machine.
  41. *
  42. * The demodulation and decoding algorithms used in this driver are
  43. * based on those developed for the TAPR DSP93 development board and the
  44. * TI 320C25 digital signal processor described in: Mills, D.L. A
  45. * precision radio clock for WWV transmissions. Electrical Engineering
  46. * Report 97-8-1, University of Delaware, August 1997, 25 pp., available
  47. * from www.eecis.udel.edu/~mills/reports.html. The algorithms described
  48. * in this report have been modified somewhat to improve performance
  49. * under weak signal conditions and to provide an automatic station
  50. * identification feature.
  51. *
  52. * The ICOM code is normally compiled in the driver. It isn't used,
  53. * unless the mode keyword on the server configuration command specifies
  54. * a nonzero ICOM ID select code. The C-IV trace is turned on if the
  55. * debug level is greater than one.
  56. *
  57. * Fudge factors
  58. *
  59. * Fudge flag4 causes the dubugging output described above to be
  60. * recorded in the clockstats file. Fudge flag2 selects the audio input
  61. * port, where 0 is the mike port (default) and 1 is the line-in port.
  62. * It does not seem useful to select the compact disc player port. Fudge
  63. * flag3 enables audio monitoring of the input signal. For this purpose,
  64. * the monitor gain is set to a default value.
  65. */
  66. /*
  67. * General definitions. These ordinarily do not need to be changed.
  68. */
  69. #define DEVICE_AUDIO "/dev/audio" /* audio device name */
  70. #define AUDIO_BUFSIZ 320 /* audio buffer size (50 ms) */
  71. #define PRECISION (-10) /* precision assumed (about 1 ms) */
  72. #define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */
  73. #define SECOND 8000 /* second epoch (sample rate) (Hz) */
  74. #define MINUTE (SECOND * 60) /* minute epoch */
  75. #define OFFSET 128 /* companded sample offset */
  76. #define SIZE 256 /* decompanding table size */
  77. #define MAXAMP 6000. /* max signal level reference */
  78. #define MAXCLP 100 /* max clips above reference per s */
  79. #define MAXSNR 40. /* max SNR reference */
  80. #define MAXFREQ 1.5 /* max frequency tolerance (187 PPM) */
  81. #define DATCYC 170 /* data filter cycles */
  82. #define DATSIZ (DATCYC * MS) /* data filter size */
  83. #define SYNCYC 800 /* minute filter cycles */
  84. #define SYNSIZ (SYNCYC * MS) /* minute filter size */
  85. #define TCKCYC 5 /* tick filter cycles */
  86. #define TCKSIZ (TCKCYC * MS) /* tick filter size */
  87. #define NCHAN 5 /* number of radio channels */
  88. #define AUDIO_PHI 5e-6 /* dispersion growth factor */
  89. /*
  90. * Tunable parameters. The DGAIN parameter can be changed to fit the
  91. * audio response of the radio at 100 Hz. The WWV/WWVH data subcarrier
  92. * is transmitted at about 20 percent percent modulation; the matched
  93. * filter boosts it by a factor of 17 and the receiver response does
  94. * what it does. The compromise value works for ICOM radios. If the
  95. * radio is not tunable, the DCHAN parameter can be changed to fit the
  96. * expected best propagation frequency: higher if further from the
  97. * transmitter, lower if nearer. The compromise value works for the US
  98. * right coast. The FREQ_OFFSET parameter can be used as a frequency
  99. * vernier to correct codec requency if greater than MAXFREQ.
  100. */
  101. #define DCHAN 3 /* default radio channel (15 Mhz) */
  102. #define DGAIN 5. /* subcarrier gain */
  103. #define FREQ_OFFSET 0. /* codec frequency correction (PPM) */
  104. /*
  105. * General purpose status bits (status)
  106. *
  107. * SELV and/or SELH are set when WWV or WWVH have been heard and cleared
  108. * on signal loss. SSYNC is set when the second sync pulse has been
  109. * acquired and cleared by signal loss. MSYNC is set when the minute
  110. * sync pulse has been acquired. DSYNC is set when the units digit has
  111. * has reached the threshold and INSYNC is set when all nine digits have
  112. * reached the threshold. The MSYNC, DSYNC and INSYNC bits are cleared
  113. * only by timeout, upon which the driver starts over from scratch.
  114. *
  115. * DGATE is lit if the data bit amplitude or SNR is below thresholds and
  116. * BGATE is lit if the pulse width amplitude or SNR is below thresolds.
  117. * LEPSEC is set during the last minute of the leap day. At the end of
  118. * this minute the driver inserts second 60 in the seconds state machine
  119. * and the minute sync slips a second.
  120. */
  121. #define MSYNC 0x0001 /* minute epoch sync */
  122. #define SSYNC 0x0002 /* second epoch sync */
  123. #define DSYNC 0x0004 /* minute units sync */
  124. #define INSYNC 0x0008 /* clock synchronized */
  125. #define FGATE 0x0010 /* frequency gate */
  126. #define DGATE 0x0020 /* data pulse amplitude error */
  127. #define BGATE 0x0040 /* data pulse width error */
  128. #define LEPSEC 0x1000 /* leap minute */
  129. /*
  130. * Station scoreboard bits
  131. *
  132. * These are used to establish the signal quality for each of the five
  133. * frequencies and two stations.
  134. */
  135. #define SELV 0x0100 /* WWV station select */
  136. #define SELH 0x0200 /* WWVH station select */
  137. /*
  138. * Alarm status bits (alarm)
  139. *
  140. * These bits indicate various alarm conditions, which are decoded to
  141. * form the quality character included in the timecode.
  142. */
  143. #define CMPERR 1 /* digit or misc bit compare error */
  144. #define LOWERR 2 /* low bit or digit amplitude or SNR */
  145. #define NINERR 4 /* less than nine digits in minute */
  146. #define SYNERR 8 /* not tracking second sync */
  147. /*
  148. * Watchcat timeouts (watch)
  149. *
  150. * If these timeouts expire, the status bits are mashed to zero and the
  151. * driver starts from scratch. Suitably more refined procedures may be
  152. * developed in future. All these are in minutes.
  153. */
  154. #define ACQSN 6 /* station acquisition timeout */
  155. #define DATA 15 /* unit minutes timeout */
  156. #define SYNCH 40 /* station sync timeout */
  157. #define PANIC (2 * 1440) /* panic timeout */
  158. /*
  159. * Thresholds. These establish the minimum signal level, minimum SNR and
  160. * maximum jitter thresholds which establish the error and false alarm
  161. * rates of the driver. The values defined here may be on the
  162. * adventurous side in the interest of the highest sensitivity.
  163. */
  164. #define MTHR 13. /* minute sync gate (percent) */
  165. #define TTHR 50. /* minute sync threshold (percent) */
  166. #define AWND 20 /* minute sync jitter threshold (ms) */
  167. #define ATHR 2500. /* QRZ minute sync threshold */
  168. #define ASNR 20. /* QRZ minute sync SNR threshold (dB) */
  169. #define QTHR 2500. /* QSY minute sync threshold */
  170. #define QSNR 20. /* QSY minute sync SNR threshold (dB) */
  171. #define STHR 2500. /* second sync threshold */
  172. #define SSNR 15. /* second sync SNR threshold (dB) */
  173. #define SCMP 10 /* second sync compare threshold */
  174. #define DTHR 1000. /* bit threshold */
  175. #define DSNR 10. /* bit SNR threshold (dB) */
  176. #define AMIN 3 /* min bit count */
  177. #define AMAX 6 /* max bit count */
  178. #define BTHR 1000. /* digit threshold */
  179. #define BSNR 3. /* digit likelihood threshold (dB) */
  180. #define BCMP 3 /* digit compare threshold */
  181. #define MAXERR 40 /* maximum error alarm */
  182. /*
  183. * Tone frequency definitions. The increments are for 4.5-deg sine
  184. * table.
  185. */
  186. #define MS (SECOND / 1000) /* samples per millisecond */
  187. #define IN100 ((100 * 80) / SECOND) /* 100 Hz increment */
  188. #define IN1000 ((1000 * 80) / SECOND) /* 1000 Hz increment */
  189. #define IN1200 ((1200 * 80) / SECOND) /* 1200 Hz increment */
  190. /*
  191. * Acquisition and tracking time constants
  192. */
  193. #define MINAVG 8 /* min averaging time */
  194. #define MAXAVG 1024 /* max averaging time */
  195. #define FCONST 3 /* frequency time constant */
  196. #define TCONST 16 /* data bit/digit time constant */
  197. /*
  198. * Miscellaneous status bits (misc)
  199. *
  200. * These bits correspond to designated bits in the WWV/H timecode. The
  201. * bit probabilities are exponentially averaged over several minutes and
  202. * processed by a integrator and threshold.
  203. */
  204. #define DUT1 0x01 /* 56 DUT .1 */
  205. #define DUT2 0x02 /* 57 DUT .2 */
  206. #define DUT4 0x04 /* 58 DUT .4 */
  207. #define DUTS 0x08 /* 50 DUT sign */
  208. #define DST1 0x10 /* 55 DST1 leap warning */
  209. #define DST2 0x20 /* 2 DST2 DST1 delayed one day */
  210. #define SECWAR 0x40 /* 3 leap second warning */
  211. /*
  212. * The on-time synchronization point for the driver is the second epoch
  213. * sync pulse produced by the FIR matched filters. As the 5-ms delay of
  214. * these filters is compensated, the program delay is 1.1 ms due to the
  215. * 600-Hz IIR bandpass filter. The measured receiver delay is 4.7 ms and
  216. * the codec delay less than 0.2 ms. The additional propagation delay
  217. * specific to each receiver location can be programmed in the fudge
  218. * time1 and time2 values for WWV and WWVH, respectively.
  219. */
  220. #define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */
  221. /*
  222. * Table of sine values at 4.5-degree increments. This is used by the
  223. * synchronous matched filter demodulators.
  224. */
  225. double sintab[] = {
  226. 0.000000e+00, 7.845910e-02, 1.564345e-01, 2.334454e-01, /* 0-3 */
  227. 3.090170e-01, 3.826834e-01, 4.539905e-01, 5.224986e-01, /* 4-7 */
  228. 5.877853e-01, 6.494480e-01, 7.071068e-01, 7.604060e-01, /* 8-11 */
  229. 8.090170e-01, 8.526402e-01, 8.910065e-01, 9.238795e-01, /* 12-15 */
  230. 9.510565e-01, 9.723699e-01, 9.876883e-01, 9.969173e-01, /* 16-19 */
  231. 1.000000e+00, 9.969173e-01, 9.876883e-01, 9.723699e-01, /* 20-23 */
  232. 9.510565e-01, 9.238795e-01, 8.910065e-01, 8.526402e-01, /* 24-27 */
  233. 8.090170e-01, 7.604060e-01, 7.071068e-01, 6.494480e-01, /* 28-31 */
  234. 5.877853e-01, 5.224986e-01, 4.539905e-01, 3.826834e-01, /* 32-35 */
  235. 3.090170e-01, 2.334454e-01, 1.564345e-01, 7.845910e-02, /* 36-39 */
  236. -0.000000e+00, -7.845910e-02, -1.564345e-01, -2.334454e-01, /* 40-43 */
  237. -3.090170e-01, -3.826834e-01, -4.539905e-01, -5.224986e-01, /* 44-47 */
  238. -5.877853e-01, -6.494480e-01, -7.071068e-01, -7.604060e-01, /* 48-51 */
  239. -8.090170e-01, -8.526402e-01, -8.910065e-01, -9.238795e-01, /* 52-55 */
  240. -9.510565e-01, -9.723699e-01, -9.876883e-01, -9.969173e-01, /* 56-59 */
  241. -1.000000e+00, -9.969173e-01, -9.876883e-01, -9.723699e-01, /* 60-63 */
  242. -9.510565e-01, -9.238795e-01, -8.910065e-01, -8.526402e-01, /* 64-67 */
  243. -8.090170e-01, -7.604060e-01, -7.071068e-01, -6.494480e-01, /* 68-71 */
  244. -5.877853e-01, -5.224986e-01, -4.539905e-01, -3.826834e-01, /* 72-75 */
  245. -3.090170e-01, -2.334454e-01, -1.564345e-01, -7.845910e-02, /* 76-79 */
  246. 0.000000e+00}; /* 80 */
  247. /*
  248. * Decoder operations at the end of each second are driven by a state
  249. * machine. The transition matrix consists of a dispatch table indexed
  250. * by second number. Each entry in the table contains a case switch
  251. * number and argument.
  252. */
  253. struct progx {
  254. int sw; /* case switch number */
  255. int arg; /* argument */
  256. };
  257. /*
  258. * Case switch numbers
  259. */
  260. #define IDLE 0 /* no operation */
  261. #define COEF 1 /* BCD bit */
  262. #define COEF1 2 /* BCD bit for minute unit */
  263. #define COEF2 3 /* BCD bit not used */
  264. #define DECIM9 4 /* BCD digit 0-9 */
  265. #define DECIM6 5 /* BCD digit 0-6 */
  266. #define DECIM3 6 /* BCD digit 0-3 */
  267. #define DECIM2 7 /* BCD digit 0-2 */
  268. #define MSCBIT 8 /* miscellaneous bit */
  269. #define MSC20 9 /* miscellaneous bit */
  270. #define MSC21 10 /* QSY probe channel */
  271. #define MIN1 11 /* latch time */
  272. #define MIN2 12 /* leap second */
  273. #define SYNC2 13 /* latch minute sync pulse */
  274. #define SYNC3 14 /* latch data pulse */
  275. /*
  276. * Offsets in decoding matrix
  277. */
  278. #define MN 0 /* minute digits (2) */
  279. #define HR 2 /* hour digits (2) */
  280. #define DA 4 /* day digits (3) */
  281. #define YR 7 /* year digits (2) */
  282. struct progx progx[] = {
  283. {SYNC2, 0}, /* 0 latch minute sync pulse */
  284. {SYNC3, 0}, /* 1 latch data pulse */
  285. {MSCBIT, DST2}, /* 2 dst2 */
  286. {MSCBIT, SECWAR}, /* 3 lw */
  287. {COEF, 0}, /* 4 1 year units */
  288. {COEF, 1}, /* 5 2 */
  289. {COEF, 2}, /* 6 4 */
  290. {COEF, 3}, /* 7 8 */
  291. {DECIM9, YR}, /* 8 */
  292. {IDLE, 0}, /* 9 p1 */
  293. {COEF1, 0}, /* 10 1 minute units */
  294. {COEF1, 1}, /* 11 2 */
  295. {COEF1, 2}, /* 12 4 */
  296. {COEF1, 3}, /* 13 8 */
  297. {DECIM9, MN}, /* 14 */
  298. {COEF, 0}, /* 15 10 minute tens */
  299. {COEF, 1}, /* 16 20 */
  300. {COEF, 2}, /* 17 40 */
  301. {COEF2, 3}, /* 18 80 (not used) */
  302. {DECIM6, MN + 1}, /* 19 p2 */
  303. {COEF, 0}, /* 20 1 hour units */
  304. {COEF, 1}, /* 21 2 */
  305. {COEF, 2}, /* 22 4 */
  306. {COEF, 3}, /* 23 8 */
  307. {DECIM9, HR}, /* 24 */
  308. {COEF, 0}, /* 25 10 hour tens */
  309. {COEF, 1}, /* 26 20 */
  310. {COEF2, 2}, /* 27 40 (not used) */
  311. {COEF2, 3}, /* 28 80 (not used) */
  312. {DECIM2, HR + 1}, /* 29 p3 */
  313. {COEF, 0}, /* 30 1 day units */
  314. {COEF, 1}, /* 31 2 */
  315. {COEF, 2}, /* 32 4 */
  316. {COEF, 3}, /* 33 8 */
  317. {DECIM9, DA}, /* 34 */
  318. {COEF, 0}, /* 35 10 day tens */
  319. {COEF, 1}, /* 36 20 */
  320. {COEF, 2}, /* 37 40 */
  321. {COEF, 3}, /* 38 80 */
  322. {DECIM9, DA + 1}, /* 39 p4 */
  323. {COEF, 0}, /* 40 100 day hundreds */
  324. {COEF, 1}, /* 41 200 */
  325. {COEF2, 2}, /* 42 400 (not used) */
  326. {COEF2, 3}, /* 43 800 (not used) */
  327. {DECIM3, DA + 2}, /* 44 */
  328. {IDLE, 0}, /* 45 */
  329. {IDLE, 0}, /* 46 */
  330. {IDLE, 0}, /* 47 */
  331. {IDLE, 0}, /* 48 */
  332. {IDLE, 0}, /* 49 p5 */
  333. {MSCBIT, DUTS}, /* 50 dut+- */
  334. {COEF, 0}, /* 51 10 year tens */
  335. {COEF, 1}, /* 52 20 */
  336. {COEF, 2}, /* 53 40 */
  337. {COEF, 3}, /* 54 80 */
  338. {MSC20, DST1}, /* 55 dst1 */
  339. {MSCBIT, DUT1}, /* 56 0.1 dut */
  340. {MSCBIT, DUT2}, /* 57 0.2 */
  341. {MSC21, DUT4}, /* 58 0.4 QSY probe channel */
  342. {MIN1, 0}, /* 59 p6 latch time */
  343. {MIN2, 0} /* 60 leap second */
  344. };
  345. /*
  346. * BCD coefficients for maximum likelihood digit decode
  347. */
  348. #define P15 1. /* max positive number */
  349. #define N15 -1. /* max negative number */
  350. /*
  351. * Digits 0-9
  352. */
  353. #define P9 (P15 / 4) /* mark (+1) */
  354. #define N9 (N15 / 4) /* space (-1) */
  355. double bcd9[][4] = {
  356. {N9, N9, N9, N9}, /* 0 */
  357. {P9, N9, N9, N9}, /* 1 */
  358. {N9, P9, N9, N9}, /* 2 */
  359. {P9, P9, N9, N9}, /* 3 */
  360. {N9, N9, P9, N9}, /* 4 */
  361. {P9, N9, P9, N9}, /* 5 */
  362. {N9, P9, P9, N9}, /* 6 */
  363. {P9, P9, P9, N9}, /* 7 */
  364. {N9, N9, N9, P9}, /* 8 */
  365. {P9, N9, N9, P9}, /* 9 */
  366. {0, 0, 0, 0} /* backstop */
  367. };
  368. /*
  369. * Digits 0-6 (minute tens)
  370. */
  371. #define P6 (P15 / 3) /* mark (+1) */
  372. #define N6 (N15 / 3) /* space (-1) */
  373. double bcd6[][4] = {
  374. {N6, N6, N6, 0}, /* 0 */
  375. {P6, N6, N6, 0}, /* 1 */
  376. {N6, P6, N6, 0}, /* 2 */
  377. {P6, P6, N6, 0}, /* 3 */
  378. {N6, N6, P6, 0}, /* 4 */
  379. {P6, N6, P6, 0}, /* 5 */
  380. {N6, P6, P6, 0}, /* 6 */
  381. {0, 0, 0, 0} /* backstop */
  382. };
  383. /*
  384. * Digits 0-3 (day hundreds)
  385. */
  386. #define P3 (P15 / 2) /* mark (+1) */
  387. #define N3 (N15 / 2) /* space (-1) */
  388. double bcd3[][4] = {
  389. {N3, N3, 0, 0}, /* 0 */
  390. {P3, N3, 0, 0}, /* 1 */
  391. {N3, P3, 0, 0}, /* 2 */
  392. {P3, P3, 0, 0}, /* 3 */
  393. {0, 0, 0, 0} /* backstop */
  394. };
  395. /*
  396. * Digits 0-2 (hour tens)
  397. */
  398. #define P2 (P15 / 2) /* mark (+1) */
  399. #define N2 (N15 / 2) /* space (-1) */
  400. double bcd2[][4] = {
  401. {N2, N2, 0, 0}, /* 0 */
  402. {P2, N2, 0, 0}, /* 1 */
  403. {N2, P2, 0, 0}, /* 2 */
  404. {0, 0, 0, 0} /* backstop */
  405. };
  406. /*
  407. * DST decode (DST2 DST1) for prettyprint
  408. */
  409. char dstcod[] = {
  410. 'S', /* 00 standard time */
  411. 'I', /* 01 set clock ahead at 0200 local */
  412. 'O', /* 10 set clock back at 0200 local */
  413. 'D' /* 11 daylight time */
  414. };
  415. /*
  416. * The decoding matrix consists of nine row vectors, one for each digit
  417. * of the timecode. The digits are stored from least to most significant
  418. * order. The maximum likelihood timecode is formed from the digits
  419. * corresponding to the maximum likelihood values reading in the
  420. * opposite order: yy ddd hh:mm.
  421. */
  422. struct decvec {
  423. int radix; /* radix (3, 4, 6, 10) */
  424. int digit; /* current clock digit */
  425. int mldigit; /* maximum likelihood digit */
  426. int count; /* match count */
  427. double digprb; /* max digit probability */
  428. double digsnr; /* likelihood function (dB) */
  429. double like[10]; /* likelihood integrator 0-9 */
  430. };
  431. /*
  432. * The station structure (sp) is used to acquire the minute pulse from
  433. * WWV and/or WWVH. These stations are distinguished by the frequency
  434. * used for the second and minute sync pulses, 1000 Hz for WWV and 1200
  435. * Hz for WWVH. Other than frequency, the format is the same.
  436. */
  437. struct sync {
  438. double epoch; /* accumulated epoch differences */
  439. double maxeng; /* sync max energy */
  440. double noieng; /* sync noise energy */
  441. long pos; /* max amplitude position */
  442. long lastpos; /* last max position */
  443. long mepoch; /* minute synch epoch */
  444. double amp; /* sync signal */
  445. double syneng; /* sync signal max */
  446. double synmax; /* sync signal max latched at 0 s */
  447. double synsnr; /* sync signal SNR */
  448. double metric; /* signal quality metric */
  449. int reach; /* reachability register */
  450. int count; /* bit counter */
  451. int select; /* select bits */
  452. char refid[5]; /* reference identifier */
  453. };
  454. /*
  455. * The channel structure (cp) is used to mitigate between channels.
  456. */
  457. struct chan {
  458. int gain; /* audio gain */
  459. struct sync wwv; /* wwv station */
  460. struct sync wwvh; /* wwvh station */
  461. };
  462. /*
  463. * WWV unit control structure (up)
  464. */
  465. struct wwvunit {
  466. l_fp timestamp; /* audio sample timestamp */
  467. l_fp tick; /* audio sample increment */
  468. double phase, freq; /* logical clock phase and frequency */
  469. double monitor; /* audio monitor point */
  470. #ifdef ICOM
  471. int fd_icom; /* ICOM file descriptor */
  472. #endif /* ICOM */
  473. int errflg; /* error flags */
  474. int watch; /* watchcat */
  475. /*
  476. * Audio codec variables
  477. */
  478. double comp[SIZE]; /* decompanding table */
  479. int port; /* codec port */
  480. int gain; /* codec gain */
  481. int mongain; /* codec monitor gain */
  482. int clipcnt; /* sample clipped count */
  483. /*
  484. * Variables used to establish basic system timing
  485. */
  486. int avgint; /* master time constant */
  487. int yepoch; /* sync epoch */
  488. int repoch; /* buffered sync epoch */
  489. double epomax; /* second sync amplitude */
  490. double eposnr; /* second sync SNR */
  491. double irig; /* data I channel amplitude */
  492. double qrig; /* data Q channel amplitude */
  493. int datapt; /* 100 Hz ramp */
  494. double datpha; /* 100 Hz VFO control */
  495. int rphase; /* second sample counter */
  496. long mphase; /* minute sample counter */
  497. /*
  498. * Variables used to mitigate which channel to use
  499. */
  500. struct chan mitig[NCHAN]; /* channel data */
  501. struct sync *sptr; /* station pointer */
  502. int dchan; /* data channel */
  503. int schan; /* probe channel */
  504. int achan; /* active channel */
  505. /*
  506. * Variables used by the clock state machine
  507. */
  508. struct decvec decvec[9]; /* decoding matrix */
  509. int rsec; /* seconds counter */
  510. int digcnt; /* count of digits synchronized */
  511. /*
  512. * Variables used to estimate signal levels and bit/digit
  513. * probabilities
  514. */
  515. double datsig; /* data signal max */
  516. double datsnr; /* data signal SNR (dB) */
  517. /*
  518. * Variables used to establish status and alarm conditions
  519. */
  520. int status; /* status bits */
  521. int alarm; /* alarm flashers */
  522. int misc; /* miscellaneous timecode bits */
  523. int errcnt; /* data bit error counter */
  524. };
  525. /*
  526. * Function prototypes
  527. */
  528. static int wwv_start P((int, struct peer *));
  529. static void wwv_shutdown P((int, struct peer *));
  530. static void wwv_receive P((struct recvbuf *));
  531. static void wwv_poll P((int, struct peer *));
  532. /*
  533. * More function prototypes
  534. */
  535. static void wwv_epoch P((struct peer *));
  536. static void wwv_rf P((struct peer *, double));
  537. static void wwv_endpoc P((struct peer *, int));
  538. static void wwv_rsec P((struct peer *, double));
  539. static void wwv_qrz P((struct peer *, struct sync *, int));
  540. static void wwv_corr4 P((struct peer *, struct decvec *,
  541. double [], double [][4]));
  542. static void wwv_gain P((struct peer *));
  543. static void wwv_tsec P((struct peer *));
  544. static int timecode P((struct wwvunit *, char *));
  545. static double wwv_snr P((double, double));
  546. static int carry P((struct decvec *));
  547. static int wwv_newchan P((struct peer *));
  548. static void wwv_newgame P((struct peer *));
  549. static double wwv_metric P((struct sync *));
  550. static void wwv_clock P((struct peer *));
  551. #ifdef ICOM
  552. static int wwv_qsy P((struct peer *, int));
  553. #endif /* ICOM */
  554. static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */
  555. /*
  556. * Transfer vector
  557. */
  558. struct refclock refclock_wwv = {
  559. wwv_start, /* start up driver */
  560. wwv_shutdown, /* shut down driver */
  561. wwv_poll, /* transmit poll message */
  562. noentry, /* not used (old wwv_control) */
  563. noentry, /* initialize driver (not used) */
  564. noentry, /* not used (old wwv_buginfo) */
  565. NOFLAGS /* not used */
  566. };
  567. /*
  568. * wwv_start - open the devices and initialize data for processing
  569. */
  570. static int
  571. wwv_start(
  572. int unit, /* instance number (used by PCM) */
  573. struct peer *peer /* peer structure pointer */
  574. )
  575. {
  576. struct refclockproc *pp;
  577. struct wwvunit *up;
  578. #ifdef ICOM
  579. int temp;
  580. #endif /* ICOM */
  581. /*
  582. * Local variables
  583. */
  584. int fd; /* file descriptor */
  585. int i; /* index */
  586. double step; /* codec adjustment */
  587. /*
  588. * Open audio device
  589. */
  590. fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
  591. if (fd < 0)
  592. return (0);
  593. #ifdef DEBUG
  594. if (debug)
  595. audio_show();
  596. #endif /* DEBUG */
  597. /*
  598. * Allocate and initialize unit structure
  599. */
  600. if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) {
  601. close(fd);
  602. return (0);
  603. }
  604. memset(up, 0, sizeof(struct wwvunit));
  605. pp = peer->procptr;
  606. pp->unitptr = (caddr_t)up;
  607. pp->io.clock_recv = wwv_receive;
  608. pp->io.srcclock = (caddr_t)peer;
  609. pp->io.datalen = 0;
  610. pp->io.fd = fd;
  611. if (!io_addclock(&pp->io)) {
  612. close(fd);
  613. free(up);
  614. return (0);
  615. }
  616. /*
  617. * Initialize miscellaneous variables
  618. */
  619. peer->precision = PRECISION;
  620. pp->clockdesc = DESCRIPTION;
  621. /*
  622. * The companded samples are encoded sign-magnitude. The table
  623. * contains all the 256 values in the interest of speed.
  624. */
  625. up->comp[0] = up->comp[OFFSET] = 0.;
  626. up->comp[1] = 1.; up->comp[OFFSET + 1] = -1.;
  627. up->comp[2] = 3.; up->comp[OFFSET + 2] = -3.;
  628. step = 2.;
  629. for (i = 3; i < OFFSET; i++) {
  630. up->comp[i] = up->comp[i - 1] + step;
  631. up->comp[OFFSET + i] = -up->comp[i];
  632. if (i % 16 == 0)
  633. step *= 2.;
  634. }
  635. DTOLFP(1. / SECOND, &up->tick);
  636. /*
  637. * Initialize the decoding matrix with the radix for each digit
  638. * position.
  639. */
  640. up->decvec[MN].radix = 10; /* minutes */
  641. up->decvec[MN + 1].radix = 6;
  642. up->decvec[HR].radix = 10; /* hours */
  643. up->decvec[HR + 1].radix = 3;
  644. up->decvec[DA].radix = 10; /* days */
  645. up->decvec[DA + 1].radix = 10;
  646. up->decvec[DA + 2].radix = 4;
  647. up->decvec[YR].radix = 10; /* years */
  648. up->decvec[YR + 1].radix = 10;
  649. #ifdef ICOM
  650. /*
  651. * Initialize autotune if available. Note that the ICOM select
  652. * code must be less than 128, so the high order bit can be used
  653. * to select the line speed 0 (9600 bps) or 1 (1200 bps).
  654. */
  655. temp = 0;
  656. #ifdef DEBUG
  657. if (debug > 1)
  658. temp = P_TRACE;
  659. #endif /* DEBUG */
  660. if (peer->ttl != 0) {
  661. if (peer->ttl & 0x80)
  662. up->fd_icom = icom_init("/dev/icom", B1200,
  663. temp);
  664. else
  665. up->fd_icom = icom_init("/dev/icom", B9600,
  666. temp);
  667. if (up->fd_icom < 0) {
  668. NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
  669. msyslog(LOG_NOTICE,
  670. "icom: %m");
  671. up->errflg = CEVNT_FAULT;
  672. }
  673. }
  674. if (up->fd_icom > 0) {
  675. if (wwv_qsy(peer, DCHAN) != 0) {
  676. NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
  677. msyslog(LOG_NOTICE,
  678. "icom: radio not found");
  679. up->errflg = CEVNT_FAULT;
  680. close(up->fd_icom);
  681. up->fd_icom = 0;
  682. } else {
  683. NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
  684. msyslog(LOG_NOTICE,
  685. "icom: autotune enabled");
  686. }
  687. }
  688. #endif /* ICOM */
  689. /*
  690. * Let the games begin.
  691. */
  692. wwv_newgame(peer);
  693. return (1);
  694. }
  695. /*
  696. * wwv_shutdown - shut down the clock
  697. */
  698. static void
  699. wwv_shutdown(
  700. int unit, /* instance number (not used) */
  701. struct peer *peer /* peer structure pointer */
  702. )
  703. {
  704. struct refclockproc *pp;
  705. struct wwvunit *up;
  706. pp = peer->procptr;
  707. up = (struct wwvunit *)pp->unitptr;
  708. if (up == NULL)
  709. return;
  710. io_closeclock(&pp->io);
  711. #ifdef ICOM
  712. if (up->fd_icom > 0)
  713. close(up->fd_icom);
  714. #endif /* ICOM */
  715. free(up);
  716. }
  717. /*
  718. * wwv_receive - receive data from the audio device
  719. *
  720. * This routine reads input samples and adjusts the logical clock to
  721. * track the A/D sample clock by dropping or duplicating codec samples.
  722. * It also controls the A/D signal level with an AGC loop to mimimize
  723. * quantization noise and avoid overload.
  724. */
  725. static void
  726. wwv_receive(
  727. struct recvbuf *rbufp /* receive buffer structure pointer */
  728. )
  729. {
  730. struct peer *peer;
  731. struct refclockproc *pp;
  732. struct wwvunit *up;
  733. /*
  734. * Local variables
  735. */
  736. double sample; /* codec sample */
  737. u_char *dpt; /* buffer pointer */
  738. int bufcnt; /* buffer counter */
  739. l_fp ltemp;
  740. peer = (struct peer *)rbufp->recv_srcclock;
  741. pp = peer->procptr;
  742. up = (struct wwvunit *)pp->unitptr;
  743. /*
  744. * Main loop - read until there ain't no more. Note codec
  745. * samples are bit-inverted.
  746. */
  747. DTOLFP((double)rbufp->recv_length / SECOND, &ltemp);
  748. L_SUB(&rbufp->recv_time, &ltemp);
  749. up->timestamp = rbufp->recv_time;
  750. dpt = rbufp->recv_buffer;
  751. for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) {
  752. sample = up->comp[~*dpt++ & 0xff];
  753. /*
  754. * Clip noise spikes greater than MAXAMP (6000) and
  755. * record the number of clips to be used later by the
  756. * AGC.
  757. */
  758. if (sample > MAXAMP) {
  759. sample = MAXAMP;
  760. up->clipcnt++;
  761. } else if (sample < -MAXAMP) {
  762. sample = -MAXAMP;
  763. up->clipcnt++;
  764. }
  765. /*
  766. * Variable frequency oscillator. The codec oscillator
  767. * runs at the nominal rate of 8000 samples per second,
  768. * or 125 us per sample. A frequency change of one unit
  769. * results in either duplicating or deleting one sample
  770. * per second, which results in a frequency change of
  771. * 125 PPM.
  772. */
  773. up->phase += up->freq / SECOND;
  774. up->phase += FREQ_OFFSET / 1e6;
  775. if (up->phase >= .5) {
  776. up->phase -= 1.;
  777. } else if (up->phase < -.5) {
  778. up->phase += 1.;
  779. wwv_rf(peer, sample);
  780. wwv_rf(peer, sample);
  781. } else {
  782. wwv_rf(peer, sample);
  783. }
  784. L_ADD(&up->timestamp, &up->tick);
  785. }
  786. /*
  787. * Set the input port and monitor gain for the next buffer.
  788. */
  789. if (pp->sloppyclockflag & CLK_FLAG2)
  790. up->port = 2;
  791. else
  792. up->port = 1;
  793. if (pp->sloppyclockflag & CLK_FLAG3)
  794. up->mongain = MONGAIN;
  795. else
  796. up->mongain = 0;
  797. }
  798. /*
  799. * wwv_poll - called by the transmit procedure
  800. *
  801. * This routine keeps track of status. If no offset samples have been
  802. * processed during a poll interval, a timeout event is declared. If
  803. * errors have have occurred during the interval, they are reported as
  804. * well.
  805. */
  806. static void
  807. wwv_poll(
  808. int unit, /* instance number (not used) */
  809. struct peer *peer /* peer structure pointer */
  810. )
  811. {
  812. struct refclockproc *pp;
  813. struct wwvunit *up;
  814. pp = peer->procptr;
  815. up = (struct wwvunit *)pp->unitptr;
  816. if (pp->coderecv == pp->codeproc)
  817. up->errflg = CEVNT_TIMEOUT;
  818. if (up->errflg)
  819. refclock_report(peer, up->errflg);
  820. up->errflg = 0;
  821. pp->polls++;
  822. }
  823. /*
  824. * wwv_rf - process signals and demodulate to baseband
  825. *
  826. * This routine grooms and filters decompanded raw audio samples. The
  827. * output signal is the 100-Hz filtered baseband data signal in
  828. * quadrature phase. The routine also determines the minute synch epoch,
  829. * as well as certain signal maxima, minima and related values.
  830. *
  831. * There are two 1-s ramps used by this program. Both count the 8000
  832. * logical clock samples spanning exactly one second. The epoch ramp
  833. * counts the samples starting at an arbitrary time. The rphase ramp
  834. * counts the samples starting at the 5-ms second sync pulse found
  835. * during the epoch ramp.
  836. *
  837. * There are two 1-m ramps used by this program. The mphase ramp counts
  838. * the 480,000 logical clock samples spanning exactly one minute and
  839. * starting at an arbitrary time. The rsec ramp counts the 60 seconds of
  840. * the minute starting at the 800-ms minute sync pulse found during the
  841. * mphase ramp. The rsec ramp drives the seconds state machine to
  842. * determine the bits and digits of the timecode.
  843. *
  844. * Demodulation operations are based on three synthesized quadrature
  845. * sinusoids: 100 Hz for the data signal, 1000 Hz for the WWV sync
  846. * signal and 1200 Hz for the WWVH sync signal. These drive synchronous
  847. * matched filters for the data signal (170 ms at 100 Hz), WWV minute
  848. * sync signal (800 ms at 1000 Hz) and WWVH minute sync signal (800 ms
  849. * at 1200 Hz). Two additional matched filters are switched in
  850. * as required for the WWV second sync signal (5 cycles at 1000 Hz) and
  851. * WWVH second sync signal (6 cycles at 1200 Hz).
  852. */
  853. static void
  854. wwv_rf(
  855. struct peer *peer, /* peerstructure pointer */
  856. double isig /* input signal */
  857. )
  858. {
  859. struct refclockproc *pp;
  860. struct wwvunit *up;
  861. struct sync *sp, *rp;
  862. static double lpf[5]; /* 150-Hz lpf delay line */
  863. double data; /* lpf output */
  864. static double bpf[9]; /* 1000/1200-Hz bpf delay line */
  865. double syncx; /* bpf output */
  866. static double mf[41]; /* 1000/1200-Hz mf delay line */
  867. double mfsync; /* mf output */
  868. static int iptr; /* data channel pointer */
  869. static double ibuf[DATSIZ]; /* data I channel delay line */
  870. static double qbuf[DATSIZ]; /* data Q channel delay line */
  871. static int jptr; /* sync channel pointer */
  872. static int kptr; /* tick channel pointer */
  873. static int csinptr; /* wwv channel phase */
  874. static double cibuf[SYNSIZ]; /* wwv I channel delay line */
  875. static double cqbuf[SYNSIZ]; /* wwv Q channel delay line */
  876. static double ciamp; /* wwv I channel amplitude */
  877. static double cqamp; /* wwv Q channel amplitude */
  878. static double csibuf[TCKSIZ]; /* wwv I tick delay line */
  879. static double csqbuf[TCKSIZ]; /* wwv Q tick delay line */
  880. static double csiamp; /* wwv I tick amplitude */
  881. static double csqamp; /* wwv Q tick amplitude */
  882. static int hsinptr; /* wwvh channel phase */
  883. static double hibuf[SYNSIZ]; /* wwvh I channel delay line */
  884. static double hqbuf[SYNSIZ]; /* wwvh Q channel delay line */
  885. static double hiamp; /* wwvh I channel amplitude */
  886. static double hqamp; /* wwvh Q channel amplitude */
  887. static double hsibuf[TCKSIZ]; /* wwvh I tick delay line */
  888. static double hsqbuf[TCKSIZ]; /* wwvh Q tick delay line */
  889. static double hsiamp; /* wwvh I tick amplitude */
  890. static double hsqamp; /* wwvh Q tick amplitude */
  891. static double epobuf[SECOND]; /* second sync comb filter */
  892. static double epomax, nxtmax; /* second sync amplitude buffer */
  893. static int epopos; /* epoch second sync position buffer */
  894. static int iniflg; /* initialization flag */
  895. int pdelay; /* propagation delay (samples) */
  896. int epoch; /* comb filter index */
  897. double dtemp;
  898. int i;
  899. pp = peer->procptr;
  900. up = (struct wwvunit *)pp->unitptr;
  901. if (!iniflg) {
  902. iniflg = 1;
  903. memset((char *)lpf, 0, sizeof(lpf));
  904. memset((char *)bpf, 0, sizeof(bpf));
  905. memset((char *)mf, 0, sizeof(mf));
  906. memset((char *)ibuf, 0, sizeof(ibuf));
  907. memset((char *)qbuf, 0, sizeof(qbuf));
  908. memset((char *)cibuf, 0, sizeof(cibuf));
  909. memset((char *)cqbuf, 0, sizeof(cqbuf));
  910. memset((char *)csibuf, 0, sizeof(csibuf));
  911. memset((char *)csqbuf, 0, sizeof(csqbuf));
  912. memset((char *)hibuf, 0, sizeof(hibuf));
  913. memset((char *)hqbuf, 0, sizeof(hqbuf));
  914. memset((char *)hsibuf, 0, sizeof(hsibuf));
  915. memset((char *)hsqbuf, 0, sizeof(hsqbuf));
  916. memset((char *)epobuf, 0, sizeof(epobuf));
  917. }
  918. /*
  919. * Baseband data demodulation. The 100-Hz subcarrier is
  920. * extracted using a 150-Hz IIR lowpass filter. This attenuates
  921. * the 1000/1200-Hz sync signals, as well as the 440-Hz and
  922. * 600-Hz tones and most of the noise and voice modulation
  923. * components.
  924. *
  925. * The subcarrier is transmitted 10 dB down from the carrier.
  926. * The DGAIN parameter can be adjusted for this and to
  927. * compensate for the radio audio response at 100 Hz.
  928. *
  929. * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB
  930. * passband ripple, -50 dB stopband ripple.
  931. */
  932. data = (lpf[4] = lpf[3]) * 8.360961e-01;
  933. data += (lpf[3] = lpf[2]) * -3.481740e+00;
  934. data += (lpf[2] = lpf[1]) * 5.452988e+00;
  935. data += (lpf[1] = lpf[0]) * -3.807229e+00;
  936. lpf[0] = isig * DGAIN - data;
  937. data = lpf[0] * 3.281435e-03
  938. + lpf[1] * -1.149947e-02
  939. + lpf[2] * 1.654858e-02
  940. + lpf[3] * -1.149947e-02
  941. + lpf[4] * 3.281435e-03;
  942. /*
  943. * The 100-Hz data signal is demodulated using a pair of
  944. * quadrature multipliers, matched filters and a phase lock
  945. * loop. The I and Q quadrature data signals are produced by
  946. * multiplying the filtered signal by 100-Hz sine and cosine
  947. * signals, respectively. The signals are processed by 170-ms
  948. * synchronous matched filters to produce the amplitude and
  949. * phase signals used by the demodulator. The signals are scaled
  950. * to produce unit energy at the maximum value.
  951. */
  952. i = up->datapt;
  953. up->datapt = (up->datapt + IN100) % 80;
  954. dtemp = sintab[i] * data / (MS / 2. * DATCYC);
  955. up->irig -= ibuf[iptr];
  956. ibuf[iptr] = dtemp;
  957. up->irig += dtemp;
  958. i = (i + 20) % 80;
  959. dtemp = sintab[i] * data / (MS / 2. * DATCYC);
  960. up->qrig -= qbuf[iptr];
  961. qbuf[iptr] = dtemp;
  962. up->qrig += dtemp;
  963. iptr = (iptr + 1) % DATSIZ;
  964. /*
  965. * Baseband sync demodulation. The 1000/1200 sync signals are
  966. * extracted using a 600-Hz IIR bandpass filter. This removes
  967. * the 100-Hz data subcarrier, as well as the 440-Hz and 600-Hz
  968. * tones and most of the noise and voice modulation components.
  969. *
  970. * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB
  971. * passband ripple, -50 dB stopband ripple.
  972. */
  973. syncx = (bpf[8] = bpf[7]) * 4.897278e-01;
  974. syncx += (bpf[7] = bpf[6]) * -2.765914e+00;
  975. syncx += (bpf[6] = bpf[5]) * 8.110921e+00;
  976. syncx += (bpf[5] = bpf[4]) * -1.517732e+01;
  977. syncx += (bpf[4] = bpf[3]) * 1.975197e+01;
  978. syncx += (bpf[3] = bpf[2]) * -1.814365e+01;
  979. syncx += (bpf[2] = bpf[1]) * 1.159783e+01;
  980. syncx += (bpf[1] = bpf[0]) * -4.735040e+00;
  981. bpf[0] = isig - syncx;
  982. syncx = bpf[0] * 8.203628e-03
  983. + bpf[1] * -2.375732e-02
  984. + bpf[2] * 3.353214e-02
  985. + bpf[3] * -4.080258e-02
  986. + bpf[4] * 4.605479e-02
  987. + bpf[5] * -4.080258e-02
  988. + bpf[6] * 3.353214e-02
  989. + bpf[7] * -2.375732e-02
  990. + bpf[8] * 8.203628e-03;
  991. /*
  992. * The 1000/1200 sync signals are demodulated using a pair of
  993. * quadrature multipliers and matched filters. However,
  994. * synchronous demodulation at these frequencies is impractical,
  995. * so only the signal amplitude is used. The I and Q quadrature
  996. * sync signals are produced by multiplying the filtered signal
  997. * by 1000-Hz (WWV) and 1200-Hz (WWVH) sine and cosine signals,
  998. * respectively. The WWV and WWVH signals are processed by 800-
  999. * ms synchronous matched filters and combined to produce the
  1000. * minute sync signal and detect which one (or both) the WWV or
  1001. * WWVH signal is present. The WWV and WWVH signals are also
  1002. * processed by 5-ms synchronous matched filters and combined to
  1003. * produce the second sync signal. The signals are scaled to
  1004. * produce unit energy at the maximum value.
  1005. *
  1006. * Note the master timing ramps, which run continuously. The
  1007. * minute counter (mphase) counts the samples in the minute,
  1008. * while the second counter (epoch) counts the samples in the
  1009. * second.
  1010. */
  1011. up->mphase = (up->mphase + 1) % MINUTE;
  1012. epoch = up->mphase % SECOND;
  1013. /*
  1014. * WWV
  1015. */
  1016. i = csinptr;
  1017. csinptr = (csinptr + IN1000) % 80;
  1018. dtemp = sintab[i] * syncx / (MS / 2.);
  1019. ciamp -= cibuf[jptr];
  1020. cibuf[jptr] = dtemp;
  1021. ciamp += dtemp;
  1022. csiamp -= csibuf[kptr];
  1023. csibuf[kptr] = dtemp;
  1024. csiamp += dtemp;
  1025. i = (i + 20) % 80;
  1026. dtemp = sintab[i] * syncx / (MS / 2.);
  1027. cqamp -= cqbuf[jptr];
  1028. cqbuf[jptr] = dtemp;
  1029. cqamp += dtemp;
  1030. csqamp -= csqbuf[kptr];
  1031. csqbuf[kptr] = dtemp;
  1032. csqamp += dtemp;
  1033. sp = &up->mitig[up->achan].wwv;
  1034. sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC;
  1035. if (!(up->status & MSYNC))
  1036. wwv_qrz(peer, sp, (int)(pp->fudgetime1 * SECOND));
  1037. /*
  1038. * WWVH
  1039. */
  1040. i = hsinptr;
  1041. hsinptr = (hsinptr + IN1200) % 80;
  1042. dtemp = sintab[i] * syncx / (MS / 2.);
  1043. hiamp -= hibuf[jptr];
  1044. hibuf[jptr] = dtemp;
  1045. hiamp += dtemp;
  1046. hsiamp -= hsibuf[kptr];
  1047. hsibuf[kptr] = dtemp;
  1048. hsiamp += dtemp;
  1049. i = (i + 20) % 80;
  1050. dtemp = sintab[i] * syncx / (MS / 2.);
  1051. hqamp -= hqbuf[jptr];
  1052. hqbuf[jptr] = dtemp;
  1053. hqamp += dtemp;
  1054. hsqamp -= hsqbuf[kptr];
  1055. hsqbuf[kptr] = dtemp;
  1056. hsqamp += dtemp;
  1057. rp = &up->mitig[up->achan].wwvh;
  1058. rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC;
  1059. if (!(up->status & MSYNC))
  1060. wwv_qrz(peer, rp, (int)(pp->fudgetime2 * SECOND));
  1061. jptr = (jptr + 1) % SYNSIZ;
  1062. kptr = (kptr + 1) % TCKSIZ;
  1063. /*
  1064. * The following section is called once per minute. It does
  1065. * housekeeping and timeout functions and empties the dustbins.
  1066. */
  1067. if (up->mphase == 0) {
  1068. up->watch++;
  1069. if (!(up->status & MSYNC)) {
  1070. /*
  1071. * If minute sync has not been acquired before
  1072. * ACQSN timeout (6 min), or if no signal is
  1073. * heard, the program cycles to the next
  1074. * frequency and tries again.
  1075. */
  1076. if (!wwv_newchan(peer))
  1077. up->watch = 0;
  1078. #ifdef ICOM
  1079. if (up->fd_icom > 0)
  1080. wwv_qsy(peer, up->dchan);
  1081. #endif /* ICOM */
  1082. } else {
  1083. /*
  1084. * If the leap bit is set, set the minute epoch
  1085. * back one second so the station processes
  1086. * don't miss a beat.
  1087. */
  1088. if (up->status & LEPSEC) {
  1089. up->mphase -= SECOND;
  1090. if (up->mphase < 0)
  1091. up->mphase += MINUTE;
  1092. }
  1093. }
  1094. }
  1095. /*
  1096. * When the channel metric reaches threshold and the second
  1097. * counter matches the minute epoch within the second, the
  1098. * driver has synchronized to the station. The second number is
  1099. * the remaining seconds until the next minute epoch, while the
  1100. * sync epoch is zero. Watch out for the first second; if
  1101. * already synchronized to the second, the buffered sync epoch
  1102. * must be set.
  1103. *
  1104. * Note the guard interval is 200 ms; if for some reason the
  1105. * clock drifts more than that, it might wind up in the wrong
  1106. * second. If the maximum frequency error is not more than about
  1107. * 1 PPM, the clock can go as much as two days while still in
  1108. * the same second.
  1109. */
  1110. if (up->status & MSYNC) {
  1111. wwv_epoch(peer);
  1112. } else if (up->sptr != NULL) {
  1113. sp = up->sptr;
  1114. if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND) {
  1115. up->rsec = (60 - sp->mepoch / SECOND) % 60;
  1116. up->rphase = 0;
  1117. up->status |= MSYNC;
  1118. up->watch = 0;
  1119. if (!(up->status & SSYNC))
  1120. up->repoch = up->yepoch = epoch;
  1121. else
  1122. up->repoch = up->yepoch;
  1123. }
  1124. }
  1125. /*
  1126. * The second sync pulse is extracted using 5-ms (40 sample) FIR
  1127. * matched filters at 1000 Hz for WWV or 1200 Hz for WWVH. This
  1128. * pulse is used for the most precise synchronization, since if
  1129. * provides a resolution of one sample (125 us). The filters run
  1130. * only if the station has been reliably determined.
  1131. */
  1132. if (up->status & SELV) {
  1133. pdelay = (int)(pp->fudgetime1 * SECOND);
  1134. mfsync = sqrt(csiamp * csiamp + csqamp * csqamp) /
  1135. TCKCYC;
  1136. } else if (up->status & SELH) {
  1137. pdelay = (int)(pp->fudgetime2 * SECOND);
  1138. mfsync = sqrt(hsiamp * hsiamp + hsqamp * hsqamp) /
  1139. TCKCYC;
  1140. } else {
  1141. pdelay = 0;
  1142. mfsync = 0;
  1143. }
  1144. /*
  1145. * Enhance the seconds sync pulse using a 1-s (8000-sample) comb
  1146. * filter. Correct for the FIR matched filter delay, which is 5
  1147. * ms for both the WWV and WWVH filters, and also for the
  1148. * propagation delay. Once each second look for second sync. If
  1149. * not in minute sync, fiddle the codec gain. Note the SNR is
  1150. * computed from the maximum sample and the envelope of the
  1151. * sample 6 ms before it, so if we slip more than a cycle the
  1152. * SNR should plummet. The signal is scaled to produce unit
  1153. * energy at the maximum value.
  1154. */
  1155. dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) /
  1156. up->avgint);
  1157. if (dtemp > epomax) {
  1158. int j;
  1159. epomax = dtemp;
  1160. epopos = epoch;
  1161. j = epoch - 6 * MS;
  1162. if (j < 0)
  1163. j += SECOND;
  1164. nxtmax = fabs(epobuf[j]);
  1165. }
  1166. if (epoch == 0) {
  1167. up->epomax = epomax;
  1168. up->eposnr = wwv_snr(epomax, nxtmax);
  1169. epopos -= pdelay + TCKCYC * MS;
  1170. if (epopos < 0)
  1171. epopos += SECOND;
  1172. wwv_endpoc(peer, epopos);
  1173. if (!(up->status & SSYNC))
  1174. up->alarm |= SYNERR;
  1175. epomax = 0;
  1176. if (!(up->status & MSYNC))
  1177. wwv_gain(peer);
  1178. }
  1179. }
  1180. /*
  1181. * wwv_qrz - identify and acquire WWV/WWVH minute sync pulse
  1182. *
  1183. * This routine implements a virtual station process used to acquire
  1184. * minute sync and to mitigate among the ten frequency and station
  1185. * combinations. During minute sync acquisition the process probes each
  1186. * frequency and station in turn for the minute pulse, which
  1187. * involves searching through the entire 480,000-sample minute. The
  1188. * process finds the maximum signal and RMS noise plus signal. Then, the
  1189. * actual noise is determined by subtracting the energy of the matched
  1190. * filter.
  1191. *
  1192. * Students of radar receiver technology will discover this algorithm
  1193. * amounts to a range-gate discriminator. A valid pulse must have peak
  1194. * amplitude at least QTHR (2500) and SNR at least QSNR (20) dB and the
  1195. * difference between the current and previous epoch must be less than
  1196. * AWND (20 ms). Note that the discriminator peak occurs about 800 ms
  1197. * into the second, so the timing is retarded to the previous second
  1198. * epoch.
  1199. */
  1200. static void
  1201. wwv_qrz(
  1202. struct peer *peer, /* peer structure pointer */
  1203. struct sync *sp, /* sync channel structure */
  1204. int pdelay /* propagation delay (samples) */
  1205. )
  1206. {
  1207. struct refclockproc *pp;
  1208. struct wwvunit *up;
  1209. char tbuf[80]; /* monitor buffer */
  1210. long epoch;
  1211. pp = peer->procptr;
  1212. up = (struct wwvunit *)pp->unitptr;
  1213. /*
  1214. * Find the sample with peak amplitude, which defines the minute
  1215. * epoch. Accumulate all samples to determine the total noise
  1216. * energy.
  1217. */
  1218. epoch = up->mphase - pdelay - SYNSIZ;
  1219. if (epoch < 0)
  1220. epoch += MINUTE;
  1221. if (sp->amp > sp->maxeng) {
  1222. sp->maxeng = sp->amp;
  1223. sp->pos = epoch;
  1224. }
  1225. sp->noieng += sp->amp;
  1226. /*
  1227. * At the end of the minute, determine the epoch of the minute
  1228. * sync pulse, as well as the difference between the current and
  1229. * previous epoches due to the intrinsic frequency error plus
  1230. * jitter. When calculating the SNR, subtract the pulse energy
  1231. * from the total noise energy and then normalize.
  1232. */
  1233. if (up->mphase == 0) {
  1234. sp->synmax = sp->maxeng;
  1235. sp->synsnr = wwv_snr(sp->synmax, (sp->noieng -
  1236. sp->synmax) / MINUTE);
  1237. if (sp->count == 0)
  1238. sp->lastpos = sp->pos;
  1239. epoch = (sp->pos - sp->lastpos) % MINUTE;
  1240. sp->reach <<= 1;
  1241. if (sp->reach & (1 << AMAX))
  1242. sp->count--;
  1243. if (sp->synmax > ATHR && sp->synsnr > ASNR) {
  1244. if (abs(epoch) < AWND * MS) {
  1245. sp->reach |= 1;
  1246. sp->count++;
  1247. sp->mepoch = sp->lastpos = sp->pos;
  1248. } else if (sp->count == 1) {
  1249. sp->lastpos = sp->pos;
  1250. }
  1251. }
  1252. if (up->watch > ACQSN)
  1253. sp->metric = 0;
  1254. else
  1255. sp->metric = wwv_metric(sp);
  1256. if (pp->sloppyclockflag & CLK_FLAG4) {
  1257. sprintf(tbuf,
  1258. "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %4ld %4ld",
  1259. up->status, up->gain, sp->refid,
  1260. sp->reach & 0xffff, sp->metric, sp->synmax,
  1261. sp->synsnr, sp->pos % SECOND, epoch);
  1262. record_clock_stats(&peer->srcadr, tbuf);
  1263. #ifdef DEBUG
  1264. if (debug)
  1265. printf("%s\n", tbuf);
  1266. #endif /* DEBUG */
  1267. }
  1268. sp->maxeng = sp->noieng = 0;
  1269. }
  1270. }
  1271. /*
  1272. * wwv_endpoc - identify and acquire second sync pulse
  1273. *
  1274. * This routine is called at the end of the second sync interval. It
  1275. * determines the second sync epoch position within the second and
  1276. * disciplines the sample clock using a frequency-lock loop (FLL).
  1277. *
  1278. * Second sync is determined in the RF input routine as the maximum
  1279. * over all 8000 samples in the second comb filter. To assure accurate
  1280. * and reliable time and frequency discipline, this routine performs a
  1281. * great deal of heavy-handed heuristic data filtering and grooming.
  1282. */
  1283. static void
  1284. wwv_endpoc(
  1285. struct peer *peer, /* peer structure pointer */
  1286. int epopos /* epoch max position */
  1287. )
  1288. {
  1289. struct refclockproc *pp;
  1290. struct wwvunit *up;
  1291. static int epoch_mf[3]; /* epoch median filter */
  1292. static int tepoch; /* current second epoch */
  1293. static int xepoch; /* last second epoch */
  1294. static int zepoch; /* last run epoch */
  1295. static int zcount; /* last run end time */
  1296. static int scount; /* seconds counter */
  1297. static int syncnt; /* run length counter */
  1298. static int maxrun; /* longest run length */
  1299. static int mepoch; /* longest run end epoch */
  1300. static int mcount; /* longest run end time */
  1301. static int avgcnt; /* averaging interval counter */
  1302. static int avginc; /* averaging ratchet */
  1303. static int iniflg; /* initialization flag */
  1304. char tbuf[80]; /* monitor buffer */
  1305. double dtemp;
  1306. int tmp2;
  1307. pp = peer->procptr;
  1308. up = (struct wwvunit *)pp->unitptr;
  1309. if (!iniflg) {
  1310. iniflg = 1;
  1311. memset((char *)epoch_mf, 0, sizeof(epoch_mf));
  1312. }
  1313. /*
  1314. * If the signal amplitude or SNR fall below thresholds, dim the
  1315. * second sync lamp and wait for hotter ions. If no stations are
  1316. * heard, we are either in a probe cycle or the ions are really
  1317. * cold.
  1318. */
  1319. scount++;
  1320. if (up->epomax < STHR || up->eposnr < SSNR) {
  1321. up->status &= ~(SSYNC | FGATE);
  1322. avgcnt = syncnt = maxrun = 0;
  1323. return;
  1324. }
  1325. if (!(up->status & (SELV | SELH)))
  1326. return;
  1327. /*
  1328. * A three-stage median filter is used to help denoise the
  1329. * second sync pulse. The median sample becomes the candidate
  1330. * epoch.
  1331. */
  1332. epoch_mf[2] = epoch_mf[1];
  1333. epoch_mf[1] = epoch_mf[0];
  1334. epoch_mf[0] = epopos;
  1335. if (epoch_mf[0] > epoch_mf[1]) {
  1336. if (epoch_mf[1] > epoch_mf[2])
  1337. tepoch = epoch_mf[1]; /* 0 1 2 */
  1338. else if (epoch_mf[2] > epoch_mf[0])
  1339. tepoch = epoch_mf[0]; /* 2 0 1 */
  1340. else
  1341. tepoch = epoch_mf[2]; /* 0 2 1 */
  1342. } else {
  1343. if (epoch_mf[1] < epoch_mf[2])
  1344. tepoch = epoch_mf[1]; /* 2 1 0 */
  1345. else if (epoch_mf[2] < epoch_mf[0])
  1346. tepoch = epoch_mf[0]; /* 1 0 2 */
  1347. else
  1348. tepoch = epoch_mf[2]; /* 1 2 0 */
  1349. }
  1350. /*
  1351. * If the epoch candidate is the same as the last one, increment
  1352. * the run counter. If not, save the length, epoch and end
  1353. * time of the current run for use later and reset the counter.
  1354. * The epoch is considered valid if the run is at least SCMP
  1355. * (10) s, the minute is synchronized and the interval since the
  1356. * last epoch is not greater than the averaging interval. Thus,
  1357. * after a long absence, the program will wait a full averaging
  1358. * interval while the comb filter charges up and noise
  1359. * dissapates..
  1360. */
  1361. tmp2 = (tepoch - xepoch) % SECOND;
  1362. if (tmp2 == 0) {
  1363. syncnt++;
  1364. if (syncnt > SCMP && up->status & MSYNC && (up->status &
  1365. FGATE || scount - zcount <= up->avgint)) {
  1366. up->status |= SSYNC;
  1367. up->yepoch = tepoch;
  1368. }
  1369. } else if (syncnt >= maxrun) {
  1370. maxrun = syncnt;
  1371. mcount = scount;
  1372. mepoch = xepoch;
  1373. syncnt = 0;
  1374. }
  1375. if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & MSYNC))
  1376. {
  1377. sprintf(tbuf,
  1378. "wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
  1379. up->status, up->gain, tepoch, up->epomax,
  1380. up->eposnr, tmp2, avgcnt, syncnt,
  1381. maxrun);
  1382. record_clock_stats(&peer->srcadr, tbuf);
  1383. #ifdef DEBUG
  1384. if (debug)
  1385. printf("%s\n", tbuf);
  1386. #endif /* DEBUG */
  1387. }
  1388. avgcnt++;
  1389. if (avgcnt < up->avgint) {
  1390. xepoch = tepoch;
  1391. return;
  1392. }
  1393. /*
  1394. * The sample clock frequency is disciplined using a first-order
  1395. * feedback loop with time constant consistent with the Allan
  1396. * intercept of typical computer clocks. During each averaging
  1397. * interval the candidate epoch at the end of the longest run is
  1398. * determined. If the longest run is zero, all epoches in the
  1399. * interval are different, so the candidate epoch is the current
  1400. * epoch. The frequency update is computed from the candidate
  1401. * epoch difference (125-us units) and time difference (seconds)
  1402. * between updates.
  1403. */
  1404. if (syncnt >= maxrun) {
  1405. maxrun = syncnt;
  1406. mcount = scount;
  1407. mepoch = xepoch;
  1408. }
  1409. xepoch = tepoch;
  1410. if (maxrun == 0) {
  1411. mepoch = tepoch;
  1412. mcount = scount;
  1413. }
  1414. /*
  1415. * The master clock runs at the codec sample frequency of 8000
  1416. * Hz, so the intrinsic time resolution is 125 us. The frequency
  1417. * resolution ranges from 18 PPM at the minimum averaging
  1418. * interval of 8 s to 0.12 PPM at the maximum interval of 1024
  1419. * s. An offset update is determined at the end of the longest
  1420. * run in each averaging interval. The frequency adjustment is
  1421. * computed from the difference between offset updates and the
  1422. * interval between them.
  1423. *
  1424. * The maximum frequency adjustment ranges from 187 PPM at the
  1425. * minimum interval to 1.5 PPM at the maximum. If the adjustment
  1426. * exceeds the maximum, the update is discarded and the
  1427. * hysteresis counter is decremented. Otherwise, the frequency
  1428. * is incremented by the adjustment, but clamped to the maximum
  1429. * 187.5 PPM. If the update is less than half the maximum, the
  1430. * hysteresis counter is incremented. If the counter increments
  1431. * to +3, the averaging interval is doubled and the counter set
  1432. * to zero; if it decrements to -3, the interval is halved and
  1433. * the counter set to zero.
  1434. */
  1435. dtemp = (mepoch - zepoch) % SECOND;
  1436. if (up->status & FGATE) {
  1437. if (abs(dtemp) < MAXFREQ * MINAVG) {
  1438. up->freq += (dtemp / 2.) / ((mcount - zcount) *
  1439. FCONST);
  1440. if (up->freq > MAXFREQ)
  1441. up->freq = MAXFREQ;
  1442. else if (up->freq < -MAXFREQ)
  1443. up->freq = -MAXFREQ;
  1444. if (abs(dtemp) < MAXFREQ * MINAVG / 2.) {
  1445. if (avginc < 3) {
  1446. avginc++;
  1447. } else {
  1448. if (up->avgint < MAXAVG) {
  1449. up->avgint <<= 1;
  1450. avginc = 0;
  1451. }
  1452. }
  1453. }
  1454. } else {
  1455. if (avginc > -3) {
  1456. avginc--;
  1457. } else {
  1458. if (up->avgint > MINAVG) {
  1459. up->avgint >>= 1;
  1460. avginc = 0;
  1461. }
  1462. }
  1463. }
  1464. }
  1465. if (pp->sloppyclockflag & CLK_FLAG4) {
  1466. sprintf(tbuf,
  1467. "wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f",
  1468. up->status, up->epomax, up->eposnr, mepoch,
  1469. up->avgint, maxrun, mcount - zcount, dtemp,
  1470. up->freq * 1e6 / SECOND);
  1471. record_clock_stats(&peer->srcadr, tbuf);
  1472. #ifdef DEBUG
  1473. if (debug)
  1474. printf("%s\n", tbuf);
  1475. #endif /* DEBUG */
  1476. }
  1477. /*
  1478. * This is a valid update; set up for the next interval.
  1479. */
  1480. up->status |= FGATE;
  1481. zepoch = mepoch;
  1482. zcount = mcount;
  1483. avgcnt = syncnt = maxrun = 0;
  1484. }
  1485. /*
  1486. * wwv_epoch - epoch scanner
  1487. *
  1488. * This routine extracts data signals from the 100-Hz subcarrier. It
  1489. * scans the receiver second epoch to determine the signal amplitudes
  1490. * and pulse timings. Receiver synchronization is determined by the
  1491. * minute sync pulse detected in the wwv_rf() routine and the second
  1492. * sync pulse detected in the wwv_epoch() routine. The transmitted
  1493. * signals are delayed by the propagation delay, receiver delay and
  1494. * filter delay of this program. Delay corrections are introduced
  1495. * separately for WWV and WWVH.
  1496. *
  1497. * Most communications radios use a highpass filter in the audio stages,
  1498. * which can do nasty things to the subcarrier phase relative to the
  1499. * sync pulses. Therefore, the data subcarrier reference phase is
  1500. * disciplined using the hardlimited quadrature-phase signal sampled at
  1501. * the same time as the in-phase signal. The phase tracking loop uses
  1502. * phase adjustments of plus-minus one sample (125 us).
  1503. */
  1504. static void
  1505. wwv_epoch(
  1506. struct peer *peer /* peer structure pointer */
  1507. )
  1508. {
  1509. struct refclockproc *pp;
  1510. struct wwvunit *up;
  1511. struct chan *cp;
  1512. static double sigmin, sigzer, sigone, engmax, engmin;
  1513. pp = peer->procptr;
  1514. up = (struct wwvunit *)pp->unitptr;
  1515. /*
  1516. * Find the maximum minute sync pulse energy for both the
  1517. * WWV and WWVH stations. This will be used later for channel
  1518. * and station mitigation. Also set the seconds epoch at 800 ms
  1519. * well before the end of the second to make sure we never set
  1520. * the epoch backwards.
  1521. */
  1522. cp = &up->mitig[up->achan];
  1523. if (cp->wwv.amp > cp->wwv.syneng)
  1524. cp->wwv.syneng = cp->wwv.amp;
  1525. if (cp->wwvh.amp > cp->wwvh.syneng)
  1526. cp->wwvh.syneng = cp->wwvh.amp;
  1527. if (up->rphase == 800 * MS)
  1528. up->repoch = up->yepoch;
  1529. /*
  1530. * Use the signal amplitude at epoch 15 ms as the noise floor.
  1531. * This gives a guard time of +-15 ms from the beginning of the
  1532. * second until the second pulse rises at 30 ms. There is a
  1533. * compromise here; we want to delay the sample as long as
  1534. * possible to give the radio time to change frequency and the
  1535. * AGC to stabilize, but as early as possible if the second
  1536. * epoch is not exact.
  1537. */
  1538. if (up->rphase == 15 * MS)
  1539. sigmin = sigzer = sigone = up->irig;
  1540. /*
  1541. * Latch the data signal at 200 ms. Keep this around until the
  1542. * end of the second. Use the signal energy as the peak to
  1543. * compute the SNR. Use the Q sample to adjust the 100-Hz
  1544. * reference oscillator phase.
  1545. */
  1546. if (up->rphase == 200 * MS) {
  1547. sigzer = up->irig;
  1548. engmax = sqrt(up->irig * up->irig + up->qrig *
  1549. up->qrig);
  1550. up->datpha = up->qrig / up->avgint;
  1551. if (up->datpha >= 0) {
  1552. up->datapt++;
  1553. if (up->datapt >= 80)
  1554. up->datapt -= 80;
  1555. } else {
  1556. up->datapt--;
  1557. if (up->datapt < 0)
  1558. up->datapt += 80;
  1559. }
  1560. }
  1561. /*
  1562. * Latch the data signal at 500 ms. Keep this around until the
  1563. * end of the second.
  1564. */
  1565. else if (up->rphase == 500 * MS)
  1566. sigone = up->irig;
  1567. /*
  1568. * At the end of the second crank the clock state machine and
  1569. * adjust the codec gain. Note the epoch is buffered from the
  1570. * center of the second in order to avoid jitter while the
  1571. * seconds synch is diddling the epoch. Then, determine the true
  1572. * offset and update the median filter in the driver interface.
  1573. *
  1574. * Use the energy at the end of the second as the noise to
  1575. * compute the SNR for the data pulse. This gives a better
  1576. * measurement than the beginning of the second, especially when
  1577. * returning from the probe channel. This gives a guard time of
  1578. * 30 ms from the decay of the longest pulse to the rise of the
  1579. * next pulse.
  1580. */
  1581. up->rphase++;
  1582. if (up->mphase % SECOND == up->repoch) {
  1583. up->status &= ~(DGATE | BGATE);
  1584. engmin = sqrt(up->irig * up->irig + up->qrig *
  1585. up->qrig);
  1586. up->datsig = engmax;
  1587. up->datsnr = wwv_snr(engmax, engmin);
  1588. /*
  1589. * If the amplitude or SNR is below threshold, average a
  1590. * 0 in the the integrators; otherwise, average the
  1591. * bipolar signal. This is done to avoid noise polution.
  1592. */
  1593. if (engmax < DTHR || up->datsnr < DSNR) {
  1594. up->status |= DGATE;
  1595. wwv_rsec(peer, 0);
  1596. } else {
  1597. sigzer -= sigone;
  1598. sigone -= sigmin;
  1599. wwv_rsec(peer, sigone - sigzer);
  1600. }
  1601. if (up->status & (DGATE | BGATE))
  1602. up->errcnt++;
  1603. if (up->errcnt > MAXERR)
  1604. up->alarm |= LOWERR;
  1605. wwv_gain(peer);
  1606. cp = &up->mitig[up->achan];
  1607. cp->wwv.syneng = 0;
  1608. cp->wwvh.syneng = 0;
  1609. up->rphase = 0;
  1610. }
  1611. }
  1612. /*
  1613. * wwv_rsec - process receiver second
  1614. *
  1615. * This routine is called at the end of each receiver second to
  1616. * implement the per-second state machine. The machine assembles BCD
  1617. * digit bits, decodes miscellaneous bits and dances the leap seconds.
  1618. *
  1619. * Normally, the minute has 60 seconds numbered 0-59. If the leap
  1620. * warning bit is set, the last minute (1439) of 30 June (day 181 or 182
  1621. * for leap years) or 31 December (day 365 or 366 for leap years) is
  1622. * augmented by one second numbered 60. This is accomplished by
  1623. * extending the minute interval by one second and teaching the state
  1624. * machine to ignore it.
  1625. */
  1626. static void
  1627. wwv_rsec(
  1628. struct peer *peer, /* peer structure pointer */
  1629. double bit
  1630. )
  1631. {
  1632. static int iniflg; /* initialization flag */
  1633. static double bcddld[4]; /* BCD data bits */
  1634. static double bitvec[61]; /* bit integrator for misc bits */
  1635. struct refclockproc *pp;
  1636. struct wwvunit *up;
  1637. struct chan *cp;
  1638. struct sync *sp, *rp;
  1639. char tbuf[80]; /* monitor buffer */
  1640. int sw, arg, nsec;
  1641. pp = peer->procptr;
  1642. up = (struct wwvunit *)pp->unitptr;
  1643. if (!iniflg) {
  1644. iniflg = 1;
  1645. memset((char *)bitvec, 0, sizeof(bitvec));
  1646. }
  1647. /*
  1648. * The bit represents the probability of a hit on zero (negative
  1649. * values), a hit on one (positive values) or a miss (zero
  1650. * value). The likelihood vector is the exponential average of
  1651. * these probabilities. Only the bits of this vector
  1652. * corresponding to the miscellaneous bits of the timecode are
  1653. * used, but it's easier to do them all. After that, crank the
  1654. * seconds state machine.
  1655. */
  1656. nsec = up->rsec;
  1657. up->rsec++;
  1658. bitvec[nsec] += (bit - bitvec[nsec]) / TCONST;
  1659. sw = progx[nsec].sw;
  1660. arg = progx[nsec].arg;
  1661. /*
  1662. * The minute state machine. Fly off to a particular section as
  1663. * directed by the transition matrix and second number.
  1664. */
  1665. switch (sw) {
  1666. /*
  1667. * Ignore this second.
  1668. */
  1669. case IDLE: /* 9, 45-49 */
  1670. break;
  1671. /*
  1672. * Probe channel stuff
  1673. *
  1674. * The WWV/H format contains data pulses in second 59 (position
  1675. * identifier) and second 1, but not in second 0. The minute
  1676. * sync pulse is contained in second 0. At the end of second 58
  1677. * QSY to the probe channel, which rotates in turn over all
  1678. * WWV/H frequencies. At the end of second 0 measure the minute
  1679. * sync pulse. At the end of second 1 measure the data pulse and
  1680. * QSY back to the data channel. Note that the actions commented
  1681. * here happen at the end of the second numbered as shown.
  1682. *
  1683. * At the end of second 0 save the minute sync amplitude latched
  1684. * at 800 ms as the signal later used to calculate the SNR.
  1685. */
  1686. case SYNC2: /* 0 */
  1687. cp = &up->mitig[up->achan];
  1688. cp->wwv.synmax = cp->wwv.syneng;
  1689. cp->wwvh.synmax = cp->wwvh.syneng;
  1690. break;
  1691. /*
  1692. * At the end of second 1 use the minute sync amplitude latched
  1693. * at 800 ms as the noise to calculate the SNR. If the minute
  1694. * sync pulse and SNR are above thresholds and the data pulse
  1695. * amplitude and SNR are above thresolds, shift a 1 into the
  1696. * station reachability register; otherwise, shift a 0. The
  1697. * number of 1 bits in the last six intervals is a component of
  1698. * the channel metric computed by the wwv_metric() routine.
  1699. * Finally, QSY back to the data channel.
  1700. */
  1701. case SYNC3: /* 1 */
  1702. cp = &up->mitig[up->achan];
  1703. /*
  1704. * WWV station
  1705. */
  1706. sp = &cp->wwv;
  1707. sp->synsnr = wwv_snr(sp->synmax, sp->amp);
  1708. sp->reach <<= 1;
  1709. if (sp->reach & (1 << AMAX))
  1710. sp->count--;
  1711. if (sp->synmax >= QTHR && sp->synsnr >= QSNR &&
  1712. !(up->status & (DGATE | BGATE))) {
  1713. sp->reach |= 1;
  1714. sp->count++;
  1715. }
  1716. sp->metric = wwv_metric(sp);
  1717. /*
  1718. * WWVH station
  1719. */
  1720. rp = &cp->wwvh;
  1721. rp->synsnr = wwv_snr(rp->synmax, rp->amp);
  1722. rp->reach <<= 1;
  1723. if (rp->reach & (1 << AMAX))
  1724. rp->count--;
  1725. if (rp->synmax >= QTHR && rp->synsnr >= QSNR &&
  1726. !(up->status & (DGATE | BGATE))) {
  1727. rp->reach |= 1;
  1728. rp->count++;
  1729. }
  1730. rp->metric = wwv_metric(rp);
  1731. if (pp->sloppyclockflag & CLK_FLAG4) {
  1732. sprintf(tbuf,
  1733. "wwv5 %04x %3d %4d %.0f/%.1f %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f",
  1734. up->status, up->gain, up->yepoch,
  1735. up->epomax, up->eposnr, up->datsig,
  1736. up->datsnr,
  1737. sp->refid, sp->reach & 0xffff,
  1738. sp->metric, sp->synmax, sp->synsnr,
  1739. rp->refid, rp->reach & 0xffff,
  1740. rp->metric, rp->synmax, rp->synsnr);
  1741. record_clock_stats(&peer->srcadr, tbuf);
  1742. #ifdef DEBUG
  1743. if (debug)
  1744. printf("%s\n", tbuf);
  1745. #endif /* DEBUG */
  1746. }
  1747. up->errcnt = up->digcnt = up->alarm = 0;
  1748. /*
  1749. * We now begin the minute scan. If not yet synchronized
  1750. * to a station, restart if the units digit has not been
  1751. * found within the DATA timeout (15 m) or if not
  1752. * synchronized within the SYNCH timeout (40 m). After
  1753. * synchronizing to a station, restart if no stations
  1754. * are found within the PANIC timeout (2 days).
  1755. */
  1756. if (up->status & INSYNC) {
  1757. if (up->watch > PANIC) {
  1758. wwv_newgame(peer);
  1759. return;
  1760. }
  1761. } else {
  1762. if (!(up->status & DSYNC)) {
  1763. if (up->watch > DATA) {
  1764. wwv_newgame(peer);
  1765. return;
  1766. }
  1767. }
  1768. if (up->watch > SYNCH) {
  1769. wwv_newgame(peer);
  1770. return;
  1771. }
  1772. }
  1773. wwv_newchan(peer);
  1774. #ifdef ICOM
  1775. if (up->fd_icom > 0)
  1776. wwv_qsy(peer, up->dchan);
  1777. #endif /* ICOM */
  1778. break;
  1779. /*
  1780. * Save the bit probability in the BCD data vector at the index
  1781. * given by the argument. Bits not used in the digit are forced
  1782. * to zero.
  1783. */
  1784. case COEF1: /* 4-7 */
  1785. bcddld[arg] = bit;
  1786. break;
  1787. case COEF: /* 10-13, 15-17, 20-23, 25-26,
  1788. 30-33, 35-38, 40-41, 51-54 */
  1789. if (up->status & DSYNC)
  1790. bcddld[arg] = bit;
  1791. else
  1792. bcddld[arg] = 0;
  1793. break;
  1794. case COEF2: /* 18, 27-28, 42-43 */
  1795. bcddld[arg] = 0;
  1796. break;
  1797. /*
  1798. * Correlate coefficient vector with each valid digit vector and
  1799. * save in decoding matrix. We step through the decoding matrix
  1800. * digits correlating each with the coefficients and saving the
  1801. * greatest and the next lower for later SNR calculation.
  1802. */
  1803. case DECIM2: /* 29 */
  1804. wwv_corr4(peer, &up->decvec[arg], bcddld, bcd2);
  1805. break;
  1806. case DECIM3: /* 44 */
  1807. wwv_corr4(peer, &up->decvec[arg], bcddld, bcd3);
  1808. break;
  1809. case DECIM6: /* 19 */
  1810. wwv_corr4(peer, &up->decvec[arg], bcddld, bcd6);
  1811. break;
  1812. case DECIM9: /* 8, 14, 24, 34, 39 */
  1813. wwv_corr4(peer, &up->decvec[arg], bcddld, bcd9);
  1814. break;
  1815. /*
  1816. * Miscellaneous bits. If above the positive threshold, declare
  1817. * 1; if below the negative threshold, declare 0; otherwise
  1818. * raise the BGATE bit. The design is intended to avoid
  1819. * integrating noise under low SNR conditions.
  1820. */
  1821. case MSC20: /* 55 */
  1822. wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9);
  1823. /* fall through */
  1824. case MSCBIT: /* 2-3, 50, 56-57 */
  1825. if (bitvec[nsec] > BTHR) {
  1826. if (!(up->misc & arg))
  1827. up->alarm |= CMPERR;
  1828. up->misc |= arg;
  1829. } else if (bitvec[nsec] < -BTHR) {
  1830. if (up->misc & arg)
  1831. up->alarm |= CMPERR;
  1832. up->misc &= ~arg;
  1833. } else {
  1834. up->status |= BGATE;
  1835. }
  1836. break;
  1837. /*
  1838. * Save the data channel gain, then QSY to the probe channel and
  1839. * dim the seconds comb filters. The newchan() routine will
  1840. * light them back up.
  1841. */
  1842. case MSC21: /* 58 */
  1843. if (bitvec[nsec] > BTHR) {
  1844. if (!(up->misc & arg))
  1845. up->alarm |= CMPERR;
  1846. up->misc |= arg;
  1847. } else if (bitvec[nsec] < -BTHR) {
  1848. if (up->misc & arg)
  1849. up->alarm |= CMPERR;
  1850. up->misc &= ~arg;
  1851. } else {
  1852. up->status |= BGATE;
  1853. }
  1854. up->status &= ~(SELV | SELH);
  1855. #ifdef ICOM
  1856. if (up->fd_icom > 0) {
  1857. up->schan = (up->schan + 1) % NCHAN;
  1858. wwv_qsy(peer, up->schan);
  1859. } else {
  1860. up->mitig[up->achan].gain = up->gain;
  1861. }
  1862. #else
  1863. up->mitig[up->achan].gain = up->gain;
  1864. #endif /* ICOM */
  1865. break;
  1866. /*
  1867. * The endgames
  1868. *
  1869. * During second 59 the receiver and codec AGC are settling
  1870. * down, so the data pulse is unusable as quality metric. If
  1871. * LEPSEC is set on the last minute of 30 June or 31 December,
  1872. * the transmitter and receiver insert an extra second (60) in
  1873. * the timescale and the minute sync repeats the second. Once
  1874. * leaps occurred at intervals of about 18 months, but the last
  1875. * leap before the most recent leap in 1995 was in 1998.
  1876. */
  1877. case MIN1: /* 59 */
  1878. if (up->status & LEPSEC)
  1879. break;
  1880. /* fall through */
  1881. case MIN2: /* 60 */
  1882. up->status &= ~LEPSEC;
  1883. wwv_tsec(peer);
  1884. up->rsec = 0;
  1885. wwv_clock(peer);
  1886. break;
  1887. }
  1888. if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
  1889. DSYNC)) {
  1890. sprintf(tbuf,
  1891. "wwv3 %2d %04x %3d %4d %5.0f %5.1f %5.0f %5.1f %5.0f",
  1892. nsec, up->status, up->gain, up->yepoch, up->epomax,
  1893. up->eposnr, up->datsig, up->datsnr, bit);
  1894. record_clock_stats(&peer->srcadr, tbuf);
  1895. #ifdef DEBUG
  1896. if (debug)
  1897. printf("%s\n", tbuf);
  1898. #endif /* DEBUG */
  1899. }
  1900. pp->disp += AUDIO_PHI;
  1901. }
  1902. /*
  1903. * The radio clock is set if the alarm bits are all zero. After that,
  1904. * the time is considered valid if the second sync bit is lit. It should
  1905. * not be a surprise, especially if the radio is not tunable, that
  1906. * sometimes no stations are above the noise and the integrators
  1907. * discharge below the thresholds. We assume that, after a day of signal
  1908. * loss, the minute sync epoch will be in the same second. This requires
  1909. * the codec frequency be accurate within 6 PPM. Practical experience
  1910. * shows the frequency typically within 0.1 PPM, so after a day of
  1911. * signal loss, the time should be within 8.6 ms..
  1912. */
  1913. static void
  1914. wwv_clock(
  1915. struct peer *peer /* peer unit pointer */
  1916. )
  1917. {
  1918. struct refclockproc *pp;
  1919. struct wwvunit *up;
  1920. l_fp offset; /* offset in NTP seconds */
  1921. pp = peer->procptr;
  1922. up = (struct wwvunit *)pp->unitptr;
  1923. if (!(up->status & SSYNC))
  1924. up->alarm |= SYNERR;
  1925. if (up->digcnt < 9)
  1926. up->alarm |= NINERR;
  1927. if (!(up->alarm))
  1928. up->status |= INSYNC;
  1929. if (up->status & INSYNC && up->status & SSYNC) {
  1930. if (up->misc & SECWAR)
  1931. pp->leap = LEAP_ADDSECOND;
  1932. else
  1933. pp->leap = LEAP_NOWARNING;
  1934. pp->second = up->rsec;
  1935. pp->minute = up->decvec[MN].digit + up->decvec[MN +
  1936. 1].digit * 10;
  1937. pp->hour = up->decvec[HR].digit + up->decvec[HR +
  1938. 1].digit * 10;
  1939. pp->day = up->decvec[DA].digit + up->decvec[DA +
  1940. 1].digit * 10 + up->decvec[DA + 2].digit * 100;
  1941. pp->year = up->decvec[YR].digit + up->decvec[YR +
  1942. 1].digit * 10;
  1943. pp->year += 2000;
  1944. L_CLR(&offset);
  1945. if (!clocktime(pp->day, pp->hour, pp->minute,
  1946. pp->second, GMT, up->timestamp.l_ui,
  1947. &pp->yearstart, &offset.l_ui)) {
  1948. up->errflg = CEVNT_BADTIME;
  1949. } else {
  1950. up->watch = 0;
  1951. pp->disp = 0;
  1952. pp->lastref = up->timestamp;
  1953. refclock_process_offset(pp, offset,
  1954. up->timestamp, PDELAY);
  1955. refclock_receive(peer);
  1956. }
  1957. }
  1958. pp->lencode = timecode(up, pp->a_lastcode);
  1959. record_clock_stats(&peer->srcadr, pp->a_lastcode);
  1960. #ifdef DEBUG
  1961. if (debug)
  1962. printf("wwv: timecode %d %s\n", pp->lencode,
  1963. pp->a_lastcode);
  1964. #endif /* DEBUG */
  1965. }
  1966. /*
  1967. * wwv_corr4 - determine maximum likelihood digit
  1968. *
  1969. * This routine correlates the received digit vector with the BCD
  1970. * coefficient vectors corresponding to all valid digits at the given
  1971. * position in the decoding matrix. The maximum value corresponds to the
  1972. * maximum likelihood digit, while the ratio of this value to the next
  1973. * lower value determines the likelihood function. Note that, if the
  1974. * digit is invalid, the likelihood vector is averaged toward a miss.
  1975. */
  1976. static void
  1977. wwv_corr4(
  1978. struct peer *peer, /* peer unit pointer */
  1979. struct decvec *vp, /* decoding table pointer */
  1980. double data[], /* received data vector */
  1981. double tab[][4] /* correlation vector array */
  1982. )
  1983. {
  1984. struct refclockproc *pp;
  1985. struct wwvunit *up;
  1986. double topmax, nxtmax; /* metrics */
  1987. double acc; /* accumulator */
  1988. char tbuf[80]; /* monitor buffer */
  1989. int mldigit; /* max likelihood digit */
  1990. int i, j;
  1991. pp = peer->procptr;
  1992. up = (struct wwvunit *)pp->unitptr;
  1993. /*
  1994. * Correlate digit vector with each BCD coefficient vector. If
  1995. * any BCD digit bit is bad, consider all bits a miss. Until the
  1996. * minute units digit has been resolved, don't to anything else.
  1997. * Note the SNR is calculated as the ratio of the largest
  1998. * likelihood value to the next largest likelihood value.
  1999. */
  2000. mldigit = 0;
  2001. topmax = nxtmax = -MAXAMP;
  2002. for (i = 0; tab[i][0] != 0; i++) {
  2003. acc = 0;
  2004. for (j = 0; j < 4; j++)
  2005. acc += data[j] * tab[i][j];
  2006. acc = (vp->like[i] += (acc - vp->like[i]) / TCONST);
  2007. if (acc > topmax) {
  2008. nxtmax = topmax;
  2009. topmax = acc;
  2010. mldigit = i;
  2011. } else if (acc > nxtmax) {
  2012. nxtmax = acc;
  2013. }
  2014. }
  2015. vp->digprb = topmax;
  2016. vp->digsnr = wwv_snr(topmax, nxtmax);
  2017. /*
  2018. * The current maximum likelihood digit is compared to the last
  2019. * maximum likelihood digit. If different, the compare counter
  2020. * and maximum likelihood digit are reset. When the compare
  2021. * counter reaches the BCMP threshold (3), the digit is assumed
  2022. * correct. When the compare counter of all nine digits have
  2023. * reached threshold, the clock is assumed correct.
  2024. *
  2025. * Note that the clock display digit is set before the compare
  2026. * counter has reached threshold; however, the clock display is
  2027. * not considered correct until all nine clock digits have
  2028. * reached threshold. This is intended as eye candy, but avoids
  2029. * mistakes when the signal is low and the SNR is very marginal.
  2030. * once correctly set, the maximum likelihood digit is ignored
  2031. * on the assumption the clock will always be correct unless for
  2032. * some reason it drifts to a different second.
  2033. */
  2034. vp->mldigit = mldigit;
  2035. if (vp->digprb < BTHR || vp->digsnr < BSNR) {
  2036. vp->count = 0;
  2037. up->status |= BGATE;
  2038. } else {
  2039. up->status |= DSYNC;
  2040. if (vp->digit != mldigit) {
  2041. vp->count = 0;
  2042. up->alarm |= CMPERR;
  2043. if (!(up->status & INSYNC))
  2044. vp->digit = mldigit;
  2045. } else {
  2046. if (vp->count < BCMP)
  2047. vp->count++;
  2048. else
  2049. up->digcnt++;
  2050. }
  2051. }
  2052. if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
  2053. INSYNC)) {
  2054. sprintf(tbuf,
  2055. "wwv4 %2d %04x %3d %4d %5.0f %2d %d %d %d %5.0f %5.1f",
  2056. up->rsec - 1, up->status, up->gain, up->yepoch,
  2057. up->epomax, vp->radix, vp->digit, vp->mldigit,
  2058. vp->count, vp->digprb, vp->digsnr);
  2059. record_clock_stats(&peer->srcadr, tbuf);
  2060. #ifdef DEBUG
  2061. if (debug)
  2062. printf("%s\n", tbuf);
  2063. #endif /* DEBUG */
  2064. }
  2065. }
  2066. /*
  2067. * wwv_tsec - transmitter minute processing
  2068. *
  2069. * This routine is called at the end of the transmitter minute. It
  2070. * implements a state machine that advances the logical clock subject to
  2071. * the funny rules that govern the conventional clock and calendar.
  2072. */
  2073. static void
  2074. wwv_tsec(
  2075. struct peer *peer /* driver structure pointer */
  2076. )
  2077. {
  2078. struct refclockproc *pp;
  2079. struct wwvunit *up;
  2080. int minute, day, isleap;
  2081. int temp;
  2082. pp = peer->procptr;
  2083. up = (struct wwvunit *)pp->unitptr;
  2084. /*
  2085. * Advance minute unit of the day. Don't propagate carries until
  2086. * the unit minute digit has been found.
  2087. */
  2088. temp = carry(&up->decvec[MN]); /* minute units */
  2089. if (!(up->status & DSYNC))
  2090. return;
  2091. /*
  2092. * Propagate carries through the day.
  2093. */
  2094. if (temp == 0) /* carry minutes */
  2095. temp = carry(&up->decvec[MN + 1]);
  2096. if (temp == 0) /* carry hours */
  2097. temp = carry(&up->decvec[HR]);
  2098. if (temp == 0)
  2099. temp = carry(&up->decvec[HR + 1]);
  2100. /*
  2101. * Decode the current minute and day. Set leap day if the
  2102. * timecode leap bit is set on 30 June or 31 December. Set leap
  2103. * minute if the last minute on leap day, but only if the clock
  2104. * is syncrhronized. This code fails in 2400 AD.
  2105. */
  2106. minute = up->decvec[MN].digit + up->decvec[MN + 1].digit *
  2107. 10 + up->decvec[HR].digit * 60 + up->decvec[HR +
  2108. 1].digit * 600;
  2109. day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
  2110. up->decvec[DA + 2].digit * 100;
  2111. /*
  2112. * Set the leap bit on the last minute of the leap day.
  2113. */
  2114. isleap = up->decvec[YR].digit & 0x3;
  2115. if (up->misc & SECWAR && up->status & INSYNC) {
  2116. if ((day == (isleap ? 182 : 183) || day == (isleap ?
  2117. 365 : 366)) && minute == 1439)
  2118. up->status |= LEPSEC;
  2119. }
  2120. /*
  2121. * Roll the day if this the first minute and propagate carries
  2122. * through the year.
  2123. */
  2124. if (minute != 1440)
  2125. return;
  2126. minute = 0;
  2127. while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */
  2128. while (carry(&up->decvec[HR + 1]) != 0);
  2129. day++;
  2130. temp = carry(&up->decvec[DA]); /* carry days */
  2131. if (temp == 0)
  2132. temp = carry(&up->decvec[DA + 1]);
  2133. if (temp == 0)
  2134. temp = carry(&up->decvec[DA + 2]);
  2135. /*
  2136. * Roll the year if this the first day and propagate carries
  2137. * through the century.
  2138. */
  2139. if (day != (isleap ? 365 : 366))
  2140. return;
  2141. day = 1;
  2142. while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */
  2143. while (carry(&up->decvec[DA + 1]) != 0);
  2144. while (carry(&up->decvec[DA + 2]) != 0);
  2145. temp = carry(&up->decvec[YR]); /* carry years */
  2146. if (temp == 0)
  2147. carry(&up->decvec[YR + 1]);
  2148. }
  2149. /*
  2150. * carry - process digit
  2151. *
  2152. * This routine rotates a likelihood vector one position and increments
  2153. * the clock digit modulo the radix. It returns the new clock digit or
  2154. * zero if a carry occurred. Once synchronized, the clock digit will
  2155. * match the maximum likelihood digit corresponding to that position.
  2156. */
  2157. static int
  2158. carry(
  2159. struct decvec *dp /* decoding table pointer */
  2160. )
  2161. {
  2162. int temp;
  2163. int j;
  2164. dp->digit++;
  2165. if (dp->digit == dp->radix)
  2166. dp->digit = 0;
  2167. temp = dp->like[dp->radix - 1];
  2168. for (j = dp->radix - 1; j > 0; j--)
  2169. dp->like[j] = dp->like[j - 1];
  2170. dp->like[0] = temp;
  2171. return (dp->digit);
  2172. }
  2173. /*
  2174. * wwv_snr - compute SNR or likelihood function
  2175. */
  2176. static double
  2177. wwv_snr(
  2178. double signal, /* signal */
  2179. double noise /* noise */
  2180. )
  2181. {
  2182. double rval;
  2183. /*
  2184. * This is a little tricky. Due to the way things are measured,
  2185. * either or both the signal or noise amplitude can be negative
  2186. * or zero. The intent is that, if the signal is negative or
  2187. * zero, the SNR must always be zero. This can happen with the
  2188. * subcarrier SNR before the phase has been aligned. On the
  2189. * other hand, in the likelihood function the "noise" is the
  2190. * next maximum down from the peak and this could be negative.
  2191. * However, in this case the SNR is truly stupendous, so we
  2192. * simply cap at MAXSNR dB (40).
  2193. */
  2194. if (signal <= 0) {
  2195. rval = 0;
  2196. } else if (noise <= 0) {
  2197. rval = MAXSNR;
  2198. } else {
  2199. rval = 20. * log10(signal / noise);
  2200. if (rval > MAXSNR)
  2201. rval = MAXSNR;
  2202. }
  2203. return (rval);
  2204. }
  2205. /*
  2206. * wwv_newchan - change to new data channel
  2207. *
  2208. * The radio actually appears to have ten channels, one channel for each
  2209. * of five frequencies and each of two stations (WWV and WWVH), although
  2210. * if not tunable only the DCHAN channel appears live. While the radio
  2211. * is tuned to the working data channel frequency and station for most
  2212. * of the minute, during seconds 59, 0 and 1 the radio is tuned to a
  2213. * probe frequency in order to search for minute sync pulse and data
  2214. * subcarrier from other transmitters.
  2215. *
  2216. * The search for WWV and WWVH operates simultaneously, with WWV minute
  2217. * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency
  2218. * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes,
  2219. * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit
  2220. * on 25 MHz.
  2221. *
  2222. * This routine selects the best channel using a metric computed from
  2223. * the reachability register and minute pulse amplitude. Normally, the
  2224. * award goes to the the channel with the highest metric; but, in case
  2225. * of ties, the award goes to the channel with the highest minute sync
  2226. * pulse amplitude and then to the highest frequency.
  2227. *
  2228. * The routine performs an important squelch function to keep dirty data
  2229. * from polluting the integrators. In order to consider a station valid,
  2230. * the metric must be at least MTHR (13); otherwise, the station select
  2231. * bits are cleared so the second sync is disabled and the data bit
  2232. * integrators averaged to a miss.
  2233. */
  2234. static int
  2235. wwv_newchan(
  2236. struct peer *peer /* peer structure pointer */
  2237. )
  2238. {
  2239. struct refclockproc *pp;
  2240. struct wwvunit *up;
  2241. struct sync *sp, *rp;
  2242. double rank, dtemp;
  2243. int i, j;
  2244. pp = peer->procptr;
  2245. up = (struct wwvunit *)pp->unitptr;
  2246. /*
  2247. * Search all five station pairs looking for the channel with
  2248. * maximum metric. If no station is found above thresholds, tune
  2249. * to WWV on 15 MHz, set the reference ID to NONE and wait for
  2250. * hotter ions.
  2251. */
  2252. sp = NULL;
  2253. j = 0;
  2254. rank = 0;
  2255. for (i = 0; i < NCHAN; i++) {
  2256. rp = &up->mitig[i].wwvh;
  2257. dtemp = rp->metric;
  2258. if (dtemp >= rank) {
  2259. rank = dtemp;
  2260. sp = rp;
  2261. j = i;
  2262. }
  2263. rp = &up->mitig[i].wwv;
  2264. dtemp = rp->metric;
  2265. if (dtemp >= rank) {
  2266. rank = dtemp;
  2267. sp = rp;
  2268. j = i;
  2269. }
  2270. }
  2271. /*
  2272. * If the strongest signal is less than the MTHR threshold (13),
  2273. * we are beneath the waves, so squelch the second sync. If the
  2274. * strongest signal is greater than the threshold, tune to that
  2275. * frequency and transmitter QTH.
  2276. */
  2277. if (rank < MTHR) {
  2278. up->dchan = (up->dchan + 1) % NCHAN;
  2279. up->status &= ~(SELV | SELH);
  2280. return (FALSE);
  2281. }
  2282. up->dchan = j;
  2283. up->status |= SELV | SELH;
  2284. up->sptr = sp;
  2285. memcpy(&pp->refid, sp->refid, 4);
  2286. peer->refid = pp->refid;
  2287. return (TRUE);
  2288. }
  2289. /*
  2290. * wwv_newgame - reset and start over
  2291. *
  2292. * There are four conditions resulting in a new game:
  2293. *
  2294. * 1 During initial acquisition (MSYNC dark) going 6 minutes (ACQSN)
  2295. * without reliably finding the minute pulse (MSYNC lit).
  2296. *
  2297. * 2 After finding the minute pulse (MSYNC lit), going 15 minutes
  2298. * (DATA) without finding the unit seconds digit.
  2299. *
  2300. * 3 After finding good data (DATA lit), going more than 40 minutes
  2301. * (SYNCH) without finding station sync (INSYNC lit).
  2302. *
  2303. * 4 After finding station sync (INSYNC lit), going more than 2 days
  2304. * (PANIC) without finding any station.
  2305. */
  2306. static void
  2307. wwv_newgame(
  2308. struct peer *peer /* peer structure pointer */
  2309. )
  2310. {
  2311. struct refclockproc *pp;
  2312. struct wwvunit *up;
  2313. struct chan *cp;
  2314. int i;
  2315. pp = peer->procptr;
  2316. up = (struct wwvunit *)pp->unitptr;
  2317. /*
  2318. * Initialize strategic values. Note we set the leap bits
  2319. * NOTINSYNC and the refid "NONE".
  2320. */
  2321. peer->leap = LEAP_NOTINSYNC;
  2322. up->watch = up->status = up->alarm = 0;
  2323. up->avgint = MINAVG;
  2324. up->freq = 0;
  2325. up->gain = MAXGAIN / 2;
  2326. /*
  2327. * Initialize the station processes for audio gain, select bit,
  2328. * station/frequency identifier and reference identifier. Start
  2329. * probing at the next channel after the data channel.
  2330. */
  2331. memset(up->mitig, 0, sizeof(up->mitig));
  2332. for (i = 0; i < NCHAN; i++) {
  2333. cp = &up->mitig[i];
  2334. cp->gain = up->gain;
  2335. cp->wwv.select = SELV;
  2336. sprintf(cp->wwv.refid, "WV%.0f", floor(qsy[i]));
  2337. cp->wwvh.select = SELH;
  2338. sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i]));
  2339. }
  2340. up->dchan = (DCHAN + NCHAN - 1) % NCHAN;;
  2341. wwv_newchan(peer);
  2342. up->achan = up->schan = up->dchan;
  2343. #ifdef ICOM
  2344. if (up->fd_icom > 0)
  2345. wwv_qsy(peer, up->dchan);
  2346. #endif /* ICOM */
  2347. }
  2348. /*
  2349. * wwv_metric - compute station metric
  2350. *
  2351. * The most significant bits represent the number of ones in the
  2352. * station reachability register. The least significant bits represent
  2353. * the minute sync pulse amplitude. The combined value is scaled 0-100.
  2354. */
  2355. double
  2356. wwv_metric(
  2357. struct sync *sp /* station pointer */
  2358. )
  2359. {
  2360. double dtemp;
  2361. dtemp = sp->count * MAXAMP;
  2362. if (sp->synmax < MAXAMP)
  2363. dtemp += sp->synmax;
  2364. else
  2365. dtemp += MAXAMP - 1;
  2366. dtemp /= (AMAX + 1) * MAXAMP;
  2367. return (dtemp * 100.);
  2368. }
  2369. #ifdef ICOM
  2370. /*
  2371. * wwv_qsy - Tune ICOM receiver
  2372. *
  2373. * This routine saves the AGC for the current channel, switches to a new
  2374. * channel and restores the AGC for that channel. If a tunable receiver
  2375. * is not available, just fake it.
  2376. */
  2377. static int
  2378. wwv_qsy(
  2379. struct peer *peer, /* peer structure pointer */
  2380. int chan /* channel */
  2381. )
  2382. {
  2383. int rval = 0;
  2384. struct refclockproc *pp;
  2385. struct wwvunit *up;
  2386. pp = peer->procptr;
  2387. up = (struct wwvunit *)pp->unitptr;
  2388. if (up->fd_icom > 0) {
  2389. up->mitig[up->achan].gain = up->gain;
  2390. rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
  2391. qsy[chan]);
  2392. up->achan = chan;
  2393. up->gain = up->mitig[up->achan].gain;
  2394. }
  2395. return (rval);
  2396. }
  2397. #endif /* ICOM */
  2398. /*
  2399. * timecode - assemble timecode string and length
  2400. *
  2401. * Prettytime format - similar to Spectracom
  2402. *
  2403. * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt
  2404. *
  2405. * s sync indicator ('?' or ' ')
  2406. * q error bits (hex 0-F)
  2407. * yyyy year of century
  2408. * ddd day of year
  2409. * hh hour of day
  2410. * mm minute of hour
  2411. * ss second of minute)
  2412. * l leap second warning (' ' or 'L')
  2413. * d DST state ('S', 'D', 'I', or 'O')
  2414. * dut DUT sign and magnitude (0.1 s)
  2415. * lset minutes since last clock update
  2416. * agc audio gain (0-255)
  2417. * iden reference identifier (station and frequency)
  2418. * sig signal quality (0-100)
  2419. * errs bit errors in last minute
  2420. * freq frequency offset (PPM)
  2421. * avgt averaging time (s)
  2422. */
  2423. static int
  2424. timecode(
  2425. struct wwvunit *up, /* driver structure pointer */
  2426. char *ptr /* target string */
  2427. )
  2428. {
  2429. struct sync *sp;
  2430. int year, day, hour, minute, second, dut;
  2431. char synchar, leapchar, dst;
  2432. char cptr[50];
  2433. /*
  2434. * Common fixed-format fields
  2435. */
  2436. synchar = (up->status & INSYNC) ? ' ' : '?';
  2437. year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 +
  2438. 2000;
  2439. day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
  2440. up->decvec[DA + 2].digit * 100;
  2441. hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10;
  2442. minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10;
  2443. second = 0;
  2444. leapchar = (up->misc & SECWAR) ? 'L' : ' ';
  2445. dst = dstcod[(up->misc >> 4) & 0x3];
  2446. dut = up->misc & 0x7;
  2447. if (!(up->misc & DUTS))
  2448. dut = -dut;
  2449. sprintf(ptr, "%c%1X", synchar, up->alarm);
  2450. sprintf(cptr, " %4d %03d %02d:%02d:%02d %c%c %+d",
  2451. year, day, hour, minute, second, leapchar, dst, dut);
  2452. strcat(ptr, cptr);
  2453. /*
  2454. * Specific variable-format fields
  2455. */
  2456. sp = up->sptr;
  2457. sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch,
  2458. up->mitig[up->dchan].gain, sp->refid, sp->metric,
  2459. up->errcnt, up->freq / SECOND * 1e6, up->avgint);
  2460. strcat(ptr, cptr);
  2461. return (strlen(ptr));
  2462. }
  2463. /*
  2464. * wwv_gain - adjust codec gain
  2465. *
  2466. * This routine is called at the end of each second. During the second
  2467. * the number of signal clips above the MAXAMP threshold (6000). If
  2468. * there are no clips, the gain is bumped up; if there are more than
  2469. * MAXCLP clips (100), it is bumped down. The decoder is relatively
  2470. * insensitive to amplitude, so this crudity works just peachy. The
  2471. * input port is set and the error flag is cleared, mostly to be ornery.
  2472. */
  2473. static void
  2474. wwv_gain(
  2475. struct peer *peer /* peer structure pointer */
  2476. )
  2477. {
  2478. struct refclockproc *pp;
  2479. struct wwvunit *up;
  2480. pp = peer->procptr;
  2481. up = (struct wwvunit *)pp->unitptr;
  2482. /*
  2483. * Apparently, the codec uses only the high order bits of the
  2484. * gain control field. Thus, it may take awhile for changes to
  2485. * wiggle the hardware bits.
  2486. */
  2487. if (up->clipcnt == 0) {
  2488. up->gain += 4;
  2489. if (up->gain > MAXGAIN)
  2490. up->gain = MAXGAIN;
  2491. } else if (up->clipcnt > MAXCLP) {
  2492. up->gain -= 4;
  2493. if (up->gain < 0)
  2494. up->gain = 0;
  2495. }
  2496. audio_gain(up->gain, up->mongain, up->port);
  2497. up->clipcnt = 0;
  2498. #if DEBUG
  2499. if (debug > 1)
  2500. audio_show();
  2501. #endif
  2502. }
  2503. #else
  2504. int refclock_wwv_bs;
  2505. #endif /* REFCLOCK */