Fixed minors and added some example tools.

master
Hannes Matuschek 12 years ago
parent 66cf0fc7f3
commit e17ed99324

@ -10,6 +10,12 @@ IF(SDR_WITH_PORTAUDIO)
add_executable(sdr_fm sdr_fm.cc) add_executable(sdr_fm sdr_fm.cc)
target_link_libraries(sdr_fm ${LIBS} libsdr) target_link_libraries(sdr_fm ${LIBS} libsdr)
add_executable(sdr_rec sdr_rec.cc)
target_link_libraries(sdr_rec ${LIBS} libsdr)
add_executable(sdr_wspr sdr_wspr.cc)
target_link_libraries(sdr_wspr ${LIBS} libsdr)
add_executable(sdr_afsk1200 sdr_afsk1200.cc) add_executable(sdr_afsk1200 sdr_afsk1200.cc)
target_link_libraries(sdr_afsk1200 ${LIBS} libsdr) target_link_libraries(sdr_afsk1200 ${LIBS} libsdr)
ENDIF(SDR_WITH_PORTAUDIO) ENDIF(SDR_WITH_PORTAUDIO)
@ -22,3 +28,6 @@ ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
add_executable(sdr_psk31 sdr_psk31.cc) add_executable(sdr_psk31 sdr_psk31.cc)
target_link_libraries(sdr_psk31 ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui) target_link_libraries(sdr_psk31 ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui)
add_executable(sdr_rtty sdr_rtty.cc)
target_link_libraries(sdr_rtty ${LIBS} libsdr)

