kopia lustrzana https://github.com/jamescoxon/dl-fldigi
222 wiersze
4.8 KiB
C++
222 wiersze
4.8 KiB
C++
// ----------------------------------------------------------------------------
|
|
// wwv.cxx -- wwv monitoring modem
|
|
//
|
|
// Copyright (C) 2006-2009
|
|
// Dave Freese, W1HKJ
|
|
//
|
|
// This file is part of fldigi.
|
|
//
|
|
// Fldigi is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Fldigi is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// This modem is only used for reception of WWV "tick" signals to determine
|
|
// the correction factor to be applied to the sound card oscillator.
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
#include "wwv.h"
|
|
#include "fl_digi.h"
|
|
|
|
using namespace std;
|
|
|
|
void wwv::tx_init(SoundBase *sc)
|
|
{
|
|
scard = sc;
|
|
phaseacc = 0;
|
|
}
|
|
|
|
void wwv::rx_init()
|
|
{
|
|
phaseacc = 0.0;
|
|
smpl_ctr = 0; // sample counter for timing wwv rx
|
|
agc = 0.0; // threshold for tick detection
|
|
ticks = 0;
|
|
calc = false;
|
|
zoom = false;
|
|
set_scope_mode(Digiscope::WWV);
|
|
put_MODEstatus(mode);
|
|
}
|
|
|
|
void wwv::init()
|
|
{
|
|
modem::init();
|
|
rx_init();
|
|
}
|
|
|
|
wwv::~wwv() {
|
|
if (hilbert) delete hilbert;
|
|
if (lpfilter) delete lpfilter;
|
|
if (vidfilter) delete vidfilter;
|
|
}
|
|
|
|
|
|
wwv::wwv() : modem()
|
|
{
|
|
double lp;
|
|
mode = MODE_WWV;
|
|
frequency = 1000;
|
|
bandwidth = 200;
|
|
samplerate = 8000;
|
|
|
|
// phase increment expected at the tick freq
|
|
phaseincr = 2.0 * M_PI * frequency / samplerate;
|
|
|
|
hilbert = new C_FIR_filter();
|
|
hilbert->init_hilbert(37, 1);
|
|
|
|
lp = 0.5 * bandwidth / samplerate;
|
|
lpfilter = new C_FIR_filter();
|
|
lpfilter->init_lowpass (FIRLEN_1, DEC_1, lp);
|
|
|
|
vidfilter = new Cmovavg(16);
|
|
|
|
makeaudio();
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//update_syncscope()
|
|
//Routine called to update the display on the sync scope display.
|
|
//For wwv this is video signal much like a FAX display
|
|
//=======================================================================
|
|
//
|
|
void wwv::update_syncscope()
|
|
{
|
|
double max = 0, min = 1e6, range;
|
|
for (int i = 0; i < 1000; i++ ) {
|
|
if (max < buffer[i]) max = buffer[i];
|
|
if (min > buffer[i]) min = buffer[i];
|
|
}
|
|
range = max - min;
|
|
for (int i = 0; i < 1000; i++ ) {
|
|
buffer[i] = 255*(buffer[i] - min) / range;
|
|
}
|
|
if (zoom)
|
|
set_video(&buffer[400], 200);
|
|
else
|
|
set_video(buffer, 1000);
|
|
buffer.next(); // change buffers
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
// wwv_rxprocess()
|
|
// Called with a block (512 samples) of audio.
|
|
// Nominal sound card sampling rate is set to 8000 Hz
|
|
//=======================================================================
|
|
|
|
int wwv::rx_process(const double *buf, int len)
|
|
{
|
|
cmplx z, znco;
|
|
|
|
while (len-- > 0) {
|
|
z = cmplx ( *buf, *buf );
|
|
buf++;
|
|
|
|
hilbert->run(z, z);
|
|
|
|
znco = cmplx ( cos(phaseacc), sin(phaseacc) );
|
|
z = znco * z;
|
|
|
|
phaseacc += phaseincr;
|
|
if (phaseacc > TWOPI) phaseacc -= TWOPI;
|
|
|
|
if (lpfilter->run ( z, z )) {
|
|
buffer[smpl_ctr % 1000] = vidfilter->run( abs(z) );
|
|
if (++smpl_ctr >= 1000) {
|
|
update_syncscope();
|
|
smpl_ctr = 0;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void wwv::set1(int x, int y)
|
|
{
|
|
int zfactor = 500;
|
|
if (zoom) zfactor = 100;
|
|
smpl_ctr -= ((2*x - y) * zfactor) / y;
|
|
if (smpl_ctr < 0) smpl_ctr += 1000;
|
|
if (smpl_ctr > 1000) smpl_ctr -= 1000;
|
|
}
|
|
|
|
char strPPM[20];
|
|
|
|
void wwv::set2(int x, int y)
|
|
{
|
|
zoom = !zoom;
|
|
}
|
|
|
|
//======================================================================
|
|
// transmit time tick
|
|
//======================================================================
|
|
|
|
void wwv::makeshape()
|
|
{
|
|
for (int i = 0; i < 32; i++)
|
|
keyshape[i] = 0.5 * (1.0 - cos (M_PI * i / 32));
|
|
}
|
|
|
|
double wwv::nco(double freq)
|
|
{
|
|
phaseacc += 2.0 * M_PI * freq / samplerate;
|
|
|
|
if (phaseacc > M_PI)
|
|
phaseacc -= 2.0 * M_PI;
|
|
|
|
return sin(phaseacc);
|
|
}
|
|
|
|
void wwv::makeaudio()
|
|
{
|
|
phaseacc = 0.0;
|
|
makeshape();
|
|
for (int i = 0; i < 400; i++) {
|
|
audio[i] = (i < 200 ? nco(1000) : 0);
|
|
quiet[i] = 0;
|
|
}
|
|
for (int i = 0; i < 32; i++) {
|
|
audio[i] *= keyshape[i];
|
|
audio[199 - i] *= keyshape[i];
|
|
}
|
|
}
|
|
|
|
int wwv::tx_process()
|
|
{
|
|
static int cycle = 4;
|
|
int c = get_tx_char();
|
|
|
|
if (c == GET_TX_CHAR_ETX || stopflag) {
|
|
stopflag = false;
|
|
return -1;
|
|
}
|
|
if (--cycle == 0) {
|
|
memcpy(play, audio, 400 * sizeof(double));
|
|
ModulateXmtr(play, 400);
|
|
cycle = 4;
|
|
} else
|
|
ModulateXmtr(quiet, 400);
|
|
ModulateXmtr(quiet, 400);
|
|
ModulateXmtr(quiet, 400);
|
|
ModulateXmtr(quiet, 400);
|
|
ModulateXmtr(quiet, 400);
|
|
return 0;
|
|
}
|