Perform least square optimization needed for the rippe_parameters function.

def estimate_param_rippe(measurements, bins, init=None, circ=False):
    """Perform least square optimization needed for the rippe_parameters function.
    """

    # Init values
    DEFAULT_INIT_RIPPE_PARAMETERS = [1., 9.6, -1.5]
    d = 3.

    def log_residuals(p, y, x):
        kuhn, lm, slope, A = p
        rippe = (np.log(A) + np.log(0.53) - 3 * np.log(kuhn) +
                 slope * (np.log(lm * x) - np.log(kuhn)) +
                 (d - 2) / ((np.power((lm * x / kuhn), 2) + d)))
        err = y - rippe

        return err

    def peval(x, param):

        if circ:
            l_cont = x.max()
            n = param[1] * x / param[0]
            n0 = param[1] * x[0] / param[0]
            n_l = param[1] * l_cont / param[0]
            s = n * (n_l - n) / n_l
            s0 = n0 * (n_l - n0) / n_l
            norm_lin = (param[3] * (0.53 * (param[0] ** -3.) *
                        np.power(n0, (param[2])) *
                        np.exp((d - 2) / ((np.power(n0, 2) + d)))))

            norm_circ = (param[3] * (0.53 * (param[0] ** -3.) *
                         np.power(s0, (param[2])) *
                         np.exp((d - 2) / ((np.power(s0, 2) + d)))))

            rippe = (param[3] * (0.53 * (param[0] ** -3.) *
                     np.power(s, (param[2])) * np.exp((d - 2) /
                     ((np.power(s, 2) + d)))) * norm_lin / norm_circ)

        else:

            rippe = (param[3] * (0.53 * (param[0] ** -3.) *
                     np.power((param[1] * x / param[0]), (param[2])) *
                     np.exp((d - 2) /
                     ((np.power((param[1] * x / param[0]), 2) + d)))))

        return rippe

    if init is None:
        init = DEFAULT_INIT_RIPPE_PARAMETERS

    A = np.sum(measurements)

    p0 = (p for p in init), A
    from scipy.optimize import leastsq
    plsq = leastsq(log_residuals, p0, args=(np.log(measurements), bins))

    y_estim = peval(bins, plsq[0])
    kuhn_x, lm_x, slope_x, A_x = plsq[0]
    plsq_out = [kuhn_x, lm_x, slope_x, d, A_x]

    np_plsq = np.array(plsq_out)

    if np.any(np.isnan(np_plsq)) or slope_x >= 0:
        warnings.warn("Problem in parameters estimation")
        plsq_out = p0

    return plsq_out, y_estim