Skip to content
Open
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ list(APPEND inspectrum_sources
samplesource.cpp
spectrogramcontrols.cpp
spectrogramplot.cpp
symbolprogoutput.cpp
threshold.cpp
traceplot.cpp
tuner.cpp
Expand Down
28 changes: 18 additions & 10 deletions src/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Cursor::Cursor(Qt::Orientation orientation, Qt::CursorShape mouseCursorShape, QO

}

void Cursor::frozen(bool enable) {
isFrozen = enable;
}
int Cursor::fromPoint(QPoint point)
{
return (orientation == Qt::Vertical) ? point.x() : point.y();
Expand All @@ -39,17 +42,22 @@ bool Cursor::pointOverCursor(QPoint point)

bool Cursor::mouseEvent(QEvent::Type type, QMouseEvent event)
{
if (isFrozen) {
return false;
}
// If the mouse pointer moves over a cursor, display a resize pointer
if (pointOverCursor(event.pos()) && type != QEvent::Leave) {
if (!cursorOverrided) {
cursorOverrided = true;
QApplication::setOverrideCursor(QCursor(cursorShape));
}
// Restore pointer if it moves off the cursor, or leaves the widget
} else if (cursorOverrided) {
cursorOverrided = false;
QApplication::restoreOverrideCursor();
}
if (pointOverCursor(event.pos()) && type != QEvent::Leave) {
if (!cursorOverrided) {
cursorOverrided = true;
QApplication::setOverrideCursor(QCursor(cursorShape));
}

// Restore pointer if it moves off the cursor, or leaves the widget
} else if (cursorOverrided) {
cursorOverrided = false;
QApplication::restoreOverrideCursor();
}


// Start dragging on left mouse button press, if over a cursor
if (type == QEvent::MouseButtonPress) {
Expand Down
3 changes: 3 additions & 0 deletions src/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Cursor : public QObject
void setPos(int newPos);
bool mouseEvent(QEvent::Type type, QMouseEvent event);

void frozen(bool enable);

signals:
void posChanged();

Expand All @@ -45,5 +47,6 @@ class Cursor : public QObject
Qt::CursorShape cursorShape;
bool dragging = false;
bool cursorOverrided = false;
bool isFrozen = false;
int cursorPosition = 0;
};
5 changes: 5 additions & 0 deletions src/cursors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ Cursors::Cursors(QObject * parent) : QObject::QObject(parent)
connect(maxCursor, &Cursor::posChanged, this, &Cursors::cursorMoved);
}

void Cursors::frozen(bool enable) {
minCursor->frozen(enable);
maxCursor->frozen(enable);
}

void Cursors::cursorMoved()
{
// Swap cursors if one has been dragged past the other
Expand Down
3 changes: 3 additions & 0 deletions src/cursors.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class Cursors : public QObject
void setSegments(int segments);
void setSelection(range_t<int> selection);

void frozen(bool enable);


public slots:
void cursorMoved();

Expand Down
42 changes: 41 additions & 1 deletion src/frequencydemod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "frequencydemod.h"
#include <liquid/liquid.h>
#include "util.h"
#include <QSettings>


FrequencyDemod::FrequencyDemod(std::shared_ptr<SampleSource<std::complex<float>>> src) : SampleBuffer(src)
{
Expand All @@ -28,11 +30,49 @@ FrequencyDemod::FrequencyDemod(std::shared_ptr<SampleSource<std::complex<float>>

void FrequencyDemod::work(void *input, void *output, int count, size_t sampleid)
{
double power_window[10];
unsigned int window_size = 10;
unsigned int window_index = 0;
double power_sum = 0.0f;
double avg_power = 0.0f;

auto in = static_cast<std::complex<float>*>(input);
auto out = static_cast<float*>(output);
freqdem fdem = freqdem_create(relativeBandwidth() / 2.0);

QSettings settings;
int sqval = settings.value("Squelch", 0).toInt();
double squelch_threshold = pow(2, sqval+2); // 100.0 * settings.value("Squelch", 0).toInt();
bool using_squelch = sqval ? true : false;

if (using_squelch) {
// Initialize power window
for (unsigned int i = 0; i < window_size; i++) {
power_window[i] = 0.0f;
}
}


for (int i = 0; i < count; i++) {
freqdem_demodulate(fdem, in[i], &out[i]);

if (using_squelch) {
double power = in[i].real() * in[i].real()
+ in[i].imag() * in[i].imag();
// Update power averaging window
power_sum -= power_window[window_index]; // Subtract oldest power
power_window[window_index] = power; // Add new power
power_sum += power; // Update sum
window_index = (window_index + 1) % window_size; // Circular buffer index
// Compute average power
avg_power = power_sum / window_size;
}
// Check if average power exceeds squelch threshold

if ( (!using_squelch) || (avg_power > squelch_threshold)) {
freqdem_demodulate(fdem, in[i], &out[i]);
} else {
out[i] = 0;
}
}
freqdem_destroy(fdem);
}
10 changes: 10 additions & 0 deletions src/inputsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,16 @@ double InputSource::rate()
return sampleRate;
}

void InputSource::setCenterFrequency(double freq)
{
centerFreq = freq;
invalidate();
}

double InputSource::centerFrequency()
{
return centerFreq;
}
std::unique_ptr<std::complex<float>[]> InputSource::getSamples(size_t start, size_t length)
{
if (inputFile == nullptr)
Expand Down
3 changes: 3 additions & 0 deletions src/inputsource.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class InputSource : public SampleSource<std::complex<float>>
QFile *inputFile = nullptr;
size_t sampleCount = 0;
double sampleRate = 0.0;
double centerFreq = 0.0;
uchar *mmapData = nullptr;
std::unique_ptr<SampleAdapter> sampleAdapter;
std::string _fmt;
Expand All @@ -54,8 +55,10 @@ class InputSource : public SampleSource<std::complex<float>>
return sampleCount;
};
void setSampleRate(double rate);
void setCenterFrequency(double freq);
void setFormat(std::string fmt);
double rate();
double centerFrequency();
bool realSignal() {
return _realSignal;
};
Expand Down
17 changes: 16 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ int main(int argc, char *argv[])
QCoreApplication::translate("main", "fmt"));
parser.addOption(formatOption);

QCommandLineOption centerFreqOption(QStringList() << "c" << "centerfreq",
QCoreApplication::translate("main", "Set center frequency."),
QCoreApplication::translate("main", "Hz"));
parser.addOption(centerFreqOption);

// Process the actual command line
parser.process(a);

Expand All @@ -57,8 +62,8 @@ int main(int argc, char *argv[])
if (args.size()>=1)
mainWin.openFile(args.at(0));

bool ok;
if (parser.isSet(rateOption)) {
bool ok;
auto rate = parser.value(rateOption).toDouble(&ok);
if(!ok) {
fputs("ERROR: could not parse rate\n", stderr);
Expand All @@ -67,6 +72,16 @@ int main(int argc, char *argv[])
mainWin.setSampleRate(rate);
}


if (parser.isSet(centerFreqOption)) {
auto centerfreq = parser.value(centerFreqOption).toDouble(&ok);
if(!ok) {
fputs("ERROR: could not parse center frequency\n", stderr);
return 1;
}
mainWin.setCenterFrequency(centerfreq);
}

mainWin.show();
return a.exec();
}
48 changes: 48 additions & 0 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@ MainWindow::MainWindow()

// Connect dock inputs
connect(dock, &SpectrogramControls::openFile, this, &MainWindow::openFile);

connect(dock->sampleRate, static_cast<void (QLineEdit::*)(const QString&)>(&QLineEdit::textChanged), this, static_cast<void (MainWindow::*)(QString)>(&MainWindow::setSampleRate));
connect(dock->centerFrequency, static_cast<void (QLineEdit::*)(const QString&)>(&QLineEdit::textChanged), this, static_cast<void (MainWindow::*)(QString)>(&MainWindow::setCenterFrequency));
connect(dock, static_cast<void (SpectrogramControls::*)(int, int)>(&SpectrogramControls::fftOrZoomChanged), plots, &PlotView::setFFTAndZoom);
connect(dock->powerMaxSlider, &QSlider::valueChanged, plots, &PlotView::setPowerMax);
connect(dock->powerMinSlider, &QSlider::valueChanged, plots, &PlotView::setPowerMin);
connect(dock->squelchSlider, &QSlider::valueChanged, plots, &PlotView::setSquelch);
connect(dock->cursorsCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableCursors);
connect(dock->cursorsFreezeCheckBox, &QCheckBox::stateChanged, plots, &PlotView::freezeCursors);
connect(dock->scalesCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableScales);
connect(dock->annosCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableAnnotations);
connect(dock->annosCheckBox, &QCheckBox::stateChanged, dock, &SpectrogramControls::enableAnnotations);
Expand All @@ -59,6 +63,9 @@ MainWindow::MainWindow()
connect(plots, &PlotView::timeSelectionChanged, dock, &SpectrogramControls::timeSelectionChanged);
connect(plots, &PlotView::zoomIn, dock, &SpectrogramControls::zoomIn);
connect(plots, &PlotView::zoomOut, dock, &SpectrogramControls::zoomOut);
connect(plots, &PlotView::coordinateClick, dock, &SpectrogramControls::coordinateClick);

void coordinateClick(double time_position, double frequency);

// Set defaults after making connections so everything is in sync
dock->setDefaults();
Expand Down Expand Up @@ -87,6 +94,14 @@ void MainWindow::openFile(QString fileName)
if (!ss.fail()) {
setSampleRate(rate);
}


std::stringstream ssfreq(centerfreq.toUtf8().constData());
double freq;
ssfreq >> freq;
if (!ssfreq.fail()) {
setCenterFrequency(freq);
}
}

try
Expand All @@ -100,9 +115,26 @@ void MainWindow::openFile(QString fileName)
}
}

