コード例 #1
0
ファイル: cc_fit.py プロジェクト: zhangwise/Cole-Cole-fit
    def initial_parameter_heuristic_2(self, spectrum):
        """
        Heuristic 2

        Initialize a Cole-Cole parameter set with heuristically determined
        parameters.

        This heuristic uses the following procedure for the CC parameters:

            - rho0 is determined by the lowest frequency magnitude
            - m is determined using a simple line search which samples the
              space 0.01 - 1.0
            - tau values are determined by logspacing the number of terms over
              the frequency range.
            - c is set to 0.5
        """
        print('Heuristic 2')
        nr_cc_pars = 1 + 3 * self.nr_cc_terms
        p0 = np.zeros((1, nr_cc_pars)).flatten()
        # rho0
        p0[0] = spectrum[0]

        # c
        c_indices = [i * 3 + 3 for i in xrange(self.nr_cc_terms)]
        p0[c_indices] = 0.5
        # tau
        tau_min = 1.0 / (2 * np.pi * self.frequencies.max())
        tau_max = 1.0 / (2 * np.pi * self.frequencies.min())

        tau_indices = [i * 3 + 2 for i in xrange(self.nr_cc_terms)]
        # log-space sampling of tau range
        # use 2 more tau values for the boundaries:
        # we do not want to set an initial tau value to one the frequency
        # boundaries.
        tau_space = np.logspace(np.log10(tau_min),
                                np.log10(tau_max),
                                self.nr_cc_terms + 2)
        p0[tau_indices] = np.log(tau_space[1:-1])

        # m
        # m is selected by testing m values within a certain value range for
        # the smallest phase rms
        m_indices = [i * 3 + 1 for i in xrange(self.nr_cc_terms)]
        test_m_values = np.linspace(0.05, 0.9, 10)
        best_index = -1
        best_rms = np.inf

        for index, test_m in enumerate(test_m_values):
            p0[m_indices] = test_m
            test_forward = colecole.cole_log(self.fin, p0)
            test_phase_rms = self._phase_rms(spectrum, test_forward)
            if test_phase_rms < best_rms:
                best_index = index
                best_rms = test_phase_rms

        p0[m_indices] = test_m_values[best_index]

        return p0
