예제 #1
0
파일: fit2p.py 프로젝트: Yobmod/dmlmung
def multi_fit(data_dir: str, plot: str = "best") -> FittedMultiData:
    """Fits all files in a folder.
    if plot = "best", plots best fitted data
    if plot = "all", plots all
    if plot = "", plot none
    """

    group_fitted = {}
    group_fitted_list = []

    for filepath in reversed(list(Path(data_dir).glob('*.csv'))):
        filename = str(filepath.name)
        array = open_file_numpy(data_dir, filename)
        data = get_data_numpy(array)
        (freq_log, imped_log, phase, imag_imped, real_imped) = data
        single_data = SingleData(data=data, params=get_params(data_dir, filename))
        # print(single_data)
        fitted_dict = fit(data_dir, filename, plot=plot)
        best_fit, chi2, f, Z, Z_fit, circuit_str, voltage = list(fitted_dict.values())[0]
        R0, R1, R2, C2, CPP2, C1, CPP = best_fit
        print(chi2, R0, R1, R2, C2, C1, CPP, CPP2)

        fit_dc = fit_single_data(stored_data=single_data, fit_params=best_fit,
                                 chi2=chi2, circuit=circuit_str, Z_fit=Z_fit)
        assert fit_dc.voltage == voltage

        if plot == "best" or "both":
            import matplotlib.pyplot as plt
            fig, ax = plt.subplots()
            plot_nyquist(ax, Z, fmt='o')
            plot_nyquist(ax, Z_fit, fmt='-')
            plt.legend(['Data', 'Fit'])
            plt.title(f"{voltage}, chi2={chi2:.3f}")  # , R2={best_fit[1]}, C2={best_fit[0]}, R3={R3}, C3={C3} ")
            # plt.show()
            fig.set_size_inches(18.5, 10.5, forward=True)
            plt.savefig(Rf'{data_dir}\{fit_dc.voltage}_bestfit2Rp.png',
                        bbox_inches='tight', dpi=500, transparent=True)

        with open(R".\res.csv", 'a') as f:
            f.write(f"{fit_dc.voltage}, \t {R0}, {R1}, {C1}, {CPP}, {R2}, {C2}, {CPP2} \n")

        group_fitted[fit_dc.voltage] = {
            'circuit_str': circuit_str,
            'fit': best_fit,
            'chi2': chi2,
            'data': (f, Z, Z_fit),
            'voltage': voltage,
            'invsqc1': 1 / (C1 ** 2 * 1000000000000),
            'invsqc2': 1 / (1 / C2 ** 2 * 1000000000000)
        }
        group_fitted_list.append(fit_dc)

    group_fitted_dc = FittedMultiData(group_fitted_list)
    # group_fitted_json = json.dumps(group_fitted, sort_keys=True, indent=4, separators=(',', ': '))
    # with open(Rf'{data_dir}\fitted_data.json', 'w') as f:
    # f.write(group_fitted_json)

    return group_fitted_dc
예제 #2
0
def main() -> None:
    data_dir = str(Path.cwd())
    settings = get_json_settings('settings')

    both_plot_exists = False
    phase_plot_exists = False
    gain_plot_exists = False
    nyquist_exists = False
    voltages = []

    for filepath in Path(data_dir).glob('*.csv'):

        filename = filepath.name
        params = get_params(data_dir,
                            filename)  # get parameters from file name
        pprint.pprint(params.voltage)
        df = open_file_numpy(
            data_dir, filename)  # open file if csv and read into numpy array
        if df is not None and df.any():
            data = get_data_numpy(
                df)  # return impedance (5 columns) or cv data (4 columns)
        else:
            data = None
        if data and len(data) == 5:
            write_imp_data(data, params)  # writes to csv
            write_zview_data(data, params)
            (freq_log, imped_log, phase, imag_imped, real_imped) = data

        if not both_plot_exists:
            bode_both = multi_bode_axes(settings, y_axes="both")  # create axes
            both_plot_exists = True  # make truthy
        multi_bode_add_data(bode_both, freq_log, imped_log, phase, params)

        if not phase_plot_exists:
            bode_phase = multi_bode_axes(settings,
                                         y_axes="phase")  # create axes
            phase_plot_exists = True  # make truthy
            # multi_bode_title(bode_phase, params, settings)
        multi_bode_add_data(bode_phase, freq_log, imped_log, phase, params)

        if not gain_plot_exists:
            bode_gain = multi_bode_axes(settings, y_axes="gain")  # create axes
            gain_plot_exists = True  # make truthy
        multi_bode_add_data(bode_gain, freq_log, imped_log, phase, params)

        if not nyquist_exists:
            nyquist = multi_nyquist_axes(settings)
            nyquist_exists = True
        multi_nyquist_add_data(nyquist, imag_imped, real_imped, params)

        voltages.append(params.voltage)

        multi_bode_plot_save(bode_both, params)
        multi_bode_plot_save(bode_phase, params)
        multi_bode_plot_save(bode_gain, params)
        multi_nyquist_plot_save(nyquist, params)  # , set_colors='twilight',)
