kopia lustrzana https://github.com/jamescoxon/dl-fldigi
280 wiersze
6.1 KiB
C++
280 wiersze
6.1 KiB
C++
// ----------------------------------------------------------------------------
|
|
// fftscan.cxx -- fftscan 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/>.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include <config.h>
|
|
|
|
#include <string>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
|
|
#include "fftscan.h"
|
|
#include "modem.h"
|
|
#include "misc.h"
|
|
#include "filters.h"
|
|
#include "fftfilt.h"
|
|
#include "digiscope.h"
|
|
#include "waterfall.h"
|
|
#include "main.h"
|
|
#include "fl_digi.h"
|
|
|
|
#include "timeops.h"
|
|
#include "debug.h"
|
|
#include "configuration.h"
|
|
|
|
using namespace std;
|
|
|
|
static char msg[30];
|
|
|
|
void fftscan::tx_init(SoundBase *sc)
|
|
{
|
|
}
|
|
|
|
void fftscan::rx_init()
|
|
{
|
|
put_MODEstatus(mode);
|
|
}
|
|
|
|
void fftscan::init()
|
|
{
|
|
modem::init();
|
|
rx_init();
|
|
set_scope_mode(Digiscope::SCOPE);
|
|
}
|
|
|
|
fftscan::~fftscan()
|
|
{
|
|
delete [] fftbuff;
|
|
delete [] dftbuff;
|
|
delete [] buffer;
|
|
delete scanfft;
|
|
}
|
|
|
|
void fftscan::restart()
|
|
{
|
|
wf_freq = frequency;
|
|
|
|
memset(dftbuff, 0, fftscanFFT_LEN * sizeof(*dftbuff));
|
|
memset(fftbuff, 0, fftscanFFT_LEN * sizeof(*fftbuff));
|
|
|
|
set_bandwidth(fftscan_BW);
|
|
|
|
scans = 0;
|
|
ticks = 0;
|
|
|
|
if (write_to_csv) stop_csv();
|
|
|
|
start_csv();
|
|
}
|
|
|
|
fftscan::fftscan()
|
|
{
|
|
mode = MODE_FFTSCAN;
|
|
|
|
samplerate = fftscan_SampleRate;
|
|
|
|
fftbuff = new double[fftscanFFT_LEN];
|
|
dftbuff = new std::complex<double>[fftscanFFT_LEN];
|
|
buffer = new double[fftscanFFT_LEN / 2];
|
|
|
|
scanfft = new g_fft<double>(fftscanFFT_LEN);
|
|
|
|
fftscanFilename = TempDir;
|
|
fftscanFilename.append("fftscan.csv");
|
|
|
|
_refresh = false;
|
|
|
|
cap &= ~CAP_TX;
|
|
restart();
|
|
}
|
|
|
|
std::complex<double> fftscan::dft (std::complex<double> *buff, double fm, double Ts, double offset)
|
|
{
|
|
std::complex<double> val;
|
|
val = std::complex<double>(0,0);
|
|
|
|
double factor = 2.0 / fftscanFFT_LEN;
|
|
double omega = fm * Ts + offset / (2.0 * fftscanFFT_LEN);
|
|
|
|
for( int i = 0; i < fftscanFFT_LEN; i++)
|
|
val += buff[i] * std::complex<double>(
|
|
cos(2 * M_PI * i * omega),
|
|
sin(2 * M_PI * i * omega) );
|
|
val *= factor;
|
|
return val;
|
|
}
|
|
|
|
void fftscan::start_csv()
|
|
{
|
|
FILE *out = fopen(fftscanFilename.c_str(), "w");
|
|
if (unlikely(!out)) {
|
|
LOG_PERROR("fopen");
|
|
return;
|
|
}
|
|
fprintf(out, "Freq, |Amp|\n");
|
|
fclose(out);
|
|
|
|
write_to_csv = true;
|
|
ticks = 0;
|
|
scans = 0;
|
|
}
|
|
|
|
void fftscan::stop_csv()
|
|
{
|
|
write_to_csv = false;
|
|
put_status("");
|
|
}
|
|
|
|
void fftscan::writeFile()
|
|
{
|
|
if (!write_to_csv) return;
|
|
|
|
// calculate elapsed time using the number of sample blocks
|
|
int nyquist = fftscanFFT_LEN / 2;
|
|
|
|
FILE *out = fopen(fftscanFilename.c_str(), "w");//"a");
|
|
if (unlikely(!out)) {
|
|
LOG_PERROR("fopen");
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < nyquist; i++) {
|
|
buffer[i] = 20 * log10f(fftbuff[i]/nyquist);
|
|
}
|
|
|
|
if (progdefaults.dft_relative) {
|
|
double maxdb = -120;
|
|
for (int i = 0; i < nyquist; i++)
|
|
if (buffer[i] > maxdb) maxdb = buffer[i];
|
|
for (int i = 0; i < nyquist; i++)
|
|
buffer[i] -= maxdb;
|
|
}
|
|
|
|
fprintf(out, "Freq,Signal,dB\n");
|
|
for (int i = 0; i < fftscanFFT_LEN / 2; i++) {
|
|
fprintf(out, "%0.1f, %f, %f\n",
|
|
1.0 * i * fftscan_SampleRate/fftscanFFT_LEN,
|
|
(fftbuff[i]/nyquist),
|
|
buffer[i]);//20 * log10f(fftbuff[i]/nyquist));
|
|
}
|
|
fclose(out);
|
|
}
|
|
|
|
//=======================================================================
|
|
//update_syncscope()
|
|
//=======================================================================
|
|
//
|
|
|
|
void fftscan::update_syncscope()
|
|
{
|
|
int nyquist = fftscanFFT_LEN/2;
|
|
|
|
for (int i = 0; i < nyquist; i++) {
|
|
buffer[i] = 20 * log10f(fftbuff[i]/nyquist);
|
|
}
|
|
|
|
if (progdefaults.dft_relative) {
|
|
double maxdb = -120;
|
|
for (int i = 0; i < nyquist; i++)
|
|
if (buffer[i] > maxdb) maxdb = buffer[i];
|
|
for (int i = 0; i < nyquist; i++)
|
|
buffer[i] -= maxdb;
|
|
}
|
|
|
|
for (int i = 0; i < nyquist; i++)
|
|
buffer[i] = 1.0 + buffer[i] / progdefaults.cnt_dft_range;
|
|
|
|
double scopebuff[nyquist];
|
|
for (int i = 1; i < nyquist - 1; i++)
|
|
scopebuff[i] = max(max(buffer[i-1], buffer[i]), buffer[i+1]);
|
|
// clear scope views
|
|
if (digiscope) digiscope->clear_axis();
|
|
wf->wfscope->clear_axis();
|
|
|
|
// vertical graticule, every 10 dB
|
|
int N = progdefaults.cnt_dft_range / 10;
|
|
for (int i = 1; i < N; i++) {
|
|
if (digiscope) digiscope->xaxis(i, 1.0 * i / N);
|
|
wf->wfscope->xaxis(i, 1.0 * i / N);
|
|
}
|
|
// horizontal graticule, every 500 Hz
|
|
for (int i = 1; i < 8; i++) {
|
|
if (digiscope) digiscope->yaxis(i, i / 8.0);
|
|
wf->wfscope->yaxis(i, i / 8.0);
|
|
}
|
|
set_scope(scopebuff, nyquist, false);
|
|
}
|
|
|
|
std::complex<double> tempbuff[fftscanFFT_LEN];
|
|
|
|
int fftscan::rx_process(const double *buf, int len)
|
|
{
|
|
if (len > fftscanFFT_LEN) return 0; // if audio playback
|
|
|
|
if (wf_freq != frequency)
|
|
restart();
|
|
|
|
scans++;
|
|
|
|
if (scans > progdefaults.cnt_dft_scans) {
|
|
if (_refresh) {
|
|
_refresh = false;
|
|
update_syncscope();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0; i < fftscanFFT_LEN - len; i++)
|
|
dftbuff[i] = dftbuff[i + len];
|
|
for (int i = 0; i < len; i++) {
|
|
dftbuff[fftscanFFT_LEN - len + i] = std::complex<double>(buf[i], 0);
|
|
}
|
|
|
|
for (int i = 0; i < fftscanFFT_LEN; i++)
|
|
tempbuff[i] = dftbuff[i];
|
|
|
|
scanfft->ComplexFFT(tempbuff);
|
|
for (int i = 0; i < fftscanFFT_LEN/2; i++)
|
|
fftbuff[i] = (fftbuff[i] * (scans - 1) + abs(tempbuff[i])) / scans;
|
|
|
|
update_syncscope();
|
|
|
|
if (scans == progdefaults.cnt_dft_scans) {
|
|
put_Status2("scan completed", 30.0);
|
|
writeFile();
|
|
return 0;
|
|
}
|
|
snprintf(msg, sizeof(msg), "scanning %d", (int)(progdefaults.cnt_dft_scans - scans + 1));
|
|
put_Status2(msg, 5.0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//=====================================================================
|
|
// fftscan transmit
|
|
//=====================================================================
|
|
|
|
int fftscan::tx_process()
|
|
{
|
|
return -1;
|
|
}
|
|
|