Pattern Matching and Alignment

In this notebook, we show how to do pattern matching and alignment using secbench primitives.

import importlib

import numpy as np
import matplotlib.pyplot as plt

# NOTE: tune the figure size as needed for better visualization in the notebook
plt.rcParams["figure.figsize"] = (14, 6)
from secbench.processing.helpers import qplot
from secbench.processing.signal import match_correlation, match_euclidean, phase_correlation

Input Generation

We start by generating a simple pattern:

pattern_width = 300

xs = np.linspace(-1, 3, pattern_width)
pattern = 2. * (np.sinc(xs**2) - np.sinc(xs - 4) + np.sinc(5 * xs) - 1)
pattern = pattern.astype(np.float32)
plt.plot(pattern)
plt.title("Reference pattern")
plt.show()
../_images/60c83d727a6d7c966d515d74b3ac2cdc67d5d9ca7b02ed3548e1a53ad0f9f15b.png

Then, we generate a trace and insert the pattern into it.

samples = 5000

offset = 300 # np.random.randint(pattern_width, samples - pattern_width)
p_start, p_end = offset, offset + pattern_width

data = np.random.normal(size=samples).astype(np.float32)
data[p_start:p_end] += pattern
print(f"offest is {offset}")

plt.plot(data)
plt.axvline(p_start, color="r")
plt.axvline(p_end, color="r")
plt.title("noisy trace with a pattern")
plt.show()
offest is 300
../_images/b64aa4b368eefd3c30a444c76ad77e8cec164d04be675720ba83cc51c33a5da6.png

Pattern Matching

Now, we run the different matchers available:

matchers = [
    ("correlation", match_correlation, "max"),
    ("Eucliean distance", match_euclidean, "min"),
    ("Phase correlation", phase_correlation, "max")]

solutions = []
for label, matcher, order in matchers:
    fig, ax1 = plt.subplots()
    ax1.set_ylabel("metric")
    score = matcher(data, pattern, dtype=np.float32)
    sol = np.argmin(score) if order == "min" else np.argmax(score)
    solutions.append(sol)
    ax1.plot(score, color="red")
    ax1.axvline(sol, color="black", linestyle="--")

    ax2 = ax1.twinx()
    ax2.plot(data, alpha=0.3, color="green")
    ax2.set_ylabel("sample value")
    plt.title(f"Pattern matching with {label}")
    plt.show()

for (label, _, _), sol in zip(matchers, solutions):
    print(f"offset found by {label}: {sol}")
../_images/4e35b4720fd55d9b82b932e60618e120ade4f94fe4fdc90e37072cbe7324bb40.png ../_images/b34655bbc649adca10f53f324794095b98a6115ccd3cd31ca20516c3451f639c.png ../_images/0ba44dc5fd3f5ad84a9772b439700467666e168c5b72019100f2aeb5a5a388d0.png
offset found by correlation: 300
offset found by Eucliean distance: 300
offset found by Phase correlation: 300

Alignment

Traces alignement simply consists of finding the pattern location in each trace and shifting them accordingly.

This section shows a basic example.

We first generate more traces using the same technique as in the previous section.

samples = 5000

data = np.zeros((50, samples), dtype=np.float32)

for i in range(data.shape[0]):
    offset = np.random.randint(1000, 1500)
    p_start, p_end = offset, offset + pattern_width
    data[i] = np.random.normal(size=samples).astype(np.float32)
    data[i, p_start:p_end] += pattern
qplot(data, plot_mean=True)
plt.title("Unaligned traces overlaid")
plt.show()
../_images/d5d8cb06b2d0745a80f8b150ff91f21dad1fd200e1846d78c30efebafd5dd6f6.png

We now run the alignment.

matchers = [
    ("correlation", match_correlation, "max"),
    ("eucliean distance", match_euclidean, "min"),
    ("phase correlation", phase_correlation, "max")]

for label, matcher, order in matchers:
    
    fig, ax1 = plt.subplots()
    ax1.set_ylabel("metric")
    score = matcher(data, pattern)
    sol = np.argmin(score, axis=1) if order == "min" else np.argmax(score, axis=1)

    d_aligned = np.copy(data)
    for i, sh in enumerate(sol):
        d_aligned[i] = np.roll(d_aligned[i], -sh)

    ax1.plot(np.mean(d_aligned, axis=0))
    plt.title(f"Alignment with {label}")
    plt.show()
../_images/8d53ac418c608cbb5a364c1d4dc5fec522b2d36c5dfc0d29953a1a222e7a5220.png ../_images/f47bc3cd831cff7cd8257b4bdb8fab111e8e083f502650c76034da680ae6aa2c.png ../_images/cfb21e4f087c1f8a92f21ee3755fc995d82fcff0dee454fc5c0a84cfa5762ac5.png