@ -76,11 +76,10 @@ public:
// The input sample rate // The input sample rate
_sampleRate = src_cfg.sampleRate(); _sampleRate = src_cfg.sampleRate();
// Symbols per bit (limit to 32 symbols per bit) // Samples per bit
_corrLen = std::min(int(_sampleRate/_baud), 31); _corrLen = int(_sampleRate/_baud);
// Compute symbol rate: // Compute symbol rate:
_symbolRate = _baud*_corrLen; _symbolRate = std::min(10*_baud, _baud*_corrLen);
// Samples per symbol (fractional): // Samples per symbol (fractional):
_mu = 0.0; _muIncr = _sampleRate/_symbolRate; _mu = 0.0; _muIncr = _sampleRate/_symbolRate;
@ -102,15 +101,17 @@ public:
for (size_t i=0; i<_corrLen; i++) { for (size_t i=0; i<_corrLen; i++) {
_markLUT[i] = std::exp(std::complex<float>(0.0, phiMark)); _markLUT[i] = std::exp(std::complex<float>(0.0, phiMark));
_spaceLUT[i] = std::exp(std::complex<float>(0.0, phiSpace)); _spaceLUT[i] = std::exp(std::complex<float>(0.0, phiSpace));
phiMark += (2.*M_PI*_Fmark)/_symbolRate; phiMark += (2.*M_PI*_Fmark)/_sampleRate;
phiSpace += (2.*M_PI*_Fspace)/_symbolRate; phiSpace += (2.*M_PI*_Fspace)/_sampleRate;
_markHist[i] = 0; _spaceHist[i] = 0; _markHist[i] = 0; _spaceHist[i] = 0;
} }
_lutIdx = 0; _lutIdx = 0;
// Get phase increment per symbol // Get phase increment per symbol
// equiv. to _phasePeriod*_baud/_symbolRate _phase = 0; _omega = _baud/_symbolRate;
_phase = 0; _phaseInc = _baud/_symbolRate; _omegaMin = _omega - 0.01*_omega;
_omegaMax = _omega + 0.01*_omega;
_gainOmega = 0.01;
// Allocate output buffer: // Allocate output buffer:
_buffer = Buffer<uint8_t>(src_cfg.bufferSize()/_corrLen + 1); _buffer = Buffer<uint8_t>(src_cfg.bufferSize()/_corrLen + 1);
@ -121,7 +122,7 @@ public:
<< " samples per symbol: " << _muIncr << std::endl << " samples per symbol: " << _muIncr << std::endl
<< " symbols per bit: " << _corrLen << std::endl << " symbols per bit: " << _corrLen << std::endl
<< " symbol rate: " << _symbolRate << "Hz" << std::endl << " symbol rate: " << _symbolRate << "Hz" << std::endl
<< " Phase incr/symbol: " << float(_phaseInc)/_phasePeriod; << " Phase incr/symbol: " << float(_omega);
Logger::get().log(msg); Logger::get().log(msg);
@ -134,34 +135,24 @@ public:
while (i<buffer.size()) { while (i<buffer.size()) {
// Update sub-sampler // Update sub-sampler
while ((_mu>1) && (i<buffer.size())) { while ((_mu>1) && (i<buffer.size())) {
// Put sample into delay line _markHist[_lutIdx] = float(buffer[i])*_markLUT[_lutIdx];
_dl[_dl_idx] = buffer[i]; _dl[_dl_idx+8] = buffer[i]; _spaceHist[_lutIdx] = float(buffer[i])*_spaceLUT[_lutIdx];
// Modulo LUT length
_lutIdx++; if (_lutIdx==_corrLen) { _lutIdx=0; }
float symbol = _getSymbol();
// Put symbol into delay line
_dl[_dl_idx] = symbol; _dl[_dl_idx+8] = symbol;
_dl_idx = (_dl_idx+1)%8; _mu -= 1; i++; _dl_idx = (_dl_idx+1)%8; _mu -= 1; i++;
} }
if (i<buffer.size()) { if (i<buffer.size()) {
// Get sample // Get interpolated symbol
float sample = interpolate(_dl.sub(_dl_idx, 8), _mu); _mu += _muIncr; float sample = interpolate(_dl.sub(_dl_idx, 8), _mu); _mu += _muIncr;
_markHist[_lutIdx] = sample*_markLUT[_lutIdx];
_spaceHist[_lutIdx] = sample*_spaceLUT[_lutIdx];
// Modulo LUT length
_lutIdx++; if (_lutIdx==_corrLen) { _lutIdx=0; }
float f = _getSymbol();
// Get symbol // Get symbol
_symbols <<= 1; _symbols |= (f>0); _symbols <<= 1; _symbols |= (sample>0);
// If transition
if ((_symbols ^ (_symbols >> 1)) & 1) {
// Phase correction
if (_phase < 0.5) {
_phase -= _phase/10;
} else {
_phase += (1-_phase)/10;
}
}
// Advance phase // Advance phase
_phase += _phaseInc; _phase += _omega;
// Sample bit // Sample bit
if (_phase >= 1) { if (_phase >= 1) {
@ -170,8 +161,21 @@ public:
// Store bit // Store bit
_lastBits <<= 1; _lastBits |= (_symbols & 1); _lastBits <<= 1; _lastBits |= (_symbols & 1);
// Put decoded bit in output buffer // Put decoded bit in output buffer
// transition -> 0; no transition -> 1
_buffer[o++] = ((_lastBits ^ (_lastBits >> 1) ^ 1) & 1); _buffer[o++] = ((_lastBits ^ (_lastBits >> 1) ^ 1) & 1);
} }
// If transition
if ((_symbols ^ (_symbols >> 1)) & 1) {
// Phase correction
/*std::cerr << "Transition at phi=" << _phase << std::endl
<< " update omega from " << _omega << " to "; */
if (_phase < 0.5) { _omega -= _gainOmega*(_phase); }
else { _omega += _gainOmega*(1-_phase); }
// Limit omega
_omega = std::min(_omegaMax, std::max(_omegaMin, _omega));
//std::cerr << _omega << std::endl;
}
} }
} }
this->send(_buffer.head(o)); this->send(_buffer.head(o));
@ -213,7 +217,8 @@ protected:
uint32_t _symbols; uint32_t _symbols;
uint32_t _lastBits; uint32_t _lastBits;
float _phase; float _phase;
float _phaseInc; float _omega, _omegaMin, _omegaMax;
float _gainOmega;
static const uint32_t _phasePeriod = 0x10000u; static const uint32_t _phasePeriod = 0x10000u;
static const uint32_t _phaseMask = 0x0ffffu; static const uint32_t _phaseMask = 0x0ffffu;

