示例#1
0
    def main_operation(self, plot=True):
        """Run the ODE integrator for the system in question and save the 
        plots."""
        torque_index = 0
        self._update_torque(self.y0[0], torque_index)
        f_baked = h.baker(
            c.f_full_torque,
            ["", "", self.i, self.b, self.k, self._get_recent_torque],
            pos_to_pass_through=(0, 1))
        # Set initial conditions
        dy = c.rk4(f_baked)
        times, y, stepsize = *self.t0, self.y0, self.dt[0] / self.divider[0]

        results = []
        update_counter = 0
        while times <= self.t_fin:
            results.append(
                [times, *y, self.total_torque, self.theta_sim, self.omega_sim])
            times, y = times + stepsize, y + dy(times, y, stepsize)
            update_counter += 1
            # For a fixed step size, we can just repeat the torque
            # recalculation every self.divider steps, so there is no
            # overshooting.
            if update_counter == self.divider:
                update_counter = 0
                torque_index += 1
                if torque_index == self.period_divider:
                    torque_index = 0
                old_theta = n.get_old_theta(times, self.delay, results)
                self._update_torque(old_theta, torque_index)

        results = np.array(results).squeeze()
        # Calculate fourier series first 50 terms.
        ind_mag_phi = fourier.get_fourier_series(50, self.w_d, self.dt,
                                                 self.g_0)
        # fourier theoretical results.
        torque_fourier = h.baker(t.calculate_sine_pi, [
            "", "", "", "", ind_mag_phi[:, 1], self.w_d * ind_mag_phi[:, 0],
            ind_mag_phi[:, 2]
        ],
                                 pos_to_pass_through=(0, 3))
        theory_fourier = t.calc_theory_soln(results[:, 0], self.t0, self.y0,
                                            self.b - self.b_prime,
                                            self.k - self.k_prime, self.i,
                                            torque_fourier)
        ss_bit_theory = theory_fourier[:, 1][np.where(
            theory_fourier[:, 0] > self.t_fin.squeeze() - 2)]
        # Find maximum error over amplitude.
        iterator_diffs = np.max(
            np.abs(m.calc_norm_errs([results[:, 1], theory_fourier[:, 1]])[1])
            / np.max(ss_bit_theory))
        exp_results = pd.DataFrame(
            np.array([
                self.b, self.k, self.t_fin, self.period_divider,
                [iterator_diffs]
            ]).T,
            columns=['b', 'k', 'tfin', 'divider', 'max-frac-err'])
        return {'all-mmts': exp_results}
示例#2
0
    def main_operation(self, plot=True):
        """Read all data from a specific folder and produce real space and 
        fourier space plots. Use for only one set of b, k, b', k', i, 
        etc. parameters at a time."""
        directory = self.prms['directory'][0]
        all_same = self.prms['all_same'][0]
        file_list = h.find_files(directory)
        filename_roots = r.check_matches(file_list,
                                         num_one='all-mmts',
                                         num_two=None)

        all_data = r.read_all_data(directory,
                                   filename_roots,
                                   disps_ext='all-mmts',
                                   torque_ext='all-mmts')
        sorted_by_params = r.sort_data(all_data, all_same=all_same)

        b = sorted_by_params[0][0]['b']
        k = sorted_by_params[0][0]['k']
        b_prime = sorted_by_params[0][0]['b\'']
        k_prime = sorted_by_params[0][0]['k\'']
        i = sorted_by_params[0][0]['i']

        # Baked theoretical response function to require wd input only,
        # which depends on the range measured.
        need_wd = h.baker(t.theory_response,
                          args=[b, k, i, b_prime, k_prime, ''],
                          pos_to_pass_through=5)
        fft_data = r.match_torques(sorted_by_params,
                                   plot_real=self.prms['plot_real'][0],
                                   savepath=directory + 'plots/')
        print(fft_data)
        if plot:
            r.prepare_to_plot(fft_data, need_wd, savepath=directory + 'plots/')
