6.16. Curve e integrazione¶
Le pagine sulla matematica hanno trattato operazioni che prendono in input un array e producono in output un array (o uno scalare) – aritmetica, riduzioni, broadcasting. Questa pagina copre una classe diversa di operazioni: quelle che trattano l’array come una funzione campionata e pongono domande sulla funzione stessa. Interpolare tra i campioni, adattare una curva ad essi, integrarli, convolverli con un altro buffer.
Tutte queste accettano input ndarray e restituiscono o uno scalare float o un ndarray di float.
6.16.1. Interpolazione¶
interp() esegue un’interpolazione lineare unidimensionale. xp è un array 1-D monotonicamente crescente di valori indipendenti; fp sono i corrispondenti valori dipendenti; x è il punto in cui l’interpolante deve essere valutato:
xp = np.array([0.0, 1.0, 2.0, 3.0])
fp = np.array([10.0, 20.0, 25.0, 30.0])
x = np.array([0.5, 1.5, 2.5])
np.interp(x, xp, fp)
# array([15.0, 22.5, 27.5])
Al di fuori dell’intervallo [xp[0], xp[-1]] il risultato viene saturato rispettivamente a fp[0] e fp[-1]; le parole chiave left= e right= sovrascrivono questi estremi.
Usata sulla camera per rimappare una tabella di calibrazione su posizioni di campionamento arbitrarie – una tabella temperatura-tensione di un termistore, una curva di risposta non lineare dei pixel, una lookup gamma per canale. Una chiamata di libreria, una passata sugli input, nessun ciclo Python.
6.16.2. Adattamento e valutazione di polinomi¶
polyfit() adatta un polinomio di grado deg ai punti dati (x, y) con i minimi quadrati e restituisce i coefficienti (grado più alto per primo):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = np.array([0.0, 1.1, 3.9, 9.1, 15.8])
coeffs = np.polyfit(x, y, 2)
# array([1.0, 0.0, 0.0]) (approximately)
Quando x viene omesso, viene usato range(len(y)) – utile per adattare velocemente un polinomio a un buffer campionato regolarmente senza un asse x associato:
np.polyfit(y, 2)
polyval() valuta in x il polinomio i cui coefficienti sono p. L’input x può essere uno scalare (restituisce un float) o un ndarray (restituisce un ndarray):
p = np.polyfit(x, y, 2)
fitted = np.polyval(p, x)
L’accoppiamento naturale è chiamare polyfit una volta in fase di calibrazione, memorizzare i coefficienti e chiamare polyval per valutare la curva risultante a ogni frame. Il passo di valutazione del polinomio è un pugno di operazioni float per campione, il che è economico anche sulle camere più piccole.
6.16.3. Convoluzione¶
convolve() restituisce la convoluzione lineare discreta a lunghezza piena di due array 1-D. È implementata solo la modalità full; la lunghezza dell’output è len(a) + len(v) - 1. Affetta il risultato per ottenere lo stesso effetto delle modalità same e valid offerte dal numpy desktop:
a = np.array([1.0, 2.0, 3.0])
v = np.array([0.5, 0.5])
np.convolve(a, v)
# array([0.5, 1.5, 2.5, 1.5])
Utile per brevi filtri FIR e kernel di smoothing (box, triangolo, gaussiano) dove impostare una catena SOS è eccessivo. Il tempo di esecuzione è proporzionale al prodotto delle lunghezze dei due array – va bene per kernel brevi ma diventa rapidamente più costoso di una convoluzione FFT per quelli lunghi.
6.16.4. Integrazione trapezoidale¶
trapz() integra una funzione campionata con la regola dei trapezi composita:
x = np.linspace(0, np.pi, num=128)
y = np.sin(x)
np.trapz(y, x) # ~ 2.0
Passa dx= quando la spaziatura dei campioni è uniforme e conta solo il passo; passa x= quando i campioni non sono spaziati uniformemente. È la chiamata giusta per integrare dati di sensore già acquisiti, dove la forma analitica non è disponibile.
Per dati campionati che siano stati limitati in banda (un buffer audio dopo un filtro anti-aliasing, per esempio), la regola dei trapezi converge come il quadrato del numero di campioni, il che significa che raddoppiare la lunghezza del buffer riduce l’errore di un fattore quattro.
Quando l’integrando non è un buffer di campioni ma una funzione Python che l’applicazione può valutare in punti arbitrari, la chiamata giusta è una diversa famiglia di solver.