Fixed minors...

master
Hannes Matuschek 12 years ago
parent 5a95ac8dab
commit cad5e766a9

@ -12,3 +12,6 @@ IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
add_executable(sdr_rds sdr_rds.cc) add_executable(sdr_rds sdr_rds.cc)
target_link_libraries(sdr_rds ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui) target_link_libraries(sdr_rds ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui)
ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO) 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)

@ -0,0 +1,191 @@
#include "baseband.hh"
#include "autocast.hh"
#include "demod.hh"
#include "portaudio.hh"
#include "wavfile.hh"
#include "gui/gui.hh"
#include <iostream>
#include <QApplication>
#include <QMainWindow>
#include <QThread>
using namespace sdr;
static void __sigint_handler(int signo) {
// On SIGINT -> stop queue properly
Queue::get().stop();
}
template <class Scalar>
class BPSK31: public Sink< std::complex<Scalar> >, public Source
{
typedef typename Traits<Scalar>::SScalar SScalar;
public:
BPSK31()
: Sink< std::complex<Scalar> >(), Source(), _lut(256)
{
_shift = 8*(sizeof(int16_t)-sizeof(Scalar));
// Initialize LUT
for (size_t i=0; i<256; i++) {
_lut[i] = std::exp(std::complex<double>(0., (-2*M_PI*i)/256))*(1<<8);
}
}
/** Destructor. */
virtual ~BPSK31() {
// pass...
}
/** Configures the FM demodulator. */
virtual void config(const Config &src_cfg) {
// Requires type & buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// Check if buffer type matches template
if (Config::typeId< std::complex<Scalar> >() != src_cfg.type()) {
ConfigError err;
err << "Can not configure BPSK31: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId< std::complex<Scalar> >();
throw err;
}
// Unreference buffer if non-empty
if (! _buffer.isEmpty()) { _buffer.unref(); }
// Allocate buffer
_buffer = Buffer<int16_t>(16);
_lut_idx = 0;
_lut_incr = ((256.*256.*2144.)/src_cfg.sampleRate());
_pll_incr = 0;
double tau = 1./20;
_alpha = 2*M_PI/(2*M_PI+src_cfg.sampleRate()*tau);
_lp_phase = 0;
// Results into a 4*31.25 Hz sample
_subsample = (256.*src_cfg.sampleRate()/(4*32.25));
_sample_count = 0;
_dec_count = 0;
LogMessage msg(LOG_DEBUG);
msg << "Configured BPSK31 node:" << std::endl
<< " sample-rate: " << src_cfg.sampleRate() << std::endl
<< " in-type / out-type: " << src_cfg.type()
<< " / " << Config::typeId<int16_t>() << std::endl
<< " in-place: " << (_can_overwrite ? "true" : "false") << std::endl
<< " output scale: 2^" << _shift << std::endl
<< " PLL tau/alpha: " << tau << "/" << _alpha;
Logger::get().log(msg);
// Propergate config
this->setConfig(Config(Config::typeId<int16_t>(), 4*31.25, 16, 1));
}
/** Performs the FM demodulation. */
virtual void process(const Buffer<std::complex<Scalar> > &buffer, bool allow_overwrite)
{
if (0 == buffer.size()) { return; }
_process(buffer, _buffer);
}
protected:
/** The actual demodulation. */
void _process(const Buffer< std::complex<Scalar> > &in, const Buffer<int16_t> &out)
{
// Calc abs phase values
for (size_t i=1; i<in.size(); i++) {
std::complex<double> val =
std::complex<double>(in[i].real(), in[i].imag()) * _lut[_lut_idx>>8];
_lut_idx += (_lut_incr+_pll_incr);
_sample_count += 256;
// Get phase difference
double phase = std::atan2(double(val.imag()), double(val.real()))/M_PI;
// low-pass
_lp_phase = (1.-_alpha)*_lp_phase + _alpha*phase;
// Correct PLL frequency by LP-ed phase
_pll_incr += _lp_phase*10;
std::cout << "Fcorr=" << 22050. * double(_pll_incr)/(1<<16)
<< "; Phi=" << 180*phase << " (" << 180*_lp_phase << ")" << std::endl;
if (_sample_count >= _subsample) {
out[_dec_count] = (_lp_phase*(1<<14));
_sample_count -= _subsample; _dec_count++;
// If 8 bits has been collected:
if (8 == _dec_count) {
// propergate resulting 8 bits
this->send(out.head(8));
_dec_count = 0;
}
}
}
}
protected:
int _shift;
/** If true, in-place demodulation is poissible. */
bool _can_overwrite;
Buffer< std::complex<SScalar> > _lut;
/** The current LUT index. It is defined in multiples of 256 for heiher precision. */
uint16_t _lut_idx;
/** The LUT increment is defined in multiples of 256 for higher precision. */
int32_t _lut_incr;
/** The PLL increment correction is defined in multiples of 256 for higher precision. */
double _pll_incr;
double _alpha;
double _lp_phase;
size_t _subsample;
size_t _sample_count;
size_t _dec_count;
/** The output buffer, unused if demodulation is performed in-place. */
Buffer<int16_t> _buffer;
};
int main(int argc, char *argv[]) {
if (2 != argc) {
std::cerr << "Usage: sdr_psk31 FILENAME" << std::endl;
return -1;
}
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
// Register handler:
signal(SIGINT, __sigint_handler);
QApplication app(argc, argv);
QMainWindow *win = new QMainWindow();
gui::Spectrum *spec = new gui::Spectrum(2, 1024, 5);
gui::SpectrumView *spec_view = new gui::SpectrumView(spec);
spec_view->setMindB(-60);
win->setCentralWidget(spec_view);
win->setMinimumSize(640, 240);
win->show();
PortAudio::init();
Queue &queue = Queue::get();
//WavSource src(argv[1]);
SigGen<int16_t> src(22050., 1024);
src.addSine(2144);
AutoCast< std::complex<int16_t> > cast;
IQBaseBand<int16_t> baseband(0.0, 2144., 400.0, 15, 1, 8000.0);
BPSK31<int16_t> demod;
PortSink sink;
src.connect(&cast, true);
cast.connect(&baseband, true);
baseband.connect(spec);
baseband.connect(&sink);
baseband.connect(&demod);
//queue.addIdle(&src, &WavSource::next);
queue.addIdle(&src, &SigGen<int16_t>::next);
queue.start();
app.exec();
queue.stop();
queue.wait();
PortAudio::terminate();
return 0;
}