@ -0,0 +1,130 @@
#include "demod.hh"
#include "rtlsource.hh"
#include "baseband.hh"
#include "autocast.hh"
#include "portaudio.hh"
#include "wavfile.hh"
#include <iostream>
#include <csignal>
using namespace sdr;
static void __sigint_handler(int signo) {
std::cerr << "Stop Queue..." << std::endl;
// On SIGINT -> stop queue properly
Queue::get().stop();
Queue::get().wait();
}
int main(int argc, char *argv[]) {
if (3 > argc) {
std::cout << "USAGE: sdr_rec FREQUENCY MODE [OUTPUT.wav]" << std::endl; return -1;
}
// get frequency
double freq = atof(argv[1]);
std::string mode = argv[2];
// Get output file (if given)
std::string outFile;
if (4 <= argc) { outFile = argv[3]; }
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
// Register handler:
signal(SIGINT, __sigint_handler);
PortAudio::init();
// obtain base-band config
double f_center = 0, f_filter = 0, flt_width = 0;
int sub_sample = 1; double out_f_sample = 12e3;
if (mode == "WFM") {
f_center = 0; f_filter = 0; flt_width = 50e3;
out_f_sample = 48e3;
} else if (mode == "NFM") {
f_center = 0; f_filter = 0; flt_width = 12.5e3;
out_f_sample = 12e3;
} else if (mode == "AM") {
f_center = 0; f_filter = 0; flt_width = 15e3;
out_f_sample = 12e3;
} else if (mode == "USB") {
f_center = 0; f_filter = 1500; flt_width = 3e3;
out_f_sample = 12e3;
} else if (mode == "LSB") {
f_center = 0; f_filter = -1500; flt_width = 3e3;
out_f_sample = 12e3;
} else {
std::cerr << "Unknown mode '" << mode
<< "': Possible values are WFM, NFM, AM, USB, LSB." << std::endl;
return -1;
}
// Create nodes
RTLSource src(freq, 1e6);
AutoCast< std::complex<int16_t> > cast;
IQBaseBand<int16_t> baseband(f_center, f_filter, flt_width, 16, sub_sample, out_f_sample);
FMDemod<int16_t> *fm_demod = 0;
FMDeemph<int16_t> *fm_deemph = 0;
AMDemod<int16_t> *am_demod = 0;
USBDemod<int16_t> *usb_demod = 0;
PortSink audio;
WavSink<int16_t> *wav_sink = 0;
if (outFile.size()) {
wav_sink = new WavSink<int16_t>(outFile);
}
// Assemble processing chain:
src.connect(&cast, true);
cast.connect(&baseband);
if (mode == "WFM") {
fm_demod = new FMDemod<int16_t>();
fm_deemph= new FMDeemph<int16_t>();
baseband.connect(fm_demod, true);
fm_demod->connect(fm_deemph, true);
fm_deemph->connect(&audio);
if (wav_sink) { fm_deemph->connect(wav_sink); }
} else if (mode == "NFM") {
fm_demod = new FMDemod<int16_t>();
fm_deemph= new FMDeemph<int16_t>();
fm_demod->connect(fm_deemph, true);
baseband.connect(fm_demod, true);
fm_demod->connect(fm_deemph, true);
fm_deemph->connect(&audio);
if (wav_sink) { fm_deemph->connect(wav_sink); }
} else if (mode == "AM") {
am_demod = new AMDemod<int16_t>();
baseband.connect(am_demod);
am_demod->connect(&audio);
if (wav_sink) { am_demod->connect(wav_sink); }
} else if ((mode == "USB") || (mode == "LSB")){
usb_demod = new USBDemod<int16_t>();
baseband.connect(usb_demod);
usb_demod->connect(&audio);
if (wav_sink) { usb_demod->connect(wav_sink); }
}
Queue::get().addStart(&src, &RTLSource::start);
Queue::get().addStop(&src, &RTLSource::stop);
std::cerr << "Start recording at " << src.frequency()
<< "Hz in mode " << mode << ". Press CTRL-C to stop recoding." << std::endl;
Queue::get().start();
Queue::get().wait();
if (fm_demod) { delete fm_demod; }
if (fm_deemph) { delete fm_deemph; }
if (usb_demod) { delete usb_demod; }
if (wav_sink) { delete wav_sink; }
PortAudio::terminate();
std::cerr << "Recording stopped." << std::endl;
return 0;
}