示例#3
0
    def main_operation(self):
        """Run the ODE integrator for the system in question."""
        # Set parameters.
        i = self.prms['i']
        b = self.prms['b']
        k = self.prms['k']
        y0 = np.array([self.prms['theta_0'], self.prms['omega_0']]).squeeze()
        t0 = self.prms['t0']
        t_fin = self.prms['tfin']

        r = ode(c.f_full_torque)  #.set_integrator('dop853')
        self._update_torque(y0[0])
        r.set_initial_value(y0, t0).set_f_params(
            i, b, k, self._get_recent_torque).set_jac_params(i, b, k)

        results = [[*t0, *y0]]

        while r.successful() and r.t < t_fin:
            y = np.real(r.integrate(r.t + self.display_dt))
            data_point = [*(r.t + self.display_dt), *y]
            results.append(data_point)
            print("Time-theta-omega", data_point)
            # Recalculate the reset the torque every dt seconds.

            # get the last set of consecutive points where the digitised
            # torque (-6th column) has the same value as the current one
            # every cycle. If the corresponding times have a range greater
            # than or equal to dt, re-measure the torque.
            matching_indices = h.find_consec_indices(self.torques[:, -6])
            if self.torques[-1, 1] - min(self.torques[matching_indices,
                                                      1]) >= self.dt:
                self._update_torque(y[0])
                print("triggered")
                r.set_initial_value(r.y,
                                    r.t).set_f_params(i, b, k,
                                                      self._get_recent_torque)

        results = np.array(results).squeeze()
        sines_torque = h.baker(t.calculate_sine_pi, [
            "", "", "", "", self.prms['g_0_mag'], self.prms['w_d'],
            np.array([0])
        ],
                               pos_to_pass_through=(0, 3))

        theory = t.calc_theory_soln(np.linspace(0, 2, 1000), t0[0], y0,
                                    (b - self.prms['b\''])[0],
                                    (k - self.prms['k\''])[0], i[0],
                                    sines_torque)
        print(
            "Init parameters: dt: {}, display_dt: {}, b: {}, b': {}, k: {}, "
            "k': {}, I: {}, y0: {}, t0: {}, tfin: {}, g0: {}, w_d: {}".format(
                self.dt, self.display_dt, b, self.prms['b\''], k,
                self.prms['k\''], i, y0, t0, t_fin, self.prms['g_0_mag'],
                self.prms['w_d']))
        print("Parameters from the C code: k': {}, b': {}, g0: {}".format(
            talk.get_k_prime(), talk.get_b_prime(), talk.get_amp()))

        plt.plot(theory[:, 0], theory[:, 1])
        plt.plot(results[:, 0], results[:, 1])
        plt.show()
