Finds a b-value (common ratio) that satisfies a total duration within
        1 millisecond. Not terribly efficient, so using lru_cache. Don't know
        a way to compute the common ratio when the sum of a finite geometric
        series is known. Found myself needing to factor polynomials with an
        arbitrarily
        high degree.

        :param start: a-value
        :param steps: how many steps
        :param total: total duration of the series of n-steps
        :return: b value

def goalDuration(start: float, steps: int, total: float) -> float:
        """
        Finds a b-value (common ratio) that satisfies a total duration within
        1 millisecond. Not terribly efficient, so using lru_cache. Don't know
        a way to compute the common ratio when the sum of a finite geometric
        series is known. Found myself needing to factor polynomials with an
        arbitrarily
        high degree.

        :param start: a-value
        :param steps: how many steps
        :param total: total duration of the series of n-steps
        :return: b value
        """
        a = start
        up = None
        dn = None
        b = 1.0
        while True:
            s = Ratchet._sumSeries(a, b, steps) - total
            if abs(s) < .001:
                break
            elif s < 0:
                dn = b
                # halfway between b and upper if upper defined
                b = (up + b) / 2 if up else b + 1
            else:
                up = b
                b = (dn + b) / 2 if dn else b / 2
        return b