DR error measures: Difference between revisions
| Line 58: | Line 58: | ||
== Solution methods == | == Solution methods == | ||
=== Analytic | === Analytic === | ||
==== | ==== Fully DR, rooted linear ==== | ||
Setting the derivative to 0 gives us the closed-form solution | Setting the derivative to 0 gives us the closed-form solution | ||
| Line 70: | Line 70: | ||
to obtain the least-squares linear error. | to obtain the least-squares linear error. | ||
= | ==== Partially DR (one related delta set, one free variable), rooted linear ==== | ||
=== Partially DR (one related delta set, one free variable), rooted linear === | |||
Suppose we wish to approximate a target delta signature of the form <math>+\delta_1 +? +\delta_3</math> with the chord <math>1:r_1:r_2:r_3</math> (where the +? is free to vary). The least-squares problem is | Suppose we wish to approximate a target delta signature of the form <math>+\delta_1 +? +\delta_3</math> with the chord <math>1:r_1:r_2:r_3</math> (where the +? is free to vary). The least-squares problem is | ||
| Line 81: | Line 79: | ||
where ''y'' represents the free delta +?. | where ''y'' represents the free delta +?. | ||
We can set the partial derivatives with respect to ''x'' and ''y'' of the inner expression equal to zero (since the derivative of sqrt() is never 0) and use SymPy to solve the system: | We can set the partial derivatives with respect to ''x'' and ''y'' of the inner expression equal to zero (since the derivative of sqrt() is never 0) and use SymPy to solve the system symbolically: | ||
<syntaxhighlight lang="py"> | <syntaxhighlight lang="py"> | ||
| Line 109: | Line 107: | ||
y = \frac{- 2 \delta_1^2 r_1 + \delta_1^2 r_2 + \delta_1^2 r_3 - \delta_1 \delta_3 r_1 + \delta_1 \delta_3 r_2 - \delta_1 \delta_3 r_3 + \delta_1 \delta_3 + \delta_3^2 r_2 - \delta_3^2}{2 \delta_1 r_1 - 2 \delta_1 - \delta_3 r_2 + \delta_3 r_3}. | y = \frac{- 2 \delta_1^2 r_1 + \delta_1^2 r_2 + \delta_1^2 r_3 - \delta_1 \delta_3 r_1 + \delta_1 \delta_3 r_2 - \delta_1 \delta_3 r_3 + \delta_1 \delta_3 + \delta_3^2 r_2 - \delta_3^2}{2 \delta_1 r_1 - 2 \delta_1 - \delta_3 r_2 + \delta_3 r_3}. | ||
</math> | </math> | ||
=== Grid method (FDR case) === | |||
=== Partially DR (one related delta set, arbitrary free deltas) === | === Partially DR (one related delta set, arbitrary free deltas) === | ||
Revision as of 01:48, 13 December 2025
This article will describe several least-squares error measures for delta-rational chords. They have the advantage of not fixing a particular interval in the chord when constructing the chord of best fit. However, like any other numerical measure of concordance or error, you should take them with a grain of salt.
Conventions and introduction
The idea motivating least-squares error measures on a chord as an approximation to a given delta signature is the following (for simplicity, let’s talk about the fully DR case first):
We want the error of a chord 1:r1:r2:...:rn (in increasing order), with n > 1, in the linear domain as an approximation to a fully delta-rational chord with signature +δ1 +δ2 ... +δn, i.e. a chord
with root real-valued harmonic x. Let be the delta signature +δ1 +δ2 ... +δn written cumulatively.
We want to measure the error without having to fix any dyad (as one might naively fix a dyad and measure errors in the other deltas). To do this we solve a least-squares error problem: use a root-sum-square error function and optimize x to minimize that function.
Domain and error model
We have two choices:
- to measure either the linear (frequency ratio) error or the logarithmic (cents) one (called the domain);
- the collection of intervals to sum over (which we call the error model):
- Rooted: Only intervals from the root real-valued harmonic x are chosen.
- Pairwise: All intervals in the chord are compared.
- All-steps: Only intervals between adjacent notes are compared.
The method to solve the problem will also differ depending on the numbers of variables involved (only one variable x for fully delta-rational).
We arrive at the following general formula: Let let be the error model, and let represent the domain function (identity or ). Then the error function to be minimized by optimizing and any free deltas is:
| Domain | Error model | Error function |
|---|---|---|
| Linear | Rooted | |
| Pairwise | ||
| All-steps | ||
| Logarithmic (nepers) |
Rooted | |
| Pairwise | ||
| All-steps |
To convert nepers to cents, multiply by
Solution methods
Analytic
Fully DR, rooted linear
Setting the derivative to 0 gives us the closed-form solution
which can be plugged back into
to obtain the least-squares linear error.
Partially DR (one related delta set, one free variable), rooted linear
Suppose we wish to approximate a target delta signature of the form with the chord (where the +? is free to vary). The least-squares problem is
where y represents the free delta +?.
We can set the partial derivatives with respect to x and y of the inner expression equal to zero (since the derivative of sqrt() is never 0) and use SymPy to solve the system symbolically:
import sympy
x = sympy.Symbol("x", real=True)
y = sympy.Symbol("y", real=True)
d1 = sympy.Symbol("\\delta_{1}", real=True)
d2 = sympy.Symbol("\\delta_{2}", real=True)
d3 = sympy.Symbol("\\delta_{3}", real=True)
r1 = sympy.Symbol("r_1", real=True)
r2 = sympy.Symbol("r_2", real=True)
r3 = sympy.Symbol("r_3", real=True)
err_squared = ((x + d1) / x - r1) ** 2 + ((x + d1 + y) / x - r2) ** 2 + ((x + d1 + y + d3) / x - r3) ** 2
err_squared.expand()
err_squared_x = sympy.diff(err_squared, x)
err_squared_y = sympy.diff(err_squared, y)
sympy.nonlinsolve([err_squared_x, err_squared_y], [x, y])The unique solution with x > 0 is
Grid method (FDR case)
Partially DR (one related delta set, arbitrary free deltas)
We similarly include a free variable yi to be optimized for every additional +?, after coalescing strings of consecutive +?'s into segments and after trimming leading and trailing free delta segments.
