6.16. Curves en integratie

De wiskundepagina’s behandelden bewerkingen die een array innemen en een array (of scalair) opleveren – rekenkunde, reducties, broadcasting. Deze pagina behandelt een andere klasse van bewerkingen: bewerkingen die de array behandelen als een bemonsterde functie en vragen stellen over de functie zelf. Interpoleren tussen monsters, er een curve op fitten, eronder integreren, ze convolueren met een andere buffer.

Al deze accepteren ndarray-invoer en geven ofwel een float-scalair ofwel een float-ndarray terug.

6.16.1. Interpolatie

interp() voert eendimensionale lineaire interpolatie uit. xp is een monotoon stijgende 1-D-array van onafhankelijke waarden; fp zijn de bijbehorende afhankelijke waarden; x is waar de interpolant moet worden geëvalueerd:

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])

Buiten het bereik [xp[0], xp[-1]] wordt het resultaat respectievelijk afgekapt tot fp[0] en fp[-1]; de trefwoorden left= en right= overschrijven die eindpunten.

Op de camera gebruikt om een kalibratietabel te herschalen naar willekeurige monsterposities – een temperatuur-naar-spanningstabel van een thermistor, een niet-lineaire pixelresponscurve, een gamma-lookup per kanaal. Eén bibliotheekaanroep, één doorloop over de invoer, geen Python-lus.

6.16.2. Polynoomfitting en -evaluatie

polyfit() fit een polynoom van graad deg aan de datapunten (x, y) met de kleinste-kwadratenmethode en geeft de coëfficiënten terug (hoogste graad eerst):

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)

Wanneer x wordt weggelaten, wordt range(len(y)) gebruikt – handig om snel een polynoom te fitten aan een regelmatig bemonsterde buffer zonder bijbehorende x-as:

np.polyfit(y, 2)

polyval() evalueert de polynoom waarvan de coëfficiënten p zijn op x. De invoer x kan een scalair zijn (geeft een float terug) of een ndarray (geeft een ndarray terug):

p = np.polyfit(x, y, 2)
fitted = np.polyval(p, x)

De natuurlijke combinatie is om polyfit eenmaal bij kalibratie aan te roepen, de coëfficiënten op te slaan en polyval aan te roepen om de resulterende curve elk frame te evalueren. De polynoomevaluatiestap is een handvol float-bewerkingen per monster, wat zelfs op de kleinste cams goedkoop is.

6.16.3. Convolutie

convolve() geeft de volledige discrete lineaire convolutie van twee 1-D-arrays terug. Alleen de full-modus is geïmplementeerd; de uitvoerlengte is len(a) + len(v) - 1. Snijd het resultaat aan om hetzelfde effect te krijgen als de same- en valid-modi die het desktop-numpy biedt:

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])

Handig voor korte FIR-filters en gladstrijkkernels (box, driehoek, gaussian) waar het opzetten van een SOS-keten overdreven is. De looptijd is evenredig met het product van de twee arraylengtes – prima voor korte kernels, maar wordt voor lange kernels al snel duurder dan een FFT-convolutie.

6.16.4. Trapeziumintegratie

trapz() integreert een bemonsterde functie met de samengestelde trapeziumregel:

x = np.linspace(0, np.pi, num=128)
y = np.sin(x)
np.trapz(y, x)             # ~ 2.0

Geef dx= mee wanneer de monsterafstand uniform is en alleen de stap van belang is; geef x= mee wanneer de monsters niet gelijkmatig verdeeld zijn. De juiste aanroep voor het integreren van reeds vastgelegde sensordata, waar de analytische vorm niet beschikbaar is.

Voor monsterdata die bandbeperkt is (een audiobuffer na een anti-aliasingfilter bijvoorbeeld), convergeert de trapeziumregel als het kwadraat van het aantal monsters, wat betekent dat het verdubbelen van de bufferlengte de fout met een factor vier verkleint.

Wanneer de integrand geen buffer van monsters is maar een Python-functie die de applicatie op willekeurige punten kan evalueren, is een andere familie van solvers de juiste keuze.