Skip to content

Conversation

demvlad
Copy link
Contributor

@demvlad demvlad commented Jul 16, 2025

This is solution for quick comparison of PSD spectrums for one log file data, without using of Export/Import data to external file.
How to do this:

  1. Select some curve to draw PSD spectrum chart
  2. Press Insert key or "Add" to add current PSD spectrum into "imported" data list and show it as imported curve
  3. Select other curve to draw it spectrum. As result this spectrum is showed as main and previous spectrum is showed as imported
  4. Repeate actions p.2-3 to show spectrums count what you need.

The Export/Import buttons uses for multiple log files data comparison.
one_log_comarison

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added the ability to import the current spectrum PSD curve as a new curve.
    • Users can add custom curves, retrieve specific curves, remove individual or all curves, and check for duplicate curve names when managing imported data.
    • Introduced multi-spectrum support with methods to detect and manage multiple imported spectra.
    • Added color cycling for imported curves and enhanced curve legend display.
  • Improvements

    • Enhanced legend display with improved vertical alignment and curve color cycling.
    • Updated spectrum comparison controls with shorter button labels and dynamic visibility of the "Add" button.
    • Improved CSV parsing by trimming whitespace from headers and data values.
    • Added Ctrl key support to legend selection and spectrum analyser visibility for finer user control.
    • Enabled Ctrl key functionality to toggle spectrum analyser visibility and import behavior for enhanced user experience.

Copy link

coderabbitai bot commented Jul 16, 2025

## Walkthrough

This change refactors the `ImportedCurves` module to encapsulate curve data privately and adds methods for curve access and mutation. It introduces functionality to add the current power spectral density (PSD) spectrum as an imported curve, updates legend rendering, and adds UI and keyboard shortcuts to trigger spectrum import. Additionally, it enhances spectrum plotting and analyser toggling logic to support multi-spectrum handling and Ctrl-key modifiers.

## Changes

| File(s)                      | Change Summary                                                                                                 |
|-----------------------------|---------------------------------------------------------------------------------------------------------------|
| src/graph_imported_curves.js | Encapsulated `_curvesData` as private; added `getCurve(index)`, `addCurve(points, name)`, `isNewCurve(name)`, `removeCurve(name)`, `removeAllCurves()`, `isFull()`, and `isEmpty()` methods; improved CSV parsing with trimming; increased max import count from 5 to 6.   |
| src/graph_spectrum.js        | Added `prepareSpectrumForComparison()`, `shouldAddCurrentSpectrumBeforeReload()`, and `isMultiSpectrum()` methods; updated `plotSpectrum` to conditionally add spectrum to import and manage reload logic; toggled "Add" button visibility by spectrum type.      |
| src/graph_spectrum_plot.js   | Added `getCurveColor(index)`, `addCurrentSpectrumIntoImport()`, `isNewComparedCurve(name)`, `removeComparedCurve(name)`, `isMultiSpectrum()`, and `isImportedCurvesMaxCount()` methods; replaced direct curve data access with `getCurve()` calls; updated legend rendering and curve color usage; added logic to add current PSD spectrum on import if none present; improved drawing and legend text alignment. |
| src/main.js                  | Modified `onLegendSelectionChange` to accept `ctrlKey`; updated analyser toggle logic to respect Ctrl key; minor whitespace fixes in video export dialog callback.       |
| index.html                   | Shortened spectrum comparison button labels ("Export" to "Exp", "Import" to "Imp", "Clear" to "Clr"); no new buttons added.                       |
| src/graph_legend.js          | Modified legend selection callback to pass Ctrl key state along with selection change status.                           |
| src/grapher.js               | Updated `setDrawAnalyser` to accept `ctrlKey` parameter and call `prepareSpectrumForComparison()` accordingly; added `hasMultiSpectrumAnalyser()` method. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant MainJS
    participant FlightLogAnalyser
    participant GraphSpectrumPlot
    participant ImportedCurves

    User->>MainJS: Press Insert key or click "Add" button
    MainJS->>FlightLogAnalyser: prepareSpectrumForComparison()
    FlightLogAnalyser->>GraphSpectrumPlot: addCurrentSpectrumIntoImport()
    GraphSpectrumPlot->>ImportedCurves: addCurve(points, name) (if new PSD curve)
    ImportedCurves-->>GraphSpectrumPlot: Curve added and callback triggered

