Hannes Matuschek 11 years ago
commit 0bbcd96d31

@ -11,27 +11,16 @@ SET(libsdr_VERSION_MAJOR "0")
SET(libsdr_VERSION_MINOR "1")
SET(libsdr_VERSION_PATCH "0")
find_package(Qt5Core)
find_package(Qt5Widgets)
find_package(FFTW)
find_package(FFTWSingle)
find_package(PortAudio)
find_package(RTLSDR)
ADD_DEFINITIONS(${Qt5Widgets_DEFINITIONS})
INCLUDE_DIRECTORIES(${Qt5Core_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}/src)
INCLUDE_DIRECTORIES(${PORTAUDIO_INCLUDE_DIRS})
# Set some variables for the configuration file
IF(Qt5Core_FOUND AND Qt5Widgets_FOUND)
set(SDR_WITH_QT5 ON)
ENDIF(Qt5Core_FOUND AND Qt5Widgets_FOUND)
IF(FFTW_FOUND)
set(SDR_WITH_FFTW ON)
ELSE(FFTW_FOUND)
@ -55,7 +44,7 @@ ENDIF(RTLSDR_FOUND)
set(LIBS ${FFTW_LIBRARIES} ${FFTWSingle_LIBRARIES} ${PORTAUDIO_LIBRARIES} ${RTLSDR_LIBRARIES} "pthread")
# Set compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS} -Wall -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fPIC")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -ggdb")

@ -1,4 +1,4 @@
# Doxyfile 1.8.5
# Doxyfile 1.8.7
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -70,15 +70,25 @@ OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-
# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi,
# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en,
# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish,
# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
# Turkish, Ukrainian and Vietnamese.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@ -259,9 +269,12 @@ OPTIMIZE_OUTPUT_VHDL = NO
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C.
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
#
# Note For files without extension you can use no_extension as a placeholder.
#
@ -500,6 +513,13 @@ HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
SHOW_GROUPED_MEMB_INC = NO
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
# The default value is: NO.
@ -521,7 +541,8 @@ SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO the members will appear in declaration order.
# name. If set to NO the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
SORT_BRIEF_DOCS = NO
@ -1220,7 +1241,8 @@ GENERATE_CHI = NO
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file.
# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@ -1460,11 +1482,11 @@ SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# are two flavours of web server based searching depending on the
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# searching and an index file used by the script. When EXTERNAL_SEARCH is
# enabled the indexing and searching needs to be provided by external tools. See
# the section "External Indexing and Searching" for details.
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# and searching needs to be provided by external tools. See the section
# "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
@ -1752,6 +1774,13 @@ MAN_OUTPUT = man
MAN_EXTENSION = .3
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_SUBDIR =
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without
@ -1779,18 +1808,6 @@ GENERATE_XML = NO
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_SCHEMA =
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
@ -1937,9 +1954,9 @@ PREDEFINED =
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all refrences to function-like macros that are alone on a line, have an
# all uppercase name, and do not end with a semicolon. Such function macros are
# typically used for boiler-plate code, and will confuse the parser if not
# remove all references to function-like macros that are alone on a line, have
# an all uppercase name, and do not end with a semicolon. Such function macros
# are typically used for boiler-plate code, and will confuse the parser if not
# removed.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@ -1959,7 +1976,7 @@ SKIP_FUNCTION_MACROS = YES
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use
# of tag files.
# Note: Each tag file must have an unique name (where the name does NOT include
# Note: Each tag file must have a unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
@ -2019,6 +2036,13 @@ CLASS_DIAGRAMS = YES
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES, the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@ -2219,6 +2243,12 @@ DOTFILE_DIRS =
MSCFILE_DIRS =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
# command).
DIAFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized

@ -1,8 +1,3 @@
IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
add_executable(sdr_spec sdr_spec.cc)
target_link_libraries(sdr_spec ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui )
ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
IF(SDR_WITH_PORTAUDIO)
add_executable(sdr_wavplay sdr_wavplay.cc)
target_link_libraries(sdr_wavplay ${LIBS} libsdr)
@ -21,12 +16,4 @@ IF(SDR_WITH_PORTAUDIO)
target_link_libraries(sdr_schumann ${LIBS} libsdr libsdr-gui)
ENDIF(SDR_WITH_PORTAUDIO)
IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
add_executable(sdr_rds sdr_rds.cc)
target_link_libraries(sdr_rds ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui)
ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
add_executable(sdr_psk31 sdr_psk31.cc)
target_link_libraries(sdr_psk31 ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui)

@ -41,22 +41,3 @@ INSTALL_HEADERS_WITH_DIRECTORY("${LIBSDR_HEADERS}" "${CMAKE_INSTALL_INCLUDEDIR}/
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/config.hh"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libsdr")
if(SDR_WITH_FFTW AND SDR_WITH_QT5)
set(libsdr_gui_SOURCES gui/spectrum.cc gui/spectrumview.cc gui/waterfallview.cc)
set(libsdr_gui_MOC_HEADERS gui/spectrum.hh gui/spectrumview.hh gui/waterfallview.hh)
set(libsdr_gui_HEADERS ${libsdr_gui_MOC_HEADERS} gui/gui.hh)
qt5_wrap_cpp(libsdr_gui_MOC_SOURCES ${libsdr_gui_MOC_HEADERS})
add_library(libsdr-gui SHARED ${libsdr_gui_SOURCES} ${libsdr_gui_MOC_SOURCES})
set_target_properties(libsdr-gui PROPERTIES OUTPUT_NAME sdr-gui)
set_target_properties(libsdr-gui PROPERTIES VERSION
"${libsdr_VERSION_MAJOR}.${libsdr_VERSION_MINOR}.${libsdr_VERSION_PATCH}")
set_target_properties(libsdr-gui PROPERTIES SOVERION "${libsdr_VERSION_MAJOR}")
set_target_properties(libsdr-gui PROPERTIES INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR})
set_target_properties(libsdr-gui PROPERTIES MACOSX_RPATH "${CMAKE_INSTALL_RPATH}")
target_link_libraries(libsdr-gui libsdr ${Qt5Core_LIBRARIES} ${Qt5Widgets_LIBRARIES})
install(TARGETS libsdr-gui DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL_HEADERS_WITH_DIRECTORY("${libsdr_gui_HEADERS}" "${CMAKE_INSTALL_INCLUDEDIR}/libsdr")
endif(SDR_WITH_FFTW AND SDR_WITH_QT5)

@ -84,9 +84,9 @@ public:
_Fc = Fc; this->setFrequencyShift(_Fc);
}
/** Returns the center frequency. */
/** Returns the filter frequency. */
inline double filterFrequency() const { return _Ff; }
/** (Re-) Sets the center frequency. */
/** (Re-) Sets the filter frequency. */
void setFilterFrequency(double Ff) {
_Ff = Ff; _update_filter_kernel();
}

@ -1,6 +1,5 @@
#cmakedefine SDR_DEBUG 1
#cmakedefine SDR_WITH_QT5 1
#cmakedefine SDR_WITH_FFTW 1
#cmakedefine SDR_WITH_PORTAUDIO 1
#cmakedefine SDR_WITH_RTLSDR 1

@ -1,7 +0,0 @@
#ifndef __SDR_GUI_GUI_HH__
#define __SDR_GUI_GUI_HH__
#include "spectrumview.hh"
#include "waterfallview.hh"
#endif