@ -0,0 +1,48 @@
#include "baseband.hh"
#include "autocast.hh"
#include "demod.hh"
#include "wavfile.hh"
#include "portaudio.hh"
using namespace sdr;
static void __sigint_handler(int signo) {
// On SIGINT -> stop queue properly
Queue::get().stop();
}
int main(int argc, char *argv[]) {
if (2 != argc) {
std::cerr << "Usage: sdr_rtty FILENAME" << std::endl;
return -1;
}
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
// Register handler:
signal(SIGINT, __sigint_handler);
PortAudio::init();
Queue &queue = Queue::get();
WavSource src(argv[1]);
AutoCast< std::complex<int16_t> > cast;
IQBaseBand<int16_t> baseband(0, 2144., 200.0, 63, 1);
baseband.setCenterFrequency(2144.0);
PortSink sink;
src.connect(&cast, true);
cast.connect(&baseband, true);
baseband.connect(&sink);
queue.addIdle(&src, &WavSource::next);
queue.start();
queue.wait();
PortAudio::terminate();
return 0;
}

@ -0,0 +1,72 @@
#include "demod.hh"
#include "rtlsource.hh"
#include "baseband.hh"
#include "autocast.hh"
#include "portaudio.hh"
#include "wavfile.hh"
#include <iostream>
#include <csignal>
using namespace sdr;
static void __sigint_handler(int signo) {
std::cerr << "Stop Queue..." << std::endl;
// On SIGINT -> stop queue properly
Queue::get().stop();
Queue::get().wait();
}
int main(int argc, char *argv[]) {
if (2 > argc) {
std::cout << "USAGE: sdr_wspr FREQUENCY [OUTPUT.wav]" << std::endl; return -1;
}
// get frequency
double freq = atof(argv[1]);
// Get output file (if given)
std::string outFile;
if (4 <= argc) { outFile = argv[3]; }
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
// Register handler:
signal(SIGINT, __sigint_handler);
PortAudio::init();
// Create nodes
RTLSource src(freq, 240e3); // <- set sample rate to 240kHz -> 20*12kHz
AutoCast< std::complex<int16_t> > cast;
IQBaseBand<int16_t> baseband(0, 1500, 3000, 16, 1, 12000);
USBDemod<int16_t> usb_demod;
PortSink audio;
WavSink<int16_t> *wav_sink = outFile.size() ? new WavSink<int16_t>(outFile) : 0;
src.connect(&cast, true);
cast.connect(&baseband, true);
baseband.connect(&usb_demod, true);
usb_demod.connect(&audio, false);
if (wav_sink) { usb_demod.connect(wav_sink); }
Queue::get().addStart(&src, &RTLSource::start);
Queue::get().addStop(&src, &RTLSource::stop);
std::cerr << "Start recording at " << src.frequency()
<< "Hz. Press CTRL-C to stop recoding." << std::endl;
Queue::get().start();
Queue::get().wait();
if (wav_sink) { delete wav_sink; }
PortAudio::terminate();
std::cerr << "Recording stopped." << std::endl;
return 0;
}

@ -32,7 +32,7 @@ public:
public: public:
/** Constructor, the filter center frequency @c Ff equals the given center frequency @c Fc. */ /** Constructor, the filter center frequency @c Ff equals the given center frequency @c Fc. */
IQBaseBand(double Fc, double width, size_t order, size_t sub_sample, double oFs=0.0) IQBaseBand(double Fc, double width, size_t order, size_t sub_sample, double oFs=0.0)
: Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(_Fc, 0), : Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
_Fc(Fc), _Ff(Fc), _Fs(0), _width(width), _order(std::max(size_t(1), order)), _Fc(Fc), _Ff(Fc), _Fs(0), _width(width), _order(std::max(size_t(1), order)),
_sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0), _sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0),
_last(0), _kernel(_order) _last(0), _kernel(_order)
@ -44,7 +44,7 @@ public:
/** Constructor. */ /** Constructor. */
IQBaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample, double oFs=0.0) IQBaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample, double oFs=0.0)
: Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(_Fc, 0), : Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
_Fc(Fc), _Ff(Ff), _Fs(0), _width(width), _order(std::max(size_t(1), order)), _Fc(Fc), _Ff(Ff), _Fs(0), _width(width), _order(std::max(size_t(1), order)),
_sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0), _sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0),
_last(0), _kernel(_order) _last(0), _kernel(_order)

@ -108,6 +108,7 @@ public:
{ {
// pass... // pass...
} }
/** Destructor. */ /** Destructor. */
virtual ~USBDemod() { virtual ~USBDemod() {
// pass... // pass...

Loading…
Cancel
Save