示例#4
0
    def _single_operation(self, times, b, k, i, b_prime, k_prime, w_d, g_0_mag,
                          phase, n_frq_peak, t0, y0):
        """One run for one value of b, k, i, b_prime, k_prime, 
        torque_amplitude, torque_phase, torque_frequency and noise. t is a time 
        array."""

        times = m.check_nyquist(times, w_d, b, b_prime, k, k_prime, i)
        decimal_periods = np.abs(5.231 * 2 * np.pi / w_d)

        time_index = 0
        num = 1
        # The index for 5.231 periods of time being elapsed is used to
        # calculate the number per segment to use for the autocorrelation.
        while time_index < 10:
            time_index = np.abs(times - num * decimal_periods).argmin()
            num += 1

        torque = g_0_mag * np.sin(w_d * times + phase)
        pi_contr = h.baker(t.calculate_sine_pi,
                           ["", "", "", "", g_0_mag, w_d, phase],
                           pos_to_pass_through=(0, 3))
        theory = t.calc_theory_soln(times, t0, y0, b - b_prime, k - k_prime, i,
                                    pi_contr)
        w_res = t.w_res_gamma(b - b_prime, k - k_prime, i)[0]
        if b - b_prime >= 0:
            if b - b_prime == 0 and np.isreal(w_res):
                # filter out the transient frequency.
                theory[:, 1] = m.remove_one_frequency(times, theory[:, 1],
                                                      w_res)
                theory[:, 2] = m.remove_one_frequency(times, theory[:, 2],
                                                      w_res)

            # Will only reach steady state if this is the case, otherwise no
            # point making a response curve. Measure one point. b - b' = 0
            # has two steady state frequencies, the transient and PI.
            ss_times = m.identify_ss(theory[:, 0],
                                     theory[:, 1],
                                     n_per_segment=time_index)

            if ss_times is not False:
                self._log('before fft')
                frq, fft_theta = m.calc_fft(
                    times[(times >= ss_times[0]) * (times <= ss_times[1])],
                    theory[:,
                           1][(times >= ss_times[0]) * (times <= ss_times[1])])
                # For low frequencies, the length of time of the signal must
                # also be sufficiently wrong for the peak position to be
                # measured properly.
                freq = m.calc_freqs(np.absolute(fft_theta),
                                    frq,
                                    n_peaks=n_frq_peak)
                amp = m.calc_one_amplitude(theory[:,
                                                  1][(times >= ss_times[0]) *
                                                     (times <= ss_times[1])])
                phase = m.calc_phase(theory[:, 1], torque)
                return True, theory, np.array([freq, amp, phase])
            else:
                return False, theory
        else:
            return False, theory
示例#5
0
def ode_integrator(y0, t0, i, b_prime, k_prime, b, k, g_0_mags, w_ds, phases,
                   t_fin, dt, torque_func):
    """Test function for ODE integration."""
    r = ode(f_analytic).set_integrator('vode')
    baked_g_0 = h.baker(torque_func, args=['', w_ds, g_0_mags, phases])
    r.set_initial_value(y0, t0).set_f_params(i, baked_g_0, b, b_prime, k,
                                             k_prime)
    results = [[t0, *y0]]
    while r.successful() and r.t < t_fin:
        data_point = [r.t + dt, *np.real(r.integrate(r.t + dt))]
        results.append(data_point)
    exp_results = np.array(results)
    return exp_results