コード例 #2
0
ファイル: cc_fit.py プロジェクト: zhangwise/Cole-Cole-fit
    def plot_spectrum(self, filename, id):
        """
        Plot the spectrum specified by id to a file.
        """
        print('Plotting spectrum {0} of {1}'.format(id + 1,
                                                    self.data.shape[0]))
        # use more frequencies
        f_e = np.logspace(np.log10(self.frequencies.min()),
                          np.log10(self.frequencies.max()),
                          100)
        fin_e = np.hstack((f_e, f_e))
        # generate forward response
        forward_orig_f = colecole.cole_log(self.fin, self.cc_pars[id])
        forward = colecole.cole_log(fin_e, self.cc_pars[id])
        forward_init = colecole.cole_log(fin_e, self.cc_pars_init[id])

        # generate forward response for each CC term
        forward_cc_terms = []
        for i in range(0, (len(self.cc_pars[id]) - 1) / 3):
            oneterm_cc = [0, (i * 3) + 1, (i * 3) + 2, (i * 3) + 3]
            forward_cc_terms.append(
                colecole.cole_log(fin_e, self.cc_pars[id][oneterm_cc]))

        fig, axes = plt.subplots(3, 1, figsize=(7, 6))

        # plot magnitude
        ax = axes[0]
        ax.semilogx(f_e,
                    (np.exp(forward_init[0, :])),
                    'b-',
                    linestyle='dashed',
                    label='initial parameters')
        ax.semilogx(f_e,
                    (np.exp(forward[0, :])),
                    'g-',
                    label='fit response')

        ax.semilogx(self.frequencies,
                    (np.exp(self.data[id, 0: len(self.data[id, :]) / 2])),
                    'r.', linewidth=2.0,
                    label='data')
        ax.set_title('magnitude RMS: {0:.3e}'.format(self.magnitude_rms[id]))
        ax.set_xlabel('frequency [Hz]')
        ax.set_ylabel(r'$|Z/\rho| [\Omega (m)]$')

        # plot phase
        ax = axes[1]
        ax.semilogx(f_e, -forward[1, :], 'g-', linewidth=2.0,
                    label='fit response')
        ax.semilogx(self.frequencies,
                    -self.data[id, len(self.data[id, :]) / 2:],
                    'r.', linewidth=2.0,
                    label='data')

        ax.semilogx(f_e,
                    -forward_init[1, :],
                    'b-', linestyle='dashed',
                    label='initial model')
        # plot single terms
        colors = ('k', 'gray')
        for nr, term in enumerate(forward_cc_terms):
            ax.semilogx(f_e,
                        -term[1, :],
                        '-', color=colors[nr % 2],
                        linestyle='dashed',
                        label='term {0}'.format(nr + 1)
                        )

        ax.legend(loc="upper center", ncol=3, bbox_to_anchor=(0, 0, 1, 1),
                  bbox_transform=fig.transFigure)
        ax.set_title('phase RMS: {0:.3e}'.format(self.phase_rms[id]))
        ax.set_xlabel('frequency [Hz]')
        ax.set_ylabel(r'$-\varphi~[mrad]$')

        # plot phase residuals
        ax = axes[2]
        pha_residuals = np.abs(forward_orig_f[1, :] -
                               self.data[id, len(self.data[id, :]) / 2:])
        ax.semilogx(self.frequencies, pha_residuals, '-')
        ax.set_xlabel('frequency [Hz]')
        ax.set_ylabel(r'abs ($\phi_{inv} - \phi_{ori}$)')
        ax.set_title(
            'RMS: {0}'.format(np.sqrt(np.sum(pha_residuals ** 2)) /
                              self.frequencies.shape[0]))

        for ax in axes:
            ax.yaxis.set_major_locator(mpl.ticker.MaxNLocator(5))
        fig.tight_layout()
        fig.subplots_adjust(top=0.8)
        fig.savefig('{0}.png'.format(filename))
        plt.close(fig)
コード例 #3
0
ファイル: cc_fit.py プロジェクト: zhangwise/Cole-Cole-fit
    def __residuals(self, p, y, x):
        """
        Compute residuals of the measured data y and the response of the
        Cole-Cole function cole_log for the x(frequency) values and the
        parameters p. Used for leastsq function.
        """

        try:
            erg = colecole.cole_log(x, p)
        except:
            raise('error')

        erg1 = np.hstack((erg[0, :], erg[1, :]))
        err = y - erg1

        # NaN check and set err to 1e10
        if(np.isnan(err).any()):
            err *= 10e10

        # y holds the original data
        # compute weighting factors according to the invers of the phase values
        # mag_ori = y[:y.shape[0] / 2]
        # pha_ori = y[y.shape[0] / 2:]

        # mean_all = np.mean(np.abs(y))

        #   mean_weight_all = np.abs(y) / mean_all

        # err /= mean_weight_all

        # we want both mag and pha to have equal mean values AFTER weighting
        # pha_mean_weight = np.abs(np.mean(mag_ori)) / np.abs(np.mean(pha_ori))
#       print('mean(mag)', np.mean(mag_ori))
#       print('mean(pha)', np.mean(pha_ori * pha_mean_weight))

#       pha_weighting = np.abs(pha_ori)**2
#       #       pha_weighting = (np.abs(pha_ori)**4)
#        pha_weighting = (np.abs(pha_ori))**2 * 10
#     #  print(pha_weighting)
#       err[err.shape[0]/2:] *= pha_weighting
#       err[err.shape[0]/2:] *= pha_mean_weight

#       # mag
#       err[0:err.shape[0]/2] *= 100

        # implement a simple form of limit checking. If the given Cole-Cole
        # parameters lie out of certain bounds, increase the residual to a very
        # large value. This will ensure that this parameter set will not be
        # used any more.