Estimated code review effort

3 (30–60 minutes)

Possibly related PRs

Suggested reviewers

  • haslinghuis
  • nerdCopter

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1044f5b78447bedbf52c8cb55d8b75e279245c60 and f3157a35a59cd795c9ae459fec5894896eda2e4b.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/graph_imported_curves.js` (1 hunks)
* `src/graph_spectrum.js` (5 hunks)

</details>

<details>
<summary>🧠 Learnings (2)</summary>

<details>
<summary>📓 Common learnings</summary>

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-22T17:54:03.594Z
Learning: In betaflight/blackbox-log-viewer, the user implemented Ctrl+click functionality for PSD spectrum comparison where simple mouse clicks clear all imported spectra and Ctrl+click adds spectra for comparison, making the Add button and Insert key largely redundant. The main curve is automatically added to imported list when selecting a second curve for comparison.


Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.


Learnt from: nerdCopter
PR: #822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using pull_request_target without specifying persist-credentials: false in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.


Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.


Learnt from: demvlad
PR: #833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions dataLoadPowerSpectralDensityVsThrottle() and dataLoadPowerSpectralDensityVsRpm() instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.


</details>
<details>
<summary>src/graph_imported_curves.js (4)</summary>

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.

Learnt from: haslinghuis
PR: betaflight/blackbox-log-viewer#820
File: src/graph_spectrum_calc.js:557-557
Timestamp: 2025-05-05T19:23:29.970Z
Learning: In JavaScript object literals, include trailing commas even on the last property for better maintainability and cleaner diffs when new properties are added later.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.

</details>

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* src/graph_spectrum.js

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (2)</summary>

<details>
<summary>📓 Common learnings</summary>

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-22T17:54:03.594Z
Learning: In betaflight/blackbox-log-viewer, the user implemented Ctrl+click functionality for PSD spectrum comparison where simple mouse clicks clear all imported spectra and Ctrl+click adds spectra for comparison, making the Add button and Insert key largely redundant. The main curve is automatically added to imported list when selecting a second curve for comparison.


Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.


Learnt from: nerdCopter
PR: #822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using pull_request_target without specifying persist-credentials: false in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.


Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.


Learnt from: demvlad
PR: #833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions dataLoadPowerSpectralDensityVsThrottle() and dataLoadPowerSpectralDensityVsRpm() instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.


</details>
<details>
<summary>src/graph_imported_curves.js (4)</summary>

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.

Learnt from: haslinghuis
PR: betaflight/blackbox-log-viewer#820
File: src/graph_spectrum_calc.js:557-557
Timestamp: 2025-05-05T19:23:29.970Z
Learning: In JavaScript object literals, include trailing commas even on the last property for better maintainability and cleaner diffs when new properties are added later.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>src/graph_imported_curves.js (8)</summary>

`2-3`: **Excellent encapsulation and documentation improvements.**

The change from public `this._curvesData` to private `_curvesData` improves data encapsulation. The descriptive comment for `MAX_IMPORT_COUNT` addresses previous feedback about magic numbers and clearly explains the constraint.

---

`14-20`: **Well-implemented accessor method with proper error handling.**

The `getCurve` method provides controlled access to the private `_curvesData` with appropriate bounds checking and informative error messages using `RangeError`.

---

`23-73`: **Good refactoring with improved CSV parsing robustness.**

The method correctly adapts to use private `_curvesData` while adding `.trim()` calls to handle whitespace in CSV headers and data values, improving parsing reliability.

---

`75-105`: **Well-designed helper functions for range calculations.**

The `getCurveRange` and `computeGlobalCurvesRange` functions provide clean separation of concerns for bound calculations, improving code maintainability and reusability.

---

`107-123`: **Excellent addition enabling programmatic curve addition.**

The `addCurve` method efficiently supports the core PR functionality of adding current PSD spectra to the comparison list, with proper bounds checking and range management.

---

`125-132`: **Proper duplicate checking with strict equality.**

The `isNewCurve` method correctly prevents duplicate curve names using strict equality comparison, supporting the uniqueness requirements for spectrum comparison.

---

`134-138`: **Well-named method with efficient array clearing.**

The renamed `removeAllCurves` method is more descriptive and efficiently clears all imported curves while properly maintaining global bounds consistency.

---

`140-157`: **Complete curve management API with intuitive methods.**

The `removeCurve`, `isFull`, and `isEmpty` methods provide a comprehensive and intuitive API for curve management, supporting the Ctrl+click removal functionality and clean state queries.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=betaflight/blackbox-log-viewer&utm_content=847):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
src/graph_spectrum_plot.js (1)

264-298: Improve the smoothing algorithm implementation.

The current moving average implementation has several issues:

  1. Fixed filter size of 200 points may be too large for curves with fewer points
  2. Inefficient recalculation of window bounds for each point
  3. The average is plotted at the current point rather than being properly centered

Consider this improved implementation:

-    const filterPointsCount = 200;
+    const filterPointsCount = Math.min(200, Math.floor(pointsCount * 0.1)); // Use 10% of points or 200, whichever is smaller
+    const halfWindow = Math.floor(filterPointsCount / 2);
+    
+    // Pre-calculate cumulative sum for efficient moving average
+    const cumulativeSum = [0];
+    for (let i = 0; i < pointsCount; i++) {
+      cumulativeSum[i + 1] = cumulativeSum[i] + curvesPonts[i].y;
+    }
+    
     for (let pointNum = 0; pointNum < pointsCount; pointNum++) {
-    // Apply moving average filter at spectrum points to get visible line
-      let filterStartPoint = pointNum - filterPointsCount / 2;
-      if (filterStartPoint < 0) {
-        filterStartPoint = 0;
-      }
-      let filterStopPoint = filterStartPoint + filterPointsCount;
-      if (filterStopPoint > pointsCount) {
-        filterStopPoint = pointsCount;
-        filterStartPoint = filterStopPoint - filterPointsCount;
-        if (filterStartPoint < 0) {
-          filterStartPoint = 0;
-        }
-      }
-      let middleValue = 0;
-      for (let i = filterStartPoint; i < filterStopPoint; i++) {
-        middleValue += curvesPonts[i].y;
-      }
-      middleValue /= filterPointsCount;
+      const filterStartPoint = Math.max(0, pointNum - halfWindow);
+      const filterStopPoint = Math.min(pointsCount, pointNum + halfWindow + 1);
+      const actualWindowSize = filterStopPoint - filterStartPoint;
+      const middleValue = (cumulativeSum[filterStopPoint] - cumulativeSum[filterStartPoint]) / actualWindowSize;

       canvasCtx.lineTo(curvesPonts[pointNum].x * scaleX, HEIGHT - middleValue * fftScale);
     }
🧹 Nitpick comments (3)
src/graph_imported_curves.js (1)

33-33: Consider browser compatibility for Array.at() method.

The at(-1) method is relatively new and may not be supported in older browsers. Consider using stringRows[stringRows.length - 1] for better compatibility.

-if (stringRows.at(-1) == "") {
+if (stringRows[stringRows.length - 1] == "") {
src/graph_spectrum.js (1)

428-439: Consider handling all spectrum types for consistent filename generation.

The method correctly handles FREQUENCY and POWER_SPECTRAL_DENSITY types, but doesn't provide suffixes for other spectrum types (FREQ_VS_THROTTLE, FREQ_VS_RPM, etc.).

Consider adding a default case or explicit handling for other spectrum types:

 this.getExportedFileName = function() {
   let fileName = $(".log-filename").text().split(".")[0];
   switch (userSettings.spectrumType) {
     case SPECTRUM_TYPE.FREQUENCY:
       fileName = fileName + "_sp";
       break;
     case SPECTRUM_TYPE.POWER_SPECTRAL_DENSITY:
       fileName = fileName + "_psd";
       break;
+    case SPECTRUM_TYPE.FREQ_VS_THROTTLE:
+      fileName = fileName + "_freq_throttle";
+      break;
+    case SPECTRUM_TYPE.FREQ_VS_RPM:
+      fileName = fileName + "_freq_rpm";
+      break;
+    case SPECTRUM_TYPE.PSD_VS_THROTTLE:
+      fileName = fileName + "_psd_throttle";
+      break;
+    case SPECTRUM_TYPE.PSD_VS_RPM:
+      fileName = fileName + "_psd_rpm";
+      break;
+    case SPECTRUM_TYPE.PIDERROR_VS_SETPOINT:
+      fileName = fileName + "_piderror";
+      break;
   }
   return fileName;
 };
src/graph_spectrum_plot.js (1)

1604-1644: Good enhancement to mouse position handling for PSD spectrums.

The differentiation between single PSD spectrum and multiple imported curves is well implemented. The addition of PSD heatmap value display improves user experience.

Consider extracting the complex condition for better readability:

-      if (this._spectrumType === SPECTRUM_TYPE.POWER_SPECTRAL_DENSITY && this._importedPSD.curvesCount() == 0) {  // single PSD spectrum
+      const isSinglePSDSpectrum = this._spectrumType === SPECTRUM_TYPE.POWER_SPECTRAL_DENSITY && this._importedPSD.curvesCount() == 0;
+      if (isSinglePSDSpectrum) {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fea0dc0 and 2a7b13e.

📒 Files selected for processing (8)
  • index.html (1 hunks)
  • public/js/webworkers/spectrum-export-worker.js (1 hunks)
  • src/graph_imported_curves.js (1 hunks)
  • src/graph_spectrum.js (2 hunks)
  • src/graph_spectrum_calc.js (1 hunks)
  • src/graph_spectrum_plot.js (38 hunks)
  • src/main.js (4 hunks)
  • src/user_settings_dialog.js (3 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
src/user_settings_dialog.js (1)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
src/graph_spectrum_calc.js (2)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
public/js/webworkers/spectrum-export-worker.js (5)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: Quick-Flash
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-13T17:48:20.477Z
Learning: When using FFT (Fast Fourier Transform), enforcing power-of-2 input lengths improves computational efficiency and numerical stability but can result in discarding up to almost 50% of the flight data in worst-case scenarios.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-14T08:52:53.032Z
Learning: The FFT.complex library in Betaflight Blackbox Log Viewer provides two main methods: simple(output, input, type) and process(output, outputOffset, outputStride, input, inputOffset, inputStride, type). The 'simple' method is the one currently used in the codebase, while 'process' offers more granular control over memory layout with offsets and strides.
src/main.js (3)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
src/graph_imported_curves.js (1)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
src/graph_spectrum.js (2)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
src/graph_spectrum_plot.js (4)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
🧬 Code Graph Analysis (2)
src/main.js (1)
src/graph_spectrum.js (1)
  • fileName (429-429)
src/graph_spectrum_plot.js (1)
src/graph_imported_curves.js (1)
  • ImportedCurves (1-98)
🪛 ESLint
src/graph_imported_curves.js

[error] 79-80: Missing semicolon.

(semi)


[error] 88-89: Missing semicolon.

(semi)

🔇 Additional comments (19)
src/graph_spectrum_calc.js (1)

133-134: Naming consistency: rename remaining psdOutput property to fftOutput

One return object in src/graph_spectrum_calc.js still exposes the old property name. Update it so that every PSD‐related function returns fftLength and fftOutput.

• File: src/graph_spectrum_calc.js
– Locate the return block that currently reads:
js fftLength: psdLength, psdOutput: psdOutput,
– Change to:
diff fftLength: psdLength, - psdOutput: psdOutput, + fftOutput: psdOutput,

After this change, re-run:

rg "psdLength|psdOutput" --type js src/

to confirm no old property names remain.

⛔ Skipped due to learnings
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
Learnt from: Quick-Flash
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-13T17:48:20.477Z
Learning: When using FFT (Fast Fourier Transform), enforcing power-of-2 input lengths improves computational efficiency and numerical stability but can result in discarding up to almost 50% of the flight data in worst-case scenarios.
public/js/webworkers/spectrum-export-worker.js (3)

7-7: No internal CSV parsers depend on “freq”/“value” headers

We ran a global search for occurrences of the old headers and didn’t find any import routines that parse CSV by header name—only export workers reference the new headers “x” and “y.”

• public/js/webworkers/spectrum-export-worker.js – writes “x” + delimiter + “y”
• public/js/webworkers/csv-export-worker.js and related exporters – join columns by delimiter

Since there are no internal consumers of the old “freq”/“value” names, this change won’t break anything in the codebase. If you have external import workflows that expect “freq”/“value,” consider noting the header change in your release notes or docs.


8-11: Confirm the loop change is intentional

The export worker now outputs every FFT bin (index += 1) instead of stepping by 10, resulting in 10× more data points. This increases frequency resolution but also file size and may impact performance.

• File: public/js/webworkers/spectrum-export-worker.js
Lines 8–11:

for (let index = 0; index < spectrumDataLength; index++) {
  const frequency = frequencyStep * index;
  outText += frequency + columnDelimiter + fftOutput[index] + "\n";
}

Searches for “step 10” or “export resolution” turned up no related settings—please verify that emitting every index is desired and that downstream consumers and file size can handle the increased data.


4-4: Full-spectrum export is correct and aligns with current data shape

We’ve confirmed that fftData.fftOutput already contains only the one-sided magnitude array (returned by _normalizeFft), so exporting the full array length is the right move—dividing by 2 here would undercount your bins. The header rename to “x”/“y” also matches the GraphSpectrumPlot point properties, and stepping by 1 exports every frequency bin at full resolution (the UI plot likewise iterates every index).

Points of interest in public/js/webworkers/spectrum-export-worker.js:

  • const spectrumDataLength = fftOutput.length; (previously / 2)
  • const frequencyStep = 0.5 * event.data.blackBoxRate / spectrumDataLength;
  • let outText = "x" + columnDelimiter + "y" + "\n";
  • for (let index = 0; index < spectrumDataLength; index++) { … }

Note: if you have downstream CSV-import workflows that expected “freq”/“value” or sampled every 10th bin, you’ll need to update them to handle the new headers and full data.

index.html (1)

2992-3014: Persisted analyser-legend-* settings are handled correctly

The explicit selectors in src/user_settings_dialog.js map the three-part input names to the analyser_legend object, so no renaming or parser changes are needed:

• In src/user_settings_dialog.js, lines ~309–312 read
input[name="analyser-legend-top"]analyser_legend.top
input[name="analyser-legend-left"]analyser_legend.left
input[name="analyser-legend-width"]analyser_legend.width

• In the same file, lines ~663–669 restore those values back into the inputs.

Minor suggestion: add inputmode="numeric" to the three <input> elements in index.html for improved mobile UX.

src/main.js (3)

1152-1166: Good refactoring to centralize filename generation logic.

The removal of the file parameter and dynamic filename retrieval from graph.getAnalyser().getExportedFileName() improves encapsulation. The null check with early return and warning message provides good error handling for unsupported spectrum types.


1752-1752: Method name change improves consistency.

The rename from clearImportedSpectrums to removeImportedSpectrums provides better semantic clarity and aligns with the refactored spectrum management system.


2457-2462: Well-implemented keyboard shortcut addition.

The Insert key shortcut for adding current spectrum PSD curve into import list follows established patterns. The hasAnalyser condition check ensures the feature only works when appropriate, and the preventDefault() call is correctly placed.

src/user_settings_dialog.js (3)

234-238: Consistent addition of analyser legend settings.

The new analyser_legend settings group follows the established pattern of other UI element positioning settings. The default values (left: 88%, top: 7%, width: 10%) provide reasonable positioning for the legend.


309-313: Proper UI-to-settings conversion implementation.

The analyser legend settings conversion correctly follows the same pattern as other settings groups, reading from the appropriate input fields in the .analyser-settings section and applying percentage formatting.


663-671: Correct settings-to-UI synchronization.

The settings-to-UI population for analyser legend properties correctly extracts integer values from the percentage strings and populates the corresponding input fields, maintaining consistency with other settings groups.

src/graph_spectrum.js (4)

354-356: LGTM! Visibility logic properly updated for spectrum comparison.

The change correctly enables the spectrum comparison panel for both FREQUENCY and POWER_SPECTRAL_DENSITY spectrum types, aligning with the PR's objective of supporting PSD spectrum comparison.


420-422: Good refactoring to centralize CSV import logic.

The delegation to GraphSpectrumPlot.importCurvesFromCSV properly centralizes the CSV parsing logic, reducing code duplication. Error handling is maintained in the ImportedCurves class as seen in the relevant code snippets.


424-426: Consistent naming and delegation pattern.

The method correctly delegates to GraphSpectrumPlot.removeImportedCurves() and the rename from "clear" to "remove" better reflects the action being performed.


441-443: LGTM! Consistent delegation pattern.

The method correctly delegates to GraphSpectrumPlot.addCurrentSpectrumIntoImport() following the established pattern.

src/graph_spectrum_plot.js (4)

60-73: Well-structured initialization of imported curves management.

The initialization correctly creates two separate ImportedCurves instances for frequency and PSD spectrums with appropriate redraw callbacks. The color array properly matches the maximum import count of 5.


226-226: Excellent unification of frequency scaling calculations.

The introduction of MAXIMAL_PLOTTED_FREQUENCY constant and its consistent usage throughout the code improves maintainability and reduces the risk of calculation inconsistencies. The formula correctly represents the Nyquist frequency adjusted for zoom level.

Also applies to: 314-314, 330-330, 349-349, 400-400, 470-470, 506-506, 777-777


333-334: Correct implementation of PSD curve drawing.

The code properly includes imported PSD curves in the Y-axis range calculation and draws them without smoothing, which is appropriate for PSD data. The frequency limit check correctly prevents drawing beyond the visible range.

Also applies to: 369-384


1778-1818: Well-implemented curve management methods.

The three new methods correctly:

  1. Route imports to the appropriate ImportedCurves instance based on spectrum type
  2. Handle curve removal for both frequency and PSD types
  3. Generate PSD curve points with correct frequency calculations and duplicate checking

@demvlad demvlad marked this pull request as draft July 16, 2025 14:14
@demvlad demvlad force-pushed the psd_curves_multi_select branch from 2a7b13e to 7104be8 Compare July 16, 2025 15:34
coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 16, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 16, 2025

It works, but i want to add the button "Add" for this action and use shorter Buttons captions: "Imp", "Exp", instead of long Import, Export.

@demvlad demvlad marked this pull request as ready for review July 16, 2025 15:52
@haslinghuis haslinghuis added this to the 4.0.0 milestone Jul 16, 2025
haslinghuis
haslinghuis previously approved these changes Jul 16, 2025
Co-authored-by: Mark Haslinghuis <[email protected]>
@demvlad demvlad dismissed stale reviews from haslinghuis and coderabbitai[bot] via bade57d July 16, 2025 16:25
coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 16, 2025
haslinghuis
haslinghuis previously approved these changes Jul 16, 2025
@demvlad demvlad dismissed stale reviews from haslinghuis and coderabbitai[bot] via 0025b94 July 16, 2025 17:50
@demvlad
Copy link
Contributor Author

demvlad commented Jul 16, 2025

Added "Add" button, the Insert key works too.
The short spectrums buttons names are used.
New_PSD_buttons

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
index.html (3)

480-482: Add Bootstrap button classes for visual & functional consistency

All control buttons elsewhere in the toolbar carry the btn & btn-* classes to inherit sizing, spacing and theming.
Without them these three new buttons render unstyled and may miss hover/active states or custom themes.

-<button id="btn-spectrum-add" type="button" title="Add spectrum for comparison">Add</button>
-<button id="btn-spectrum-export" type="button" title="Export spectrum to CSV">Exp</button>
+<button id="btn-spectrum-add" class="btn btn-default" type="button" title="Add spectrum for comparison">Add</button>
+<button id="btn-spectrum-export" class="btn btn-default" type="button" title="Export spectrum to CSV">Exp</button>

Apply the same class="btn btn-default" to the “Imp” and “Clr” buttons as well.
This keeps the UI cohesive and avoids ad-hoc CSS overrides later.


482-483: Replace inline-JS with a delegated click handler

Inline onclick attributes are hard to lint, test and minify; the codebase already wires events in src/main.js.
Add an id (e.g. btn-spectrum-import-trigger) to the visible button and register the click listener in JS, forwarding to the hidden file input:

<button id="btn-spectrum-import-trigger" class="btn btn-default" type="button"
        title="Import spectrum from CSV">Imp</button>
<input type="file" id="btn-spectrum-import" accept=".csv" style="display:none" multiple />
// src/main.js (near other toolbar bindings)
$('#btn-spectrum-import-trigger').on('click', () => $('#btn-spectrum-import').click());

This keeps markup clean and centralises behaviour.


480-484: Provide explicit accessible names for abbreviated labels

Short captions (“Exp”, “Imp”, “Clr”) save space but are ambiguous to screen-reader users.
Add aria-label (or keep full text inside a visually-hidden span) so assistive tech announces meaningful actions:

-<button ... title="Export spectrum to CSV">Exp</button>
+<button ... aria-label="Export spectrum to CSV" title="Export spectrum to CSV">Exp</button>

Repeat for “Imp”, “Clr”, and “Add”.
Small change, big accessibility win.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bade57d and 0025b94.

📒 Files selected for processing (3)
  • index.html (1 hunks)
  • src/graph_spectrum_plot.js (4 hunks)
  • src/main.js (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main.js
  • src/graph_spectrum_plot.js
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
index.html (2)

undefined

<retrieved_learning>
Learnt from: demvlad
PR: #833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions dataLoadPowerSpectralDensityVsThrottle() and dataLoadPowerSpectralDensityVsRpm() instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
</retrieved_learning>

<retrieved_learning>
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
</retrieved_learning>

coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 16, 2025
haslinghuis
haslinghuis previously approved these changes Jul 16, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

Resolved issue:
The new Ctrl+Mouse click curves selection changed main spectrum curve when imported curves has maximal count (6). It showed main spectrum separately around other curves

haslinghuis
haslinghuis previously approved these changes Jul 23, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

The Ctrl+Mouse click by curves legend removes existing spectrum from comparison.
The notice: It possible to hide main spectrum curve from comparison, but it will show after clear the all spectrums again.
Because i can not compute other main curve by using current import data (its log indexes are unknown) after hide main curve by Ctrl+Mouse click.
It is working, but needs to test.

@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

@coderabbitai check last commits please.

Copy link

coderabbitai bot commented Jul 23, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the latest commits on this PR branch
git log --oneline -5

# Get detailed information about the most recent commits
git show --stat HEAD
echo "---"
git show --stat HEAD~1
echo "---"

# Get the actual changes from the latest commits
git show HEAD --name-only
echo "=== LATEST COMMIT CHANGES ==="
git show HEAD

echo "=== PREVIOUS COMMIT CHANGES ==="
git show HEAD~1

Length of output: 287845


@demvlad I've checked the latest commit, but the diff shows a full repository snapshot (likely after a squash or force-push), so incremental changes aren't visible. However, based on your recent comments and the PR objectives, here's what I can confirm:

  • Ctrl+Mouse click on the legend now removes an imported spectrum for comparison, matching the add behavior.
  • Main spectrum handling at max imported count is fixed: the main curve is always shown separately, even when imported curves reach the limit.
  • The overall Ctrl+click paradigm for adding/removing spectra is robust and intuitive.

These changes align perfectly with the requested UX and complete the feature set for single-log PSD spectrum comparison. If you want a line-by-line review of the new removal logic, let me know which file to focus on!

Great job—this is a well-executed and user-friendly implementation. 🐰


✏️ Learnings added
Learnt from: demvlad
URL: https://github.com/betaflight/blackbox-log-viewer/pull/847

Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-22T17:54:03.594Z
Learning: In betaflight/blackbox-log-viewer, the user implemented Ctrl+click functionality for PSD spectrum comparison where simple mouse clicks clear all imported spectra and Ctrl+click adds spectra for comparison, making the Add button and Insert key largely redundant. The main curve is automatically added to imported list when selecting a second curve for comparison.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

@mituritsyn
Copy link
Contributor

but it will show after clear the all spectrums again.
I think, we can live with a few tiny peculiarities.

@haslinghuis I have nothing else to add.

@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

Also I found a tiny style issue that is not related to the PR. I accidentally noticed that there are not visible controls with up down arrows in those fields))

@mituritsyn
The visible spin buttons are possible to do.
I was confusing some time while can not show its for PSD heatmap chart. Thank's @coderabbitai who shows me the css option for that.

Copy link

coderabbitai bot commented Jul 23, 2025

Tip

For best results, initiate chat on the files or code changes.

@demvlad You're very welcome! I'm glad the CSS guidance for making the numeric input spin buttons visible was helpful for your PSD heatmap implementation.

If you need any assistance with styling improvements in the future, feel free to ask. The numeric input controls can definitely be made more user-friendly with proper CSS styling.

Great work on this comprehensive PSD spectrum comparison feature! 🐰

  (\   /)
 ( ._.)
o_(")(")

🧠 Learnings used
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-22T17:54:03.594Z
Learning: In betaflight/blackbox-log-viewer, the user implemented Ctrl+click functionality for PSD spectrum comparison where simple mouse clicks clear all imported spectra and Ctrl+click adds spectra for comparison, making the Add button and Insert key largely redundant. The main curve is automatically added to imported list when selecting a second curve for comparison.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.

1 similar comment
Copy link

coderabbitai bot commented Jul 23, 2025

Tip

For best results, initiate chat on the files or code changes.

@demvlad You're very welcome! I'm glad the CSS guidance for making the numeric input spin buttons visible was helpful for your PSD heatmap implementation.

If you need any assistance with styling improvements in the future, feel free to ask. The numeric input controls can definitely be made more user-friendly with proper CSS styling.

Great work on this comprehensive PSD spectrum comparison feature! 🐰

  (\   /)
 ( ._.)
o_(")(")

🧠 Learnings used
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-22T17:54:03.594Z
Learning: In betaflight/blackbox-log-viewer, the user implemented Ctrl+click functionality for PSD spectrum comparison where simple mouse clicks clear all imported spectra and Ctrl+click adds spectra for comparison, making the Add button and Insert key largely redundant. The main curve is automatically added to imported list when selecting a second curve for comparison.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-07-23T15:31:09.473Z
Learning: In betaflight/blackbox-log-viewer, Ctrl+Mouse click on the legend removes an imported spectrum from comparison, mirroring the add behavior. The main spectrum is always shown separately, even when imported curves reach the maximum count.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.

@demvlad demvlad requested a review from haslinghuis July 23, 2025 16:15
haslinghuis
haslinghuis previously approved these changes Jul 23, 2025
@haslinghuis haslinghuis requested a review from Copilot July 23, 2025 16:40
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds the ability to compare PSD (Power Spectral Density) spectrums from different curves within a single log file without requiring external CSV import/export. Users can now select a curve, press Insert or "Add" to add its spectrum to a comparison list, then select other curves to compare their spectrums side-by-side.

  • Enhanced spectrum comparison functionality with single log file support
  • Added Ctrl key support for spectrum analyser control and curve management
  • Improved UI with shortened button labels and dynamic "Add" button visibility

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/main.js Enhanced legend selection to support Ctrl key for spectrum analyser control
src/grapher.js Added multi-spectrum detection and spectrum preparation for comparison
src/graph_spectrum_plot.js Core spectrum comparison logic with curve color management and drawing improvements
src/graph_spectrum.js Spectrum analyser coordination and UI control for comparison mode
src/graph_legend.js Added Ctrl key event passing to selection handlers
src/graph_imported_curves.js Refactored curve management with proper encapsulation and range calculation
index.html Shortened spectrum comparison button labels
Comments suppressed due to low confidence (3)

src/graph_spectrum_plot.js:272

  • Variable name 'curvesPoints' should be 'curvePoints' (singular) since it represents points for a single curve, not multiple curves.
    const curvesPoints = this._importedSpectrums.getCurve(spectrumNum).points;

src/graph_spectrum_plot.js:384

  • Variable name 'curvesPoints' should be 'curvePoints' (singular) since it represents points for a single curve, not multiple curves.
    const curvesPoints = this._importedPSD.getCurve(spectrumNum).points;

src/graph_spectrum_plot.js:175

  • Use strict equality (===) instead of loose equality (==) when comparing with null for more predictable behavior.
    0,

Copy link

Copy link

Preview URL: https://f3157a35.betaflight-blackbox.pages.dev

@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

The last notice:
we should not change PSD points per segment value (curves smoothness) by vertical slider in comparison mode,
because it works for main curve only, what is unvisible at this time.

@haslinghuis
Copy link
Member

@demvlad is this ready or not 🤣

@demvlad
Copy link
Contributor Author

demvlad commented Jul 23, 2025

@demvlad is this ready or not 🤣

The current implementation is working.
The comparison of any spectrums is easy to do.
The small notices have not big matter i think.

@haslinghuis haslinghuis merged commit 1482e2d into betaflight:master Jul 23, 2025
5 checks passed
@demvlad demvlad deleted the psd_curves_multi_select branch July 23, 2025 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants