commit no. 7

This commit is contained in:
2026-03-25 19:48:24 +01:00
parent cf397eaa2d
commit 7b9a87fbc0
8 changed files with 628 additions and 274 deletions

View File

@@ -13,16 +13,44 @@ static double binToFreqHelper(int bin, double sampleRate, bool isIQ, int fftSize
}
}
void Cursors::pushAvg(AvgState& st, float dB, int bin) const {
// Reset if cursor moved to a different bin or averaging was reduced.
if (bin != st.lastBin) {
st.samples.clear();
st.sum = 0.0;
st.lastBin = bin;
}
st.samples.push_back(dB);
st.sum += dB;
int maxN = std::max(1, avgCount);
while (static_cast<int>(st.samples.size()) > maxN) {
st.sum -= st.samples.front();
st.samples.pop_front();
}
}
float Cursors::avgDBA() const {
return avgA_.samples.empty() ? cursorA.dB
: static_cast<float>(avgA_.sum / avgA_.samples.size());
}
float Cursors::avgDBB() const {
return avgB_.samples.empty() ? cursorB.dB
: static_cast<float>(avgB_.sum / avgB_.samples.size());
}
void Cursors::update(const std::vector<float>& spectrumDB,
double sampleRate, bool isIQ, int fftSize) {
// Update dB values at cursor bin positions
if (cursorA.active && cursorA.bin >= 0 &&
cursorA.bin < static_cast<int>(spectrumDB.size())) {
cursorA.dB = spectrumDB[cursorA.bin];
pushAvg(avgA_, cursorA.dB, cursorA.bin);
}
if (cursorB.active && cursorB.bin >= 0 &&
cursorB.bin < static_cast<int>(spectrumDB.size())) {
cursorB.dB = spectrumDB[cursorB.bin];
pushAvg(avgB_, cursorB.dB, cursorB.bin);
}
}
@@ -33,12 +61,12 @@ void Cursors::draw(const SpectrumDisplay& specDisplay,
float viewLo, float viewHi) const {
ImDrawList* dl = ImGui::GetWindowDrawList();
auto drawCursor = [&](const CursorInfo& c, ImU32 color, const char* label) {
auto drawCursor = [&](const CursorInfo& c, float dispDB, ImU32 color, const char* label) {
if (!c.active) return;
float x = specDisplay.freqToScreenX(c.freq, posX, sizeX,
sampleRate, isIQ, freqScale,
viewLo, viewHi);
float dbNorm = (c.dB - minDB) / (maxDB - minDB);
float dbNorm = (dispDB - minDB) / (maxDB - minDB);
dbNorm = std::clamp(dbNorm, 0.0f, 1.0f);
float y = posY + sizeY * (1.0f - dbNorm);
@@ -53,13 +81,13 @@ void Cursors::draw(const SpectrumDisplay& specDisplay,
char buf[128];
if (std::abs(c.freq) >= 1e6)
std::snprintf(buf, sizeof(buf), "%s: %.6f MHz %.1f dB",
label, c.freq / 1e6, c.dB);
label, c.freq / 1e6, dispDB);
else if (std::abs(c.freq) >= 1e3)
std::snprintf(buf, sizeof(buf), "%s: %.3f kHz %.1f dB",
label, c.freq / 1e3, c.dB);
label, c.freq / 1e3, dispDB);
else
std::snprintf(buf, sizeof(buf), "%s: %.1f Hz %.1f dB",
label, c.freq, c.dB);
label, c.freq, dispDB);
ImVec2 textSize = ImGui::CalcTextSize(buf);
float tx = std::min(x + 8, posX + sizeX - textSize.x - 4);
@@ -69,76 +97,86 @@ void Cursors::draw(const SpectrumDisplay& specDisplay,
dl->AddText({tx, ty}, color, buf);
};
drawCursor(cursorA, IM_COL32(255, 255, 0, 220), "A");
drawCursor(cursorB, IM_COL32(0, 200, 255, 220), "B");
float aDB = avgDBA(), bDB = avgDBB();
drawCursor(cursorA, aDB, IM_COL32(255, 255, 0, 220), "A");
drawCursor(cursorB, bDB, IM_COL32(0, 200, 255, 220), "B");
// Delta display
// Delta display (two lines, column-aligned on '=')
if (showDelta && cursorA.active && cursorB.active) {
double dFreq = cursorB.freq - cursorA.freq;
float dDB = cursorB.dB - cursorA.dB;
char buf[128];
float dDB = bDB - aDB;
char val1[48], val2[48];
if (std::abs(dFreq) >= 1e6)
std::snprintf(buf, sizeof(buf), "dF=%.6f MHz dA=%.1f dB",
dFreq / 1e6, dDB);
std::snprintf(val1, sizeof(val1), "%.6f MHz", dFreq / 1e6);
else if (std::abs(dFreq) >= 1e3)
std::snprintf(buf, sizeof(buf), "dF=%.3f kHz dA=%.1f dB",
dFreq / 1e3, dDB);
std::snprintf(val1, sizeof(val1), "%.3f kHz", dFreq / 1e3);
else
std::snprintf(buf, sizeof(buf), "dF=%.1f Hz dA=%.1f dB",
dFreq, dDB);
std::snprintf(val1, sizeof(val1), "%.1f Hz", dFreq);
std::snprintf(val2, sizeof(val2), "%.1f dB", dDB);
ImVec2 textSize = ImGui::CalcTextSize(buf);
float tx = posX + sizeX - textSize.x - 8;
ImVec2 labelSz = ImGui::CalcTextSize("dF = ");
ImVec2 v1Sz = ImGui::CalcTextSize(val1);
ImVec2 v2Sz = ImGui::CalcTextSize(val2);
float valW = std::max(v1Sz.x, v2Sz.x);
float lineH = labelSz.y;
float totalW = labelSz.x + valW;
float tx = posX + sizeX - totalW - 8;
float ty = posY + 4;
dl->AddRectFilled({tx - 4, ty - 2}, {tx + textSize.x + 4, ty + textSize.y + 2},
IM_COL32(0, 0, 0, 200));
dl->AddText({tx, ty}, IM_COL32(255, 200, 100, 255), buf);
ImU32 col = IM_COL32(255, 200, 100, 255);
float eqX = tx + labelSz.x; // values start here (right of '= ')
dl->AddText({tx, ty}, col, "dF =");
dl->AddText({eqX + valW - v1Sz.x, ty}, col, val1);
dl->AddText({tx, ty + lineH + 2}, col, "dA =");
dl->AddText({eqX + valW - v2Sz.x, ty + lineH + 2}, col, val2);
}
// (Hover cursor line is drawn cross-panel by Application.)
}
void Cursors::drawPanel() const {
ImGui::Text("Cursors:");
ImGui::Separator();
auto showCursor = [](const char* label, const CursorInfo& c) {
void Cursors::drawPanel() {
auto showCursor = [](const char* label, const CursorInfo& c, float dispDB) {
if (!c.active) {
ImGui::Text("%s: (inactive)", label);
ImGui::TextDisabled("%s: --", label);
return;
}
if (std::abs(c.freq) >= 1e6)
ImGui::Text("%s: %.6f MHz, %.1f dB", label, c.freq / 1e6, c.dB);
ImGui::Text("%s: %.6f MHz, %.1f dB", label, c.freq / 1e6, dispDB);
else if (std::abs(c.freq) >= 1e3)
ImGui::Text("%s: %.3f kHz, %.1f dB", label, c.freq / 1e3, c.dB);
ImGui::Text("%s: %.3f kHz, %.1f dB", label, c.freq / 1e3, dispDB);
else
ImGui::Text("%s: %.1f Hz, %.1f dB", label, c.freq, c.dB);
ImGui::Text("%s: %.1f Hz, %.1f dB", label, c.freq, dispDB);
};
showCursor("A", cursorA);
showCursor("B", cursorB);
float aDB = avgDBA(), bDB = avgDBB();
showCursor("A", cursorA, aDB);
showCursor("B", cursorB, bDB);
if (cursorA.active && cursorB.active) {
double dF = cursorB.freq - cursorA.freq;
float dA = cursorB.dB - cursorA.dB;
ImGui::Separator();
float dA = bDB - aDB;
if (std::abs(dF) >= 1e6)
ImGui::Text("Delta: %.6f MHz, %.1f dB", dF / 1e6, dA);
ImGui::Text("D: %.6f MHz, %.1f dB", dF / 1e6, dA);
else if (std::abs(dF) >= 1e3)
ImGui::Text("Delta: %.3f kHz, %.1f dB", dF / 1e3, dA);
ImGui::Text("D: %.3f kHz, %.1f dB", dF / 1e3, dA);
else
ImGui::Text("Delta: %.1f Hz, %.1f dB", dF, dA);
ImGui::Text("D: %.1f Hz, %.1f dB", dF, dA);
}
if (hover.active) {
ImGui::Separator();
if (std::abs(hover.freq) >= 1e6)
ImGui::Text("Hover: %.6f MHz, %.1f dB", hover.freq / 1e6, hover.dB);
ImGui::TextDisabled("%.6f MHz, %.1f dB", hover.freq / 1e6, hover.dB);
else if (std::abs(hover.freq) >= 1e3)
ImGui::Text("Hover: %.3f kHz, %.1f dB", hover.freq / 1e3, hover.dB);
ImGui::TextDisabled("%.3f kHz, %.1f dB", hover.freq / 1e3, hover.dB);
else
ImGui::Text("Hover: %.1f Hz, %.1f dB", hover.freq, hover.dB);
ImGui::TextDisabled("%.1f Hz, %.1f dB", hover.freq, hover.dB);
}
// Averaging slider (logarithmic scale)
ImGui::SetNextItemWidth(-1);
ImGui::SliderInt("##avgcount", &avgCount, 1, 20000, avgCount == 1 ? "No avg" : "Avg: %d",
ImGuiSliderFlags_Logarithmic);
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Cursor averaging (samples)");
}
void Cursors::setCursorA(double freq, float dB, int bin) {