Пример #1
0
def _time_of_flights_backwall_LT(conf):
    probe = common.load_probe(conf)
    examination_object = arim.io.examination_object_from_conf(conf)
    tx_list, rx_list = arim.ut.fmc(probe.numelements)

    # Backwall paths
    backwall_paths = bim.backwall_paths(
        examination_object.couplant_material,
        examination_object.block_material,
        probe.to_oriented_points(),
        examination_object.frontwall,
        examination_object.backwall,
    )

    path = backwall_paths["LT"]
    arim.ray.ray_tracing_for_paths([path])
    return path.rays.times
Пример #2
0
# views = {viewname: view for viewname, view in views.items() if viewname in {"L-T", "T-L"}}  # debug
print("Views: " + ", ".join(views.keys()))
arim.ray.ray_tracing(views.values(), convert_to_fortran_order=True)

#%% Ray tracing for wall echoes
frontwall_path = bim.frontwall_path(
    examination_object.couplant_material,
    examination_object.block_material,
    *probe.to_oriented_points(),
    *examination_object.frontwall,
)

backwall_paths = bim.backwall_paths(
    examination_object.couplant_material,
    examination_object.block_material,
    probe.to_oriented_points(),
    examination_object.frontwall,
    examination_object.backwall,
)
# backwall_paths = {pathname: path for pathname, path in backwall_paths.items() if pathname in {"LL"}} # debug
wall_paths = {f"Backwall {key}": path for key, path in backwall_paths.items()}
wall_paths["Frontwall"] = frontwall_path
arim.ray.ray_tracing_for_paths(wall_paths.values())
print("Wall paths: " + ", ".join(wall_paths.keys()))

