mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
Spectrum overlap fixes. Spectrum time and power zomming. Implements #779
This commit is contained in:
parent
076a4f6306
commit
043a76faf8
@ -33,6 +33,8 @@
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(GLSpectrum::MsgReportSampleRate, Message)
|
||||
MESSAGE_CLASS_DEFINITION(GLSpectrum::MsgReportWaterfallShare, Message)
|
||||
MESSAGE_CLASS_DEFINITION(GLSpectrum::MsgReportFFTOverlap, Message)
|
||||
MESSAGE_CLASS_DEFINITION(GLSpectrum::MsgReportPowerScale, Message)
|
||||
|
||||
const float GLSpectrum::m_maxFrequencyZoom = 10.0f;
|
||||
|
||||
@ -1315,20 +1317,20 @@ void GLSpectrum::applyChanges()
|
||||
m_waterfallHeight = 0;
|
||||
}
|
||||
|
||||
if (!m_invertedWaterfall)
|
||||
{
|
||||
waterfallTop = m_topMargin;
|
||||
frequencyScaleTop = waterfallTop + m_waterfallHeight + 1;
|
||||
histogramTop = waterfallTop + m_waterfallHeight + m_frequencyScaleHeight + 1;
|
||||
m_histogramHeight = height() - m_topMargin - m_waterfallHeight - m_frequencyScaleHeight - m_bottomMargin;
|
||||
}
|
||||
else
|
||||
if (m_invertedWaterfall)
|
||||
{
|
||||
histogramTop = m_topMargin;
|
||||
m_histogramHeight = height() - m_topMargin - m_waterfallHeight - m_frequencyScaleHeight - m_bottomMargin;
|
||||
waterfallTop = histogramTop + m_histogramHeight + m_frequencyScaleHeight + 1;
|
||||
frequencyScaleTop = histogramTop + m_histogramHeight + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
waterfallTop = m_topMargin;
|
||||
frequencyScaleTop = waterfallTop + m_waterfallHeight + 1;
|
||||
histogramTop = waterfallTop + m_waterfallHeight + m_frequencyScaleHeight + 1;
|
||||
m_histogramHeight = height() - m_topMargin - m_waterfallHeight - m_frequencyScaleHeight - m_bottomMargin;
|
||||
}
|
||||
|
||||
m_timeScale.setSize(m_waterfallHeight);
|
||||
|
||||
@ -1336,7 +1338,10 @@ void GLSpectrum::applyChanges()
|
||||
{
|
||||
float scaleDiv = ((float)m_sampleRate / (float)m_timingRate) * (m_ssbSpectrum ? 2 : 1);
|
||||
float halfFFTSize = m_fftSize / 2;
|
||||
scaleDiv *= halfFFTSize / (halfFFTSize - m_fftOverlap);
|
||||
|
||||
if (halfFFTSize > m_fftOverlap) {
|
||||
scaleDiv *= halfFFTSize / (halfFFTSize - m_fftOverlap);
|
||||
}
|
||||
|
||||
if (!m_invertedWaterfall) {
|
||||
m_timeScale.setRange(m_timingRate > 1 ? Unit::TimeHMS : Unit::Time, (m_waterfallHeight * m_fftSize) / scaleDiv, 0);
|
||||
@ -1437,7 +1442,10 @@ void GLSpectrum::applyChanges()
|
||||
{
|
||||
float scaleDiv = ((float)m_sampleRate / (float)m_timingRate) * (m_ssbSpectrum ? 2 : 1);
|
||||
float halfFFTSize = m_fftSize / 2;
|
||||
scaleDiv *= halfFFTSize / (halfFFTSize - m_fftOverlap);
|
||||
|
||||
if (halfFFTSize > m_fftOverlap) {
|
||||
scaleDiv *= halfFFTSize / (halfFFTSize - m_fftOverlap);
|
||||
}
|
||||
|
||||
if (!m_invertedWaterfall) {
|
||||
m_timeScale.setRange(m_timingRate > 1 ? Unit::TimeHMS : Unit::Time, (m_waterfallHeight * m_fftSize) / scaleDiv, 0);
|
||||
@ -2278,7 +2286,7 @@ void GLSpectrum::wheelEvent(QWheelEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void GLSpectrum::frequencyZoom(QWheelEvent *event)
|
||||
void GLSpectrum::zoom(QWheelEvent *event)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
const QPointF& p = event->position();
|
||||
@ -2286,30 +2294,63 @@ void GLSpectrum::frequencyZoom(QWheelEvent *event)
|
||||
const QPointF& p = event->pos();
|
||||
#endif
|
||||
|
||||
if (event->delta() > 0) // zoom in
|
||||
float pwx = (p.x() - m_leftMargin) / (width() - m_leftMargin - m_rightMargin); // x position in window
|
||||
|
||||
if ((pwx >= 0.0f) && (pwx <= 1.0f))
|
||||
{
|
||||
if (m_frequencyZoomFactor < m_maxFrequencyZoom) {
|
||||
m_frequencyZoomFactor += 0.5f;
|
||||
} else {
|
||||
return;
|
||||
if (event->delta() > 0) // zoom in
|
||||
{
|
||||
if (m_frequencyZoomFactor < m_maxFrequencyZoom) {
|
||||
m_frequencyZoomFactor += 0.5f;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_frequencyZoomFactor > 1.0f) {
|
||||
m_frequencyZoomFactor -= 0.5f;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
frequencyZoom(pwx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_frequencyZoomFactor > 1.0f) {
|
||||
m_frequencyZoomFactor -= 0.5f;
|
||||
} else {
|
||||
return;
|
||||
float pwyh, pwyw;
|
||||
|
||||
if (m_invertedWaterfall) // histo on top
|
||||
{
|
||||
pwyh = (p.y() - m_topMargin) / m_histogramHeight;
|
||||
pwyw = (p.y() - m_topMargin - m_histogramHeight - m_frequencyScaleHeight) / m_waterfallHeight;
|
||||
}
|
||||
else // waterfall on top
|
||||
{
|
||||
pwyw = (p.y() - m_topMargin) / m_waterfallHeight;
|
||||
pwyh = (p.y() - m_topMargin - m_waterfallHeight - m_frequencyScaleHeight) / m_histogramHeight;
|
||||
}
|
||||
|
||||
//qDebug("GLSpectrum::zoom: pwyh: %f pwyw: %f", pwyh, pwyw);
|
||||
|
||||
if ((pwyw >= 0.0f) && (pwyw <= 1.0f)) {
|
||||
timeZoom(event->delta() > 0);
|
||||
}
|
||||
|
||||
if ((pwyh >= 0.0f) && (pwyh <= 1.0f) && !m_linear) {
|
||||
powerZoom(pwyh, event->delta() > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float pw = (p.x() - m_leftMargin) / (width() - m_leftMargin - m_rightMargin); // position in window
|
||||
pw = pw < 0.0f ? 0.0f : pw > 1.0f ? 1.0 : pw;
|
||||
void GLSpectrum::frequencyZoom(float pw)
|
||||
{
|
||||
m_frequencyZoomPos += (pw - 0.5f) * (1.0f / m_frequencyZoomFactor);
|
||||
float lim = 0.5f / m_frequencyZoomFactor;
|
||||
m_frequencyZoomPos = m_frequencyZoomPos < lim ? lim : m_frequencyZoomPos > 1 - lim ? 1 - lim : m_frequencyZoomPos;
|
||||
|
||||
qDebug("GLSpectrum::spectrumZoom: pw: %f p: %f z: %f", pw, m_frequencyZoomPos, m_frequencyZoomFactor);
|
||||
qDebug("GLSpectrum::frequencyZoom: pw: %f p: %f z: %f", pw, m_frequencyZoomPos, m_frequencyZoomFactor);
|
||||
updateFFTLimits();
|
||||
}
|
||||
|
||||
@ -2331,6 +2372,47 @@ void GLSpectrum::frequencyPan(QMouseEvent *event)
|
||||
updateFFTLimits();
|
||||
}
|
||||
|
||||
void GLSpectrum::timeZoom(bool zoomInElseOut)
|
||||
{
|
||||
if ((m_fftOverlap == 0) && !zoomInElseOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (zoomInElseOut && (m_fftOverlap == m_fftSize/2 - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_fftOverlap = m_fftOverlap + (zoomInElseOut ? 1 : -1);
|
||||
m_changesPending = true;
|
||||
|
||||
if (m_messageQueueToGUI)
|
||||
{
|
||||
MsgReportFFTOverlap *msg = new MsgReportFFTOverlap(m_fftOverlap);
|
||||
m_messageQueueToGUI->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void GLSpectrum::powerZoom(float pw, bool zoomInElseOut)
|
||||
{
|
||||
m_powerRange = m_powerRange + (zoomInElseOut ? -2 : 2);
|
||||
|
||||
if (pw > 2.0/3.0) { // bottom
|
||||
m_referenceLevel = m_referenceLevel + (zoomInElseOut ? -2 : 2);
|
||||
} else if (pw > 1.0/3.0) { // middle
|
||||
m_referenceLevel = m_referenceLevel + (zoomInElseOut ? -1 : 1);
|
||||
} // top
|
||||
|
||||
m_powerRange = m_powerRange < 1 ? 1 : m_powerRange > 100 ? 100 : m_powerRange;
|
||||
m_referenceLevel = m_referenceLevel < -110 ? -110 : m_referenceLevel > 0 ? 0 : m_referenceLevel;
|
||||
m_changesPending = true;
|
||||
|
||||
if (m_messageQueueToGUI)
|
||||
{
|
||||
MsgReportPowerScale *msg = new MsgReportPowerScale(m_referenceLevel, m_powerRange);
|
||||
m_messageQueueToGUI->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void GLSpectrum::resetFrequencyZoom()
|
||||
{
|
||||
m_frequencyZoomFactor = 1.0f;
|
||||
@ -2421,7 +2503,7 @@ void GLSpectrum::channelMarkerMove(QWheelEvent *event, int mul)
|
||||
}
|
||||
}
|
||||
|
||||
frequencyZoom(event);
|
||||
zoom(event);
|
||||
}
|
||||
|
||||
void GLSpectrum::enterEvent(QEvent* event)
|
||||
|
@ -75,6 +75,39 @@ public:
|
||||
Real m_waterfallShare;
|
||||
};
|
||||
|
||||
class MsgReportFFTOverlap : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
MsgReportFFTOverlap(int overlap) :
|
||||
Message(),
|
||||
m_overlap(overlap)
|
||||
{}
|
||||
|
||||
int getOverlap() const { return m_overlap; }
|
||||
|
||||
private:
|
||||
int m_overlap;
|
||||
};
|
||||
|
||||
class MsgReportPowerScale : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
MsgReportPowerScale(int refLevel, int range) :
|
||||
Message(),
|
||||
m_refLevel(refLevel),
|
||||
m_range(range)
|
||||
{}
|
||||
|
||||
Real getRefLevel() const { return m_refLevel; }
|
||||
Real getRange() const { return m_range; }
|
||||
|
||||
private:
|
||||
Real m_refLevel;
|
||||
Real m_range;
|
||||
};
|
||||
|
||||
GLSpectrum(QWidget* parent = nullptr);
|
||||
virtual ~GLSpectrum();
|
||||
|
||||
@ -349,8 +382,11 @@ private:
|
||||
void mouseReleaseEvent(QMouseEvent* event);
|
||||
void wheelEvent(QWheelEvent*);
|
||||
void channelMarkerMove(QWheelEvent*, int mul);
|
||||
void frequencyZoom(QWheelEvent*);
|
||||
void zoom(QWheelEvent*);
|
||||
void frequencyZoom(float pw);
|
||||
void frequencyPan(QMouseEvent*);
|
||||
void timeZoom(bool zoomInElseOut);
|
||||
void powerZoom(float pw, bool zoomInElseOut);
|
||||
void resetFrequencyZoom();
|
||||
void updateFFTLimits();
|
||||
void setFrequencyScale();
|
||||
|
@ -630,6 +630,29 @@ bool GLSpectrumGUI::handleMessage(const Message& message)
|
||||
{
|
||||
const GLSpectrum::MsgReportWaterfallShare& report = (const GLSpectrum::MsgReportWaterfallShare&) message;
|
||||
m_settings.m_waterfallShare = report.getWaterfallShare();
|
||||
return true;
|
||||
}
|
||||
else if (GLSpectrum::MsgReportFFTOverlap::match(message))
|
||||
{
|
||||
const GLSpectrum::MsgReportFFTOverlap& report = (const GLSpectrum::MsgReportFFTOverlap&) message;
|
||||
m_settings.m_fftOverlap = report.getOverlap();
|
||||
ui->fftOverlap->blockSignals(true);
|
||||
ui->fftOverlap->setValue(m_settings.m_fftOverlap);
|
||||
ui->fftOverlap->blockSignals(false);
|
||||
return true;
|
||||
}
|
||||
else if (GLSpectrum::MsgReportPowerScale::match(message))
|
||||
{
|
||||
const GLSpectrum::MsgReportPowerScale& report = (const GLSpectrum::MsgReportPowerScale&) message;
|
||||
m_settings.m_refLevel = report.getRefLevel();
|
||||
m_settings.m_powerRange = report.getRange();
|
||||
ui->refLevel->blockSignals(true);
|
||||
ui->levelRange->blockSignals(true);
|
||||
ui->refLevel->setValue(m_settings.m_refLevel);
|
||||
ui->levelRange->setValue(m_settings.m_powerRange);
|
||||
ui->levelRange->blockSignals(false);
|
||||
ui->refLevel->blockSignals(false);
|
||||
return true;
|
||||
}
|
||||
else if (SpectrumVis::MsgStartStop::match(message))
|
||||
{
|
||||
|
@ -973,15 +973,31 @@ Any change in the spectrum settings is not reflected in the markers. You have to
|
||||
|
||||
<h4>Mouse scroll wheel</h4>
|
||||
|
||||
<h5>Channel moving</h5>
|
||||
|
||||
When the mouse is over the center line of a channel:
|
||||
|
||||
- scrolling will move the channel by +/- 10 Hz at each scroll up/down respectively
|
||||
- combined with Ctrl it will move the channel by +/- 100 Hz
|
||||
- combined with Shift it will move the channel by +/- 1 kHz
|
||||
|
||||
When the mouse is not over the center line of a channel it will zoom in/out along X (frequency) axis by a 0.5 step at each scroll up/down respectively between 1x (no zoom) and 10x. Note that in order to zoom on the center line of a channel you may move the mouse pointer in the top margin (center line moving is not active there but zooming is).
|
||||
<h5>Frequency zooming</h5>
|
||||
|
||||
When zooming is active use Alt + left click to move the center frequency to the clicked point.
|
||||
When the mouse is in the spectrum area but not over the center line of a channel it will zoom in/out along X (frequency) axis by a 0.5 step at each scroll up/down respectively between 1x (no zoom) and 10x. Note that in order to zoom on the center line of a channel you may move the mouse pointer in the top margin (center line moving is not active there but zooming is).
|
||||
|
||||
When frequency zooming is active use Alt + left click to move the center frequency to the clicked point.
|
||||
|
||||
<h5>Power zooming</h5>
|
||||
|
||||
When the mouse is inside the power scale (spectrum) the power range is decreased by 2 (zoom in) or increased by 2 (zoom in) at each wheel step forward or backward respectively. The behavior of the reference level depends on where in the scale is the mouse pointer:
|
||||
|
||||
- in the top third: the reference level is maintained thus the reference level at the top stays the same
|
||||
- in the middle third: the reference level is decreased by 1 (zoom in) or increased by 1 (zoom out) at each wheel step forward or backward thus the level in the middle stays the same
|
||||
- in the bottom third: the reference level is decreased by 2 (zoom in) or increased by 2 (zoom out) at each wheel step forward or backward thus the level at the bottom stays the same
|
||||
|
||||
<h5>Time zooming</h5>
|
||||
|
||||
When the mouse is inside the time scale (waterfall) the overlap is increased by 1 (zoom in) or decreased by 1 (zoom out) at each wheel step forward or backward respectively. Overlap is bounded by 0 and half of the FFT size minus one.
|
||||
|
||||
<h3>7. Status</h3>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user