I have a signal where I would like to implement a peak detection algorithm where it **only** collects peaks that follow exponential decay behaviour and stop at a certain height. Here is an example of a signal that I am dealing with

I would like the detection to implement similar to the question in this link,

Peak Detection in Real-Time Python

I know with signals, I might face with noise within the signal. I would like it the algorithm to also be able to compare the neighbouring peaks and select the highest peak. I have looked into the following links:

Also, looked into some of the following GitHub links:

I found the code where it helped me to collect peaks above a certain threshold. The code can be found below:

```
def peakdet(v, delta, x=None):
"""
Converted from MATLAB script at http://billauer.co.il/peakdet.html
Returns two arrays
function (maxtab, mintab)=peakdet(v, delta, x)
%PEAKDET Detect peaks in a vector
% (MAXTAB, MINTAB) = PEAKDET(V, DELTA) finds the local
% maxima and minima ("peaks") in the vector V.
% MAXTAB and MINTAB consists of two columns. Column 1
% contains indices in V, and column 2 the found values.
%
% With (MAXTAB, MINTAB) = PEAKDET(V, DELTA, X) the indices
% in MAXTAB and MINTAB are replaced with the corresponding
% X-values.
%
% A point is considered a maximum peak if it has the maximal
% value, and was preceded (to the left) by a value lower by
% DELTA.
% Eli Billauer, 3.4.05 (Explicitly not copyrighted).
% This function is released to the public domain; Any use is allowed.
"""
maxtab = ()
mintab = ()
if x is None:
x = arange(len(v))
v = asarray(v)
if len(v) != len(x):
sys.exit('Input vectors v and x must have same length')
if not isscalar(delta):
sys.exit('Input argument delta must be a scalar')
if delta <= 0:
sys.exit('Input argument delta must be positive')
mn, mx = Inf, -Inf
mnpos, mxpos = NaN, NaN
lookformax = True
for i in arange(len(v)):
this = v(i)
if this > mx:
mx = this
mxpos = x(i)
if this < mn:
mn = this
mnpos = x(i)
if lookformax:
if this < mx - delta:
maxtab.append((mxpos, mx))
mn = this
mnpos = x(i)
lookformax = False
else:
if this > mn + delta:
mintab.append((mnpos, mn))
mx = this
mxpos = x(i)
lookformax = True
return array(maxtab), array(mintab)
```

Where would I need to modify to get what I need and if any other algorithms can perform better peak detection with exponential decay?

I tried to work with the second link and used it with what I need, find the code I used below:

Function:

```
def thresholding_algo(y, lag, threshold, influence):
signals = np.zeros(len(y))
filteredY = np.array(y)
avgFilter = (0)*len(y)
stdFilter = (0)*len(y)
avgFilter(lag - 1) = np.mean(y(0:lag))
stdFilter(lag - 1) = np.std(y(0:lag), ddof=1)
for i in range(lag, len(y)):
if abs(y(i) - avgFilter(i-1)) > threshold * stdFilter (i-1):
if y(i) > avgFilter(i-1):
signals(i) = 1
else:
signals(i) = -1
filteredY(i) = influence * y(i) + (1 - influence) * filteredY(i-1)
avgFilter(i) = np.mean(filteredY((i+1-lag):(i+1)))
stdFilter(i) = np.std(filteredY((i+1-lag):(i+1)), ddof=1)
else:
signals(i) = 0
filteredY(i) = y(i)
avgFilter(i) = np.mean(filteredY((i+1-lag):(i+1)))
stdFilter(i) = np.std(filteredY((i+1-lag):(i+1)), ddof=1)
return dict(signals = np.asarray(signals), avgFilter = np.asarray(avgFilter), stdFilter = np.asarray(stdFilter))
```

Code:

```
# Settings: lag = 30, threshold = 5, influence = 0
lag = 30
threshold = 5
influence = 1
# Run algo with settings from above
result = thresholding_algo(process_y, lag=lag, threshold=threshold, influence=influence)
# Plot result
pylab.subplot(211)
pylab.plot(np.arange(1, len(process_y)+1), process_y)
pylab.plot(np.arange(1, len(process_y)+1), result("avgFilter"), color="cyan", lw=2)
pylab.plot(np.arange(1, len(process_y)+1), result("avgFilter") + threshold * result("stdFilter"), color="green", lw=2)
pylab.plot(np.arange(1, len(process_y)+1), result("avgFilter") - threshold * result("stdFilter"), color="red", lw=2)
pylab.subplot(212)
pylab.step(np.arange(1, len(process_y)+1), result("signals"), color="blue", lw=2)
pylab.ylim(-1.5, 1.5)
S_max_peaks = np.array(result("avgFilter") + threshold * result("stdFilter"), dtype=np.int32)
S_min_peaks = np.array(result("avgFilter") - threshold * result("stdFilter"), dtype=np.int32)
# Forming arrays to get the peaks to get the y and x axes for signal:
S_x_max_peaks, S_y_max_peaks = x_time(S_max_peaks), process_y(S_max_peaks)
S_x_min_peaks, S_y_min_peaks = x_time(S_min_peaks), process_y(S_min_peaks)
```

Where `process_y`

is the signal. The result is shown below,

What did I do wrong here?

I managed to create custom function but it only prints out the highest peaks, it does not collect peaks that lies within assigned conditions. The code can be found below:

```
def custom_peakdetection(y_axis, data_ahead, peak_height, x_axis=None):
"""
keyword arguments:
y_axis -- A list containg the signal over which to find peaks
x_axis -- A x-axis whose values correspond to the 'y_axis' list and is used in the return to specify the postion of the peaks. If omitted the index of the y_axis is used. (default: None)
data_ahead -- (optional) distance to look ahead and previous from a peak candidate to determine if it is the actual peak
peak_height -- (optional) this specifies a minimum height of the peak
return -- two lists (maxtab, mintab) containing the positive and negative peaks respectively. Each cell of the lists contains a tupple of:
(position, peak_value) to get the average peak value do 'np.mean(maxtab, 0)(1)' on the results
"""
maxtab = ()
mintab = ()
if x_axis is None:
x = arange(len(y_axis))
else:
x = asarray(x_axis)
y = asarray(y_axis)
if len(y) != len(x):
sys.exit('Input vectors y and x must have same length')
if not isscalar(peak_height):
sys.exit('Input argument peak_height must be a scalar')
# if peak_height <= 0:
# sys.exit('Input argument peak_height must be positive')
# maxima and minima candidates are temporarily stored in mx and mn respectively:
mn, mx = np.Inf, -np.Inf
mnpos, mxpos = NaN, NaN
# Obtaining the maximum and minimum peaks of the signal:
key_list = list(x)
value_list = list(y)
signal_dict = dict(zip(key_list, value_list))
signal_full_dict = defaultdict(list)
for key, value in chain(signal_dict.items()):
signal_full_dict(key).append(value)
max_peak = max(signal_full_dict.items(), key = lambda x: x(1))(1)
min_peak = min(signal_full_dict.items(), key = lambda x: x(1))(1)
mxpkpos = max(signal_full_dict.items(), key = lambda x: x(1))(0)
mnpkpos = min(signal_full_dict.items(), key = lambda x: x(1))(0)
maxtab.append((mxpkpos, max_peak))
mintab.append((mnpkpos, min_peak))
for i in arange(1, len(y)):
this = y(i)
prev = y(i - data_ahead)
ahead = y(i:i + data_ahead)
ahead = np.asscalar(ahead)
# if (this > mx) & (this < prev) & (this > ahead) & (this < max_peak) & (this > peak_height):
if (this > mx) & (this < prev) & (this > ahead) & (this > peak_height):
mx = this
mxpos = x(i)
maxtab.append((mxpos, mx))
# if (this < mn) & (this > prev) & (this < ahead) & (this < min_peak) & (this < peak_height):
if (this < mn) & (this > prev) & (this < ahead) & (this < peak_height):
mn = this
mnpos = x(i)
mintab.append((mnpos, mn))
return (maxtab, mintab)
# return array(maxtab), array(mintab)
```