@ -1,271 +0,0 @@
#include "spectrum.hh"
#include "config.hh"
using namespace sdr;
using namespace sdr::gui;
/* ********************************************************************************************* *
* SpectrumProvider
* ********************************************************************************************* */
SpectrumProvider::SpectrumProvider(QObject *parent)
: QObject(parent)
{
// pass...
}
SpectrumProvider::~SpectrumProvider() {
// pass...
}
/* ********************************************************************************************* *
* Spectrum
* ********************************************************************************************* */
Spectrum::Spectrum(double rrate, size_t fftsize, size_t max_avg, QObject *parent) :
SpectrumProvider(parent), _rrate(rrate), _fft_size(fftsize), _fft_buffer(fftsize),
_compute(fftsize), _spectrum(fftsize), _sample_count(0), _N_samples(0),
_trafo_count(0), _Ntrafo(max_avg),
_samples_left(0), _input_type(Config::Type_UNDEFINED), _sample_rate(0)
{
// Construct FFT plan
_plan = fftw_plan_dft_1d(
fftsize, (fftw_complex *)_fft_buffer.ptr(), (fftw_complex *)_fft_buffer.ptr(),
FFTW_FORWARD, FFTW_ESTIMATE);
// Set spectrum to 0:
for (size_t i=0; i<_fft_size; i++) { _spectrum[i] = 0; _compute[i] = 0; }
}
Spectrum::~Spectrum() {
fftw_destroy_plan(_plan);
}
void
Spectrum::config(const Config &src_cfg) {
// Requires at least sample rate and type
if (!src_cfg.hasType() || !src_cfg.hasSampleRate()) { return; }
// Store sample rate
_sample_rate = src_cfg.sampleRate();
_samples_left = 0;
_trafo_count = 0; _sample_count=0;
_input_type = src_cfg.type();
// Compute number of averages to compute to meet rrate approximately
_N_samples = _sample_rate/(_Ntrafo*_rrate);
LogMessage msg(LOG_DEBUG);
msg << "Configured SpectrumView: " << std::endl
<< " Data type: " << _input_type << std::endl
<< " sample-rate: " << _sample_rate << std::endl
<< " FFT size: " << _fft_size << std::endl
<< " # sample drops: " << _N_samples-1 << std::endl
<< " # averages: " << _Ntrafo << std::endl
<< " refresh rate: " << _sample_rate/(_N_samples*_Ntrafo) << "Hz";
Logger::get().log(msg);
// Signal spectrum reconfiguration
emit spectrumConfigured();
}
bool
Spectrum::isInputReal() const {
switch (_input_type) {
case Config::Type_u8:
case Config::Type_s8:
case Config::Type_u16:
case Config::Type_s16:
case Config::Type_f32:
case Config::Type_f64:
return true;
default:
break;
}
return false;
}
double
Spectrum::sampleRate() const {
return _sample_rate;
}
size_t
Spectrum::fftSize() const {
return _fft_size;
}
const Buffer<double> &
Spectrum::spectrum() const {
return _spectrum;
}
void
Spectrum::handleBuffer(const RawBuffer &buffer, bool allow_overwrite)
{
double scale=1, offset=0;
switch (_input_type) {
case Config::Type_u8: scale = 1<<8; offset=-128; break;
case Config::Type_cu8: scale = 1<<8; offset=-128; break;
case Config::Type_s8: scale = 1<<8; offset=0; break;
case Config::Type_cs8: scale = 1<<8; offset=0; break;
case Config::Type_u16: scale = 1<<16; offset=-32768; break;
case Config::Type_cu16: scale = 1<<16; offset=-32768; break;
case Config::Type_s16: scale = 1<<16; offset=0; break;
case Config::Type_cs16: scale = 1<<16; offset=0; break;
default: break;
}
// Dispatch by input type:
if (Config::Type_u8 == _input_type) {
Buffer<uint8_t> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = (double(input[i])+offset)/scale; _samples_left++;
// Once a FFT buffer is completed -> transform
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_s8 == _input_type) {
Buffer<int8_t> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = (double(input[i])+offset)/scale; _samples_left++;
// Once a FFT buffer is completed -> transform
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_u16 == _input_type) {
Buffer<uint16_t> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = (double(input[i])+offset)/scale; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_s16 == _input_type) {
Buffer<int16_t> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = (double(input[i])+offset)/scale; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_f32 == _input_type) {
Buffer<float> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = input[i]; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_f64 == _input_type) {
Buffer<double> input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = input[i]; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0;}
}
} else if (Config::Type_cu8 == _input_type) {
Buffer< std::complex<uint8_t> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = std::complex<double>(
double(input[i].real())+offset,
double(input[i].imag())+offset)/scale;
_samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_cs8 == _input_type) {
Buffer< std::complex<int8_t> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = std::complex<double>(
double(input[i].real())+offset,
double(input[i].imag())+offset)/scale;
_samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_cu16 == _input_type) {
Buffer< std::complex<uint16_t> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = std::complex<double>(
double(input[i].real())+offset,double(input[i].imag())+offset)/scale;
_samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_cs16 == _input_type) {
Buffer< std::complex<int16_t> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = std::complex<double>(
double(input[i].real())+offset,double(input[i].imag())+offset)/scale;
_samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_cf32 == _input_type) {
Buffer< std::complex<float> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = input[i]; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else if (Config::Type_cf64 == _input_type) {
Buffer< std::complex<double> > input(buffer);
for (size_t i=0; i<input.size(); i++, _sample_count++) {
// Skip until _N_samples is reached
if (_sample_count < _N_samples) { continue; }
// Copy value into buffer
_fft_buffer[_samples_left] = input[i]; _samples_left++;
if (_samples_left == _fft_size) { _updateFFT(); _samples_left=0; _sample_count=0; }
}
} else {
RuntimeError err;
err << "SpectrumView: Can not process buffer of type " << _input_type
<< ", unsupported type.";
throw err;
}
}
void
Spectrum::_updateFFT() {
// calc fft
fftw_execute(_plan);
// Update _compute with PSD
for(size_t i=0; i<_fft_size; i++) {
_compute[i] += std::real(std::conj(_fft_buffer[i])*_fft_buffer[i])/_Ntrafo;
}
_trafo_count++;
// If number of averages reached:
if (_trafo_count == _Ntrafo) {
// copy _compute to _spectrum and reset _compute to 0
for (size_t i=0; i<_fft_size; i++) {
_spectrum[i] = _compute[i];
_compute[i] = 0;
}
// done...
_trafo_count=0;
// signal spectrum update
emit spectrumUpdated();
}
}