示例#6
0
    def main_operation(self, plot=True):
        """Run the ODE integrator for the system in question and save the 
        plots."""
        torque_index = 0
        self._update_torque(self.y0[0], torque_index)

        f_baked = h.baker(
            c.f_full_torque,
            ["", "", self.i, self.b, self.k, self._get_recent_torque],
            pos_to_pass_through=(0, 1))
        # Set initial conditions
        dy = c.rk4(f_baked)
        times, y, stepsize = *self.t0, self.y0, self.dt[0] / self.divider[0]

        results = []
        update_counter = 0
        while times <= self.t_fin:
            results.append(
                [times, *y, self.total_torque, self.theta_sim, self.omega_sim])
            times, y = times + stepsize, y + dy(times, y, stepsize)
            update_counter += 1
            # For a fixed step size, we can just repeat the torque
            # recalculation every self.divider steps, so there is no
            # overshooting.
            if update_counter == self.divider:
                update_counter = 0
                torque_index += 1
                if torque_index == self.period_divider:
                    torque_index = 0
                old_theta = n.get_old_theta(times, self.delay, results)
                self._update_torque(old_theta, torque_index)

        results = np.array(results).squeeze()
        # Calculate fourier series first num_terms terms.
        ind_mag_phi = fourier.get_fourier_series(self.num_terms, self.w_d,
                                                 self.dt, self.g_0)
        # fourier theoretical results.
        torque_fourier = h.baker(t.calculate_sine_pi, [
            "", "", "", "", ind_mag_phi[:, 1], self.w_d * ind_mag_phi[:, 0],
            ind_mag_phi[:, 2]
        ],
                                 pos_to_pass_through=(0, 3))
        theory_fourier = t.calc_theory_soln(results[:, 0], self.t0, self.y0,
                                            self.b - self.b_prime,
                                            self.k - self.k_prime, self.i,
                                            torque_fourier)
        f_torque = fourier.get_torque(results[:, 0], ind_mag_phi[:, 0],
                                      ind_mag_phi[:, 1], ind_mag_phi[:, 2],
                                      self.w_d)

        if plot:
            times = m.check_nyquist(results[:, 0], self.w_d, self.b,
                                    self.b_prime, self.k, self.k_prime, self.i)
            decimal_periods = np.abs(5.231 * 2 * np.pi / self.w_d)
            time_index = 0
            num = 1
            # The index for 5.231 periods of time being elapsed is used to
            # calculate the number per segment to use for the auto-correlation.
            while time_index < 10:
                time_index = np.abs(times - num * decimal_periods).argmin()
                num += 1

            print(
                "Init parameters: dt: {}, b: {}, b': {}, k: {}, k': {}, I: {}, "
                "y0: {}, t0: {}, tfin: {}, g0: {}, w_d: {}".format(
                    self.dt, self.b, self.b_prime, self.k, self.k_prime,
                    self.i, self.y0, self.t0, self.t_fin, self.g_0, self.w_d))

            # Find absolute errors and plot.
            iterator_diffs = m.calc_norm_errs(
                [results[:, 1], theory_fourier[:, 1]],
                [results[:, 2], theory_fourier[:, 2]])[1]
            simu_diffs = m.calc_norm_errs([results[:, 4], results[:, 1]],
                                          [results[:, 5], results[:, 2]])[1]
            real_space_data = \
                [[[[theory_fourier[:, 0], theory_fourier[:, 1]],
                   [results[:, 0], results[:, 1]],
                   [results[:, 0], results[:, 4]]],
                  [[results[:, 0], iterator_diffs[0]],
                   [results[:, 0], simu_diffs[0]]]],
                 [[[theory_fourier[:, 0], theory_fourier[:, 2]],
                   [results[:, 0], results[:, 2]],
                   [results[:, 0], results[:, 5]]],
                  [[results[:, 0], iterator_diffs[1]],
                   [results[:, 0], simu_diffs[1]]]]]
            p.two_by_n_plotter(
                real_space_data,
                self.filename,
                self.prms,
                tag='fourier-added',
                savepath=self.savepath,
                show=True,
                x_axes_labels=['t/s', 't/s'],
                y_top_labels=[r'$\theta$/rad', r'$\dot{\theta}$/rad/s'],
                y_bottom_labels=[
                    r'$\Delta\theta$/rad', r'$\Delta\dot{\theta}$/rad/s'
                ])
        results = np.hstack((results, np.array([f_torque]).T))
        exp_results = pd.DataFrame(results,
                                   columns=[
                                       't', 'theta', 'omega', 'total-torque',
                                       'theta-sim', 'omega-sim', 'sine-torque'
                                   ])
        return {'all-mmts': exp_results}
