Dado un punto de partida aproximada, se puede usar un algoritmo simple que encuentra un máximo local más cercano a este punto. Su código de ajuste ya puede estar haciendo eso (no estaba seguro de si lo estaba usando con éxito o no).
Aquí hay algo de código que demuestra hallazgo pico simple a partir de un determinado punto de partida por el usuario:
#!/usr/bin/env python
from __future__ import division
import numpy as np
from matplotlib import pyplot as plt
# Sample data with two peaks: small one at t=0.4, large one at t=0.8
ts = np.arange(0, 1, 0.01)
xs = np.exp(-((ts-0.4)/0.1)**2) + 2*np.exp(-((ts-0.8)/0.1)**2)
# Say we have an approximate starting point of 0.35
start_point = 0.35
# Nearest index in "ts" to this starting point is...
start_index = np.argmin(np.abs(ts - start_point))
# Find the local maxima in our data by looking for a sign change in
# the first difference
# From http://stackoverflow.com/a/9667121/188535
maxes = (np.diff(np.sign(np.diff(xs))) < 0).nonzero()[0] + 1
# Find which of these peaks is closest to our starting point
index_of_peak = maxes[np.argmin(np.abs(maxes - start_index))]
print "Peak centre at: %.3f" % ts[index_of_peak]
# Quick plot showing the results: blue line is data, green dot is
# starting point, red dot is peak location
plt.plot(ts, xs, '-b')
plt.plot(ts[start_index], xs[start_index], 'og')
plt.plot(ts[index_of_peak], xs[index_of_peak], 'or')
plt.show()
Este método sólo funciona si el ascenso hasta el pico es perfectamente lisa desde su punto de partida. Si esto necesita ser más resistente al ruido, no lo he usado, pero PyDSTool parece que podría ayudar. Este SciPy post detalla cómo usarlo para detectar picos 1D en un conjunto de datos ruidoso.
Asuma que en este punto ha encontrado el centro del pico. Ahora para el ancho: hay varios métodos que puede usar, pero el más fácil es, probablemente, el "ancho completo a la mitad de máximo" (FWHM). De nuevo, esto es simple y, por lo tanto, frágil. Se romperá por dobles picos cercanos, o por datos ruidosos.
El FWHM es exactamente lo que su nombre sugiere: usted encuentra el ancho del pico si está a medio camino del máximo. Aquí hay algo de código que hace que (sólo continúa en la de arriba):
# FWHM...
half_max = xs[index_of_peak]/2
# This finds where in the data we cross over the halfway point to our peak. Note
# that this is global, so we need an extra step to refine these results to find
# the closest crossovers to our peak.
# Same sign-change-in-first-diff technique as above
hm_left_indices = (np.diff(np.sign(np.diff(np.abs(xs[:index_of_peak] - half_max)))) > 0).nonzero()[0] + 1
# Add "index_of_peak" to result because we cut off the left side of the data!
hm_right_indices = (np.diff(np.sign(np.diff(np.abs(xs[index_of_peak:] - half_max)))) > 0).nonzero()[0] + 1 + index_of_peak
# Find closest half-max index to peak
hm_left_index = hm_left_indices[np.argmin(np.abs(hm_left_indices - index_of_peak))]
hm_right_index = hm_right_indices[np.argmin(np.abs(hm_right_indices - index_of_peak))]
# And the width is...
fwhm = ts[hm_right_index] - ts[hm_left_index]
print "Width: %.3f" % fwhm
# Plot to illustrate FWHM: blue line is data, red circle is peak, red line
# shows FWHM
plt.plot(ts, xs, '-b')
plt.plot(ts[index_of_peak], xs[index_of_peak], 'or')
plt.plot(
[ts[hm_left_index], ts[hm_right_index]],
[xs[hm_left_index], xs[hm_right_index]], '-r')
plt.show()
No tiene por qué ser la anchura total a medio máximo - como un comentarista señala, se puede tratar de averiguar donde es el umbral normal de los operadores para la detección de picos, y conviértalo en un algoritmo para este paso del proceso.
Una forma más robusta podría ser ajustar una curva gaussiana (o su propio modelo) a un subconjunto de los datos centrados en el pico, por ejemplo, desde un mínimo local en un lado hasta un mínimo local en el otro y utilice uno de los parámetros de esa curva (por ejemplo, sigma) para calcular el ancho.
Me doy cuenta de que esto es una gran cantidad de código, pero he evitado deliberadamente las funciones de búsqueda de índices para "mostrar mi trabajo" un poco más, y por supuesto las funciones de trazado están ahí para demostrar.
Afortunadamente, esto le brinda al menos un buen punto de partida para encontrar algo más adecuado para su conjunto en particular.
Encuentra el umbral en el cual el ojo humano no puede distinguir el color del fondo. Debería ser bastante constante. Luego, solo limite sus puntos de datos de modo que los que están por encima de ese umbral sean "vistos" por el ojo humano y solo agrupen esos puntos de datos y encuentren el ancho de cada grupo. – Blender
¿Tal vez tome la derivada de la curva para encontrar picos y pendientes fácilmente? ¿No es el ancho de las bandas bastante constante? Son las amplitudes y posiciones las que varían según lo entiendo. –
@Blender, ¿podría dar más detalles sobre su punto? – aitchnyu