@ -58,7 +58,7 @@ public:
case Config::Type_s8: _cast = _int8_cint16; break; case Config::Type_s8: _cast = _int8_cint16; break;
case Config::Type_cu8: _cast = _cuint8_cint16; break; case Config::Type_cu8: _cast = _cuint8_cint16; break;
case Config::Type_cs8: _cast = _cint8_cint16; break; case Config::Type_cs8: _cast = _cint8_cint16; break;
case Config::Type_u16: case Config::Type_u16: _cast = _uint16_cint16; break;
case Config::Type_s16: _cast = _int16_cint16; break; case Config::Type_s16: _cast = _int16_cint16; break;
case Config::Type_cu16: case Config::Type_cu16:
case Config::Type_cs16: _cast = _identity; break; case Config::Type_cs16: _cast = _identity; break;
@ -80,6 +80,7 @@ public:
msg << "Configure AutoCast node:" << std::endl msg << "Configure AutoCast node:" << std::endl
<< " input type: " << src_cfg.type() << std::endl << " input type: " << src_cfg.type() << std::endl
<< " output type: " << Traits<Scalar>::scalarId; << " output type: " << Traits<Scalar>::scalarId;
Logger::get().log(msg);
// Propergate config // Propergate config
this->setConfig(Config(Config::typeId<Scalar>(), src_cfg.sampleRate(), src_cfg.bufferSize(), 1)); this->setConfig(Config(Config::typeId<Scalar>(), src_cfg.sampleRate(), src_cfg.bufferSize(), 1));
@ -223,6 +224,17 @@ protected:
return 4*N; return 4*N;
} }
/** uint16 -> complex int16. */
static size_t _uint16_cint16(const RawBuffer &in, const RawBuffer &out) {
size_t N = in.bytesLen()/2;
int16_t *values = reinterpret_cast<int16_t *>(in.data());
for (size_t i=0; i<N; i++) {
reinterpret_cast<std::complex<int16_t> *>(out.data())[i]
= std::complex<int16_t>(int32_t(values[i])-(2<<15));
}
return 4*N;
}
/** int16 -> complex int16. */ /** int16 -> complex int16. */
static size_t _int16_cint16(const RawBuffer &in, const RawBuffer &out) { static size_t _int16_cint16(const RawBuffer &in, const RawBuffer &out) {
size_t N = in.bytesLen()/2; size_t N = in.bytesLen()/2;

@ -201,7 +201,7 @@ public:
// Check if buffer type matches template // Check if buffer type matches template
if (Config::typeId< std::complex<iScalar> >() != src_cfg.type()) { if (Config::typeId< std::complex<iScalar> >() != src_cfg.type()) {
ConfigError err; ConfigError err;
err << "Can not configure USBDemod: Invalid type " << src_cfg.type() err << "Can not configure FMDemod: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId< std::complex<iScalar> >(); << ", expected " << Config::typeId< std::complex<iScalar> >();
throw err; throw err;
} }

@ -21,12 +21,12 @@ public:
case Config::Type_s8: case Config::Type_s8:
case Config::Type_cu8: case Config::Type_cu8:
case Config::Type_cs8: case Config::Type_cs8:
_scale = 127; break; _scale = 1<<6; break;
case Config::Type_u16: case Config::Type_u16:
case Config::Type_s16: case Config::Type_s16:
case Config::Type_cu16: case Config::Type_cu16:
case Config::Type_cs16: case Config::Type_cs16:
_scale = 32000; break; _scale = 1<<14; break;
default: default:
_scale = 1; break; _scale = 1; break;
} }

