示例#1
0
def prepare_to_plot(grouped_mmts, theory_resp, savepath=None, show=True):
    """For this particular arrangement of measurements, reformat the grouped 
    data to be plotted.
    :param grouped_mmts: The measurements of frequency, amplitude and phase 
    returned by measure_all_groups.
    :param theory_resp: Theory's response function baked to require just the 
    driving angular frequency.
    :param savepath: The path to save the graphs to.
    :param show: Whether to show each graph or not."""
    mmts = [[[], []]]

    for parameter_set in grouped_mmts:
        to_plot = np.array(parameter_set[-1])
        # Convert to angular frequencies.
        simulated_ang_freqs = to_plot[:, 0, 0, :] * 2 * np.pi
        # Sort by frequencies.
        sort_args = simulated_ang_freqs[:, 0].argsort()
        simulated_ang_freqs = simulated_ang_freqs[sort_args].squeeze()
        simulated_amps = to_plot[:, 0, 1, :][sort_args].squeeze()
        simulated_phase = to_plot[:, 0, 2, :][sort_args].squeeze()

        mmts[0][0].append([
            simulated_ang_freqs, simulated_amps,
            r"k={:.1e}, k'={:.1e}, b={:.1e}, b'={:.1e}".format(
                parameter_set[2][0], parameter_set[3][0], parameter_set[0][0],
                parameter_set[1][0])
        ])
        mmts[0][1].append([
            simulated_ang_freqs, simulated_phase,
            r"k={:.1e}, k'={:.1e}, b={:.1e}, b'={:.1e}".format(
                parameter_set[2][0], parameter_set[3][0], parameter_set[0][0],
                parameter_set[1][0])
        ])

    # Generate evenly spaced angular frequencies.
    even_spaced_wd = np.linspace(10, 140, 5000)
    mmts[0][0].append([
        even_spaced_wd,
        np.absolute(theory_resp(even_spaced_wd)), r'Theoretical'
    ])
    mmts[0][1].append([
        even_spaced_wd,
        np.angle(theory_resp(even_spaced_wd)), r'Theoretical'
    ])
    p.two_by_n_plotter(mmts,
                       '', {
                           'i': grouped_mmts[0][4],
                           'g_0_mag': grouped_mmts[0][5],
                           'phi': grouped_mmts[0][6],
                           't0': grouped_mmts[0][7],
                           'tfin': grouped_mmts[0][8],
                           'theta_0': grouped_mmts[0][9],
                           'omega_0': grouped_mmts[0][10]
                       },
                       savepath=savepath,
                       show=show,
                       x_axes_labels=['$\omega$/rad/s'],
                       tag='response-curve-{}'.format(h.time_for_name()),
                       y_top_labels=[r'$\left|R(\omega)\right|$/rad/(Nm)'],
                       y_bottom_labels=[r'$\phi(R(\omega))$/rad'])
示例#2
0
def read_plot(filepaths, savepath=None, show=True):
    """Read a CSV file's columns and immediately plot its displacement as a 
    function of time. Point to multiple files to plot them on a single plot."""
    if type(filepaths) is not str and type(filepaths) is not list:
        raise Exception('Invalid type.')
    if not h.check_iterable(filepaths):
        filepaths = [filepaths]

    to_plot = [[[], []]]
    for filepath in filepaths:
        data = pd.read_csv(filepath, index_col=0)
        to_plot[0][0].append([data['t'], data['theta']])
        to_plot[0][1].append([data['t'], data['omega']])
    p.two_by_n_plotter(to_plot,
                       start='real-comparison',
                       params_dict={},
                       savepath=savepath,
                       show=show,
                       x_axes_labels=['t/s'],
                       y_bottom_labels=[r'$\dot{\theta}$/rad/s'],
                       y_top_labels=[r'$\theta$/rad'])
示例#3
0
def match_torques(grouped_sets, plot_real=False, savepath=None):
    """Match the times to the torques and displacements and return an array 
    of those values for each of the parameter combinations.
    :param grouped_sets: All grouped data.
    :param plot_real: Plot the real space data and save with logs.
    :param savepath: Save path to send to the n_plotter function."""

    fft_mmts = []
    for group in grouped_sets:
        # a list of dictionaries with the same parameter values except for w_d.
        b = group[0]['b']
        b_prime = group[0]['b\'']
        k = group[0]['k']
        k_prime = group[0]['k\'']
        i = group[0]['i']
        g_0_mag = group[0]['g_0_mag']
        phi = group[0]['phi']
        t0 = group[0]['t0'].squeeze()
        tfin = group[0]['tfin']
        w_d = group[0]['w_d']
        theta_0 = group[0]['theta_0']
        omega_0 = group[0]['omega_0']
        delay = group[0]['delay']
        one_group = [
            b, b_prime, k, k_prime, i, g_0_mag, phi, t0, tfin, theta_0,
            omega_0, delay
        ]
        one_dataset = []
        for dataset in group:
            # one dictionary with real space data and torque values.
            disps = dataset['disps']
            torques = dataset['torques']
            analytic_torque = torques['total-torque'] - k_prime * torques[
                'theta-sim'] - b_prime * torques['omega-sim']
            analytic, theta_sim, omega_sim = [], [], []

            for t in disps['t']:
                # match up the real and torque data times.
                idx = (np.abs(torques['t'] - t)).argmin()
                analytic.append(analytic_torque[idx])
                theta_sim.append(torques['theta-sim'][idx])
                omega_sim.append(torques['omega-sim'][idx])
            output = np.vstack(
                (disps.as_matrix().T, analytic, theta_sim, omega_sim)).T

            if plot_real:
                expected_torque = g_0_mag * np.sin(w_d * torques['t'] + phi)

                # Get the number of segments to use per correlation
                # calculation - equal to one period of the expected torque.
                period = 2 * np.pi / w_d
                match_one_period = np.abs(torques['t'] - period)
                index_of_period = match_one_period.argmin()
                if match_one_period[index_of_period] < 0:
                    index_of_period += 1

                real_space = \
                    [
                        [
                            [
                                [output[:, 0], output[:, 1]]
                            ],
                            [
                                [torques['t'], expected_torque],
                                [torques['t'], analytic_torque]
                            ]
                        ]
                    ]

                p.two_by_n_plotter(real_space,
                                   't-torque', {
                                       'b': b,
                                       'b\'': b_prime,
                                       'k': k,
                                       'k\'': k_prime,
                                       'i': i,
                                       'g_0_mag': g_0_mag,
                                       'phi': phi,
                                       't0': t0,
                                       'tfin': tfin,
                                       'theta_0': theta_0,
                                       'omega_0': omega_0,
                                       'delay': delay
                                   },
                                   show=True,
                                   savepath=savepath,
                                   x_axes_labels=['t/s'],
                                   tag='{}'.format(time()),
                                   y_top_labels=[r'$\theta$/rad'],
                                   y_bottom_labels=[r'$G_{s}(t)$/Nm'])

            # Times have now been matched and we are ready to obtain frequency,
            # amplitude and phase values from the output data.
            # Do once for simulated values and compare to measured values.
            measure_for = [[output[:, 1], output[:, 2]]]
            mmts = []
            for measure in measure_for:
                # Normalise the theta by the analytic torque amplitude to get
                # the response function.
                mmts.append(
                    m.one_mmt_set(output[:, 0], measure[0] / g_0_mag,
                                  output[:, 3], b, b_prime, k, k_prime, i))
            one_dataset.append(mmts)
            one_group.append(one_dataset)
        fft_mmts.append(one_group)
    return fft_mmts
示例#4
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}
示例#5
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
        ]
示例#6
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)$]'
                           ])