From cc8c20c170311ebafaaf46684065e60abcbd27ae Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Wed, 6 Aug 2014 17:38:07 +0200 Subject: [PATCH 1/6] tests... --- examples/sdr_afsk1200.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/examples/sdr_afsk1200.cc b/examples/sdr_afsk1200.cc index b604574..cb1786d 100644 --- a/examples/sdr_afsk1200.cc +++ b/examples/sdr_afsk1200.cc @@ -130,8 +130,7 @@ public: while ((_mu>1) && (i0)&0x1u); + _symbols <<= 1; _symbols |= (f>0); // If transition if ((_symbols ^ (_symbols >> 1)) & 0x1u) { @@ -247,15 +246,18 @@ public: _ptr = _rxbuffer; } - virtual void process(const Buffer &buffer, bool allow_overwrite) { - for (size_t i=0; i &buffer, bool allow_overwrite) + { + for (size_t i=0; i 2)) { *_ptr = 0; if (! check_crc_ccitt(_rxbuffer, _ptr-_rxbuffer)) { - std::cerr << "Got invalid buffer : " << _rxbuffer << std::endl; + std::cerr << "Got invalid buffer (" << std::dec << (_ptr-_rxbuffer) + << "): " << _rxbuffer << std::endl; } else { std::cerr << "GOT: " << _rxbuffer << std::endl; } @@ -281,8 +283,9 @@ public: _state = 0; continue; } std::cerr << "Got byte: " << std::hex << int( (_bitbuffer>>1) & 0xff ) - << ": " << char(_bitbuffer>>1) << std::endl; - *_ptr++ = (_bitbuffer >> 1); _bitbuffer = 0x80u; continue; + << ": " << char(_bitbuffer>>1) + << " (" << char(_bitbuffer>>2) << ")" << std::endl; + *_ptr++ = (_bitbuffer >> 1); _bitbuffer = 0x0080u; continue; } _bitbuffer >>= 1; } From 66cf0fc7f3fe903fbc9e25bf2640193bb50e1ce2 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Thu, 7 Aug 2014 11:26:02 +0200 Subject: [PATCH 2/6] Fixed AFSK1200 demod. --- examples/sdr_afsk1200.cc | 69 ++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/examples/sdr_afsk1200.cc b/examples/sdr_afsk1200.cc index 427b331..59caab0 100644 --- a/examples/sdr_afsk1200.cc +++ b/examples/sdr_afsk1200.cc @@ -77,14 +77,13 @@ public: _sampleRate = src_cfg.sampleRate(); // Symbols per bit (limit to 32 symbols per bit) - _corrLen = std::min(int(_sampleRate/_baud), 32); + _corrLen = std::min(int(_sampleRate/_baud), 31); // Compute symbol rate: _symbolRate = _baud*_corrLen; // Samples per symbol (fractional): _mu = 0.0; _muIncr = _sampleRate/_symbolRate; - // Delayline for interpolating sub-sampler _dl = Buffer(2*8); for (size_t i=0; i<(2*8); i++) { _dl[i] = 0; } @@ -110,7 +109,8 @@ public: _lutIdx = 0; // Get phase increment per symbol - _phase = 0; _phaseInc = _phaseMask/_corrLen; + // equiv. to _phasePeriod*_baud/_symbolRate + _phase = 0; _phaseInc = _baud/_symbolRate; // Allocate output buffer: _buffer = Buffer(src_cfg.bufferSize()/_corrLen + 1); @@ -145,7 +145,7 @@ public: _markHist[_lutIdx] = sample*_markLUT[_lutIdx]; _spaceHist[_lutIdx] = sample*_spaceLUT[_lutIdx]; // Modulo LUT length - _lutIdx++; if (_lutIdx == _corrLen) { _lutIdx=0; } + _lutIdx++; if (_lutIdx==_corrLen) { _lutIdx=0; } float f = _getSymbol(); // Get symbol _symbols <<= 1; _symbols |= (f>0); @@ -153,10 +153,10 @@ public: // If transition if ((_symbols ^ (_symbols >> 1)) & 1) { // Phase correction - if (_phase < (_phasePeriod/2)) { - _phase += _phaseInc/8; + if (_phase < 0.5) { + _phase -= _phase/10; } else { - _phase -= _phaseInc/8; + _phase += (1-_phase)/10; } } @@ -164,9 +164,9 @@ public: _phase += _phaseInc; // Sample bit - if (_phase >= _phasePeriod) { - // Modulo 2 pi - _phase &= _phaseMask; + if (_phase >= 1) { + // Modulo "2 pi" + _phase = fmodf(_phase, 1.0); // Store bit _lastBits <<= 1; _lastBits |= (_symbols & 1); // Put decoded bit in output buffer @@ -212,8 +212,8 @@ protected: uint32_t _symbols; uint32_t _lastBits; - uint32_t _phase; - uint32_t _phaseInc; + float _phase; + float _phaseInc; static const uint32_t _phasePeriod = 0x10000u; static const uint32_t _phaseMask = 0x0ffffu; @@ -247,15 +247,23 @@ public: } _bitstream = 0; - _bitbuffer = 0x00; + _bitbuffer = 0; _state = 0; _ptr = _rxbuffer; + + // Allocate output buffer + _buffer = Buffer(512); + + // propergate config + this->setConfig(Config(Traits::scalarId, 0, 512, 1)); } virtual void process(const Buffer &buffer, bool allow_overwrite) { for (size_t i=0; i 2)) { *_ptr = 0; @@ -263,33 +271,46 @@ public: std::cerr << "Got invalid buffer: " << _rxbuffer << std::endl; } else { std::cerr << "GOT: " << _rxbuffer << std::endl; + memcpy(_buffer.ptr(), _rxbuffer, _ptr-_rxbuffer); + this->send(_buffer.head(_ptr-_rxbuffer)); } - } + } _state = 1; _ptr = _rxbuffer; - _bitbuffer = 0x80u; + _bitbuffer = 0x80; continue; } + // If 7 ones are received in a row -> error, wait or sync byte if ((_bitstream & 0x7f) == 0x7f) { _state = 0; continue; } + // If state == wait for sync byte -> receive next bit if (!_state) { continue; } - if ((_bitstream & 0x3f) == 0x3e) { /* stuffed bit */ continue; } + /* stuffed bit */ + if ((_bitstream & 0x3f) == 0x3e) { continue; } - if (_bitstream & 1) { _bitbuffer |= 0x100; } + // prepend bit to bitbuffer + _bitbuffer |= ((_bitstream & 1) << 8); + // If 8 bits have been received (stored in b8-b1 of _bitbuffer) if (_bitbuffer & 1) { + // Check for buffer overrun if ((_ptr-_rxbuffer) >= 512) { Logger::get().log(LogMessage(LOG_ERROR, "AX.25 packet too long.")); - _state = 0; continue; + // Wait for next sync byte + _state = 0; + continue; } - std::cerr << "Got byte: " << std::hex << int( (_bitbuffer>>1) & 0xff ) - << ": " << char(_bitbuffer>>1) - << " (" << char(_bitbuffer>>2) << ")" << std::endl; - *_ptr++ = (_bitbuffer >> 1); _bitbuffer = 0x0080u; continue; + + // Store received byte and ... + *_ptr++ = (_bitbuffer >> 1); + // reset bit buffer + _bitbuffer = 0x80; + continue; } + // Shift bitbuffer one to the left _bitbuffer >>= 1; } } @@ -301,6 +322,8 @@ protected: uint8_t _rxbuffer[512]; uint8_t *_ptr; + + Buffer _buffer; }; From e17ed99324d44753c8a7566dc115d746765fc4f6 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Mon, 29 Sep 2014 14:06:46 +0200 Subject: [PATCH 3/6] Fixed minors and added some example tools. --- examples/CMakeLists.txt | 13 +++- examples/sdr_afsk1200.cc | 67 ++++++++++---------- examples/sdr_rec.cc | 130 +++++++++++++++++++++++++++++++++++++++ examples/sdr_rtty.cc | 48 +++++++++++++++ examples/sdr_wspr.cc | 72 ++++++++++++++++++++++ src/baseband.hh | 4 +- src/demod.hh | 1 + 7 files changed, 300 insertions(+), 35 deletions(-) create mode 100644 examples/sdr_rec.cc create mode 100644 examples/sdr_rtty.cc create mode 100644 examples/sdr_wspr.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 05d5617..32c61b3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -10,8 +10,14 @@ IF(SDR_WITH_PORTAUDIO) add_executable(sdr_fm sdr_fm.cc) target_link_libraries(sdr_fm ${LIBS} libsdr) -add_executable(sdr_afsk1200 sdr_afsk1200.cc) -target_link_libraries(sdr_afsk1200 ${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) + target_link_libraries(sdr_afsk1200 ${LIBS} libsdr) ENDIF(SDR_WITH_PORTAUDIO) IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND 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) 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) + diff --git a/examples/sdr_afsk1200.cc b/examples/sdr_afsk1200.cc index 59caab0..95ecc31 100644 --- a/examples/sdr_afsk1200.cc +++ b/examples/sdr_afsk1200.cc @@ -76,11 +76,10 @@ public: // The input sample rate _sampleRate = src_cfg.sampleRate(); - // Symbols per bit (limit to 32 symbols per bit) - _corrLen = std::min(int(_sampleRate/_baud), 31); - + // Samples per bit + _corrLen = int(_sampleRate/_baud); // Compute symbol rate: - _symbolRate = _baud*_corrLen; + _symbolRate = std::min(10*_baud, _baud*_corrLen); // Samples per symbol (fractional): _mu = 0.0; _muIncr = _sampleRate/_symbolRate; @@ -102,15 +101,17 @@ public: for (size_t i=0; i<_corrLen; i++) { _markLUT[i] = std::exp(std::complex(0.0, phiMark)); _spaceLUT[i] = std::exp(std::complex(0.0, phiSpace)); - phiMark += (2.*M_PI*_Fmark)/_symbolRate; - phiSpace += (2.*M_PI*_Fspace)/_symbolRate; + phiMark += (2.*M_PI*_Fmark)/_sampleRate; + phiSpace += (2.*M_PI*_Fspace)/_sampleRate; _markHist[i] = 0; _spaceHist[i] = 0; } _lutIdx = 0; // Get phase increment per symbol - // equiv. to _phasePeriod*_baud/_symbolRate - _phase = 0; _phaseInc = _baud/_symbolRate; + _phase = 0; _omega = _baud/_symbolRate; + _omegaMin = _omega - 0.01*_omega; + _omegaMax = _omega + 0.01*_omega; + _gainOmega = 0.01; // Allocate output buffer: _buffer = Buffer(src_cfg.bufferSize()/_corrLen + 1); @@ -121,7 +122,7 @@ public: << " samples per symbol: " << _muIncr << std::endl << " symbols per bit: " << _corrLen << std::endl << " symbol rate: " << _symbolRate << "Hz" << std::endl - << " Phase incr/symbol: " << float(_phaseInc)/_phasePeriod; + << " Phase incr/symbol: " << float(_omega); Logger::get().log(msg); @@ -134,34 +135,24 @@ public: while (i1) && (i0); - - // If transition - if ((_symbols ^ (_symbols >> 1)) & 1) { - // Phase correction - if (_phase < 0.5) { - _phase -= _phase/10; - } else { - _phase += (1-_phase)/10; - } - } - + _symbols <<= 1; _symbols |= (sample>0); // Advance phase - _phase += _phaseInc; + _phase += _omega; // Sample bit if (_phase >= 1) { @@ -170,8 +161,21 @@ public: // Store bit _lastBits <<= 1; _lastBits |= (_symbols & 1); // Put decoded bit in output buffer + // transition -> 0; no transition -> 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)); @@ -213,7 +217,8 @@ protected: uint32_t _symbols; uint32_t _lastBits; float _phase; - float _phaseInc; + float _omega, _omegaMin, _omegaMax; + float _gainOmega; static const uint32_t _phasePeriod = 0x10000u; static const uint32_t _phaseMask = 0x0ffffu; diff --git a/examples/sdr_rec.cc b/examples/sdr_rec.cc new file mode 100644 index 0000000..bd8e6c0 --- /dev/null +++ b/examples/sdr_rec.cc @@ -0,0 +1,130 @@ +#include "demod.hh" +#include "rtlsource.hh" +#include "baseband.hh" +#include "autocast.hh" +#include "portaudio.hh" +#include "wavfile.hh" + +#include +#include + +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 > cast; + IQBaseBand baseband(f_center, f_filter, flt_width, 16, sub_sample, out_f_sample); + FMDemod *fm_demod = 0; + FMDeemph *fm_deemph = 0; + AMDemod *am_demod = 0; + USBDemod *usb_demod = 0; + PortSink audio; + WavSink *wav_sink = 0; + + if (outFile.size()) { + wav_sink = new WavSink(outFile); + } + + // Assemble processing chain: + src.connect(&cast, true); + cast.connect(&baseband); + + if (mode == "WFM") { + fm_demod = new FMDemod(); + fm_deemph= new FMDeemph(); + 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(); + fm_deemph= new FMDeemph(); + 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(); + 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(); + 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; +} diff --git a/examples/sdr_rtty.cc b/examples/sdr_rtty.cc new file mode 100644 index 0000000..301d870 --- /dev/null +++ b/examples/sdr_rtty.cc @@ -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 > cast; + IQBaseBand 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; +} diff --git a/examples/sdr_wspr.cc b/examples/sdr_wspr.cc new file mode 100644 index 0000000..aa834f3 --- /dev/null +++ b/examples/sdr_wspr.cc @@ -0,0 +1,72 @@ +#include "demod.hh" +#include "rtlsource.hh" +#include "baseband.hh" +#include "autocast.hh" +#include "portaudio.hh" +#include "wavfile.hh" + +#include +#include + +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 > cast; + IQBaseBand baseband(0, 1500, 3000, 16, 1, 12000); + USBDemod usb_demod; + PortSink audio; + WavSink *wav_sink = outFile.size() ? new WavSink(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; +} diff --git a/src/baseband.hh b/src/baseband.hh index a079575..4304fe4 100644 --- a/src/baseband.hh +++ b/src/baseband.hh @@ -32,7 +32,7 @@ public: public: /** 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) - : Sink(), Source(), FreqShiftBase(_Fc, 0), + : Sink(), Source(), FreqShiftBase(Fc, 0), _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), _last(0), _kernel(_order) @@ -44,7 +44,7 @@ public: /** Constructor. */ IQBaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample, double oFs=0.0) - : Sink(), Source(), FreqShiftBase(_Fc, 0), + : Sink(), Source(), FreqShiftBase(Fc, 0), _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), _last(0), _kernel(_order) diff --git a/src/demod.hh b/src/demod.hh index 7c7ea87..729fa43 100644 --- a/src/demod.hh +++ b/src/demod.hh @@ -108,6 +108,7 @@ public: { // pass... } + /** Destructor. */ virtual ~USBDemod() { // pass... From e97a6ac12ea12efba8053d9b540b7a0d63183139 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Mon, 29 Sep 2014 14:07:28 +0200 Subject: [PATCH 4/6] Cleanup --- examples/sdr_rtty.cc | 48 ----------------------------- examples/sdr_wspr.cc | 72 -------------------------------------------- 2 files changed, 120 deletions(-) delete mode 100644 examples/sdr_rtty.cc delete mode 100644 examples/sdr_wspr.cc diff --git a/examples/sdr_rtty.cc b/examples/sdr_rtty.cc deleted file mode 100644 index 301d870..0000000 --- a/examples/sdr_rtty.cc +++ /dev/null @@ -1,48 +0,0 @@ -#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 > cast; - IQBaseBand 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; -} diff --git a/examples/sdr_wspr.cc b/examples/sdr_wspr.cc deleted file mode 100644 index aa834f3..0000000 --- a/examples/sdr_wspr.cc +++ /dev/null @@ -1,72 +0,0 @@ -#include "demod.hh" -#include "rtlsource.hh" -#include "baseband.hh" -#include "autocast.hh" -#include "portaudio.hh" -#include "wavfile.hh" - -#include -#include - -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 > cast; - IQBaseBand baseband(0, 1500, 3000, 16, 1, 12000); - USBDemod usb_demod; - PortSink audio; - WavSink *wav_sink = outFile.size() ? new WavSink(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; -} From ea3968e516642df3a436c5eda0b72b95e41d3383 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Mon, 29 Sep 2014 16:07:28 +0200 Subject: [PATCH 5/6] Fixed interpol subsampler. --- src/gui/spectrum.cc | 2 +- src/subsample.hh | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/gui/spectrum.cc b/src/gui/spectrum.cc index 03c1361..7eec3ba 100644 --- a/src/gui/spectrum.cc +++ b/src/gui/spectrum.cc @@ -43,7 +43,7 @@ Spectrum::config(const Config &src_cfg) { << " Data type: " << _input_type << std::endl << " sample-rate: " << _sample_rate << std::endl << " FFT size: " << _fft_size << std::endl - << " # sample drops: " << _N_samples << 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); diff --git a/src/subsample.hh b/src/subsample.hh index 1814e7e..7941865 100644 --- a/src/subsample.hh +++ b/src/subsample.hh @@ -234,6 +234,14 @@ public: for (size_t i=0; i<16; i++) { _dl[i] = 0; } _mu = 0; + LogMessage msg(LOG_DEBUG); + msg << "Configure InpolSubSampler node:" << std::endl + << " by: " << _frac << std::endl + << " type: " << src_cfg.type() << std::endl + << " sample-rate: " << src_cfg.sampleRate() + << " -> " << src_cfg.sampleRate()/_frac; + Logger::get().log(msg); + // Propergate config this->setConfig(Config(Traits::scalarId, src_cfg.sampleRate()/_frac, bufSize, 1)); } @@ -242,14 +250,16 @@ public: virtual void process(const Buffer &buffer, bool allow_overwrite) { size_t i=0, o=0; while (i 1) && (isend(_buffer.head(o)); } From b5d07817f76b2415727ece0eb784987079499521 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Fri, 3 Oct 2014 01:00:07 +0200 Subject: [PATCH 6/6] Added SpectrumProvider interface and fixed some minors. --- src/freqshift.hh | 3 ++- src/gui/spectrum.cc | 33 ++++++++++++++++++++++++++++- src/gui/spectrum.hh | 45 ++++++++++++++++++++++++++++++---------- src/gui/spectrumview.cc | 2 +- src/gui/spectrumview.hh | 4 ++-- src/gui/waterfallview.cc | 2 +- src/gui/waterfallview.hh | 4 ++-- src/subsample.hh | 11 ++++++++-- src/wavfile.cc | 4 +--- 9 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/freqshift.hh b/src/freqshift.hh index 7b035ae..c18fe4b 100644 --- a/src/freqshift.hh +++ b/src/freqshift.hh @@ -4,6 +4,7 @@ #include "config.hh" #include "traits.hh" #include "node.hh" +#include "operators.hh" namespace sdr { @@ -95,7 +96,7 @@ protected: protected: /** The size of the LUT. */ - static const size_t _lut_size = 127; + static const size_t _lut_size = 128; }; diff --git a/src/gui/spectrum.cc b/src/gui/spectrum.cc index 7eec3ba..811b5c4 100644 --- a/src/gui/spectrum.cc +++ b/src/gui/spectrum.cc @@ -5,8 +5,25 @@ 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) : - QObject(parent), _rrate(rrate), _fft_size(fftsize), _fft_buffer(fftsize), + 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) @@ -69,6 +86,20 @@ Spectrum::isInputReal() const { return false; } +double +Spectrum::sampleRate() const { + return _sample_rate; +} + +size_t +Spectrum::fftSize() const { + return _fft_size; +} + +const Buffer & +Spectrum::spectrum() const { + return _spectrum; +} void Spectrum::handleBuffer(const RawBuffer &buffer, bool allow_overwrite) diff --git a/src/gui/spectrum.hh b/src/gui/spectrum.hh index 2780d77..60ed7e6 100644 --- a/src/gui/spectrum.hh +++ b/src/gui/spectrum.hh @@ -9,9 +9,39 @@ 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 &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 QObject, public SinkBase +class Spectrum : public SpectrumProvider, public SinkBase { Q_OBJECT @@ -36,20 +66,13 @@ public: bool isInputReal() const; /** Retunrs the sample rate. */ - inline double sampleRate() const { return _sample_rate; } + double sampleRate() const; /** Returns the FFT size. */ - inline size_t fftSize() const { return _fft_size; } + size_t fftSize() const; /** Returns the current spectrum. */ - inline const Buffer &spectrum() const { return _spectrum; } - - -signals: - /** Gets emitted once the spectrum was updated. */ - void spectrumUpdated(); - /** Gets emitted once the spectrum was reconfigured. */ - void spectrumConfigured(); + const Buffer &spectrum() const; protected: /** Updates the FFT in the _compute buffer. */ diff --git a/src/gui/spectrumview.cc b/src/gui/spectrumview.cc index 395a660..dc98ed0 100644 --- a/src/gui/spectrumview.cc +++ b/src/gui/spectrumview.cc @@ -8,7 +8,7 @@ using namespace sdr; using namespace sdr::gui; -SpectrumView::SpectrumView(Spectrum *spectrum, QWidget *parent) +SpectrumView::SpectrumView(SpectrumProvider *spectrum, QWidget *parent) : QWidget(parent), _spectrum(spectrum), _numXTicks(11), _numYTicks(6), _maxF(std::numeric_limits::infinity()), _mindB(-60) { diff --git a/src/gui/spectrumview.hh b/src/gui/spectrumview.hh index 12cb351..b61205d 100644 --- a/src/gui/spectrumview.hh +++ b/src/gui/spectrumview.hh @@ -18,7 +18,7 @@ Q_OBJECT public: /** @param rrate Specifies the (approx) refreshrate of the FFT plot. */ - explicit SpectrumView(Spectrum *spectrum, QWidget *parent=0); + explicit SpectrumView(SpectrumProvider *spectrum, QWidget *parent=0); inline size_t numXTicks() const { return _numXTicks; } inline void setNumXTicks(size_t N) { _numXTicks=N; update(); } @@ -51,7 +51,7 @@ protected: protected: /** Holds a weak reference to the spectrum recorder object. */ - Spectrum *_spectrum; + SpectrumProvider *_spectrum; /// The font being used for axis labels QFont _axisFont; /// The plot area diff --git a/src/gui/waterfallview.cc b/src/gui/waterfallview.cc index c39ba35..6735ddf 100644 --- a/src/gui/waterfallview.cc +++ b/src/gui/waterfallview.cc @@ -73,7 +73,7 @@ LinearColorMap::map(const double &value) { /* ****************************************************************************************** * * Implementation of WaterFallView * ****************************************************************************************** */ -WaterFallView::WaterFallView(Spectrum *spectrum, size_t height, QWidget *parent) +WaterFallView::WaterFallView(SpectrumProvider *spectrum, size_t height, QWidget *parent) : QWidget(parent), _spectrum(spectrum), _N(_spectrum->fftSize()), _M(height), _waterfall(_N,_M) { setMinimumHeight(height); diff --git a/src/gui/waterfallview.hh b/src/gui/waterfallview.hh index b6af394..c53265b 100644 --- a/src/gui/waterfallview.hh +++ b/src/gui/waterfallview.hh @@ -75,7 +75,7 @@ public: * @param spectrum Specifies the spectrum sink. * @param height Specifies the number of PSDs to display. * @param parent The parent widget. */ - explicit WaterFallView(Spectrum *spectrum, size_t height=100, QWidget *parent = 0); + explicit WaterFallView(SpectrumProvider *spectrum, size_t height=100, QWidget *parent = 0); signals: void click(double f); @@ -93,7 +93,7 @@ protected slots: protected: /** The spectrum sink. */ - Spectrum *_spectrum; + SpectrumProvider *_spectrum; /** The size of the spectrum. */ size_t _N; /** "Height of the spectrum. */ diff --git a/src/subsample.hh b/src/subsample.hh index 7941865..f5ac16d 100644 --- a/src/subsample.hh +++ b/src/subsample.hh @@ -247,11 +247,18 @@ public: } /** Performs the sub-sampling. */ - virtual void process(const Buffer &buffer, bool allow_overwrite) { + virtual void process(const Buffer &buffer, bool allow_overwrite) + { + // Short cut + if (1 == _frac) { + this->send(buffer, allow_overwrite); + return; + } + size_t i=0, o=0; while (i 1) && (i= 1) && (i stop queue.")); - // and signal queue to stop - Queue::get().stop(); + signalEOS(); return; }