Lines Matching +full:double +full:- +full:channel
2 * refclock_wwv - clock driver for NIST WWV/H time/frequency station
43 * kHz and mu-law companding. This is the same standard as used by the
53 * Report 97-8-1, University of Delaware, August 1997, 25 pp., available
61 * a nonzero ICOM ID select code. The C-IV trace is turned on if the
68 * port, where 0 is the mike port (default) and 1 is the line-in port.
74 * CEVNT_PROP propagation failure - no stations heard
82 #define PRECISION (-10) /* precision assumed (about 1 ms) */
99 #define AUDIO_PHI 5e-6 /* dispersion growth factor */
113 #define DCHAN 3 /* default radio channel (15 Mhz) */
201 * Tone frequency definitions. The increments are for 4.5-deg sine
233 * The on-time synchronization point is the positive-going zero crossing
234 * of the first cycle of the 5-ms second pulse. The IIR baseband filter
236 * ms at 1000 Hz. The fudge value -0.45 ms due to the codec and other
242 * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
243 * generally within .02 ms short-term with .02 ms jitter. The long-term
247 #define PDELAY ((.91 + 4.7 - 0.45) / 1000) /* system delay (s) */
250 * Table of sine values at 4.5-degree increments. This is used by the
253 double sintab[] = {
254 0.000000e+00, 7.845910e-02, 1.564345e-01, 2.334454e-01, /* 0-3 */
255 3.090170e-01, 3.826834e-01, 4.539905e-01, 5.224986e-01, /* 4-7 */
256 5.877853e-01, 6.494480e-01, 7.071068e-01, 7.604060e-01, /* 8-11 */
257 8.090170e-01, 8.526402e-01, 8.910065e-01, 9.238795e-01, /* 12-15 */
258 9.510565e-01, 9.723699e-01, 9.876883e-01, 9.969173e-01, /* 16-19 */
259 1.000000e+00, 9.969173e-01, 9.876883e-01, 9.723699e-01, /* 20-23 */
260 9.510565e-01, 9.238795e-01, 8.910065e-01, 8.526402e-01, /* 24-27 */
261 8.090170e-01, 7.604060e-01, 7.071068e-01, 6.494480e-01, /* 28-31 */
262 5.877853e-01, 5.224986e-01, 4.539905e-01, 3.826834e-01, /* 32-35 */
263 3.090170e-01, 2.334454e-01, 1.564345e-01, 7.845910e-02, /* 36-39 */
264 -0.000000e+00, -7.845910e-02, -1.564345e-01, -2.334454e-01, /* 40-43 */
265 -3.090170e-01, -3.826834e-01, -4.539905e-01, -5.224986e-01, /* 44-47 */
266 -5.877853e-01, -6.494480e-01, -7.071068e-01, -7.604060e-01, /* 48-51 */
267 -8.090170e-01, -8.526402e-01, -8.910065e-01, -9.238795e-01, /* 52-55 */
268 -9.510565e-01, -9.723699e-01, -9.876883e-01, -9.969173e-01, /* 56-59 */
269 -1.000000e+00, -9.969173e-01, -9.876883e-01, -9.723699e-01, /* 60-63 */
270 -9.510565e-01, -9.238795e-01, -8.910065e-01, -8.526402e-01, /* 64-67 */
271 -8.090170e-01, -7.604060e-01, -7.071068e-01, -6.494480e-01, /* 68-71 */
272 -5.877853e-01, -5.224986e-01, -4.539905e-01, -3.826834e-01, /* 72-75 */
273 -3.090170e-01, -2.334454e-01, -1.564345e-01, -7.845910e-02, /* 76-79 */
294 #define DECIM9 4 /* BCD digit 0-9 */
295 #define DECIM6 5 /* BCD digit 0-6 */
296 #define DECIM3 6 /* BCD digit 0-3 */
297 #define DECIM2 7 /* BCD digit 0-2 */
300 #define MSC21 10 /* QSY probe channel */
365 {MSCBIT, DUTS}, /* 50 dut+- */
373 {MSC21, DUT4}, /* 58 0.4 QSY probe channel */
379 * BCD coefficients for maximum-likelihood digit decode
382 #define N15 -1. /* max negative number */
385 * Digits 0-9
388 #define N9 (N15 / 4) /* space (-1) */
390 double bcd9[][4] = {
405 * Digits 0-6 (minute tens)
408 #define N6 (N15 / 3) /* space (-1) */
410 double bcd6[][4] = {
422 * Digits 0-3 (day hundreds)
425 #define N3 (N15 / 2) /* space (-1) */
427 double bcd3[][4] = {
436 * Digits 0-2 (hour tens)
439 #define N2 (N15 / 2) /* space (-1) */
441 double bcd2[][4] = {
461 * order. The maximum-likelihood timecode is formed from the digits
462 * corresponding to the maximum-likelihood values reading in the
469 double digprb; /* max digit probability */
470 double digsnr; /* likelihood function (dB) */
471 double like[10]; /* likelihood integrator 0-9 */
481 double epoch; /* accumulated epoch differences */
482 double maxeng; /* sync max energy */
483 double noieng; /* sync noise energy */
488 double amp; /* sync signal */
489 double syneng; /* sync signal max */
490 double synmax; /* sync signal max latched at 0 s */
491 double synsnr; /* sync signal SNR */
492 double metric; /* signal quality metric */
500 * The channel structure (cp) is used to mitigate between channels.
514 double phase, freq; /* logical clock phase and frequency */
515 double monitor; /* audio monitor point */
516 double pdelay; /* propagation delay (s) */
526 double comp[SIZE]; /* decompanding table */
538 double epomax; /* second sync amplitude */
539 double eposnr; /* second sync SNR */
540 double irig; /* data I channel amplitude */
541 double qrig; /* data Q channel amplitude */
543 double datpha; /* 100 Hz VFO control */
548 * Variables used to mitigate which channel to use
550 struct chan mitig[NCHAN]; /* channel data */
552 int dchan; /* data channel */
553 int schan; /* probe channel */
554 int achan; /* active channel */
567 double datsig; /* data signal max */
568 double datsnr; /* data signal SNR (dB) */
591 static void wwv_rf (struct peer *, double);
593 static void wwv_rsec (struct peer *, double);
596 double [], double [][4]);
600 static double wwv_snr (double, double);
604 static double wwv_metric (struct sync *);
610 static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */
627 * wwv_start - open the devices and initialize data for processing
646 double step; /* codec adjustment */
663 pp = peer->procptr;
664 pp->io.clock_recv = wwv_receive;
665 pp->io.srcclock = peer;
666 pp->io.datalen = 0;
667 pp->io.fd = fd;
668 if (!io_addclock(&pp->io)) {
673 pp->unitptr = up;
678 peer->precision = PRECISION;
679 pp->clockdesc = DESCRIPTION;
682 * The companded samples are encoded sign-magnitude. The table
685 up->comp[0] = up->comp[OFFSET] = 0.;
686 up->comp[1] = 1.; up->comp[OFFSET + 1] = -1.;
687 up->comp[2] = 3.; up->comp[OFFSET + 2] = -3.;
690 up->comp[i] = up->comp[i - 1] + step;
691 up->comp[OFFSET + i] = -up->comp[i];
695 DTOLFP(1. / WWV_SEC, &up->tick);
701 up->decvec[MN].radix = 10; /* minutes */
702 up->decvec[MN + 1].radix = 6;
703 up->decvec[HR].radix = 10; /* hours */
704 up->decvec[HR + 1].radix = 3;
705 up->decvec[DA].radix = 10; /* days */
706 up->decvec[DA + 1].radix = 10;
707 up->decvec[DA + 2].radix = 4;
708 up->decvec[YR].radix = 10; /* years */
709 up->decvec[YR + 1].radix = 10;
724 if (peer->ttl != 0) {
725 if (peer->ttl & 0x80)
726 up->fd_icom = icom_init("/dev/icom", B1200,
729 up->fd_icom = icom_init("/dev/icom", B9600,
732 if (up->fd_icom > 0) {
735 close(up->fd_icom);
736 up->fd_icom = 0;
752 * wwv_shutdown - shut down the clock
763 pp = peer->procptr;
764 up = pp->unitptr;
768 io_closeclock(&pp->io);
770 if (up->fd_icom > 0)
771 close(up->fd_icom);
778 * wwv_receive - receive data from the audio device
797 double sample; /* codec sample */
802 peer = rbufp->recv_peer;
803 pp = peer->procptr;
804 up = pp->unitptr;
807 * Main loop - read until there ain't no more. Note codec
808 * samples are bit-inverted.
810 DTOLFP((double)rbufp->recv_length / WWV_SEC, <emp);
811 L_SUB(&rbufp->recv_time, <emp);
812 up->timestamp = rbufp->recv_time;
813 dpt = rbufp->recv_buffer;
814 for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) {
815 sample = up->comp[~*dpt++ & 0xff];
824 up->clipcnt++;
825 } else if (sample < -MAXAMP) {
826 sample = -MAXAMP;
827 up->clipcnt++;
838 up->phase += (up->freq + clock_codec) / WWV_SEC;
839 if (up->phase >= .5) {
840 up->phase -= 1.;
841 } else if (up->phase < -.5) {
842 up->phase += 1.;
848 L_ADD(&up->timestamp, &up->tick);
854 if (pp->sloppyclockflag & CLK_FLAG2)
855 up->port = 2;
857 up->port = 1;
858 if (pp->sloppyclockflag & CLK_FLAG3)
859 up->mongain = MONGAIN;
861 up->mongain = 0;
866 * wwv_poll - called by the transmit procedure
882 pp = peer->procptr;
883 up = pp->unitptr;
884 if (up->errflg)
885 refclock_report(peer, up->errflg);
886 up->errflg = 0;
887 pp->polls++;
892 * wwv_rf - process signals and demodulate to baseband
895 * output signal is the 100-Hz filtered baseband data signal in
899 * There are two 1-s ramps used by this program. Both count the 8000
902 * counts the samples starting at the 5-ms second sync pulse found
905 * There are two 1-m ramps used by this program. The mphase ramp counts
908 * the minute starting at the 800-ms minute sync pulse found during the
924 double isig /* input signal */
931 static double lpf[5]; /* 150-Hz lpf delay line */
932 double data; /* lpf output */
933 static double bpf[9]; /* 1000/1200-Hz bpf delay line */
934 double syncx; /* bpf output */
935 static double mf[41]; /* 1000/1200-Hz mf delay line */
936 double mfsync; /* mf output */
938 static int iptr; /* data channel pointer */
939 static double ibuf[DATSIZ]; /* data I channel delay line */
940 static double qbuf[DATSIZ]; /* data Q channel delay line */
942 static int jptr; /* sync channel pointer */
943 static int kptr; /* tick channel pointer */
945 static int csinptr; /* wwv channel phase */
946 static double cibuf[SYNSIZ]; /* wwv I channel delay line */
947 static double cqbuf[SYNSIZ]; /* wwv Q channel delay line */
948 static double ciamp; /* wwv I channel amplitude */
949 static double cqamp; /* wwv Q channel amplitude */
951 static double csibuf[TCKSIZ]; /* wwv I tick delay line */
952 static double csqbuf[TCKSIZ]; /* wwv Q tick delay line */
953 static double csiamp; /* wwv I tick amplitude */
954 static double csqamp; /* wwv Q tick amplitude */
956 static int hsinptr; /* wwvh channel phase */
957 static double hibuf[SYNSIZ]; /* wwvh I channel delay line */
958 static double hqbuf[SYNSIZ]; /* wwvh Q channel delay line */
959 static double hiamp; /* wwvh I channel amplitude */
960 static double hqamp; /* wwvh Q channel amplitude */
962 static double hsibuf[TCKSIZ]; /* wwvh I tick delay line */
963 static double hsqbuf[TCKSIZ]; /* wwvh Q tick delay line */
964 static double hsiamp; /* wwvh I tick amplitude */
965 static double hsqamp; /* wwvh Q tick amplitude */
967 static double epobuf[WWV_SEC]; /* second sync comb filter */
968 static double epomax, nxtmax; /* second sync amplitude buffer */
973 double dtemp;
976 pp = peer->procptr;
977 up = pp->unitptr;
998 * Baseband data demodulation. The 100-Hz subcarrier is
999 * extracted using a 150-Hz IIR lowpass filter. This attenuates
1000 * the 1000/1200-Hz sync signals, as well as the 440-Hz and
1001 * 600-Hz tones and most of the noise and voice modulation
1008 * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB
1009 * passband ripple, -50 dB stopband ripple, phase delay 0.97 ms.
1011 data = (lpf[4] = lpf[3]) * 8.360961e-01;
1012 data += (lpf[3] = lpf[2]) * -3.481740e+00;
1014 data += (lpf[1] = lpf[0]) * -3.807229e+00;
1015 lpf[0] = isig * DGAIN - data;
1016 data = lpf[0] * 3.281435e-03
1017 + lpf[1] * -1.149947e-02
1018 + lpf[2] * 1.654858e-02
1019 + lpf[3] * -1.149947e-02
1020 + lpf[4] * 3.281435e-03;
1023 * The 100-Hz data signal is demodulated using a pair of
1026 * multiplying the filtered signal by 100-Hz sine and cosine
1027 * signals, respectively. The signals are processed by 170-ms
1032 i = up->datapt;
1033 up->datapt = (up->datapt + IN100) % 80;
1035 up->irig -= ibuf[iptr];
1037 up->irig += dtemp;
1041 up->qrig -= qbuf[iptr];
1043 up->qrig += dtemp;
1048 * extracted using a 600-Hz IIR bandpass filter. This removes
1049 * the 100-Hz data subcarrier, as well as the 440-Hz and 600-Hz
1052 * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB
1053 * passband ripple, -50 dB stopband ripple, phase delay 0.91 ms.
1055 syncx = (bpf[8] = bpf[7]) * 4.897278e-01;
1056 syncx += (bpf[7] = bpf[6]) * -2.765914e+00;
1058 syncx += (bpf[5] = bpf[4]) * -1.517732e+01;
1060 syncx += (bpf[3] = bpf[2]) * -1.814365e+01;
1062 syncx += (bpf[1] = bpf[0]) * -4.735040e+00;
1063 bpf[0] = isig - syncx;
1064 syncx = bpf[0] * 8.203628e-03
1065 + bpf[1] * -2.375732e-02
1066 + bpf[2] * 3.353214e-02
1067 + bpf[3] * -4.080258e-02
1068 + bpf[4] * 4.605479e-02
1069 + bpf[5] * -4.080258e-02
1070 + bpf[6] * 3.353214e-02
1071 + bpf[7] * -2.375732e-02
1072 + bpf[8] * 8.203628e-03;
1080 * by 1000-Hz (WWV) and 1200-Hz (WWVH) sine and cosine signals,
1081 * respectively. The WWV and WWVH signals are processed by 800-
1085 * processed by 5-ms synchronous matched filters and combined to
1094 up->mphase = (up->mphase + 1) % WWV_MIN;
1095 epoch = up->mphase % WWV_SEC;
1104 ciamp -= cibuf[jptr];
1107 csiamp -= csibuf[kptr];
1113 cqamp -= cqbuf[jptr];
1116 csqamp -= csqbuf[kptr];
1120 sp = &up->mitig[up->achan].wwv;
1121 sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC;
1122 if (!(up->status & MSYNC))
1123 wwv_qrz(peer, sp, (int)(pp->fudgetime1 * WWV_SEC));
1132 hiamp -= hibuf[jptr];
1135 hsiamp -= hsibuf[kptr];
1141 hqamp -= hqbuf[jptr];
1144 hsqamp -= hsqbuf[kptr];
1148 rp = &up->mitig[up->achan].wwvh;
1149 rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC;
1150 if (!(up->status & MSYNC))
1151 wwv_qrz(peer, rp, (int)(pp->fudgetime2 * WWV_SEC));
1159 if (up->mphase == 0) {
1160 up->watch++;
1161 if (!(up->status & MSYNC)) {
1170 up->watch = 0;
1178 if (up->status & LEPSEC) {
1179 up->mphase -= WWV_SEC;
1180 if (up->mphase < 0)
1181 up->mphase += WWV_MIN;
1187 * When the channel metric reaches threshold and the second
1201 if (up->status & MSYNC) {
1203 } else if (up->sptr != NULL) {
1204 sp = up->sptr;
1205 if (sp->metric >= TTHR && epoch == sp->mepoch % WWV_SEC)
1207 up->rsec = (60 - sp->mepoch / WWV_SEC) % 60;
1208 up->rphase = 0;
1209 up->status |= MSYNC;
1210 up->watch = 0;
1211 if (!(up->status & SSYNC))
1212 up->repoch = up->yepoch = epoch;
1214 up->repoch = up->yepoch;
1220 * The second sync pulse is extracted using 5-ms (40 sample) FIR
1226 if (up->status & SELV)
1229 else if (up->status & SELH)
1236 * Enhance the seconds sync pulse using a 1-s (8000-sample) comb
1246 dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) /
1247 up->avgint);
1253 j = epoch - 6 * MS;
1259 up->epomax = epomax;
1260 up->eposnr = wwv_snr(epomax, nxtmax);
1261 epopos -= TCKCYC * MS;
1265 if (!(up->status & SSYNC))
1266 up->alarm |= SYNERR;
1268 if (!(up->status & MSYNC))
1275 * wwv_qrz - identify and acquire WWV/WWVH minute sync pulse
1281 * involves searching through the entire 480,000-sample minute. The
1287 * amounts to a range-gate discriminator. A valid pulse must have peak
1297 struct sync *sp, /* sync channel structure */
1306 pp = peer->procptr;
1307 up = pp->unitptr;
1314 epoch = up->mphase - pdelay - SYNSIZ;
1317 if (sp->amp > sp->maxeng) {
1318 sp->maxeng = sp->amp;
1319 sp->pos = epoch;
1321 sp->noieng += sp->amp;
1330 if (up->mphase == 0) {
1331 sp->synmax = sp->maxeng;
1332 sp->synsnr = wwv_snr(sp->synmax, (sp->noieng -
1333 sp->synmax) / WWV_MIN);
1334 if (sp->count == 0)
1335 sp->lastpos = sp->pos;
1336 epoch = (sp->pos - sp->lastpos) % WWV_MIN;
1337 sp->reach <<= 1;
1338 if (sp->reach & (1 << AMAX))
1339 sp->count--;
1340 if (sp->synmax > ATHR && sp->synsnr > ASNR) {
1342 sp->reach |= 1;
1343 sp->count++;
1344 sp->mepoch = sp->lastpos = sp->pos;
1345 } else if (sp->count == 1) {
1346 sp->lastpos = sp->pos;
1349 if (up->watch > ACQSN)
1350 sp->metric = 0;
1352 sp->metric = wwv_metric(sp);
1353 if (pp->sloppyclockflag & CLK_FLAG4) {
1356 up->status, up->gain, sp->refid,
1357 sp->reach & 0xffff, sp->metric, sp->synmax,
1358 sp->synsnr, sp->pos % WWV_SEC, epoch);
1359 record_clock_stats(&peer->srcadr, tbuf);
1365 sp->maxeng = sp->noieng = 0;
1371 * wwv_endpoc - identify and acquire second sync pulse
1375 * disciplines the sample clock using a frequency-lock loop (FLL).
1380 * great deal of heavy-handed heuristic data filtering and grooming.
1404 double dtemp;
1407 pp = peer->procptr;
1408 up = pp->unitptr;
1421 if (up->epomax < STHR || up->eposnr < SSNR) {
1422 up->status &= ~(SSYNC | FGATE);
1426 if (!(up->status & (SELV | SELH)))
1430 * A three-stage median filter is used to help denoise the
1465 tmp2 = (tepoch - xepoch) % WWV_SEC;
1468 if (syncnt > SCMP && up->status & MSYNC && (up->status &
1469 FGATE || scount - zcount <= up->avgint)) {
1470 up->status |= SSYNC;
1471 up->yepoch = tepoch;
1479 if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
1483 up->status, up->gain, tepoch, up->epomax,
1484 up->eposnr, tmp2, avgcnt, syncnt,
1486 record_clock_stats(&peer->srcadr, tbuf);
1493 if (avgcnt < up->avgint) {
1499 * The sample clock frequency is disciplined using a first-order
1506 * epoch difference (125-us units) and time difference (seconds)
1538 * to zero; if it decrements to -3, the interval is halved and
1541 dtemp = (mepoch - zepoch) % WWV_SEC;
1542 if (up->status & FGATE) {
1544 up->freq += (dtemp / 2.) / ((mcount - zcount) *
1546 if (up->freq > MAXFREQ)
1547 up->freq = MAXFREQ;
1548 else if (up->freq < -MAXFREQ)
1549 up->freq = -MAXFREQ;
1554 if (up->avgint < MAXAVG) {
1555 up->avgint <<= 1;
1561 if (avginc > -3) {
1562 avginc--;
1564 if (up->avgint > MINAVG) {
1565 up->avgint >>= 1;
1571 if (pp->sloppyclockflag & CLK_FLAG4) {
1574 up->status, up->epomax, up->eposnr, mepoch,
1575 up->avgint, maxrun, mcount - zcount, dtemp,
1576 up->freq * 1e6 / WWV_SEC);
1577 record_clock_stats(&peer->srcadr, tbuf);
1587 up->status |= FGATE;
1595 * wwv_epoch - epoch scanner
1597 * This routine extracts data signals from the 100-Hz subcarrier. It
1609 * disciplined using the hardlimited quadrature-phase signal sampled at
1610 * the same time as the in-phase signal. The phase tracking loop uses
1611 * phase adjustments of plus-minus one sample (125 us).
1621 static double sigmin, sigzer, sigone, engmax, engmin;
1623 pp = peer->procptr;
1624 up = pp->unitptr;
1628 * WWV and WWVH stations. This will be used later for channel
1633 cp = &up->mitig[up->achan];
1634 if (cp->wwv.amp > cp->wwv.syneng)
1635 cp->wwv.syneng = cp->wwv.amp;
1636 if (cp->wwvh.amp > cp->wwvh.syneng)
1637 cp->wwvh.syneng = cp->wwvh.amp;
1638 if (up->rphase == 800 * MS)
1639 up->repoch = up->yepoch;
1643 * This gives a guard time of +-15 ms from the beginning of the
1650 if (up->rphase == 15 * MS)
1651 sigmin = sigzer = sigone = up->irig;
1656 * compute the SNR. Use the Q sample to adjust the 100-Hz
1659 if (up->rphase == 200 * MS) {
1660 sigzer = up->irig;
1661 engmax = sqrt(up->irig * up->irig + up->qrig *
1662 up->qrig);
1663 up->datpha = up->qrig / up->avgint;
1664 if (up->datpha >= 0) {
1665 up->datapt++;
1666 if (up->datapt >= 80)
1667 up->datapt -= 80;
1669 up->datapt--;
1670 if (up->datapt < 0)
1671 up->datapt += 80;
1680 else if (up->rphase == 500 * MS)
1681 sigone = up->irig;
1693 * returning from the probe channel. This gives a guard time of
1697 up->rphase++;
1698 if (up->mphase % WWV_SEC == up->repoch) {
1699 up->status &= ~(DGATE | BGATE);
1700 engmin = sqrt(up->irig * up->irig + up->qrig *
1701 up->qrig);
1702 up->datsig = engmax;
1703 up->datsnr = wwv_snr(engmax, engmin);
1710 if (engmax < DTHR || up->datsnr < DSNR) {
1711 up->status |= DGATE;
1714 sigzer -= sigone;
1715 sigone -= sigmin;
1716 wwv_rsec(peer, sigone - sigzer);
1718 if (up->status & (DGATE | BGATE))
1719 up->errcnt++;
1720 if (up->errcnt > MAXERR)
1721 up->alarm |= LOWERR;
1723 cp = &up->mitig[up->achan];
1724 cp->wwv.syneng = 0;
1725 cp->wwvh.syneng = 0;
1726 up->rphase = 0;
1732 * wwv_rsec - process receiver second
1735 * implement the per-second state machine. The machine assembles BCD
1738 * Normally, the minute has 60 seconds numbered 0-59. If the leap
1748 double bit
1752 static double bcddld[4]; /* BCD data bits */
1753 static double bitvec[61]; /* bit integrator for misc bits */
1761 pp = peer->procptr;
1762 up = pp->unitptr;
1777 nsec = up->rsec;
1778 up->rsec++;
1779 bitvec[nsec] += (bit - bitvec[nsec]) / TCONST;
1792 case IDLE: /* 9, 45-49 */
1796 * Probe channel stuff
1801 * QSY to the probe channel, which rotates in turn over all
1804 * QSY back to the data channel. Note that the actions commented
1811 cp = &up->mitig[up->achan];
1812 cp->wwv.synmax = cp->wwv.syneng;
1813 cp->wwvh.synmax = cp->wwvh.syneng;
1823 * the channel metric computed by the wwv_metric() routine.
1824 * Finally, QSY back to the data channel.
1827 cp = &up->mitig[up->achan];
1832 sp = &cp->wwv;
1833 sp->synsnr = wwv_snr(sp->synmax, sp->amp);
1834 sp->reach <<= 1;
1835 if (sp->reach & (1 << AMAX))
1836 sp->count--;
1837 if (sp->synmax >= QTHR && sp->synsnr >= QSNR &&
1838 !(up->status & (DGATE | BGATE))) {
1839 sp->reach |= 1;
1840 sp->count++;
1842 sp->metric = wwv_metric(sp);
1847 rp = &cp->wwvh;
1848 rp->synsnr = wwv_snr(rp->synmax, rp->amp);
1849 rp->reach <<= 1;
1850 if (rp->reach & (1 << AMAX))
1851 rp->count--;
1852 if (rp->synmax >= QTHR && rp->synsnr >= QSNR &&
1853 !(up->status & (DGATE | BGATE))) {
1854 rp->reach |= 1;
1855 rp->count++;
1857 rp->metric = wwv_metric(rp);
1858 if (pp->sloppyclockflag & CLK_FLAG4) {
1861 up->status, up->gain, up->yepoch,
1862 up->epomax, up->eposnr, up->datsig,
1863 up->datsnr,
1864 sp->refid, sp->reach & 0xffff,
1865 sp->metric, sp->synmax, sp->synsnr,
1866 rp->refid, rp->reach & 0xffff,
1867 rp->metric, rp->synmax, rp->synsnr);
1868 record_clock_stats(&peer->srcadr, tbuf);
1874 up->errcnt = up->digcnt = up->alarm = 0;
1884 if (up->status & INSYNC) {
1885 if (up->watch > PANIC) {
1889 } else if (up->status & DSYNC) {
1890 if (up->watch > SYNCH) {
1894 } else if (up->watch > DATA) {
1906 case COEF1: /* 4-7 */
1910 case COEF: /* 10-13, 15-17, 20-23, 25-26,
1911 30-33, 35-38, 40-41, 51-54 */
1912 if (up->status & DSYNC)
1918 case COEF2: /* 18, 27-28, 42-43 */
1929 wwv_corr4(peer, &up->decvec[arg], bcddld, bcd2);
1933 wwv_corr4(peer, &up->decvec[arg], bcddld, bcd3);
1937 wwv_corr4(peer, &up->decvec[arg], bcddld, bcd6);
1941 wwv_corr4(peer, &up->decvec[arg], bcddld, bcd9);
1951 wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9);
1954 case MSCBIT: /* 2-3, 50, 56-57 */
1956 if (!(up->misc & arg))
1957 up->alarm |= CMPERR;
1958 up->misc |= arg;
1959 } else if (bitvec[nsec] < -BTHR) {
1960 if (up->misc & arg)
1961 up->alarm |= CMPERR;
1962 up->misc &= ~arg;
1964 up->status |= BGATE;
1969 * Save the data channel gain, then QSY to the probe channel and
1975 if (!(up->misc & arg))
1976 up->alarm |= CMPERR;
1977 up->misc |= arg;
1978 } else if (bitvec[nsec] < -BTHR) {
1979 if (up->misc & arg)
1980 up->alarm |= CMPERR;
1981 up->misc &= ~arg;
1983 up->status |= BGATE;
1985 up->status &= ~(SELV | SELH);
1987 if (up->fd_icom > 0) {
1988 up->schan = (up->schan + 1) % NCHAN;
1989 wwv_qsy(peer, up->schan);
1991 up->mitig[up->achan].gain = up->gain;
1994 up->mitig[up->achan].gain = up->gain;
2010 if (up->status & LEPSEC)
2016 up->status &= ~LEPSEC;
2018 up->rsec = 0;
2022 if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
2026 nsec, up->status, up->gain, up->yepoch, up->epomax,
2027 up->eposnr, up->datsig, up->datsnr, bit);
2028 record_clock_stats(&peer->srcadr, tbuf);
2034 pp->disp += AUDIO_PHI;
2057 pp = peer->procptr;
2058 up = pp->unitptr;
2059 if (!(up->status & SSYNC))
2060 up->alarm |= SYNERR;
2061 if (up->digcnt < 9)
2062 up->alarm |= NINERR;
2063 if (!(up->alarm))
2064 up->status |= INSYNC;
2065 if (up->status & INSYNC && up->status & SSYNC) {
2066 if (up->misc & SECWAR)
2067 pp->leap = LEAP_ADDSECOND;
2069 pp->leap = LEAP_NOWARNING;
2070 pp->second = up->rsec;
2071 pp->minute = up->decvec[MN].digit + up->decvec[MN +
2073 pp->hour = up->decvec[HR].digit + up->decvec[HR +
2075 pp->day = up->decvec[DA].digit + up->decvec[DA +
2076 1].digit * 10 + up->decvec[DA + 2].digit * 100;
2077 pp->year = up->decvec[YR].digit + up->decvec[YR +
2079 pp->year += 2000;
2081 if (!clocktime(pp->day, pp->hour, pp->minute,
2082 pp->second, GMT, up->timestamp.l_ui,
2083 &pp->yearstart, &offset.l_ui)) {
2084 up->errflg = CEVNT_BADTIME;
2086 up->watch = 0;
2087 pp->disp = 0;
2088 pp->lastref = up->timestamp;
2090 up->timestamp, PDELAY + up->pdelay);
2094 pp->lencode = timecode(up, pp->a_lastcode,
2095 sizeof(pp->a_lastcode));
2096 record_clock_stats(&peer->srcadr, pp->a_lastcode);
2099 printf("wwv: timecode %d %s\n", pp->lencode,
2100 pp->a_lastcode);
2106 * wwv_corr4 - determine maximum-likelihood digit
2111 * maximum-likelihood digit, while the ratio of this value to the next
2119 double data[], /* received data vector */
2120 double tab[][4] /* correlation vector array */
2125 double topmax, nxtmax; /* metrics */
2126 double acc; /* accumulator */
2131 pp = peer->procptr;
2132 up = pp->unitptr;
2142 topmax = nxtmax = -MAXAMP;
2147 acc = (vp->like[i] += (acc - vp->like[i]) / TCONST);
2156 vp->digprb = topmax;
2157 vp->digsnr = wwv_snr(topmax, nxtmax);
2160 * The current maximum-likelihood digit is compared to the last
2161 * maximum-likelihood digit. If different, the compare counter
2162 * and maximum-likelihood digit are reset. When the compare
2173 if (vp->digprb < BTHR || vp->digsnr < BSNR) {
2174 up->status |= BGATE;
2176 if (vp->digit != mldigit) {
2177 up->alarm |= CMPERR;
2178 if (vp->count > 0)
2179 vp->count--;
2180 if (vp->count == 0)
2181 vp->digit = mldigit;
2183 if (vp->count < BCMP)
2184 vp->count++;
2185 if (vp->count == BCMP) {
2186 up->status |= DSYNC;
2187 up->digcnt++;
2191 if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
2195 up->rsec - 1, up->status, up->gain, up->yepoch,
2196 up->epomax, vp->radix, vp->digit, mldigit,
2197 vp->count, vp->digprb, vp->digsnr);
2198 record_clock_stats(&peer->srcadr, tbuf);
2208 * wwv_tsec - transmitter minute processing
2224 pp = peer->procptr;
2225 up = pp->unitptr;
2231 temp = carry(&up->decvec[MN]); /* minute units */
2232 if (!(up->status & DSYNC))
2239 temp = carry(&up->decvec[MN + 1]);
2241 temp = carry(&up->decvec[HR]);
2243 temp = carry(&up->decvec[HR + 1]);
2252 minute = up->decvec[MN].digit + up->decvec[MN + 1].digit *
2253 10 + up->decvec[HR].digit * 60 + up->decvec[HR +
2255 day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
2256 up->decvec[DA + 2].digit * 100;
2261 isleap = up->decvec[YR].digit & 0x3;
2262 if (up->misc & SECWAR && up->status & INSYNC) {
2265 up->status |= LEPSEC;
2276 while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */
2277 while (carry(&up->decvec[HR + 1]) != 0);
2279 temp = carry(&up->decvec[DA]); /* carry days */
2281 temp = carry(&up->decvec[DA + 1]);
2283 temp = carry(&up->decvec[DA + 2]);
2294 while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */
2295 while (carry(&up->decvec[DA + 1]) != 0);
2296 while (carry(&up->decvec[DA + 2]) != 0);
2297 temp = carry(&up->decvec[YR]); /* carry years */
2299 carry(&up->decvec[YR + 1]);
2304 * carry - process digit
2309 * match the maximum-likelihood digit corresponding to that position.
2319 dp->digit++;
2320 if (dp->digit == dp->radix)
2321 dp->digit = 0;
2322 temp = dp->like[dp->radix - 1];
2323 for (j = dp->radix - 1; j > 0; j--)
2324 dp->like[j] = dp->like[j - 1];
2325 dp->like[0] = temp;
2326 return (dp->digit);
2331 * wwv_snr - compute SNR or likelihood function
2333 static double
2335 double signal, /* signal */
2336 double noise /* noise */
2339 double rval;
2366 * wwv_newchan - change to new data channel
2368 * The radio actually appears to have ten channels, one channel for each
2370 * if not tunable only the DCHAN channel appears live. While the radio
2371 * is tuned to the working data channel frequency and station for most
2382 * This routine selects the best channel using a metric computed from
2384 * award goes to the the channel with the highest metric; but, in case
2385 * of ties, the award goes to the channel with the highest minute sync
2402 double rank, dtemp;
2405 pp = peer->procptr;
2406 up = pp->unitptr;
2409 * Search all five station pairs looking for the channel with
2416 rp = &up->mitig[i].wwvh;
2417 dtemp = rp->metric;
2423 rp = &up->mitig[i].wwv;
2424 dtemp = rp->metric;
2440 up->status &= ~(SELV | SELH);
2442 up->dchan = (up->dchan + 1) % NCHAN;
2443 if (up->status & METRIC) {
2444 up->status &= ~METRIC;
2449 up->dchan = j;
2450 up->sptr = sp;
2451 memcpy(&pp->refid, sp->refid, 4);
2452 peer->refid = pp->refid;
2453 up->status |= METRIC;
2454 if (sp->select & SELV) {
2455 up->status |= SELV;
2456 up->pdelay = pp->fudgetime1;
2457 } else if (sp->select & SELH) {
2458 up->status |= SELH;
2459 up->pdelay = pp->fudgetime2;
2461 up->pdelay = 0;
2466 if (up->fd_icom > 0)
2467 wwv_qsy(peer, up->dchan);
2474 * wwv_newgame - reset and start over
2497 pp = peer->procptr;
2498 up = pp->unitptr;
2504 if (up->status)
2505 up->errflg = CEVNT_TIMEOUT;
2506 peer->leap = LEAP_NOTINSYNC;
2507 up->watch = up->status = up->alarm = 0;
2508 up->avgint = MINAVG;
2509 up->freq = 0;
2510 up->gain = MAXGAIN / 2;
2515 * probing at the strongest channel or the default channel if
2518 memset(up->mitig, 0, sizeof(up->mitig));
2520 cp = &up->mitig[i];
2521 cp->gain = up->gain;
2522 cp->wwv.select = SELV;
2523 snprintf(cp->wwv.refid, sizeof(cp->wwv.refid), "WV%.0f",
2525 cp->wwvh.select = SELH;
2526 snprintf(cp->wwvh.refid, sizeof(cp->wwvh.refid), "WH%.0f",
2529 up->dchan = (DCHAN + NCHAN - 1) % NCHAN;
2531 up->schan = up->dchan;
2535 * wwv_metric - compute station metric
2539 * the minute sync pulse amplitude. The combined value is scaled 0-100.
2541 double
2546 double dtemp;
2548 dtemp = sp->count * MAXAMP;
2549 if (sp->synmax < MAXAMP)
2550 dtemp += sp->synmax;
2552 dtemp += MAXAMP - 1;
2560 * wwv_qsy - Tune ICOM receiver
2562 * This routine saves the AGC for the current channel, switches to a new
2563 * channel and restores the AGC for that channel. If a tunable receiver
2569 int chan /* channel */
2576 pp = peer->procptr;
2577 up = pp->unitptr;
2578 if (up->fd_icom > 0) {
2579 up->mitig[up->achan].gain = up->gain;
2580 rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
2582 up->achan = chan;
2583 up->gain = up->mitig[up->achan].gain;
2591 * timecode - assemble timecode string and length
2593 * Prettytime format - similar to Spectracom
2598 * q error bits (hex 0-F)
2608 * agc audio gain (0-255)
2610 * sig signal quality (0-100)
2629 * Common fixed-format fields
2631 synchar = (up->status & INSYNC) ? ' ' : '?';
2632 year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 +
2634 day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
2635 up->decvec[DA + 2].digit * 100;
2636 hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10;
2637 minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10;
2639 leapchar = (up->misc & SECWAR) ? 'L' : ' ';
2640 dst = dstcod[(up->misc >> 4) & 0x3];
2641 dut = up->misc & 0x7;
2642 if (!(up->misc & DUTS))
2643 dut = -dut;
2644 snprintf(tc, tcsiz, "%c%1X", synchar, up->alarm);
2651 * Specific variable-format fields
2653 sp = up->sptr;
2655 up->watch, up->mitig[up->dchan].gain, sp->refid,
2656 sp->metric, up->errcnt, up->freq / WWV_SEC * 1e6,
2657 up->avgint);
2665 * wwv_gain - adjust codec gain
2683 pp = peer->procptr;
2684 up = pp->unitptr;
2691 if (up->clipcnt == 0) {
2692 up->gain += 4;
2693 if (up->gain > MAXGAIN)
2694 up->gain = MAXGAIN;
2695 } else if (up->clipcnt > MAXCLP) {
2696 up->gain -= 4;
2697 if (up->gain < 0)
2698 up->gain = 0;
2700 audio_gain(up->gain, up->mongain, up->port);
2701 up->clipcnt = 0;