void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_C:
dock->cursorsCheckBox->setChecked(! plots->cursorsAreEnabled());
break;
case Qt::Key_W:
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
QApplication::closeAllWindows();
}
break;

default:
QMainWindow::keyPressEvent(event); // Pass to base class
}
}

void MainWindow::invalidateEvent()
{
plots->setSampleRate(input->rate());
plots->setCenterFrequency(input->centerFrequency());

// Only update the text box if it is not already representing
// the current value. Otherwise the cursor might jump or the
Expand All @@ -129,6 +161,22 @@ void MainWindow::setSampleRate(double rate)
dock->sampleRate->setText(QString::number(rate));
}

void MainWindow::setCenterFrequency(QString freq)
{
auto centerFreq = freq.toDouble();
input->setCenterFrequency(centerFreq);
plots->setCenterFrequency(centerFreq);

// Save the sample rate in settings as we're likely to be opening the same file across multiple runs
QSettings settings;
settings.setValue("CenterFrequency", centerFreq);
}

void MainWindow::setCenterFrequency(double freq)
{
dock->centerFrequency->setText(QString::number(freq));
}

void MainWindow::setFormat(QString fmt)
{
input->setFormat(fmt.toUtf8().constData());
Expand Down
3 changes: 3 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ class MainWindow : public QMainWindow, Subscriber
public:
MainWindow();
void changeSampleRate(double rate);
void keyPressEvent(QKeyEvent *event) override;

public slots:
void openFile(QString fileName);
void setSampleRate(QString rate);
void setSampleRate(double rate);
void setCenterFrequency(QString centerfreq);
void setCenterFrequency(double centerfreq);
void setFormat(QString fmt);
void invalidateEvent() override;

Expand Down
Loading