I've spent a lot of time on thinking about what to write. On the one hand, I 
didn't want to write screeds and screeds, on the other hand I wanted to supply 
background information to underpin my favoured solution.

For those not interested in the details, please skip to "Proposed solutions".


# Numerical precision: rounding problem
Starting off with a completely undamped beam, damping is implemented by raising 
one end and lowering the other end of the beam.
Let dy be the vertical distance between left and right end of the completely 
undamped beam. With infinite damping, LilyPond will raise the lower end by dy/2 
and raise the lower end by dy/2. Theoretically, this will lead to two end 
points with the exact same y value, i.e. a horizontal beam.

**Problem:** due to limited numerical precision there may be tiny rounding 
problems when dividing by 2 and adding.
Even the slightest vertical distance between the end points, however, will 
later be quantized (i.e. increased) to valid sit/straddle/hang positions and 
thus yield noticeable slopes.
The numeric rounding issue may even overcompensate the slope so that the beam's 
direction flips.
That's what happened when we see a raising beam that really should be 
descending (or, ideally, be  horizontal).

All these calculations are very sensitive to the slightest deviations and 
highly depend on beam slope, beam span, stave size, line width, indent, etc.

**One solution would be to avoid the precision problem.**

In the following list, DELTA unquanted_y is the remaining vertical distance 
(should be 0) of both ends of the beam.
As you can see, even the original dy sign may flip and the numeric "error" is 
so small I had to use exponential notation:

~~~
original dy = -0.680277, DELTA unquanted_y =  5.5511e-17
original dy = -0.431074, DELTA unquanted_y =  2.7756e-17
original dy =  1.301622, DELTA unquanted_y =  0.0000e+00
original dy = -0.680277, DELTA unquanted_y = -5.5511e-17
original dy = -0.431074, DELTA unquanted_y =  2.7756e-17
original dy =  1.301622, DELTA unquanted_y =  0.0000e+00
original dy =  1.303842, DELTA unquanted_y =  0.0000e+00
original dy = -0.428570, DELTA unquanted_y = -2.7756e-17
original dy = -0.679738, DELTA unquanted_y =  5.5511e-17
original dy =  1.303842, DELTA unquanted_y =  0.0000e+00
original dy = -0.428570, DELTA unquanted_y =  2.7756e-17
original dy = -0.679738, DELTA unquanted_y =  5.5511e-17
~~~

The sligthest deviation between left and right beam end Y position will be 
drastically amplified by quanting to valid sit/straddle/hang positions later on.

After avoiding the rounding problem, there are no unwanted DELTAs left in the 
case of  infinite damping:

~~~
original dy = -0.680277, DELTA unquanted_y =  0.0000e+00
original dy = -0.431074, DELTA unquanted_y =  0.0000e+00
original dy =  1.301622, DELTA unquanted_y =  0.0000e+00
original dy = -0.680277, DELTA unquanted_y =  0.0000e+00
original dy = -0.431074, DELTA unquanted_y =  0.0000e+00
original dy =  1.301622, DELTA unquanted_y =  0.0000e+00
original dy =  1.303842, DELTA unquanted_y =  0.0000e+00
original dy = -0.428570, DELTA unquanted_y =  0.0000e+00
original dy = -0.679738, DELTA unquanted_y =  0.0000e+00
original dy =  1.303842, DELTA unquanted_y =  0.0000e+00
original dy = -0.428570, DELTA unquanted_y =  0.0000e+00
original dy = -0.679738, DELTA unquanted_y =  0.0000e+00
~~~



# Damping mechanism
Beam damping is needed because "beam angles should not deviate far from the 
horizontal" (Gould).
Starting off with the slope of a straight line that links the outer noteheads 
of the beam, LilyPond applies a rather simple damping formula to the slope:

**`slope = 0.6 * tanh (slope) / (damping + concaveness);`**

Let's have a look a the numerator first:

**Numerator**
One may wonder about the hyperbolic tangent (tanh), but it turns out to be very 
suitable as a damping factor:
![](https://upload.wikimedia.org/wikipedia/commons/8/87/Hyperbolic_Tangent.svg)

* It's symmetric to the origin and can be used both for positive and negative 
slopes
* For small |x|, there is practically no damping at all
* |tanh(x)| will never become greater than 1, however large x may be.
* For values of |x| > 3, tanh(x) is practically 1.

Consequently, the numerator of the damping term 0.6 * tanh(slope) an never 
exceed the value of 0.6 (i.e. an angle of 31°).

**Denominator**
damping has a default value of 1, concaveness is 0 for non-concave beams.
Concave groups of notes should always have a horizontal beam - independent of 
damping.So S So that's a special case we'll set aside for the moment.

By specifying damping values other than 1, we can increase damping (damping > 
1) to get flatter beams 

From a purely mathematical point of view, damping and concaveness play a very 
similar role, because the tanh-damped numerator is divided by the sum of 
damping and concaveness.

The idea of achieving horizontal beams by dividing a denominator (that can 
never becom greater than 0.6) by an infinite damping value is absolutely 
correct, but **there are numeric problems** (see below).




# "Rounding up"

While damping may theoretically lead to a very flat slope, according to the 
well-known sit/straddle/hang rules even the faintest slope will be "rounded up" 
to a noticeable slant. That's why we need "infinite" damping to get actual 0 
slopes. 
The smallest remaining slope after damping will inevitably be "rounded up" as 
described.



# Proposed solution (1)
As concaveness and damping play the exact same role in the damping formula, it 
suggests itself to treat them in the same way:
Why not setting the same threshold of 10000 for damping than it has already 
been done for concaveness?
That way, a damping value >= 10000 will force the beams to be horizontal 
completely avoiding numeric calamities:

~~~
-if (concaveness >= 10000)
+if ((concaveness >= 10000) || (damping >= 10000))
~~~

This would be, in my opinion, the preferable and consistent solution.
A concaveness value >= 10000 will lead to horizontal beaming, and so will a 
damping value of >= 10000.

Why should be a concavenss of 10000 be sufficient, but damping has to be 
inifinte if both play a similar role in the damping formula.

Full regression test passed.


# Proposed solution (2)
As we have seen, the odd inconsistencies are a side effect of numeric rounding 
inaccuracies that can be avoided by avoiding the division by 2.

**Original coding:**
~~~
      unquanted_y_[LEFT] += (dy - damped_dy) / 2;
      unquanted_y_[RIGHT] -= (dy - damped_dy) / 2;
~~~

**Easiest solution:**
~~~
      unquanted_y_[LEFT] += dy - damped_dy);