@ -1,114 +0,0 @@
#ifndef __SDR_GUI_SPECTRUM_HH__
#define __SDR_GUI_SPECTRUM_HH__
#include <QObject>
#include <fftw3.h>
#include "sdr.hh"
namespace sdr {
namespace gui {
class SpectrumProvider: public QObject
{
Q_OBJECT
public:
SpectrumProvider(QObject *parent=0);
virtual ~SpectrumProvider();
/** Returns true if the input is real. */
virtual bool isInputReal() const = 0;
/** Retunrs the sample rate. */
virtual double sampleRate() const = 0;
/** Returns the FFT size. */
virtual size_t fftSize() const = 0;
/** Returns the current spectrum. */
virtual const Buffer<double> &spectrum() const = 0;
signals:
/** Gets emitted once the spectrum was updated. */
void spectrumUpdated();
/** Gets emitted once the spectrum was reconfigured. */
void spectrumConfigured();
};
/** Calculates the power spectrum of a singnal. The spectrum gets updated with a specified
* rate (if possible). */
class Spectrum : public SpectrumProvider, public SinkBase
{
Q_OBJECT
public:
/** Constructs a new spectrum recorder (sink).
* @param rrate Specifies the desired refresh-rate of the spectrum.
* @param fftsize Specifies the size (bins) of the spectrum.
* @param max_avg Specifies the max. number of averages to take.
* @param parent Specifies the parent of the @c Spectrum instance. */
explicit Spectrum(double rrate=2, size_t fftsize=1024, size_t max_avg=1, QObject *parent = 0);
/** Destructor. */
virtual ~Spectrum();
/** Configures the Sink. */
virtual void config(const Config &src_cfg);
/** Receives the data stream and updates the _fft_buffer. */
virtual void handleBuffer(const RawBuffer &buffer, bool allow_overwrite);
/** Returns true if the input is real. */
bool isInputReal() const;
/** Retunrs the sample rate. */
double sampleRate() const;
/** Returns the FFT size. */
size_t fftSize() const;
/** Returns the current spectrum. */
const Buffer<double> &spectrum() const;
protected:
/** Updates the FFT in the _compute buffer. */
void _updateFFT();
protected:
/** The desired refresh rate for the spectrum plot. */
double _rrate;
/** Size of the FFT (resolution). */
size_t _fft_size;
/** Input and compute buffer for the FFT. */
Buffer< std::complex<double> > _fft_buffer;
/** Summation buffer of the spectrum. */
Buffer< double > _compute;
/** The current spectrum. */
Buffer< double > _spectrum;
/** Specifies the number of received samples since last FFT. */
size_t _sample_count;
/** Specifies the number of samples to drop before performing a FFT. */
size_t _N_samples;
/** Number of transforms in the _compute buffer. */
size_t _trafo_count;
/** Max. number of transforms. */
size_t _Ntrafo;
/** Number of samples, left in the buffer by the previous input. */
size_t _samples_left;
/** The input type. */
Config::Type _input_type;
/** The sample-rate of the input. */
double _sample_rate;
/** The FFTW plan. */
fftw_plan _plan;
};
}
}
#endif // SPECTRUM_HH