예제 #3
0
def multi_fit(data_dir: str,
              plot: str = "both",
              output_dir: str = "") -> FittedMultiData:
    """Fits all files in a folder.
    if plot = "best", plots best fitted data
    if plot = "all", plots all
    if plot = "", plot none
    """
    data_path = Path(data_dir)

    output_path = Path(
        output_dir) if output_dir else data_path.parent / "output"
    group_fitted = {}
    group_fitted_list = []

    for filepath in list(data_path.glob('*.csv'))[1:]:
        filename = str(filepath.name)
        array = open_file_numpy(data_dir, filename)
        data = get_data_numpy(array)
        (freq_log, imped_log, phase, imag_imped, real_imped) = data
        single_data = SingleData(data=data,
                                 params=get_params(data_dir, filename))
        # print(single_data)
        fitted_dict = fit(data_dir, filename, plot=plot)

        if plot in ("all", "both"):
            number_printed = 21
        elif plot == "best":
            number_printed = 1

        for i in range(number_printed):
            loop_fit, chi2_loop, f_array, Z_loop, Z_fit_loop, circuit_str, voltage = list(
                fitted_dict.values())[i]
            fit_dc = FittedSingleData(stored_data=single_data,
                                      fit_params=loop_fit,
                                      chi2=chi2_loop,
                                      circuit=circuit_str,
                                      Z_fit=Z_fit_loop)
            R0, R1, C1, CPP, R2, C2, CPP2, R3, C3, CPP3 = loop_fit

            import matplotlib.pyplot as plt
            fig, ax = plt.subplots()
            plot_nyquist(ax, Z_loop, fmt='o')
            plot_nyquist(ax, Z_fit_loop, fmt='-')
            plt.legend(['Data', 'Fit'])
            plt.title(f"{voltage}_{chi2_loop:.4f}")
            fig.set_size_inches(8.5, 5.5, forward=True)

            plt.gcf().text(
                1.1,
                0.1,
                f"R0={R0: .0f}\n\n R1={R1: .0f}\n C1={C1}\n CPE1={CPP}\n\n  R2={R2: .0f}\n C2={C2}\n CPE2={CPP2}\n\n  R3={R3:.0f}\n C3={C3}\n CPE3={CPP3}\n\n {circuit_str}\n\n chi2v={chi2_loop}",
                fontsize=12)

            chi_str = f"{chi2_loop: .8f}".replace('.', '_')
            plt.savefig(
                Rf'{output_path}\{voltage}_chi_{chi_str}_{circuit_str}.png',
                bbox_inches='tight',
                dpi=500,
                transparent=True)

            if i == 0 and plot in ("best", "both"):
                plt.savefig(
                    Rf'{output_path}\best\{voltage}_chi_{chi_str}_{circuit_str}_b.png',
                    bbox_inches='tight',
                    dpi=500,
                    transparent=True)
                with open(R".\res_best.csv", 'a') as data_f:
                    data_f.write(
                        f"""{fit_dc.voltage}, \t  \n {chi2_loop} {R0}, {R1}, {C1}, {CPP}, {R2}, {C2},
                             {CPP2}, {R3}, {C3}, {CPP3}, \n""")
            plt.close()
            # plt.show()
            group_fitted[fit_dc.voltage] = {
                'circuit_str': circuit_str,
                'fit': loop_fit,
                'chi2': chi2_loop,
                'data': (f_array, Z_loop, Z_fit_loop),
                'voltage': voltage,
                'invsqc1': 1 / (C1**2),
                'invsqc2': 1 / (C2**2)
            }
            # group_fitted_json = json.dumps(group_fitted, sort_keys=True, indent=4, separators=(',', ': '))
            # with open(Rf'{data_dir}\fitted_data.json', 'w') as f:
            # f.write(group_fitted_json)
            group_fitted_list.append(fit_dc)
    group_fitted_dc = FittedMultiData(group_fitted_list)
    return group_fitted_dc
