Example #1
0
def fit_radium_calib():
    energies = [3.953, 5.332, 7.02]  # MeV
    error_energies = np.array([0.001, 0.001, 0.01]) / math.sqrt(12)
    channels = [240, 815, 1495]
    error_channels = [10, 10, 8]
    fit = Fit(LINEAR)
    fit.set_data(xdata=channels,
                 xerrors=error_channels,
                 ydata=energies,
                 yerrors=error_energies)
    fit.set_labels(xlabel="Kanal", ylabel="Energie / MeV")
    fit.iterative_fit(5)
    plt.clf()
    plt.minorticks_on()
    fit.plot(box="tl",
             units={
                 "slope": "keV/Kanal",
                 "offset": "MeV"
             },
             factors={"slope": 1000})
    plt.savefig("out/radium_calib_fit." + SAVETYPE)
    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="bl")
    plt.savefig("out/radium_calib_residual." + SAVETYPE)
Example #2
0
def plot_caesium_absorber():
    depth, events, slabs = np.loadtxt("data/caesium_bleiabschirmung.txt",
                                      unpack=True)
    error_depth = np.sqrt(slabs) * 0.1
    error_events = np.sqrt(events + 1)

    plt.clf()
    plt.minorticks_on()
    plt.errorbar(depth, events, xerr=error_depth, yerr=error_events, fmt=',')
    plt.xlabel("Tiefe / mm")
    plt.ylabel("ln(Anzahl)")
    plt.savefig("out/caesium_absorber_nolog." + SAVETYPE)

    ln_events = np.log(events)
    error_ln_events = np.abs(1 / events) * error_events

    depth /= 10  # mm=>cm
    error_depth /= 10

    plt.clf()
    plt.minorticks_on()

    func = lambda x, mu, lnI0: -x * mu + lnI0

    fit = Fit(func)
    fit.set_data(xdata=depth,
                 ydata=ln_events,
                 xerrors=error_depth,
                 yerrors=error_ln_events)
    fit.set_labels(xlabel="Tiefe / cm", ylabel="ln(Anzahl)")
    fit.iterative_fit(5)
    fit.plot(box="tr", units={"mu": "1/cm"})
    plt.savefig("out/caesium_absorber_fit." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tr")
    plt.savefig("out/caesium_absorber_residual." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit = fit.filtered(depth <= 2)
    fit.iterative_fit(5)
    fit.plot(box="tr", units={"mu": "1/cm"})
    plt.savefig("out/caesium_absorber_fit2." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tr")
    plt.savefig("out/caesium_absorber_residual2." + SAVETYPE)

    mu = fit.uvalue("mu")
    print("Absorptionskoeffizient:", mu, "1/cm")
    mu1 = mu / ufloat(11.342, 0.001)
    print("Massenabsorptionskoeffizient:", mu1, "cm^2/g")
Example #3
0
def plot_yag_lifetime():
    time, voltage = _load_oscilloscope_csv("data/ALL0010/F0010CH2.CSV")
    time *= 1E6  # us
    voltage *= 1000  # mV

    error_voltage = voltage[time < 0].std()
    print("Fehler:", error_voltage, "mV")

    fit = Fit(EXPONENTIAL_DECAY)
    fit.set_data(xdata=time, ydata=voltage, yerrors=error_voltage)
    fit.set_labels(xlabel="Zeit / us", ylabel="Spannung / mV")
    fit = fit.filtered(np.logical_and(time > 0, time < 1500))
    fit.set_params(A=0.1, offset=0.20, T=250)
    fit.iterative_fit(1)

    print("Lebensdauer:", formatUFloat(fit.uvalue("T"), "us"), "- Chi^2:",
          fit.chi2, "- ndf:", fit.ndf, "- Chi^2/ndf:", fit.chi2ndf)

    plt.clf()
    fit.plot(box="tr", units={"T": "us", "A": "mV", "offset": "mV"})
    plt.savefig("out/yag_lifetime." + SAVETYPE)
Example #4
0
def plot_strontium():
    m = {
        0: 0,
        5: 0.03,
        6: 0.04,
        7: 0.05,
        8: 0.08,
        9: 0.10,
        10: 0.17,
        11: 0.25,
        12: 0.37,
        13: 0.50,
        14: 0.64,
        15: 0.83,
        16: 1.01,
        17: 1.23,
        18: 1.39,
        19: 1.57,
        20: 1.88,
        21: 2.29,
        22: 2.79,
        23: 3.46,
    }

    nr, count = np.loadtxt("data/strontium_alu.txt", unpack=True)
    absorb = np.zeros_like(nr)
    for i, x in enumerate(nr):
        absorb[i] = m[x] / 10

    scale = 1 / count[0]

    error_count = np.sqrt(count + 1)
    error_absorb = 0.01 / 10

    count *= scale
    error_count *= scale

    func = lambda x, A, mu, offset: A * np.exp(-x * mu) + offset

    fit = Fit(func)
    fit.set_data(xdata=absorb,
                 ydata=count,
                 xerrors=error_absorb,
                 yerrors=error_count)
    fit.set_params(A=1, mu=1, offset=0)
    fit.set_labels(xlabel="Dicke / cm", ylabel="Anteil")
    fit.iterative_fit(5)

    plt.clf()
    plt.minorticks_on()
    plt.xlim(0, .35)
    fit.plot(box="tr", units={"mu": "1/cm"})
    plt.savefig("out/strontium_fit." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tr")
    plt.savefig("out/strontium_residual." + SAVETYPE)

    rho = ufloat(2.7, 0.1)
    mu = fit.uvalue("mu")
    print("Absorptionskoeffizient:", mu, "1/cm")
    mu1 = mu / rho
    print("Massenabsorptionskoeffizient:", mu1, "cm^2/g")

    E = umath.pow(17 / mu1, 1 / 1.14)
    print("Maximalenergie:", E, "MeV")

    R1 = 0.412 * umath.pow(E, 1.265 - 0.0954 * umath.log(E))
    R = R1 / rho

    print("Reichweite:", R1, "g/cm^2")
    print("Reichweite:", R, "cm")
Example #5
0
def plot_ionisation_raw():
    distances, voltages, error_voltages = np.loadtxt(
        "data/radium_ionisationskammer.txt", unpack=True)

    # discard 38.80cm
    distances = distances[:-1]
    voltages = voltages[:-1]
    error_voltages = error_voltages[:-1]

    for distance, voltage, error_voltage in zip(distances, voltages,
                                                error_voltages):
        distance = ufloat(distance, 0.05)
        voltage = ufloat(voltage, error_voltage)

        print("$({:L}) \\unit{{cm}}$ & $({:L}) \\unit{{mV}}$ \\\\".format(
            distance, voltage))

    plt.clf()
    plt.minorticks_on()
    plt.errorbar(distances, voltages, xerr=0.05, yerr=error_voltages, fmt=',')
    plt.xlabel("Distanz / cm")
    plt.ylabel("Spannung / mV")
    plt.savefig("out/radium_ionisation_raw." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()

    currents = []
    error_currents = []
    for voltage, error_voltage in zip(voltages, error_voltages):
        current = ufloat(voltage, error_voltage)  #+ ufloat(5, 3)
        currents.append(current.n)
        error_currents.append(current.s)

    currents = np.array(currents)
    error_currents = np.array(error_currents)

    distances -= 39

    plt.clf()
    plt.minorticks_on()
    plt.errorbar(distances, currents, xerr=0.05, yerr=error_currents, fmt=',')
    plt.xlabel("Distanz / cm")
    plt.ylabel("Strom / nA")
    plt.savefig("out/radium_ionisation." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()

    x = distances[1:] + np.abs(np.diff(distances) / 2)
    y = -np.diff(currents) / np.diff(distances)
    plt.plot(x, y, 's-')

    plt.xlabel("Distanz / cm")
    plt.ylabel("- Änderung des Stromes / nA / cm")
    plt.savefig("out/radium_ionisation_diff." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit = Fit(LINEAR)
    fit.set_data(xdata=(7.42, 6.92, 6.42),
                 ydata=currents[9:12],
                 xerrors=0.25,
                 yerrors=error_currents[9:12])
    fit.set_labels(xlabel="Distanz / cm", ylabel="Strom / nA")
    fit.iterative_fit(5)
    fit.plot(box="tr", units={"slope": "nA/cm", "offset": "nA"})
    plt.savefig("out/radium_ionisation_po_fit." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tl")
    plt.savefig("out/radium_ionisation_po_residual." + SAVETYPE)

    middle = (ufloat(currents[9], error_currents[9]) +
              ufloat(currents[11], error_currents[11])) / 2
    print("Middle:", middle, "nA")
    r = (middle - fit.uvalue("offset")) / fit.uvalue("slope")
    print("Range:", r, "cm")
Example #6
0
def calc_radium_range():
    peak = {
        35: (1100, 1800),
        35.5: (1000, 1700),
        36: (900, 1600),
        36.5: (800, 1500),
        37: (600, 1400),
        37.5: (500, 1200),
        38: (300, 1000),
        38.5: (100, 700)
    }

    distances = []
    error_distances = []
    integrals = []
    error_integrals = []

    for distanceStr in ("35_0", "35_5", "36_0", "36_5", "37_0", "37_5", "38_0",
                        "38_5"):
        filename = "data/Radium%s.TKA" % distanceStr

        distance = ufloat(float(distanceStr.replace("_", ".")), 0.05)

        tka = TkaFile(filename)
        lower, upper = peak[distance.n]

        data = tka.data[lower:upper]

        distance = distance - 35 + ufloat(3.17, 0.17)

        integral = ufloat(data.sum(), math.sqrt((data + 1).sum()))
        integral_fixed = integral * distance**2

        print(
            "$({:L}) \\unit{{cm}}$ & {:d} & {:d} &  ${:dL}$ &  ${:dL} \\unit{{cm^2}}$ \\\\"
            .format(distance, lower, upper, integral, integral_fixed))

        distances.append(distance.n)
        error_distances.append(distance.s)
        integrals.append(integral_fixed.n)
        error_integrals.append(integral_fixed.s)

    distances = np.array(distances)
    integrals = np.array(integrals)
    error_distances = np.array(error_distances)
    error_integrals = np.array(error_integrals)

    plt.clf()
    plt.minorticks_on()
    plt.errorbar(distances,
                 integrals,
                 xerr=error_distances,
                 yerr=error_integrals,
                 fmt="s")

    #plt.plot(distances, integrals, 's')
    plt.xlabel("Distanz / cm")
    plt.ylabel("korrigierte Summe / cm^2")
    plt.ylim(0, plt.ylim()[1])
    plt.savefig("out/radium_range." + SAVETYPE)
    #plt.show()

    plt.clf()
    plt.minorticks_on()
    scale = 1 / integrals[0:3].mean()

    fit = Fit(LINEAR)
    fit.set_params(offset=1, slope=-0.5)
    fit.set_data(xdata=distances[1:],
                 ydata=integrals[1:] * scale,
                 xerrors=error_distances[1:],
                 yerrors=error_integrals[1:] * scale)
    fit.set_labels(xlabel="Distanz / cm", ylabel="Intensität")
    fit.iterative_fit(5)
    fit.plot(plot_data=True, plot_fit=True, box="bl", units={"slope": "1/cm"})
    plt.ylim(0, plt.ylim()[1])
    plt.savefig("out/radium_range_fit." + SAVETYPE)

    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tr")
    plt.savefig("out/radium_range_residual." + SAVETYPE)

    r = (0.5 - fit.uvalue("offset")) / fit.uvalue("slope")
    print("Range:", r, "cm")
Example #7
0
def radium_calib_2():
    E, proj_range = np.loadtxt("ranges.txt", unpack=True)
    real_range = proj_range / 1.184e-3

    energy_from_range = interp1d(real_range, E, kind='cubic')

    energies = []
    error_energies = []
    for distance in (0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5):
        distance = ufloat(35 + distance, 0.05)
        total_distance = (distance - 35) + ufloat(3.17, 0.17)
        for peak in (3.52, 4.99, 7.18):
            peak = ufloat(peak, 0.01)

            rest = peak - total_distance
            try:
                upper = energy_from_range(rest.n + rest.s)
                lower = energy_from_range(rest.n - rest.s)
                value = energy_from_range(rest.n)
            except ValueError as e:
                #print(e)
                #print("orig distance:", peak, "cm  ", "rest distance:", rest, "cm  ")
                pass
            else:
                error = max(upper - value, value - lower)
                energy = ufloat(value, error)
                #print("orig distance:", peak, "cm  ", "total distance:", total_distance, "cm  ", "rest distance:", rest, "cm  ", "rest energy:", energy, "MeV")
                print(
                    "$({:L}) \\unit{{cm}}$ & $({:L}) \\unit{{cm}}$ & $({:L}) \\unit{{cm}}$ & $({:L}) \\unit{{cm}}$ & $({:L}) \\unit{{MeV}}$ \\\\"
                    .format(peak, distance, total_distance, rest, energy))

                energies.append(value)
                error_energies.append(error)

    # PART2 !!!
    channels = [
        220, 780, 1460, 620, 1340, 450, 1260, 150, 1170, 990, 820, 620, 390
    ]
    error_channels = [20, 20, 20, 20, 20, 20, 20, 100, 20, 20, 20, 20, 30]
    energies = energies[:len(channels)]
    error_energies = error_energies[:len(channels)]

    for energy, error_energy, channel, error_channel in zip(
            energies, error_energies, channels, error_channels):
        e = ufloat(energy, error_energy)
        c = ufloat(channel, error_channel)
        print("$({:L}) \\unit{{MeV}}$ & ${:L}$ \\\\".format(e, c))

    fit = Fit(LINEAR)
    fit.set_data(xdata=channels,
                 xerrors=error_channels,
                 ydata=energies,
                 yerrors=error_energies)
    fit.set_labels(xlabel="Kanal", ylabel="Energie / MeV")
    fit.iterative_fit(5)
    plt.clf()
    plt.minorticks_on()
    fit.plot(box="tl",
             units={
                 "slope": "keV/Kanal",
                 "offset": "MeV"
             },
             factors={"slope": 1000})
    plt.savefig("out/radium_calib2_fit." + SAVETYPE)
    plt.clf()
    plt.minorticks_on()
    fit.plot_residual(box="tr")
    plt.savefig("out/radium_calib2_residual." + SAVETYPE)
Example #8
0
def plot_diode_kennlinie():
    current, power = np.loadtxt("data/kennlinie_diode.txt", unpack=True)
    error_current = 1 / math.sqrt(12)
    error_power = 1 / math.sqrt(12)

    plt.clf()
    plt.errorbar(current,
                 power,
                 xerr=error_current,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Strom / mA")
    plt.ylabel("Leistung / mW")
    plt.savefig("out/kennlinie_diode_raw." + SAVETYPE)

    fit_indices_list = []
    fit_indices_list.append(current > 200)

    valid = current > 200
    valid[current > 410] = False
    fit_indices_list.append(valid)

    valid = current > 410
    fit_indices_list.append(valid)

    zero_power = power[current < 150]
    background = zero_power.mean()
    print("Background:", background, "mW")
    power -= background

    func = lambda x, slope, threshold: (x - threshold) * slope
    fit = Fit(func)
    fit.set_params(slope=0.85, threshold=190)
    fit.set_data(xdata=current,
                 ydata=power,
                 xerrors=error_current,
                 yerrors=error_power)
    fit.set_labels(xlabel="Strom / mA", ylabel="Leistung / mW")

    for i, fit_indices in enumerate(fit_indices_list):
        subfit = fit.filtered(fit_indices)

        plt.clf()
        plt.errorbar(current,
                     power,
                     xerr=error_current,
                     yerr=error_power,
                     fmt=',',
                     color="black")
        subfit.iterative_fit(5)

        #plt.axhline(background, color="blue")
        #plt.axvline(subfit.value("threshold"), color="blue")
        print("Threshold:", formatUFloat(subfit.uvalue("threshold"),
                                         unit="mA"))
        print("Slope:", formatUFloat(subfit.uvalue("slope"), unit="W/A"))
        print("Chi^2/ndf:", subfit.chi2ndf)
        print("===")

        subfit.plot(range=(subfit.value("threshold"), current.max()),
                    color="black",
                    plot_fit=False,
                    plot_data=True,
                    fmt="s")
        subfit.plot(range=(subfit.value("threshold"), current.max()),
                    box="tl",
                    color="red",
                    plot_data=False,
                    units={
                        "threshold": "mA",
                        "slope": "W/A"
                    })
        plt.savefig("out/kennlinie_diode_%d_fit." % i + SAVETYPE)

        plt.clf()
        subfit.plot_residual(box="br", color="black", fmt="s")
        plt.savefig("out/kennlinie_diode_%d_residual." % i + SAVETYPE)
Example #9
0
def plot_qswitch():
    frequency, error_frequency, power = np.loadtxt("data/frequenz_qswitch.txt",
                                                   unpack=True)
    error_power = 1 / math.sqrt(12)

    power /= 1000
    error_power /= 1000

    plt.clf()
    plt.errorbar(frequency,
                 power,
                 xerr=error_frequency,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Frequenz / Hz")
    plt.ylabel("Leistung / mW")
    plt.savefig("out/qswitch_raw." + SAVETYPE)

    #power -= power[0]

    fit = Fit(POLY3)
    fit.set_data(xdata=frequency,
                 ydata=power,
                 xerrors=error_frequency,
                 yerrors=error_power)
    fit.set_params(a0=380, a1=0.005, a2=-7e-8)
    fit.set_labels(xlabel="Frequenz / Hz", ylabel="Leistung / mW")

    subfit = fit.filtered(np.logical_and(frequency < 20e3, frequency > 1e3))
    subfit.iterative_fit(5)

    plt.clf()
    subfit.plot(box="br",
                units={
                    "a3": "mW/Hz^3",
                    "a2": "mW/Hz^2",
                    "a1": "mW/Hz",
                    "a0": "mW"
                })
    plt.savefig("out/qswitch_power_fit." + SAVETYPE)

    plt.clf()
    subfit.plot_residual(box="tr")
    plt.savefig("out/qswitch_power_residual." + SAVETYPE)

    plt.clf()
    time, voltage = _load_oscilloscope_csv("data/ALL0023/F0023CH2.CSV")
    time *= 1E6
    time -= -935

    plt.plot(time, voltage, ".", color="black")

    pause = np.logical_and(time > 300, time < 900)
    one_period = np.logical_and(time > 0, time < 1000)
    print(one_period, one_period.sum())

    mean_voltage = ufloat(voltage[one_period].mean(),
                          voltage[pause].std() / math.sqrt(one_period.sum()))
    peak_voltage = ufloat(voltage[one_period].max(), voltage[pause].std())

    print("ErrorL:", voltage[pause].std())

    print("Mean voltage:", mean_voltage, "V")
    print("Peak voltage:", peak_voltage, "V")

    frequency = 1.01798e3  # Hz
    mean_power = subfit.ueval(frequency)
    print("Mean power:", mean_power * 1000, "uW")

    peak_power = mean_power * peak_voltage / mean_voltage
    print("Peak power:", peak_power * 1000, "uW")

    plt.axhline(mean_voltage.n, color="red", linewidth=2)
    plt.axhline(peak_voltage.n, color="red", linewidth=2)

    plt.xlabel("Zeit / us")
    plt.ylabel("Spannung / V")

    plt.savefig("out/qswitch_osci." + SAVETYPE)
Example #10
0
def plot_ktp():
    current, power, error_power = np.loadtxt("data/ktp_kristall.txt",
                                             unpack=True)
    error_current = 1 / math.sqrt(12)

    # uW -> mW
    power /= 1000
    error_power /= 1000

    plt.clf()
    plt.errorbar(current,
                 power,
                 xerr=error_current,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Strom / mA")
    plt.ylabel("Leistung mit KTP / mW")
    plt.xlim(0, 700)
    plt.savefig("out/ktp_raw." + SAVETYPE)

    lower = np.logical_and(current > 182.10, current < 410)
    upper = current >= 410

    diode_power, error_diode_power = current2diode_power(
        current, error_current)

    plt.clf()
    plt.errorbar(diode_power,
                 power,
                 xerr=error_diode_power,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Diodenleistung / mW")
    plt.ylabel("Laserleistung mit KTP / mW")
    plt.savefig("out/ktp_raw2." + SAVETYPE)

    yag_power, error_yag_power = diode_power2yag_power(diode_power,
                                                       error_diode_power)

    plt.clf()
    plt.errorbar(yag_power,
                 power,
                 xerr=error_yag_power,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Laserleistung ohne KTP / mW")
    plt.ylabel("Laserleistung mit KTP / mW")
    plt.xlim(0, 10)
    plt.savefig("out/ktp_raw3." + SAVETYPE)

    plt.clf()
    fit = Fit(POLY2)
    fit.set_data(xdata=yag_power,
                 ydata=power,
                 xerrors=error_yag_power,
                 yerrors=error_power)
    fit.set_labels(xlabel="Laserleistung ohne KTP / mW",
                   ylabel="Laserleistung mit KTP / mW")

    fit = fit.filtered(yag_power > 2)

    fit.iterative_fit(5)

    fit.plot(box="tl", units={"a2": "1/mW", "a0": "mW"})
    plt.savefig("out/ktp_fit." + SAVETYPE)

    plt.clf()
    fit.plot_residual(box="tl")
    plt.savefig("out/ktp_residual." + SAVETYPE)
Example #11
0
def plot_yag_kennlinie():
    current, power, error_power = np.loadtxt("data/kennlinie_yag2.txt",
                                             unpack=True)
    error_current = 1 / math.sqrt(12)

    plt.clf()
    plt.errorbar(current,
                 power,
                 xerr=error_current,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Strom / mA")
    plt.ylabel("Leistung / mW")
    plt.xlim(0, 700)
    plt.savefig("out/kennlinie_yag_raw." + SAVETYPE)

    lower = np.logical_and(current > 182.10, current < 410)
    upper = current >= 410

    fit_indices_list = []
    fit_indices_list.append(power > 0.10)
    #fit_indices_list.append(np.logical_and(power > 0.10, lower))
    #fit_indices_list.append(np.logical_and(power > 0.10, upper))

    diode_power, error_diode_power = current2diode_power(
        current, error_current)

    zero_power = power[current < 150]
    background = zero_power.mean()
    print("Background:", background, "mW")
    power -= background

    plt.clf()
    plt.errorbar(diode_power,
                 power,
                 xerr=error_diode_power,
                 yerr=error_power,
                 fmt=',',
                 color="black")
    plt.xlabel("Diodenleistung / mW")
    plt.ylabel("Laserleistung / mW")
    plt.savefig("out/kennlinie_yag_raw2." + SAVETYPE)

    func = lambda x, slope, threshold: (x - threshold) * slope
    fit = Fit(func)
    fit.set_params(slope=0.016, threshold=16)
    fit.set_data(xdata=diode_power,
                 ydata=power,
                 xerrors=error_diode_power,
                 yerrors=error_power)
    fit.set_labels(xlabel="Diodenleistung / mW", ylabel="Laserleistung / mW")
    fit.iterative_fit(1)

    plt.clf()
    fit.plot(plot_data=True, plot_fit=True, box="tr")
    plt.savefig("out/kennlinie_yag_linear_fit." + SAVETYPE)
    plt.clf()
    fit.plot_residual(box="br", fmt="s")
    plt.savefig("out/kennlinie_yag_linear_residual." + SAVETYPE)

    fit = Fit(POLY2)
    fit.set_data(xdata=diode_power,
                 ydata=power,
                 xerrors=error_diode_power,
                 yerrors=error_power)
    fit.set_labels(xlabel="Diodenleistung / mW", ylabel="Laserleistung / mW")
    fit.iterative_fit(5)

    for i, fit_indices in enumerate(fit_indices_list):
        plt.clf()
        fit.plot(plot_fit=False)
        subfit = fit[fit_indices]
        subfit.iterative_fit(5)

        #zero_power = power[power < 0.03]
        #zero = umean(zero_power)
        #plt.axhline(zero.n, color="blue")

        print(subfit)

        x = 200
        try:
            i_threshold = solve_quadratic(subfit.uvalue("a0"),
                                          subfit.uvalue("a1"),
                                          subfit.uvalue("a2"))
            i_slope = 2 * x * subfit.uvalue("a2") + subfit.uvalue("a1")
        except ValueError:
            print("no solution", i)
        else:
            print("Threshold:", formatUFloat(i_threshold, unit="mW"))
            print("Efficiency:", formatUFloat(i_slope * 100, unit="%"))
            lines = "threshold = " + formatUFloat(
                i_threshold, unit="mW"
            ) + "\n" + "efficiency at %d mW = " % x + formatUFloat(
                i_slope * 100, unit="%")
            info_box(lines, location="tl")

        subfit.plot(plot_data=False)
        plt.savefig("out/kennlinie_yag_%d_fit." % i + SAVETYPE)

        plt.clf()
        subfit.plot_residual(box="br", color="black", fmt="s")
        plt.savefig("out/kennlinie_yag_%d_residual." % i + SAVETYPE)

        plt.clf()
        x = diode_power[diode_power > i_threshold.n]
        plt.plot(x,
                 100 * (2 * x * subfit.value("a2") + subfit.value("a1")),
                 color="black")
        #x_new = diode_power - i_threshold.n
        #plt.plot(diode_power, 100*(x_new*subfit.value("a2") + subfit.value("a1") + subfit.value("a0")/x_new), color="red")
        plt.xlabel("Diodenleistung / mW")
        plt.ylabel("Effizienz / %")
        plt.savefig("out/kennlinie_yag_%d_efficiency." % i + SAVETYPE)