Skip to content

Calculations with db are wrong #1569

Open

Description

@BernhardJosef

Describe the bug
The result of adding 2 levels is wrong
The result of subtracting 2 levels is wrong

To Reproduce
Level level1 = new Level(1.6, Level.ParseUnit("dB"));
Level level2 = new Level(0.7, Level.ParseUnit("dB"));

Level level3 = level1 - level2;
Level level4 = level1 + level2;

Expected behavior
db additions or subtractions should be executed without any transformations

Additional context
see https://sengpielaudio.com/calculator-db.htm

Activity

  1. angularsen commented on Jul 26, 2025

    @angularsen
    Owner

    Hi, thanks for reporting.

    If you are able to, could you please create a pull request with a unit test that highlights the two errors and what the results should be? Huge bonus points if you also provide a fix for the implementation.

    It will help move this along much faster, I have limited time to look into it.

  2. angularsen commented on Jul 27, 2025

    @angularsen
    Owner

    Relevant changes coming in #1587
    Let's re-evaluate after those are merged.

  3. github-actions commented on Aug 27, 2025

    @github-actions
    Contributor

    This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  4. github-actions commented on Sep 4, 2025

    @github-actions
    Contributor

    This issue was automatically closed due to inactivity.

  5. added
    pinnedIssues that should not be auto-closed due to inactivity.
    and removed on Sep 18, 2025
  6. angularsen commented on Jul 31, 2026

    @angularsen
    Owner

    I think the core issue here is that Level + Level and Level - Level currently encode one specific interpretation of dB arithmetic, but users can reasonably expect another.

    Today, logarithmic quantities implement +/- as linear-space aggregation:

    Level total = level1 + level2;

    This means roughly:

    10 * log10(10^(level1 / 10) + 10^(level2 / 10))

    So this does not produce direct value arithmetic:

    1.6 dB + 0.7 dB != 2.3 dB

    That behavior is useful when adding quantities represented in dB, but it is surprising when the user wants to add/subtract dB values as gains/ratios.

    For v6, I think we should make this explicit and avoid +/- for logarithmic quantities. My current preference is to provide named APIs for the two meanings:

    // Convert to linear space, operate, convert back.
    Level total = level1.LinearAdd(level2);
    Level total = levels.LinearSum();
    Level mean = levels.LinearMean();
    
    // Operate directly on the logarithmic values.
    Level gain = level1.LogValueAdd(level2);
    Level delta = level1.LogValueSubtract(level2);
    Level gain = Level.FromDecibels(level1.Decibels + level2.Decibels);

    The exact names can be discussed, but I think the important part is this split:

    • Linear* means convert to linear space, do the operation, convert back.
    • LogValue* means operate directly on the logarithmic unit values.
    • +/- should probably be removed for logarithmic quantities, because both interpretations are common enough that the operators are ambiguous.

    How does this match your expectation?

  7. BernhardJosef commented on Aug 3, 2026

    @BernhardJosef
    Author

    I think, you implemented sound level measurement in dB and this is ok. My use of dB is a ratio of 2 quantities and this is also a very common application. Several ratios(attenuation, amplification, ...) expressed in logarithmic can be added or subtracted instead of multipication.

    So I think you should add dB as unit to Ratio. Adding a ratio to a quantity multiplies the quantity with the ratio. Multiplication of a quantity with a ratio should have the same result.
    dB is one of several ambiguous units abbreviations.

    Your proposed work around is not applicable for me. I use UnitsNet within C#-scripting and the expressions are written by the users of our Software.
    I would prefere a logarithmic ratio instead of changing dB for sound level measurement.

    I can support you with the test of ratio unit dB

  8. Rafael-SOWNet commented on Aug 6, 2026

    @Rafael-SOWNet

    I reproduced this with your code verbatim against master (assembly 6.0.0.0), and I do not
    think it is a bug — but the reasoning is worth writing down, and it did turn up something
    adjacent that was untested.

    Level is a logarithmic quantity, so + combines two levels in linear power space rather
    than adding their decibel numbers:

    UnitsNet returns 10·log10(10^(L1/10) ± 10^(L2/10)) L1 ± L2
    level1 + level2 4.18357203248652 dB 4.183572032487 ✓ 2.3 ✗
    level1 - level2 -5.67764957318026 dB -5.67764957318 ✓ 0.9 ✗

    So the results match the logarithmic definition exactly, to the last digit UnitsNet prints.

    Your expectation — "dB additions or subtractions should be executed without any
    transformations" — is the correct operation for a gain, which is a dimensionless ratio,
    not a level. Combining two levels and applying a gain to a level are different operations, and
    the calculator you linked has separate entries for them. The arithmetic one already works today:

    Level.FromDecibels(level1.Decibels + level2.Decibels)   // 2.3 dB
    Level.FromDecibels(level1.Decibels - level2.Decibels)   // 0.9 dB

    If your signals are genuinely levels relative to the same reference, 4.18 dB is the right
    answer for their sum.


    @angularsen — you asked for a test showing the errors and the expected results. Since the
    arithmetic turns out to be correct there is no failing test to write, but reproducing this did
    surface two silent returns that nothing covered:

    Level.FromDecibels(40)  - Level.FromDecibels(40)   ->  -Infinity dB
    Level.FromDecibels(0.7) - Level.FromDecibels(1.6)  ->  NaN dB
    

    The second is inconsistent with the constructor, which rejects a non-positive ratio with
    ArgumentOutOfRangeException and the message "The base-10 logarithm of a number ≤ 0 is
    undefined", while operator- performs that same logarithm and returns NaN silently.

    #1725 pins all three cases as characterisation tests. It changes no behaviour — making
    operator- throw would be a breaking change and your call, so I have deliberately left it out
    and can open that separately if you want it.

    You had also said to re-evaluate after #1587; that merged on 2025-08-03, and the above is
    measured after it.

  9. Rafael-SOWNet commented on Aug 7, 2026

    @Rafael-SOWNet

    I owe both of you a correction: I wrote that comment without reading this thread properly, and
    it shows. @angularsen had already set out the linear-space-vs-dB-value split on 31 July, in more
    detail than I did, and had already named Level.FromDecibels(a.Decibels + b.Decibels) — which I
    then offered back as if it were an answer. @BernhardJosef had already explained on 3 August why
    that shape does not work for him. Restating the first and ignoring the second was not useful.

    Reading it properly, the disagreement is narrower than "is this a bug", and there is one thing I
    can add that is measured rather than argued.

    Every dB-carrying quantity in UnitsNet composes in linear space. None composes as a gain.
    Measured on master, assembly 6.0.0.0:

    type 1.6 + 0.7 dB-value addition would give
    Level (dB) 4.18357203248652 2.3
    PowerRatio (dBW) 4.18357203248652 2.3
    AmplitudeRatio (dBV) 7.1822515393836 2.3
    Ratio no dB unit exists —

    AmplitudeRatio and PowerRatio are named "ratio" but are referenced to a volt and a watt, so
    they are levels too. Ratio is dimensionless but is not logarithmic and has no dB unit. So
    @BernhardJosef's case — a dimensionless logarithmic gain, where composing two gains multiplies
    the linear ratios and therefore adds the decibels — currently has no type at all. That is why no
    workaround built out of the existing types fits it.

    Which raises a question about the v6 plan rather than an objection to it. The proposal removes
    +/- because both interpretations are common enough to be ambiguous. But the ambiguity looks
    like it comes from a missing type rather than from the operators: within a level, + can only
    sensibly mean linear-space combination; within a dimensionless dB gain, + can only sensibly
    mean dB addition. If both types existed, the operand types would disambiguate and + would be
    unambiguous in each.

    That matters specifically for @BernhardJosef's constraint, which named methods cannot meet:
    end users write the expressions in C# script, so whatever is correct has to be spelled a + b.

    I am not proposing this over your plan — you know the compatibility surface and I have landed
    nothing here yet. I am asking whether a separate logarithmic-ratio type was already considered
    and rejected, because if it was, the reasoning would be worth having in the thread.

    On #1725: it pins the current - edge cases, and I should flag that two of them are unaffected
    by the v6 direction while one is not. v - v giving -Infinity and smaller - larger giving
    NaN silently will need an answer under any spelling, including LinearSubtract; the
    constructor already rejects the same non-positive logarithm with ArgumentOutOfRangeException.
    The addition test in that PR does pin operator behaviour you intend to remove, so treat it as a
    record of today rather than as something to preserve — happy to drop it if you would rather not
    have it in the suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugpinnedIssues that should not be auto-closed due to inactivity.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions