Source code for pyecsca.sca.trace.match
"""Provides functions for matching a pattern within a trace to it."""
import numpy as np
from scipy.signal import find_peaks
from public import public
from typing import List
from .process import normalize
from .edit import trim
from .trace import Trace
[docs]
@public
def match_pattern(trace: Trace, pattern: Trace, threshold: float = 0.8) -> List[int]:
"""
Match a :paramref:`~.match_pattern.pattern` to a :paramref:`~.match_pattern.trace`.
Return the indices where the pattern matches, e.g. those where correlation
of the two traces has peaks larger than :paramref:`~.match_pattern.threshold`.
Uses the :py:func:`scipy.signal.find_peaks` function.
:param trace: The trace to match into.
:param pattern: The pattern to match.
:param threshold: The threshold passed to :py:func:`scipy.signal.find_peaks` as a ``prominence`` value.
:return: Indices where the pattern matches.
"""
normalized = normalize(trace)
pattern_samples = normalize(pattern).samples
correlation = np.correlate(normalized.samples, pattern_samples, "same")
correlation = (correlation - np.mean(correlation)) / (np.max(correlation))
peaks, props = find_peaks(correlation, prominence=(threshold, None))
pairs = sorted(zip(peaks, props["prominences"]), key=lambda it: it[1], reverse=True)
half = len(pattern_samples) // 2
filtered_peaks: List[int] = []
for peak, _ in pairs:
if not filtered_peaks:
filtered_peaks.append(peak - half)
else:
for other_peak in filtered_peaks:
if abs((peak - half) - other_peak) <= len(pattern_samples):
break
else:
filtered_peaks.append(peak - half)
return filtered_peaks
[docs]
@public
def match_part(
trace: Trace, offset: int, length: int, threshold: float = 0.8
) -> List[int]:
"""
Match a part of a :paramref:`~.match_part.trace` starting at :paramref:`~.match_part.offset` of :paramref:`~.match_part.length` to the :paramref:`~.match_part.trace`.
Returns indices where the pattern matches, e.g. those where correlation of the two
traces has peaks larger than :paramref:`~.match_part.threshold`.
Uses the :py:func:`scipy.signal.find_peaks` function.
:param trace: The trace to match into.
:param offset: The start of the pattern in the trace to match.
:param length: The length of the pattern in the trace to match.
:param threshold: The threshold passed to :py:func:`scipy.signal.find_peaks` as a ``prominence`` value.
:return: Indices where the part of the trace matches matches.
"""
return match_pattern(trace, trim(trace, offset, offset + length), threshold)