6.16. Curvas e integração

As páginas de matemática cobriram operações que recebem um array e produzem um array (ou escalar) – aritmética, reduções, broadcasting. Esta página cobre uma classe diferente de operações: as que tratam o array como uma função amostrada e fazem perguntas sobre a própria função. Interpolar entre amostras, ajustar uma curva a elas, integrar sob elas, convoluí-las com outro buffer.

Todas elas aceitam entradas ndarray e retornam um escalar float ou um ndarray de floats.

6.16.1. Interpolação

interp() faz interpolação linear unidimensional. xp é um array 1-D monotonicamente crescente de valores independentes; fp são os valores dependentes correspondentes; x é onde o interpolante deve ser avaliado:

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

Fora da faixa [xp[0], xp[-1]], o resultado é fixado em fp[0] e fp[-1] respectivamente; as palavras-chave left= e right= sobrescrevem esses extremos.

Usada na câmera para remapear uma tabela de calibração para posições de amostra arbitrárias – uma tabela temperatura-para-tensão de um termistor, uma curva de resposta de pixel não linear, uma busca de gama por canal. Uma chamada de biblioteca, uma passagem sobre as entradas, nenhum laço Python.

6.16.2. Ajuste e avaliação de polinômios

polyfit() ajusta um polinômio de grau deg aos pontos de dados (x, y) por mínimos quadrados e retorna os coeficientes (de maior grau primeiro):

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 é omitido, range(len(y)) é usado – útil para ajustar rapidamente um polinômio a um buffer amostrado regularmente sem um eixo x associado:

np.polyfit(y, 2)

polyval() avalia o polinômio cujos coeficientes são p em x. A entrada x pode ser um escalar (retorna um float) ou um ndarray (retorna um ndarray):

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

O pareamento natural é chamar polyfit uma vez no momento da calibração, armazenar os coeficientes e chamar polyval para avaliar a curva resultante a cada quadro. A etapa de avaliação do polinômio são poucas operações de float por amostra, o que é barato até nas câmeras menores.

6.16.3. Convolução

convolve() retorna a convolução linear discreta de comprimento completo de dois arrays 1-D. Apenas o modo full está implementado; o comprimento da saída é len(a) + len(v) - 1. Fatie o resultado para obter o mesmo efeito dos modos same e valid que o numpy de desktop oferece:

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

Útil para filtros FIR curtos e kernels de suavização (caixa, triângulo, gaussiano) onde montar uma cadeia SOS seria exagero. O tempo de execução é proporcional ao produto dos comprimentos dos dois arrays – adequado para kernels curtos, mas rapidamente fica mais caro do que uma convolução por FFT para kernels longos.

6.16.4. Integração trapezoidal

trapz() integra uma função amostrada pela regra trapezoidal composta:

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

Passe dx= quando o espaçamento das amostras for uniforme e apenas o passo importar; passe x= quando as amostras não forem igualmente espaçadas. É a chamada certa para integrar dados de sensor já capturados, onde a forma analítica não está disponível.

Para dados de amostra que tenham sido limitados em banda (um buffer de áudio após um filtro anti-aliasing, por exemplo), a regra trapezoidal converge com o quadrado da contagem de amostras, o que significa que dobrar o comprimento do buffer reduz o erro por um fator de quatro.

Quando o integrando não é um buffer de amostras, mas uma função Python que a aplicação pode avaliar em pontos arbitrários, uma família diferente de solucionadores é a escolha certa.