#%% Toneburst and time vector
max_delay_scat = max(
    (
        view.tx_path.rays.times.max() + view.rx_path.rays.times.max()
        for view in views.values()
    )
Пример #3
0
def make_model_walls(conf, use_multifreq=False, wall_keys=WALL_KEYS):
    """
    Generate a FMC containing the walls

    Parameters
    ----------
    conf : dict
    wall_keys : set
    use_multifreq : bool

    Returns
    -------
    Frame
    """
    probe = common.load_probe(conf)
    examination_object = arim.io.examination_object_from_conf(conf)
    tx_list, rx_list = arim.ut.fmc(probe.numelements)
    wall_keys = set(wall_keys)

    model_options = dict(
        probe_element_width=probe.dimensions.x[0],
        use_directivity=True,
        use_beamspread=True,
        use_transrefl=True,
        use_attenuation=True,
    )

    unknown_wall_keys = wall_keys - WALL_KEYS
    if unknown_wall_keys:
        raise ValueError(f"Unknown wall keys: {unknown_wall_keys}")

    # used paths:
    wall_paths = []

    if "frontwall" in wall_keys:
        # Frontwall path
        frontwall_path = bim.frontwall_path(
            examination_object.couplant_material,
            examination_object.block_material,
            *probe.to_oriented_points(),
            *examination_object.frontwall,
        )
        wall_paths.append(frontwall_path)

    # Backwall paths
    backwall_paths = bim.backwall_paths(
        examination_object.couplant_material,
        examination_object.block_material,
        probe.to_oriented_points(),
        examination_object.frontwall,
        examination_object.backwall,
        max_number_of_reflection=2,
    )
    if "backwall_LL" in wall_keys:
        wall_paths.append(backwall_paths["LL"])
    if "backwall_LT" in wall_keys:
        wall_paths.append(backwall_paths["LT"])
        wall_paths.append(backwall_paths["TL"])
    if "backwall_LLLL" in wall_keys:
        wall_paths.append(backwall_paths["LLLL"])

    arim.ray.ray_tracing_for_paths(wall_paths)

    # Toneburst
    numcycles = conf["model"]["toneburst"]["numcycles"]
    centre_freq = common.get_centre_freq(conf, probe)
    max_delay = max(path.rays.times.max() for path in wall_paths)
    dt = 0.25 / centre_freq  # to adjust so that the whole toneburst is sampled
    _tmax = max_delay + 4 * numcycles / centre_freq
    numsamples = scipy.fftpack.next_fast_len(math.ceil(_tmax / dt))
    time = arim.Time(0.0, dt, numsamples)
    freq_array = np.fft.rfftfreq(len(time), dt)
    toneburst = arim.model.make_toneburst(numcycles,
                                          centre_freq,
                                          dt,
                                          numsamples,
                                          wrap=True)
    toneburst_f = np.fft.rfft(toneburst)

    # convert to dict due to bim API
    wall_paths_dict = dict(zip(range(len(wall_paths)), wall_paths))
    if use_multifreq:
        transfer_function_iterator = bim.multifreq_wall_transfer_functions(
            wall_paths_dict, tx_list, rx_list, freq_array, **model_options)
    else:
        transfer_function_iterator = bim.singlefreq_wall_transfer_functions(
            wall_paths_dict, tx_list, rx_list, centre_freq, freq_array,
            **model_options)

    scanlines = None
    for _, transfer_function_wall_f in transfer_function_iterator:
        tmp_scanlines = arim.signal.rfft_to_hilbert(transfer_function_wall_f *
                                                    toneburst_f,
                                                    numsamples,
                                                    axis=-1)
        if scanlines is None:
            scanlines = tmp_scanlines
        else:
            scanlines += tmp_scanlines

    return arim.Frame(scanlines, time, tx_list, rx_list, probe,
                      examination_object)
Пример #4
0
def measure_model_scaling(dataset_name,
                          save,
                          method="frontwall_pulse_echo",
                          noshow=False):
    conf = arim.io.load_conf(dataset_name)
    aplt.conf["savefig"] = save
    result_dir = conf["result_dir"]
    root_dir = conf["root_dir"]

    logger.info(f"dataset_name: {dataset_name}")

    frame = common.load_frame(conf, apply_filter=True, expand=True)

    model_options = dict(
        frequency=common.get_centre_freq(conf, frame.probe),
        probe_element_width=frame.probe.dimensions.x[0],
    )

    def db(x):
        return 20 * np.log10(x)

    model_amps = {}
    model_times = {}
    exp_amps = {}
    exp_times = {}

    def to_2d(x):
        n = frame.probe.numelements
        if len(x) == (n * (n + 1)) // 2:
            # hmc
            y = np.full((n, n), np.nan, x.dtype)
            y[np.triu_indices(n)] = x
            y = np.fmax(y, y.T)  # fill lower part
            np.testing.assert_allclose(y, y.T)
        elif len(x) == n**2:
            # fmc
            y = x.reshape((n, n))
        else:
            raise ValueError
        return y

    # %% Frontwall model

    frontwall_path = bim.frontwall_path(
        frame.examination_object.couplant_material,
        frame.examination_object.block_material,
        *frame.probe.to_oriented_points(),
        *frame.examination_object.frontwall,
    )

    frontwall_ray_weights, frontwall_ray_weights_dict = bim.ray_weights_for_wall(
        frontwall_path, **model_options)

    model_times["frontwall"] = frontwall_path.rays.times[frame.tx, frame.rx]
    model_amps["frontwall"] = np.abs(frontwall_ray_weights[frame.tx, frame.rx])

    # %% Backwalls model

    backwall_paths = bim.backwall_paths(
        frame.examination_object.couplant_material,
        frame.examination_object.block_material,
        frame.probe.to_oriented_points(),
        frame.examination_object.frontwall,
        frame.examination_object.backwall,
    )

    arim.ray.ray_tracing_for_paths(backwall_paths.values())

    for wall_key_, backwall_path in backwall_paths.items():
        wall_key = f"backwall_{wall_key_}"
        backwall_ray_weights, backwall_ray_weights_dict = bim.ray_weights_for_wall(
            backwall_path, **model_options)

        model_times[wall_key] = backwall_path.rays.times[frame.tx, frame.rx]
        model_amps[wall_key] = np.abs(backwall_ray_weights[frame.tx, frame.rx])

    # %% Measure

    window_size = int(0.5e-6 / frame.time.step)
    window_size_t = window_size * frame.time.step

    for wall_key in model_times.keys():
        exp_times_tmp = np.zeros(frame.numscanlines)
        exp_amps_tmp = np.zeros(frame.numscanlines)

        for i in range(frame.numscanlines):
            time_idx = np.searchsorted(frame.time.samples,
                                       model_times[wall_key][i])
            window = slice(time_idx - window_size, time_idx + window_size)

            max_idx = np.argmax(np.abs(frame.scanlines[i, window]))

            exp_times_tmp[i] = frame.time.samples[window][max_idx]
            exp_amps_tmp[i] = np.abs(frame.scanlines[i, window])[max_idx]

        exp_amps[wall_key] = exp_amps_tmp
        exp_times[wall_key] = exp_times_tmp

    # %% Ascan

    tx_idx = 0
    rx_idx = frame.probe.numelements - 1

    idx = np.flatnonzero((frame.tx == tx_idx) & (frame.rx == rx_idx))[0]

    plt.figure()
    plt.plot(frame.time.samples, np.abs(frame.scanlines[idx]), "-")
    for i, (wall_key, t) in enumerate(model_times.items()):
        #    plt.axvline(t[idx], label=wall_key, color=f"C{i+1}", zorder=-1)
        plt.axvspan(
            t[idx] - window_size_t,
            t[idx] + window_size_t,
            label=wall_key,
            color=f"C{i+1}",
            alpha=0.25,
            zorder=-1,
        )
        plt.plot(exp_times[wall_key][idx], exp_amps[wall_key][idx], f"C{i+1}o")

    plt.gca().xaxis.set_major_formatter(aplt.micro_formatter)
    plt.title(f"Ascan tx={tx_idx}, rx={rx_idx}")

    _t_walls = np.array([t[idx] for t in model_times.values()])
    _tmin = max(frame.time.start, _t_walls.min() - 5e-6)
    _tmax = min(frame.time.end, _t_walls.max() + 5e-6)
    plt.xlim([_tmin, _tmax])
    plt.legend()
    plt.xlabel("time (µs)")
    plt.ylabel("amplitude (linear)")
    if save:
        plt.savefig(str(result_dir / f"ascan_{tx_idx}_{rx_idx}"))

    # %% Compare all models

    def make_model_scalings():
        tmp = []
        scan_to_use_dict = {
            "all": np.ones(frame.numscanlines, bool),
            "pulse_echo": frame.tx == frame.rx,
        }

        for ref_wall_key in [
                "frontwall", "backwall_LL", "backwall_LT", "backwall_TT"
        ]:
            for to_use_key, scan_to_use in scan_to_use_dict.items():
                x = model_amps[ref_wall_key][scan_to_use]
                y = exp_amps[ref_wall_key][scan_to_use]
                ols_res = sm.OLS(y, x).fit()
                model_scaling = ols_res.params[0]

                tmp.append((
                    f"{ref_wall_key}_{to_use_key}",
                    model_scaling,
                    ols_res.rsquared,
                    ref_wall_key,
                ))

        return pd.DataFrame(tmp,
                            columns=("method", "model_scaling", "rsquared",
                                     "ref_wall_key")).set_index("method")

    model_scaling_df = make_model_scalings()
    if save:
        # save csv
        model_scaling_df.to_csv(result_dir / "model_scalings.csv")

        # save yaml
        model_scaling = float(model_scaling_df.model_scaling[method])
        model_conf = dict(model=dict(scaling=model_scaling))
        with (root_dir / "conf.d/22_model_scaling.yaml").open("w") as f:
            f.write("# generated by measure_model_scaling\n")
            f.write(f"# method={method}\n")
            yaml.dump(model_conf, f, default_flow_style=False)

    # %% Select one method

    is_pulse_echo = frame.tx == frame.rx
    model_scaling = model_scaling_df.loc[method, "model_scaling"]

    # %% line plots for pulse-echo

    # Model predicts no amplitude for LT, TL and TT
    for wall_key in ["frontwall", "backwall_LL"]:
        plt.figure()

        plt.plot(
            db(model_amps[wall_key][is_pulse_echo] * model_scaling),
            "--",
            label=f" model",
        )
        plt.plot(db(exp_amps[wall_key][is_pulse_echo]), label=f"exp")

        plt.xlabel("element index")
        plt.ylabel("amplitude dB ")
        plt.title(
            f"{wall_key} amplitudes\npulse-echo - scaling method {method}")
        plt.legend()
        if save:
            plt.savefig(
                str(result_dir / f"wall_amps_{wall_key}_{method}_pulse_echo"))

    # %% line plots for a given tx

    idx = frame.probe.numelements - 1

    for wall_key in ["frontwall", "backwall_LL", "backwall_LT", "backwall_TT"]:
        plt.figure()

        plt.plot(db(to_2d(model_amps[wall_key] * model_scaling)[idx]),
                 "--",
                 label=f" model")
        plt.plot(db(to_2d(exp_amps[wall_key])[idx]), label=f"exp")

        plt.xlabel("rx index")
        plt.ylabel("amplitude dB ")
        plt.title(f"{wall_key} amplitudes\ntx={idx} - scaling method {method}")
        plt.legend()
        if save:
            plt.savefig(
                str(result_dir / f"wall_amps_{wall_key}_{method}_{idx}"))

    if noshow:
        plt.close("all")
    else:
        plt.show()

    return model_scaling_df
Пример #5
0
def plot_timetraces_full(dataset_name, save, noshow=False):
    conf = arim.io.load_conf(dataset_name)
    result_dir = conf["result_dir"]

    logger.info(f"dataset_name: {dataset_name}")

    frame = common.load_frame(conf)
    examination_object = arim.io.block_in_immersion_from_conf(conf)
    probe_p = frame.probe.to_oriented_points()
    scatterers = common.defect_oriented_point(conf)
    views = bim.make_views(
        examination_object,
        probe_p,
        scatterers,
        max_number_of_reflection=1,
        tfm_unique_only=False,
    )
    arim.ray.ray_tracing(views.values())

    frontwall_path = bim.frontwall_path(
        examination_object.couplant_material,
        examination_object.block_material,
        *frame.probe.to_oriented_points(),
        *examination_object.frontwall,
    )
    backwall_paths = bim.backwall_paths(
        examination_object.couplant_material,
        examination_object.block_material,
        frame.probe.to_oriented_points(),
        examination_object.frontwall,
        examination_object.backwall,
        max_number_of_reflection=1,
    )
    wall_paths = [frontwall_path] + list(backwall_paths.values())
    arim.ray.ray_tracing_for_paths(wall_paths)

    def make_linestyles():
        linestyles = itertools.product(
            ["-", "--", "-.", ":"],
            plt.rcParams["axes.prop_cycle"].by_key()["color"])
        return itertools.cycle(linestyles)

    #%% Ascan
    def plot_ascan(tx, rx):
        scanline = np.abs(frame.get_scanline(tx, rx))
        plt.figure(figsize=FIGSIZE)
        plt.plot(frame.time.samples, scanline, "k")
        plt.xlabel("Time (µs)")
        plt.title(f"tx={tx}, rx={rx}")

        linestyle_cycler = make_linestyles()
        for path, (ls, color) in zip(wall_paths, linestyle_cycler):
            plt.axvline(
                path.rays.times[tx, rx],
                label=path.name,
                ymin=0,
                color=color,
                ls=ls,
                lw=2.5,
            )
        for view, (ls, color) in zip(views.values(), linestyle_cycler):
            plt.axvline(
                view.tx_path.rays.times[tx, 0] +
                view.rx_path.rays.times[rx, 0],
                label=view.name,
                ymin=0,
                color=color,
                ls=ls,
            )
        plt.gca().xaxis.set_major_formatter(aplt.micro_formatter)
        plt.gca().xaxis.set_minor_formatter(aplt.micro_formatter)
        plt.ylim([scanline.min(), scanline.max()])
        plt.legend()
        if save:
            plt.savefig(result_dir / f"ascan_full_{tx}_{rx}")

    plot_ascan(0, 0)
    plot_ascan(0, frame.probe.numelements - 1)

    #%% Bscan
    def plot_bscan(scanlines_idx, filename, **kwargs):
        fig, ax = plt.subplots(figsize=FIGSIZE)
        aplt.plot_bscan(frame,
                        scanlines_idx,
                        ax=ax,
                        savefig=False,
                        cmap="Greys",
                        **kwargs)
        linestyle_cycler = make_linestyles()
        tx_arr = frame.tx[scanlines_idx]
        rx_arr = frame.rx[scanlines_idx]
        y = np.arange(len(tx_arr))
        for path, (ls, color) in zip(wall_paths, linestyle_cycler):
            plt.plot(
                path.rays.times[tx_arr, rx_arr],
                y,
                label=path.name,
                color=color,
                ls=ls,
                lw=3.0,
            )
        for view, (ls, color) in zip(views.values(), linestyle_cycler):
            plt.plot(
                view.tx_path.rays.times[tx_arr, 0] +
                view.rx_path.rays.times[rx_arr, 0],
                y,
                label=view.name,
                color=color,
                ls=ls,
            )
        plt.legend()
        if save:
            plt.savefig(result_dir / filename)

    plot_bscan(frame.tx == frame.rx, "bscan_full_1")
    plot_bscan(frame.tx == 0, "bscan_full_2")
    plot_bscan(frame.tx == frame.probe.numelements - 1, "bscan_full_3")

    #%%
    if noshow:
        plt.close("all")
    else:
        plt.show()