@ -1,5 +1,6 @@
#include "wavfile.hh" #include "wavfile.hh"
#include "config.hh" #include "config.hh"
#include "logger.hh"
#include <cstring> #include <cstring>
@ -146,15 +147,15 @@ WavSource::open(const std::string &filename)
_sample_rate = sample_rate; _sample_rate = sample_rate;
_frames_left = _frame_count; _frames_left = _frame_count;
#ifdef SDR_DEBUG LogMessage msg(LOG_DEBUG);
std::cerr << "Configured WavSource:" << std::endl msg << "Configured WavSource:" << std::endl
<< " file: " << filename << std::endl << " file: " << filename << std::endl
<< " type:" << _type << std::endl << " type:" << _type << std::endl
<< " sample-rate: " << _sample_rate << std::endl << " sample-rate: " << _sample_rate << std::endl
<< " frame-count: " << _frame_count << std::endl << " frame-count: " << _frame_count << std::endl
<< " duration: " << _frame_count/_sample_rate << "s" << std::endl << " duration: " << _frame_count/_sample_rate << "s" << std::endl
<< " buffer-size: " << _buffer_size << std::endl; << " buffer-size: " << _buffer_size;
#endif Logger::get().log(msg);
// unreference buffer if not empty // unreference buffer if not empty
if (! _buffer.isEmpty()) { _buffer.unref(); } if (! _buffer.isEmpty()) { _buffer.unref(); }
@ -195,10 +196,12 @@ WavSource::isReal() const {
} }
void void
WavSource::next() { WavSource::next()
{
if ((0 == _frames_left)) { if ((0 == _frames_left)) {
// Close file // Close file
_file.close(); _file.close();
Logger::get().log(LogMessage(LOG_DEBUG, "WavSource: End of file -> stop queue."));
// and signal queue to stop // and signal queue to stop
Queue::get().stop(); Queue::get().stop();
return; return;

Loading…
Cancel
Save