#       #rho0
#       if(p[0] > 10e6 or np.abs(np.exp(p[0]) - np.exp(y[0])) > 0.5):
#           err *= 1e10

        # m
        if(p[1] < 0 or (len(p) > 4 and p[4] < 0)):
            err *= 1e10

        if(p[1] > 1 or (len(p) > 4 and p[4] > 1)):
            err *= 1e10

        # tau
        if(p[2] < -12):
            err += 1e10
        # c
        if(p[3] < 0 or p[3] > 1):
            err *= 1e10

        # 2 CC terms and tau
        if(len(p) > 4 and (p[6] < 0 or p[6] > 1)):
            err *= 1e10

        return err
コード例 #4
0
ファイル: cc_fit.py プロジェクト: zhangwise/Cole-Cole-fit
    def fit_spectrum(self, spectrum, p0):
        """
        Fit a spectrum, given the data, the frequencies, and the starting
        parameters.

        Return the fit results, the magnitude and phase RMS, and the forward
        response of the fit parameters.
        """
        nr_to_fit = len(spectrum) / 2

        y_meas = np.hstack(
            (spectrum[0:nr_to_fit],
             spectrum[len(spectrum) / 2:len(spectrum) / 2 + nr_to_fit]))
        x = np.hstack((self.fin[0:nr_to_fit],
                       self.fin[len(self.fin) / 2:len(self.fin) /
                                2 + nr_to_fit]))

        # the actual fitting routine
        plsq, cov, info, mesg, success = leastsq(
            self.__residuals, p0, args=(y_meas, x),
            full_output=1,
            maxfev=10000000)
        # plsq,cov,info,mesg,success = leastsq(
        #   self.__residuals, p0, Dfun=self.__Dres,
        #   args=(y_meas, x), maxfev= 10000000, full_output=1)

        # compute spectral response using fit results
        forward = colecole.cole_log(self.fin, plsq)

        # compute mag rms
        mag_rms = np.sqrt(
            sum((spectrum[0:len(spectrum) / 2] - forward[0, :]) ** 2))
        mag_rms /= (len(spectrum / 2))

        # compute pha rms
        pha_rms = self._phase_rms(spectrum, forward)

        # compute complex rms
        rms = np.sqrt(
            sum((spectrum[0:len(spectrum) / 2] - forward[0, :]) ** 2) +
            sum((spectrum[len(spectrum) / 2:len(spectrum)] -
                 forward[1, :]) ** 2))
        rms /= len(spectrum)

        # calculate final chi square
        chisq = sum(info["fvec"] * info["fvec"])

        # deegrees of freedom
        dof = len(self.fin) / 2 - len(p0)

        # residuals d - f
        # mx_fvec = self.__residuals(plsq, y_meas, x)

        # compute fit errors ('aymptotic standard error')
        np.seterr(all='raise')
        if cov is not None:
            errors = np.zeros((plsq.shape[0]))
            for i, pmin in enumerate(plsq):
                try:
                    # uncertainties are calculated as per gnuplot, "fixing" the
                    # result -                # for non unit values of the
                    # reduced chisq.
                    errors[i] = np.sqrt(cov[i, i]) * np.sqrt(chisq / dof)
                except FloatingPointError:
                    print('FloatingPointError:')
                    print(cov[i, i])
                    print(chisq / dof, chisq, dof)
                    errors[i] = np.nan

        else:
            errors = None

        # verbose output of fit results if option is selected
        plot = False
        if plot:
            if cov is not None:
                print("Fitted parameters at minimum, with 68% C.I.:")
                for i, pmin in enumerate(plsq):
                    print('{0:02} {1:.10} +/- {2:.10} ({3:.10}%)'.format(
                        i, pmin, errors[i], errors[i] / pmin * 100))
                print
                print "Correlation matrix"
                for i in range(len(plsq)):
                    for j in range(i + 1):
                        print('{0}'.format(
                            cov[i, j] / np.sqrt(cov[i, i] * cov[j, j])))
                    print('')
                print('')

        # return values
        fit_parameters = plsq

        # TODO: Sort CC terms for descending Tau values
        #       sort fit_parameters, mag_rms, pha_rms, forward, errors

        return fit_parameters, mag_rms, pha_rms, forward, errors