~~~
That way, left end will be changed by the full amount, thus avoiding the 
malicious division while leaving the right end untouched.
The absolute Y positions are not important, they will be adjusted anyway later 
on.

**Safest solution**
~~~
      unquanted_y_[LEFT] = unquanted_y_[LEFT] + (dy - damped_dy) - ((dy - 
damped_dy) / 2);
      unquanted_y_[RIGHT] -= (dy - damped_dy) / 2;
~~~
Sacrificing the += abbreviation is essential to avoid cumulation of rounding 
errors here.
LEFT and RIGHT unquanted_y values now are identical to the original coding, 
apart from the slight rounding problem 17 places after the decimal point.

Full regression test passed for both variants.


# Solution (1) or (2)?
I'm well aware of the fact that conding discussions should take place in 
rietveld, but this time it's about deciding between two approaches.

As soon as we've agreed on one of the possible solutions, I'll upload a patch.
What do you think?
I'll favour the threshold solution (1)

Thanks
Torsten



---

** [issues:#1493] Problem with horizontal beams**

**Status:** Started
**Created:** Wed Jan 26, 2011 12:21 PM UTC by Anonymous
**Last Updated:** Mon Jan 15, 2018 04:36 PM UTC
**Owner:** Torsten Hämmerle
**Attachments:**

- 
[beams.ly](https://sourceforge.net/p/testlilyissues/issues/1493/attachment/beams.ly)
 (807 Bytes; application/octet-stream)
- 
[screenshot.png](https://sourceforge.net/p/testlilyissues/issues/1493/attachment/screenshot.png)
 (18.9 kB; image/png)


*Originally created by:* *anonymous

*Originally created by:* 
[ralphbug...@gmail.com](http://code.google.com/u/106131861630194758622/)

James Lowe :
There seems to be an inconsistency with setting horizontal beams.

We have a snippet where we state that

\override Beam \#'damping = \#+inf.0

Should generate horizontal beams in all cases.

However the simple example attached shows some odd inconsistencies.

   \version "2.13.40"

\relative c''  \{
    \override Beam \#'damping = \#+inf.0
     f16 g a b    a c d g,    a b a c   d e f g, % all beams horizontal
     f16 g a b    a c d g,    a b a c   d e f g, % all beams horizontal
     f16 g a b    a c d g,    a b a c   d e f g, % 2nd and 4th group not 
Horizontal
     f16 g a b    a c d g,    a b a c   d e f g, % 2nd and 4th group not 
Horizontal
\}

\relative c''  \{
    \override Beam \#'damping = \#+inf.0
     f16 g a b    a c d g,    a b a c   d e f g, \break % 4th group not 
Horizontal
     f16 g a b    a c d g,    a b a c   d e f g, \break % 2nd and 4th group not 
Horizontal
     f16 g a b    a c d g,    a b a c   d e f g, \break % 2nd and 4th group not 
Horizontal
     f16 g a b    a c d g,    a b a c   d e f g, \break % 2nd and 4th group not 
Horizontal
\}

Phil Holmes :

I'd suggest the snippet is worth sorting out, too.  What do you reckon - adding 
the commands

   \override Beam \#'details \#'damping-direction-penalty = \#0
   \override Beam \#'details \#'round-to-zero-slope = \#0

to the existing snippet, or a new one pointed to by the old one, that says "if  
\override Beam \#'damping = \#+inf.0 doesn't do what you want, add the other 
commands too, as shown here"?


---

Sent from sourceforge.net because testlilyissues-a...@lists.sourceforge.net is 
subscribed to https://sourceforge.net/p/testlilyissues/issues/

To unsubscribe from further messages, a project admin can change settings at 
https://sourceforge.net/p/testlilyissues/admin/issues/options.  Or, if this is 
a mailing list, you can unsubscribe from the mailing list.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Testlilyissues-auto mailing list
testlilyissues-a...@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/testlilyissues-auto
  • [Lilypond-... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto
    • [Lily... Auto mailings of changes to Lily Issues via Testlilyissues-auto

Reply via email to