@ -1,192 +0,0 @@
#include "spectrumview.hh"
#include <QPaintEvent>
#include <QPainter>
#include <QPaintEngine>
#include <QResizeEvent>
#include <QFontMetrics>
using namespace sdr;
using namespace sdr::gui;
SpectrumView::SpectrumView(SpectrumProvider *spectrum, QWidget *parent)
: QWidget(parent), _spectrum(spectrum), _numXTicks(11), _numYTicks(6),
_maxF(std::numeric_limits<double>::infinity()), _mindB(-60)
{
// Assemble pens
_axisPen = QPen(Qt::black);
_axisPen.setWidth(3);
_axisPen.setStyle(Qt::SolidLine);
_graphPen = QPen(Qt::blue);
_axisPen.setWidth(2);
_axisPen.setStyle(Qt::SolidLine);
// Connect to update signal
QObject::connect(_spectrum, SIGNAL(spectrumUpdated()), this, SLOT(update()));
QObject::connect(_spectrum, SIGNAL(spectrumConfigured()), this, SLOT(update()));
}
SpectrumView::~SpectrumView() {
// pass...
}
void
SpectrumView::mouseReleaseEvent(QMouseEvent *evt) {
// If event is accepted -> determine frequency
if ((evt->pos().x() < _plotArea.left()) || (evt->pos().x() > _plotArea.right())) { return; }
double f=0;
if (_spectrum->isInputReal()) {
double dfdx = _spectrum->sampleRate()/(2*_plotArea.width());
f = dfdx * (evt->pos().x()-_plotArea.left());
} else {
double dfdx = _spectrum->sampleRate()/_plotArea.width();
f = -_spectrum->sampleRate()/2 + dfdx * (evt->pos().x()-_plotArea.left());
}
emit click(f);
// Forward to default impl:
QWidget::mouseReleaseEvent(evt);
// redraw
update();
}
void
SpectrumView::resizeEvent(QResizeEvent *evt) {
// First, forward to default impl.
QWidget::resizeEvent(evt);
// If resize event was accepted, recalc plot area
if (evt->isAccepted()) {
QSize ws = evt->size();
QFontMetrics fm(_axisFont);
int leftMargin = 15 + 6*fm.width("x");
int topMargin = 10;
int rightMargin = 3*fm.width("x");
int bottomMargin = 15 + 2*fm.xHeight();
_plotArea = QRect(
leftMargin, topMargin,
ws.width()-leftMargin-rightMargin,
ws.height()-bottomMargin-topMargin);
}
}
void
SpectrumView::paintEvent(QPaintEvent *evt) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.save();
// Clip region to update
painter.setClipRect(evt->rect());
// Draw background
painter.fillRect(QRect(0,0, this->width(), this->height()), QColor(Qt::white));
_drawAxis(painter);
_drawGraph(painter);
painter.restore();
}
void
SpectrumView::_drawGraph(QPainter &painter) {
// Draw spectrum
painter.save();
painter.setClipRect(_plotArea);
painter.setPen(_graphPen);
double height = _plotArea.height();
double width = _plotArea.width();
if (_spectrum->isInputReal()) {
double df = double(2*width)/_spectrum->fftSize();
double dh = double(height)/_mindB;
int xoff = _plotArea.x();
int yoff = _plotArea.y();
for (size_t i=1; i<_spectrum->fftSize()/2; i++) {
int x1 = xoff+df*(i-1), x2 = xoff+df*(i);
int y1 = yoff+dh*(10*log10(_spectrum->spectrum()[i-1])-10*log10(_spectrum->fftSize()));
int y2 = yoff+dh*(10*log10(_spectrum->spectrum()[i])-10*log10(_spectrum->fftSize()));
painter.drawLine(x1, y1, x2, y2);
}
} else {
double df = double(width)/_spectrum->fftSize();
double dh = double(height)/_mindB;
int xoff = _plotArea.x();
int yoff = _plotArea.y();
for (size_t i=1; i<_spectrum->fftSize(); i++) {
int idx1 = (_spectrum->fftSize()/2+i-1) % _spectrum->fftSize();
int idx2 = (_spectrum->fftSize()/2+i) % _spectrum->fftSize();
int x1 = xoff+df*(i-1), x2 = xoff+df*(i);
int y1 = yoff+dh*(10*log10(_spectrum->spectrum()[idx1])-10*log10(_spectrum->fftSize()));
int y2 = yoff+dh*(10*log10(_spectrum->spectrum()[idx2])-10*log10(_spectrum->fftSize()));
painter.drawLine(x1,y1, x2,y2);
}
}
painter.restore();
}
void
SpectrumView::_drawAxis(QPainter &painter) {
painter.save();
// Get some sizes
double height = _plotArea.height();
double width = _plotArea.width();
painter.setPen(_axisPen);
// Axes
painter.drawLine(_plotArea.topLeft(), _plotArea.bottomLeft());
painter.drawLine(_plotArea.bottomLeft(), _plotArea.bottomRight());
// draw y-ticks & labels
double dh = double(height)/_mindB;
double x = _plotArea.topLeft().x();
double y = _plotArea.topLeft().y();
double ddB = _mindB/(_numYTicks-1);
QFontMetrics fm(_axisFont); QRect bb; double db=0;
for (size_t i=0; i<_numYTicks; i++, db+=ddB) {
QString label = QString("%1").arg(db);
bb = fm.boundingRect(label);
y = _plotArea.topLeft().y() + db*dh;
bb.translate(x-8-bb.width(),y+fm.strikeOutPos());
painter.drawLine(x-5,y, x,y);
painter.drawText(bb, label);
}
// Draw x ticks & labels (real spectrum)
if (_spectrum->isInputReal()) {
double dx = double(width)/(_numXTicks-1);
double maxF = std::min(_maxF, _spectrum->sampleRate()/2);
double df = maxF/(_numXTicks-1);
double x = _plotArea.bottomLeft().x();
double y = _plotArea.bottomLeft().y();
double f = 0;
for (size_t i=0; i<11; i++, f +=df, x += dx) {
QString label = QString("%1").arg(f);
bb = fm.boundingRect(label);
bb.translate(x-bb.width()/2,y+8+fm.overlinePos());
painter.drawLine(x,y, x,y+5);
painter.drawText(bb, label);
}
} else {
double dx = double(width)/(_numXTicks-1);
double df = _spectrum->sampleRate()/(_numXTicks-1);
double x = _plotArea.bottomLeft().x();
double y = _plotArea.bottomLeft().y();
double f = -_spectrum->sampleRate()/2;
for (size_t i=0; i<_numXTicks; i++, f +=df, x += dx) {
QString label = QString("%1").arg(f);
bb = fm.boundingRect(label);
bb.translate(x-bb.width()/2,y+8+fm.overlinePos());
painter.drawLine(x,y, x,y+5);
painter.drawText(bb, label);
}
}
painter.restore();
}

@ -1,74 +0,0 @@
#ifndef __SDR_GUI_SPECTRUMVIEW_HH__
#define __SDR_GUI_SPECTRUMVIEW_HH__
#include <QWidget>
#include <QPen>
#include "sdr.hh"
#include "spectrum.hh"
namespace sdr {
namespace gui {
/** A simple widget to display a PSD with live update. */
class SpectrumView: public QWidget
{
Q_OBJECT
public:
/** @param rrate Specifies the (approx) refreshrate of the FFT plot. */
explicit SpectrumView(SpectrumProvider *spectrum, QWidget *parent=0);
inline size_t numXTicks() const { return _numXTicks; }
inline void setNumXTicks(size_t N) { _numXTicks=N; update(); }
inline size_t numYTicks() const { return _numYTicks; }
inline void setNumYTicks(size_t N) { _numYTicks = N; }
inline double mindB() const { return _mindB; }
inline void setMindB(double mindB) { _mindB = mindB; }
/// Destructor.
virtual ~SpectrumView();
signals:
void click(double f);
protected:
/** Handles mouse clicks. */
virtual void mouseReleaseEvent(QMouseEvent *evt);
/** Updates _plotArea on resize events. */
virtual void resizeEvent(QResizeEvent *evt);
/** Draws the spectrum. */
virtual void paintEvent(QPaintEvent *evt);
/** Draws the spectrum graph */
void _drawGraph(QPainter &painter);
/** Draw the axes, ticks and labels. */
void _drawAxis(QPainter &painter);
protected:
/** Holds a weak reference to the spectrum recorder object. */
SpectrumProvider *_spectrum;
/// The font being used for axis labels
QFont _axisFont;
/// The plot area
QRect _plotArea;
/// Axis pen.
QPen _axisPen;
/// The pen used to draw the graph.
QPen _graphPen;
size_t _numXTicks;
size_t _numYTicks;
double _maxF;
/** Lower bound of the PSD plot. */
double _mindB;
};
}
}
#endif // __SDR_GUI_SPECTRUMVIEW_HH__

@ -1,212 +0,0 @@
#include "waterfallview.hh"
#include <QPainter>
#include <QPaintEvent>
#include <QDebug>
using namespace sdr;
using namespace sdr::gui;
/* ****************************************************************************************** *
* Implementation of ColorMap
* ****************************************************************************************** */
ColorMap::ColorMap(double min, double max)
: _min(min), _max(max)
{
// pass...
}
ColorMap::~ColorMap() {
// pass...
}
/* ****************************************************************************************** *
* Implementation of GrayScaleColorMap
* ****************************************************************************************** */
GrayScaleColorMap::GrayScaleColorMap(double min, double max)
: ColorMap(min, max)
{
// pass...
}
GrayScaleColorMap::~GrayScaleColorMap() {
// pass...
}
QColor
GrayScaleColorMap::map(const double &value) {
int h = 255*value;
return QColor(h,h,h);
}
/* ****************************************************************************************** *
* Implementation of LinearColorMap
* ****************************************************************************************** */
LinearColorMap::LinearColorMap(const QVector<QColor> &colors, double min, double max)
: ColorMap(min, max), _colors(colors)
{
// pass...
}
LinearColorMap::~LinearColorMap() {
// pass...
}
QColor
LinearColorMap::map(const double &value) {
// Calc indices
double upper = ceil(value*(_colors.size()-1));
double lower = floor(value*(_colors.size()-1));
int idx = int(lower);
if (lower == upper) { return _colors[idx]; }
double dv = upper-(value*(_colors.size()-1));
double dr = dv * (_colors[idx].red() - _colors[idx+1].red());
double dg = dv * (_colors[idx].green() - _colors[idx+1].green());
double db = dv * (_colors[idx].blue() - _colors[idx+1].blue());
return QColor(int(_colors[idx+1].red()+dr),
int(_colors[idx+1].green()+dg),
int(_colors[idx+1].blue()+db));
}
/* ****************************************************************************************** *
* Implementation of WaterFallView
* ****************************************************************************************** */
WaterFallView::WaterFallView(SpectrumProvider *spectrum, size_t hist, Direction dir, QWidget *parent)
: QWidget(parent), _spectrum(spectrum), _N(_spectrum->fftSize()), _M(hist), _dir(dir),
_waterfall(_N,_M)
{
switch (dir) {
case BOTTOM_UP:
case TOP_DOWN:
setMinimumHeight(hist);
break;
case LEFT_RIGHT:
case RIGHT_LEFT:
setMinimumWidth(hist);
break;
}
// Fill waterfall pixmap
_waterfall.fill(Qt::black);
// Create color map
//_colorMap = new GrayScaleColorMap(-120, 0);
QVector<QColor> colors; colors.reserve(4);
colors << Qt::black << Qt::red << Qt::yellow << Qt::white;
_colorMap = new LinearColorMap(colors, -60, 0);
// Get notified once a new spectrum is available:
QObject::connect(_spectrum, SIGNAL(spectrumUpdated()), this, SLOT(_onSpectrumUpdated()));
QObject::connect(_spectrum, SIGNAL(spectrumConfigured()), this, SLOT(_onSpectrumConfigure()));
}
void
WaterFallView::_onSpectrumUpdated() {
if (_waterfall.isNull() || (_M==0) || (_N==0)) { return; }
QPainter painter(&_waterfall);
// scroll pixmap one pixel up
QRect target(0,0, _N, _M-1), source(0,1,_N,_M-1);
painter.drawPixmap(target, _waterfall, source);
// Draw new spectrum
for (size_t i=0; i<_N; i++) {
int idx = (_spectrum->fftSize()/2+i) % _spectrum->fftSize();
double value;
if ((TOP_DOWN == _dir) || (LEFT_RIGHT == _dir)) {
value = 10*log10(_spectrum->spectrum()[_spectrum->fftSize()-1-idx])-10*log10(_N);
} else {
value = 10*log10(_spectrum->spectrum()[idx])-10*log10(_N);
}
// Reset NaNs
if (value != value) { value = std::numeric_limits<double>::min(); }
painter.setPen((*_colorMap)(value));
painter.drawPoint(i, _M-1);
}
// Trigger update
this->update();
}
void
WaterFallView::_onSpectrumConfigure() {
// Update spectrum width
_N = _spectrum->fftSize();
// Replace WaterFall pixmap
_waterfall = QPixmap(_N, _M);
// Fill waterfall pixmap
_waterfall.fill(Qt::black);
// Trigger update
this->update();
}
void
WaterFallView::mouseReleaseEvent(QMouseEvent *evt) {
// If event is accepted -> determine frequency
if ((evt->pos().x() < 0) || (evt->pos().x() > this->width())) { return; }
double f=0;
if ((BOTTOM_UP == _dir) || (TOP_DOWN == _dir)) {
double dfdx = _spectrum->sampleRate()/this->width();
f = -_spectrum->sampleRate()/2 + dfdx*evt->pos().x();
emit click(f);
} else {
double dfdx = _spectrum->sampleRate()/this->height();
f = -_spectrum->sampleRate()/2 + dfdx*evt->pos().y();
emit click(f);
}
// Forward to default impl:
QWidget::mouseReleaseEvent(evt);
// redraw
this->update();
}
void
WaterFallView::paintEvent(QPaintEvent *evt)
{
QWidget::paintEvent(evt);
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::SmoothPixmapTransform|QPainter::Antialiasing);
// Assemble trafo
QTransform trafo;
switch (_dir) {
case BOTTOM_UP:
trafo.scale(this->width()/qreal(_N), this->height()/qreal(_M));
break;
case LEFT_RIGHT:
trafo.scale(this->width()/qreal(_M), this->height()/qreal(_N));
trafo.translate(_M,0);
trafo.rotate(90);
break;
case TOP_DOWN:
trafo.scale(this->width()/qreal(_N), this->height()/qreal(_M));
trafo.translate(_N,_M);
trafo.rotate(180);
break;
case RIGHT_LEFT:
trafo.scale(this->width()/qreal(_M), this->height()/qreal(_N));
trafo.translate(0,_N);
trafo.rotate(270);
break;
}
painter.setTransform(trafo);
QRect exposedRect = painter.matrix().inverted()
.mapRect(evt->rect())
.adjusted(-1, -1, 1, 1);
// the adjust is to account for half pixels along edges
painter.drawPixmap(exposedRect, _waterfall, exposedRect);
//painter.drawPixmap(0,0, _waterfall);
painter.restore();
}

@ -1,119 +0,0 @@
#ifndef __SDR_GUI_WATERFALLVIEW_HH__
#define __SDR_GUI_WATERFALLVIEW_HH__
#include <QWidget>
#include <QImage>
#include "spectrum.hh"
namespace sdr {
namespace gui {
/** Interface for all color maps. */
class ColorMap
{
protected:
/** Hidden constructor. */
ColorMap(double min, double max);
public:
/** Destructor. */
virtual ~ColorMap();
/** Maps a value to a color. */
inline QColor operator()(const double &value) {
if (value > _max) { return this->map(1); }
if (value < _min) { return this->map(0); }
return this->map((value-_min)/(_max-_min));
}
/** Maps a value on the interval [0,1] to a color.
* Needs to be implemented by all sub-classes. */
virtual QColor map(const double &value) = 0;
protected:
/** Minimum value. */
double _min;
/** Maximum value. */
double _max;
};
/** A simple gray-scale color map. */
class GrayScaleColorMap: public ColorMap
{
public:
/** Constructor.
* @param mindB Specifices the minimum value in dB of the color-scale. Mapping values [min, max]
* to a gray-scale. */
GrayScaleColorMap(double min, double max);
/** Destructor. */
virtual ~GrayScaleColorMap();
/** Implements the color mapping. */
virtual QColor map(const double &value);
};
/** A linear interpolating color map. */
class LinearColorMap: public ColorMap {
public:
LinearColorMap(const QVector<QColor> &colors, double min, double max);
/** Destructor. */
virtual ~LinearColorMap();
virtual QColor map(const double &value);
protected:
QVector<QColor> _colors;
};
/** A simple waterfall display of the spectrogram. */
class WaterFallView : public QWidget
{
Q_OBJECT
public:
typedef enum {
BOTTOM_UP, TOP_DOWN, LEFT_RIGHT, RIGHT_LEFT
} Direction;
public:
/** Constructor.
* @param spectrum Specifies the spectrum sink.
* @param hist Specifies the number of PSDs to display.
* @param parent The parent widget. */
explicit WaterFallView(SpectrumProvider *spectrum, size_t hist=100, Direction dir=BOTTOM_UP, QWidget *parent = 0);
signals:
void click(double f);
protected:
/** Handles mouse clicks. */
virtual void mouseReleaseEvent(QMouseEvent *evt);
/** Draws the scaled waterfall spectrogram. */
virtual void paintEvent(QPaintEvent *evt);
protected slots:
/** Gets called once a new PSD is available. */
void _onSpectrumUpdated();
/** Gets called once the spectrum provider gets reconfigured. */
void _onSpectrumConfigure();
protected:
/** The spectrum sink. */
SpectrumProvider *_spectrum;
/** The size of the spectrum. */
size_t _N;
/** "Height of the spectrum. */
size_t _M;
/** Specifies the direction of the waterfall. */
Direction _dir;
/** The waterfall spectrogram. */
QPixmap _waterfall;
/** The color map to be used. */
ColorMap *_colorMap;
};
}
}
#endif // WATERFALLVIEW_HH