示例#7
0
    def _one_run(self,
                 theta_0,
                 omega_0,
                 t0,
                 i,
                 b_prime,
                 k_prime,
                 b,
                 k,
                 g_0_mag,
                 w_d,
                 phase,
                 t_fin,
                 dt,
                 num_terms,
                 create_plot=False):
        """Compare experiment to theory for one set of parameters and return the 
        difference between the two. Uses only Fourier torque expression."""
        y0 = np.array([theta_0, omega_0]).squeeze()
        times = np.arange(t0, t_fin, dt / self.divider)
        try:
            w_d = t.w_res_gamma(b - b_prime, k - k_prime, i)[0]
        except ValueError:
            return []
        # Standard sine calculation.
        # Calculate fourier series first num_terms terms.
        ind_mag_phi = fourier.get_fourier_series(num_terms, w_d, dt, g_0_mag)
        f_torque = fourier.get_torque(times, ind_mag_phi[:, 0],
                                      ind_mag_phi[:, 1], ind_mag_phi[:,
                                                                     2], w_d)

        # Calculate theoretical results.
        torque_sine = h.baker(
            t.calculate_sine_pi,
            ["", "", "", "", g_0_mag, w_d, phase - dt * w_d / 2],
            pos_to_pass_through=(0, 3))
        theory = t.calc_theory_soln(times, t0, y0, b - b_prime, k - k_prime, i,
                                    torque_sine)

        # fourier theoretical results.
        torque_fourier = h.baker(t.calculate_sine_pi, [
            "", "", "", "", ind_mag_phi[:, 1], w_d * ind_mag_phi[:, 0],
            ind_mag_phi[:, 2]
        ],
                                 pos_to_pass_through=(0, 3))
        theory_fourier = t.calc_theory_soln(times, t0, y0, b - b_prime,
                                            k - k_prime, i, torque_fourier)

        # Normalise error by amplitude
        max_theta_diff = np.max(np.abs(theory_fourier[:, 1] - theory[:, 1]))
        max_omega_diff = np.max(np.abs(theory_fourier[:, 2] - theory[:, 2]))
        norm_theta_diff = (theory_fourier[:, 1] - theory[:, 1]) / np.max(
            theory_fourier[:, 1])
        norm_omega_diff = (theory_fourier[:, 2] - theory[:, 2]) / np.max(
            theory_fourier[:, 2])
        max_theta_norm = np.max(np.abs(norm_theta_diff))
        max_omega_norm = np.max(np.abs(norm_omega_diff))

        # Plotting - for 4 subplots on 1 figure.
        if create_plot:
            self._update_filename()
            plotting_data = \
                [
                    [
                        [[theory_fourier[:, 0], theory_fourier[:, 1],
                          r'Digitised'],
                         [theory[:, 0], theory[:, 1], r'Analogue']],
                        [[theory_fourier[:, 0], norm_theta_diff]],
                    ],
                    [
                        [[theory_fourier[:, 0], theory_fourier[:, 2],
                          r'Digitised'],
                         [theory[:, 0], theory[:, 2], r'Analogue']],
                        [[theory_fourier[:, 0], norm_omega_diff]],
                    ]
                ]
            params = {
                'theta_0': theta_0,
                'omega_0': omega_0,
                't0': t0,
                'I': i,
                'b\'': b_prime,
                'k\'': k_prime,
                'b': b,
                'k': k,
                'g_0_mag': g_0_mag,
                'w_d': w_d,
                'phi': phase,
                't_fin': t_fin,
                'dt': dt
            }
            p.two_by_n_plotter(
                plotting_data,
                self.filename,
                params,
                savepath=self.plotpath,
                show=True,
                x_axes_labels=['t/s', 't/s'],
                tag='with-uniform-noise-torque-over-100',
                y_top_labels=[r'$\theta$/rad', r'$\dot{\theta}$/rad/s'],
                y_bottom_labels=[
                    r'$(\theta_{sim}-\theta_{an})/|\theta_{max}|$',
                    r'$(\dot{\theta}_{sim}-\dot{\theta}_{an})/'
                    r'|\dot{\theta}_{max}|$'
                ],
                legend={
                    'loc': 'upper center',
                    'bbox_to_anchor': (0.5, 1),
                    'ncol': 2
                })
        print(b, k, i, num_terms, max_theta_norm, max_omega_norm)
        return [
            b, k, i, num_terms, max_theta_diff, max_omega_diff, max_theta_norm,
            max_omega_norm
        ]