예제 #4
0
def fit(data_dir, filename, plot: str = ""):

    array = open_file_numpy(data_dir, filename)
    params = get_params(data_dir, filename)
    print(array.shape)
    data = get_data_numpy(array)
    (freq_log, imped_log, phase, imag_imped, real_imped) = data
    freq = np.power(10, freq_log)

    # np.savetxt("zzz.csv", np.concatenate((freq, real_imped, -imag_imped), axis=1), delimiter=",")
    # f, Z = preprocessing.readCSV("zzz.csv")
    f = freq[:, 0]
    Z = np.array(real_imped + 1j * -imag_imped, dtype=np.complex)[:, 0]

    circuit_str_5a = 'R0-p(R1,CPE1)-p(R2,CPE2)-p(R3,CPE3)'

    R0_guesses = [6850]
    R1_guesses = [1E7, 1E6]
    C1_guesses = [5E-8, 1E-8, 5E-9]
    CPP_guesses = [0.8, 0.9, 1.0]
    R2_guesses = [1E7, 1E5, 1E6, 1E4]
    C2_guesses = [1E-6, 1E-7, 1E-8]
    CPP2_guesses = [0.9, 0.8, 1.0]
    R3_guesses = [1E7, 1E5, 1E6]
    C3_guesses = [1E-5, 1E-6, 1E-7, 1E-8]
    CPP3_guesses = [0.5]
    initial_guesses_5a = []

    for R0 in R0_guesses:
        for R1 in R1_guesses:
            for C1 in C1_guesses:
                for CPP in CPP_guesses:
                    for R2 in R2_guesses:
                        for C2 in C2_guesses:
                            for CPP2 in CPP2_guesses:
                                for R3 in R3_guesses:
                                    for CPP3 in CPP3_guesses:
                                        for C3 in C3_guesses:
                                            initial_guesses_5a.append([
                                                R0, R1, C1, CPP, R2, C2, CPP2,
                                                R3, C3, CPP3
                                            ])
    num_init_guesses = len(initial_guesses_5a)
    print(f"{num_init_guesses} guess combinations for {circuit_str_5a}")
    assert all(initial_guesses_5a), "Cannot use 0 for any initial guesses"
    chi_sentinal = 0.1
    num_remaining = num_init_guesses
    fitted_dict = {}
    for initial_guess in initial_guesses_5a:

        # print(params.voltage, initial_guess)
        num_remaining -= 1
        circuit = CustomCircuit(circuit=circuit_str_5a,
                                initial_guess=initial_guess)
        circuit.fit(
            f,
            Z,
            global_opt=False,
            bounds=(
                # R0        R1      C1     CPP1         R2      C2      CPP2      R3    C3      CPP3"
                [6800, 0, 1E-9, 0.78, 0, 0, 0.78, 0, 0, 0.48],
                [7000, np.inf, 1E-6, 1, np.inf, 1E-5, 1, np.inf, 1E-5, 0.52]))

        fitted_params = circuit.parameters_
        R0, R1, C1, CPP, R2, C2, CPP2, R3, C3, CPP3 = circuit.parameters_
        Z_fit = circuit.predict(f)

        dof = len(Z) - len(
            initial_guess
        )  # Degrees of freedom - i.e. number of data points - number of variables

        Re_Z = np.real(Z)  # Extract real part of Z
        Re_Z_fit = np.real(Z_fit)  # Extract real part of Z_fit
        variance_re = sum(
            (Re_Z - Re_Z.mean())**2) / (len(Re_Z) - 1)  # Variance
        Chi_square_re = sum(((Re_Z - Re_Z_fit)**2) / variance_re)

        Im_Z = np.imag(Z)  # Extract real part of Z
        Im_Z_fit = np.imag(Z_fit)  # Extract real part of Z_fit
        variance_im = sum(
            (Im_Z - Im_Z.mean())**2) / (len(Im_Z) - 1)  # Variance
        Chi_square_im = sum(((Im_Z - Im_Z_fit)**2) / variance_im)

        Zsq = np.sqrt(abs(Re_Z**2 + Im_Z**2))
        Zsq_fit = np.sqrt(abs(Re_Z_fit**2 + Im_Z_fit**2))
        variance = sum((Zsq - Zsq.mean())**2) / (len(Z) - 1)  # Variance
        Chi_square = sum(((Zsq - Zsq_fit)**2) / variance)
        chi_square_diag = sqrt(Chi_square_re**2 + Chi_square_im**2)

        red_Chi_sq = Chi_square / dof  # Reduced Chi squared
        std_err = np.sqrt(red_Chi_sq) * 100
        fitted_dict[tuple(initial_guess)] = (fitted_params, red_Chi_sq, f, Z,
                                             Z_fit, circuit_str_5a,
                                             params.voltage)

        divisor = 60 if num_init_guesses > 60 else num_init_guesses
        if num_remaining in range(1, num_init_guesses,
                                  int(num_init_guesses / divisor)):
            print(f"{initial_guess}  -  {num_remaining} guesses left")

        # if chi_square_diag < chi_sentinal or chi_square_diag < 0.005 or Chi_square_re < chi_re_sentinal or Chi_square_re < 0.0038:
        if red_Chi_sq < chi_sentinal:
            chi_sentinal = red_Chi_sq * 1.02
            print(
                f"Fit {params.voltage}, red_chi2={red_Chi_sq:.8f}, chi2_re={Chi_square_re:.3f}, chi2_im={Chi_square_im:.3f}, std_err={std_err:.4f}, circuit={circuit_str_5a}\t {num_remaining} guesses left"
            )

    fitted_tuple = sorted(fitted_dict.items(), key=lambda item: item[1][1])
    sorted_fitted_dict = OrderedDict(fitted_tuple)
    # pprint.pprint(sorted_fitted_dict)
    return sorted_fitted_dict