@ -10,7 +10,7 @@ namespace sdr {
/** A simple BPSK31 "demodulator". This node consumes a complex input stream with a sample-rate of
* at least 2000Hz and produces a bitstream with 31.25 Hz "sample-rate". Use the @c Varicode node
* to decode this bitstream to ASCII chars. The BPSK31 signal should be centered around 0Hz, this
* to decode this bitstream to ASCII chars. The BPSK31 signal should be centered around 0Hz. This
* node uses a simple PLL to adjust for small detunings. */
template <class Scalar>
class BPSK31: public Sink< std::complex<Scalar> >, public Source
@ -60,6 +60,7 @@ public:
_superSample = 64;
}
/** Destructor. */
virtual ~BPSK31() {
// pass...
}
@ -155,17 +156,20 @@ public:
protected:
/** Returns @c true if there is a phase transition at the current sample. */
inline bool _hasTransition() const {
return ((_hist[_hist_idx-1]>=0) && (_hist[_hist_idx]<=0)) ||
((_hist[_hist_idx-1]<=0) && (_hist[_hist_idx]>=0));
}
/** Returns the current constellation. */
inline int _currentContellation() const {
float value = 0;
for (size_t i=0; i<=_hist_idx; i++) { value += _hist[i]; }
return (value > 0) ? 1 : -1;
}
/** Computes the phase error. */
inline float _phaseError(const std::complex<float> &value) const {
float r2 = value.real()*value.real();
float i2 = value.imag()*value.imag();
@ -174,6 +178,7 @@ protected:
return -value.real()*value.imag()/nrm2;
}
/** Updates the PLL (@c _F and @c _P). */
inline void _updatePLL(const std::complex<float> &sample) {
float phi = _phaseError(sample);
_F += _beta*phi;
@ -184,6 +189,7 @@ protected:
//std::cerr << "Update PLL: P=" << _P << "; F=" << _F << ", err= " << phi << std::endl;
}
/** Updates the sub-sampler. */
inline void _updateSampler(const std::complex<Scalar> &value) {
// decrease fractional sub-sample counter
_mu-=1;
@ -202,6 +208,7 @@ protected:
_dl_idx = (_dl_idx + 1) % 8;
}
/** Updates the PPL state (@c _mu and @c _omega). */
inline void _errorTracking(const std::complex<float> &sample) {
// Update last 2 constellation and phases
_p_2T = _p_1T; _p_1T = _p_0T; _p_0T = sample;
@ -229,10 +236,14 @@ protected:
float _P;
/** Frequency of the carrier PLL. */
float _F;
/** Upper and lower frequency limit of the carrier PLL. */
float _Fmin, _Fmax;
/** Gain factors of the carrier PLL. */
float _alpha, _beta;
/** Lower frequency limit of the carrier PLL. */
float _Fmin;
/** Upper frequency limit of the carrier PLL. */
float _Fmax;
/** Gain factor of the carrier PLL. */
float _alpha;
/** Gain factor of the carrier PLL. */
float _beta;
/** The delay line for the interpolating sub-sampler. */
Buffer< std::complex<float> > _dl;
/** The current index of the delay line. */
@ -247,14 +258,24 @@ protected:
float _omega;
/** Relative error of the subsample rate. */
float _omega_rel;
/** Limits of the sub-sample rate. */
float _min_omega, _max_omega;
/** Minimum of the sub-sample rate. */
float _min_omega;
/** Maximum of the sub-sample rate. */
float _max_omega;
/** Gain of the sub-sample rate correction. */
float _gain_omega;
/** Last 3 phases. */
std::complex<float> _p_0T, _p_1T, _p_2T;
/** Last 3 constellations. */
std::complex<float> _c_0T, _c_1T, _c_2T;
/** Phase at T = 0 (samples). */
std::complex<float> _p_0T;
/** Phase at T=-1 (samples). */
std::complex<float> _p_1T;
/** Phase at T=-2 (samples). */
std::complex<float> _p_2T;
/** Constellation at T=0 (samples). */
std::complex<float> _c_0T;
/** Constellation at T=-1 (samples). */
std::complex<float> _c_1T;
/** Constellation at T=-2 (samples). */
std::complex<float> _c_2T;
/** The last @c _superSample phases. */
Buffer<float> _hist;
/** Current phase history index. */

@ -291,6 +291,8 @@
#include "demod.hh"
#include "psk31.hh"
#include "fftplan.hh"
#ifdef SDR_WITH_FFTW
#include "filternode.hh"
#endif

Loading…
Cancel
Save