示例#8
0
    def main_operation(self, plot=False):
        # feed in fixed b - b', k - k', torque, i, noise level and type,
        # but a range of driving frequencies to test.

        b_s = self.prms['b_s']
        k_s = self.prms['k_s']
        i_s = self.prms['i_s']
        b_primes = self.prms['b\'s']
        k_primes = self.prms['k\'s']
        w_ds = np.arange(self.prms['w_d_start'], self.prms['w_d_final'],
                         self.prms['w_d_step'])
        g_0_mags = self.prms['g0s']
        phases = self.prms['phis']
        t0 = self.prms['t0'].squeeze()
        y0 = np.array([self.prms['theta_0'], self.prms['omega_0']]).squeeze()
        times = np.arange(t0, self.prms['tfin'], self.prms['dt'])

        # Get the theoretical position of the peak and generate a finely
        # spaced set of frequency points around it to measure with greater
        # resolution here.
        w2_res = (k_s - k_primes) / i_s - (b_s - b_primes)**2 / (2 * i_s**2)
        gamma = (b_s - b_primes) / i_s

        # 5 * bandwidth on either side
        gamma = np.absolute(gamma)
        width = 5 * gamma if gamma != 0 else self.prms['w_d_step']
        if w2_res >= 0:
            w_res = np.sqrt(w2_res)
        else:
            w_res = 0
        w_range = np.linspace(w_res - width if w_res - width > 2 else 2,
                              w_res + width, 100)
        single_run = h.baker(
            self._single_operation,
            [times, '', '', '', '', '', '', '', '', '', t0, y0],
            pos_to_pass_through=(1, 9))

        ws = [w_ds, w_range]
        for j in range(len(ws)):
            all_times = h.all_combs(single_run, b_s, k_s, i_s, b_primes,
                                    k_primes, ws[j], g_0_mags, phases, 1)

            # final argument 1/2 for 1 frequency peak expected.
            fft_data = []
            real_data = []
            for i in range(len(all_times)):
                real_data.append(all_times[i][-1][1])
                if all_times[i][-1][0]:
                    fft_data.append(all_times[i][-1][-1])
            if j == 0:
                fft_mmts = np.array(fft_data)
            else:
                fft_mmts = np.append(fft_mmts, np.array(fft_data), axis=0)
                fft_mmts = fft_mmts[fft_mmts[:, 0, 0].argsort()]

        ang_freqs = np.array([fft_mmts[:, 0, 0], fft_mmts[:, 0, 1]
                              ]).T * 2 * np.pi
        amps = np.array([fft_mmts[:, 1, 0], fft_mmts[:, 1, 1]]).T / g_0_mags
        phases = np.array([fft_mmts[:, 2, 0], fft_mmts[:, 2, 1]]).T

        # For a single set of data, get the transfer function once only. This
        # allows error to be calculated as specifically the experimental
        # ang_freqs are used.
        fft_theory = np.array(
            h.all_combs(t.theory_response, b_s, k_s, i_s, b_primes, k_primes,
                        ang_freqs[:, 0]))

        theory_amps = np.absolute(fft_theory[:, -1])
        theory_phases = np.angle(fft_theory[:, -1])
        amp_err, phase_err = m.calc_norm_errs([amps[:, 0], theory_amps],
                                              [phases[:, 0], theory_phases])[1]

        theory_n_mmt = \
            [[[[ang_freqs, theory_amps], [ang_freqs, amps]],
              [[ang_freqs, amp_err / np.max(amps[:, 0])]]],
             [[[ang_freqs, theory_phases], [ang_freqs, phases]],
              [[ang_freqs, phase_err / np.max(np.absolute(phases[:, 0]))]]]]

        p.two_by_n_plotter(theory_n_mmt,
                           self.filename,
                           self.prms,
                           savepath=self.plotpath,
                           show=False,
                           x_axes_labels=['$\omega$/rad/s', '$\omega$/rad/s'],
                           y_top_labels=[
                               r'$\left|R(\omega)\right|$/rad/(Nm)',
                               r'arg[$R(\omega)$]/rad'
                           ],
                           y_bottom_labels=[
                               r'Normalised error in $\left|R(\omega)\right|$',
                               r'Normalised error in arg[$R(\omega)$]'
                           ])