예제 #5
0
파일: fit2p.py 프로젝트: Yobmod/dmlmung
def fit(data_dir, filename, plot: str = ""):

    array = open_file_numpy(data_dir, filename)
    params = get_params(data_dir, filename)
    print(array.shape)
    data = get_data_numpy(array)
    (freq_log, imped_log, phase, imag_imped, real_imped) = data
    freq = np.power(10, freq_log)

    # np.savetxt("zzz.csv", np.concatenate((freq, real_imped, -imag_imped), axis=1), delimiter=",")
    # f, Z = preprocessing.readCSV("zzz.csv")
    f = freq[:, 0]
    Z = np.array(real_imped + 1j * -imag_imped, dtype=np.complex)[:, 0]

    circuit_str_5a = 'R0-p(R1-p(R2,CPE2),CPE1)'

    R0_guesses = [6850]
    R1_guesses = [1E7, 1E6, 1E8, 5E8]
    C1_guesses = [5E-8, 1E-8, 5E-9, 5E-7, 1E-6]  # , 5E-9, 5E-8, 1E-8]
    CPP_guesses = [0.8, 0.9, 1.0]
    R2_guesses = [1E5, 1E6, 1E7, 1E8]
    C2_guesses = [5E-6, 1E-6, 1E-7, 1E-8]
    CPP2_guesses = [0.8, 0.9, 1.0]
    initial_guesses_5a = []

    for R0 in R0_guesses:
        for R1 in R1_guesses:
            for C1 in C1_guesses:
                for CPP in CPP_guesses:
                    for R2 in R2_guesses:
                        for C2 in C2_guesses:
                            for CPP2 in CPP2_guesses:
                                initial_guesses_5a.append([R0, R1, R2, C2, CPP2, C1, CPP])
    num_init_guesses = len(initial_guesses_5a)
    print(f"{num_init_guesses} guess combinations")
    assert all(initial_guesses_5a), "Cannot use 0 for any initial guesses"
    chi_sentinal = 1.0
    chi_re_sentinal = 1.0
    num_remaining = num_init_guesses
    fitted_dict = {}
    for initial_guess in initial_guesses_5a:
        # print(params.voltage, initial_guess)
        num_remaining -= 1
        circuit = CustomCircuit(circuit=circuit_str_5a, initial_guess=initial_guess)
        circuit.fit(f, Z, global_opt=False, bounds=(
            # R0        R1      R2          C2      CPP2        C1     CPP1
            [6800,      0,      0,          1E-9,      0.78,     1E-9,      0.78],
            # [7000,      1E8,    1E-5,      1,      1E8,      1E-5,      1]
            [7000,      np.inf, np.inf,   1E-5,       1,        1E-5,     1]
        ))

        fitted_params = circuit.parameters_
        R0, R1, R2, C2, CPP2, C1, CPP = circuit.parameters_
        Z_fit = circuit.predict(f)

        # dof = len(Z)-len(initial_guess)                        # Degrees of freedom - i.e. number of data points - number of variables

        Re_Z = np.real(Z)                                        # Extract real part of Z
        Re_Z_fit = np.real(Z_fit)                                # Extract real part of Z_fit
        variance_re = sum((Re_Z-Re_Z.mean())**2) / (len(Re_Z)-1)    # Variance
        Chi_square_re = sum(((Re_Z-Re_Z_fit)**2)/variance_re)

        Im_Z = np.imag(Z)                                        # Extract real part of Z
        Im_Z_fit = np.imag(Z_fit)                                # Extract real part of Z_fit
        variance_im = sum((Im_Z-Im_Z.mean())**2) / (len(Im_Z)-1)    # Variance
        Chi_square_im = sum(((Im_Z-Im_Z_fit)**2)/variance_im)

        variance = sum((Z-Z.mean())**2) / (len(Z)-1)    # Variance
        Chi_square = sum(((Z-Z_fit)**2)/variance)
        chi_square_diag = sqrt(Chi_square_re**2 + Chi_square_im**2)

        red_Chi_sq = Chi_square_re  # Reduced Chi squared

        fitted_dict[tuple(initial_guess)] = (fitted_params, red_Chi_sq, f, Z, Z_fit, circuit_str_5a, params.voltage)

        if num_remaining in range(1, num_init_guesses, int(num_init_guesses / 60)):
            print(f"{initial_guess}  -  {num_remaining} guesses left")

        if chi_square_diag < chi_sentinal or chi_square_diag < 0.01 or Chi_square_re < chi_re_sentinal or Chi_square_re < 0.005:
            if chi_square_diag < chi_sentinal:
                chi_sentinal = chi_square_diag * 1.1
            if Chi_square_re < chi_re_sentinal:
                chi_re_sentinal = Chi_square_re * 1.1

            print(f"Fit {params.voltage}, chi2_re={Chi_square_re:.3f}, chi2_im={Chi_square_im:.3f}, chi2_diag={chi_square_diag:.3f}, circuit={circuit_str_5a}\t {num_remaining} guesses left")

            if plot in ("all", "both"):
                import matplotlib.pyplot as plt
                fig, ax = plt.subplots()
                plot_nyquist(ax, Z, fmt='o')
                plot_nyquist(ax, Z_fit, fmt='-')
                plt.legend(['Data', 'Fit'])
                plt.title(f"{params.voltage}_{red_Chi_sq:.4f}")
                plt.gcf().text(
                    0.8, 0.7,
                    f" R0={R0:.0f}\n\n R1={R1:.0f}\n C1= {C1}\n CPE1={CPP}\n\n R2={R2:.0f}\n C2={C2}\n CPE2={CPP2}\n\n {circuit_str_5a}",
                    fontsize=12)

                fig.set_size_inches(8.5, 5.5, forward=True)
                chi_str = f"{red_Chi_sq: .6f}".replace('.', '_')
                plt.savefig(Rf'{data_dir}\all\{params.voltage}_chi_{chi_str}_{circuit_str_5a}.png',
                            bbox_inches='tight', dpi=500, transparent=True)
                plt.close()
                # plt.show()

    fitted_tuple = sorted(fitted_dict.items(), key=lambda item: item[1][1])
    sorted_fitted_dict = OrderedDict(fitted_tuple)
    # pprint.pprint(sorted_fitted_dict)
    return sorted_fitted_dict