Introdução
Importação
Como a biblioteca é em português e a maioria das bibliotecas são em inglês, é muito difícil haver algum tipo de conflito de nomes. Então, sinta-se à vontade para fazer:
from LabIFSC2 import *
Ou, se não quiser poluir o namespace global, use:
import LabIFSC2 as lab
Classe Medida
A principal classe da biblioteca é a Medida. Ela recebe 3 argumentos para sua inicialização1:
- Nominal (): Valor(es) medido(s).
- Unidade: Unidade da medida (precisa ser a mesma do valor nominal e da incerteza).
- Incerteza (): Incerteza experimental.
Para um exemplo prático, consideraremos um tipo de medida comum, o IMC (Índice de Massa Corporal), não confundir com (ICMC). Suponhamos que uma pessoa foi medida (valores fictícios) com uma fita métrica e temos certeza apenas na casa de 1 cm de sua altura e usamos uma balança com precisão de 100 g para medir a sua massa.
Com o LabIFSC2, podemos fazer os cálculos assim:
massa = Medida(75, 'kg', 0.1)
altura = Medida(1.75, 'm', 0.01)
imc = massa / altura**2
print(imc) # (2,45 ± 0,03)x10¹ kg/m²
Você pode acessar o valor nominal e a incerteza fazendo medida.nominal(unidade) ou medida.incerteza(unidade). Repare que é necessário especificar uma unidade, visto que o valor nominal/incerteza são totalmente dependentes dela. É importante notar que somente em casos bem específicos você vai acessar diretamente esses valores. Se você usa muito essas funções, talvez não esteja usando a biblioteca corretamente.
print(imc.nominal('kg/m²')) # 24.5
print(imc.incerteza('kg/m²')) # 0.3
Várias medições
Podemos também criar uma medida baseada em várias medições. Imagine que você está medindo o diâmetro de um fio levemente irregular. Você pode preencher o valor nominal como sendo uma lista de medições, a biblioteca irá considerar o valor nominal como a média dos valores.
diametro=Medida([1.76,1.80,1.77,1.78],'cm',0.005)
print(diametro) #(1,78 ± 0,02) cm
Mas se a incerteza experimental for maior que o desvio padrão, então não temos certeza se essa variação é devido ao fio ter um formato irregular ou por efeitos aleatórios de medição, a incerteza então é a incerteza experimental.
Esse comportamento pode ser visto nesse exemplo, preste atenção nas incertezas:
diametro=Medida([1.76,1.80,1.77,1.78],'cm',0.005)
print(diametro) #(1,78 ± 0,02) cm
diametro_incerteza_grande=Medida([1.76,1.80,1.77,1.78],'cm',0.1)
print(diametro_incerteza_grande)#(1,8 ± 0,1) cm
Medidas sem incerteza
É possível criar medidas com incerteza zero. Nesse caso, a biblioteca somente realizará as conversões de unidade. Isso é interessante para um conjunto grande de medidas em que a incerteza é muito pequena, por exemplo, as medidas de voltagem de um osciloscópio, em que a precisão de tempo é enorme. É possível tratar os tempos como exatos, assim um grande ganho em performance é observado, visto que não ocorrerá nenhuma simulação Monte Carlo
Comparando Medidas
Se uma segunda pessoa afirmar que seu IMC é de (25 ± 0.1), podemos dizer que seus IMCs são equivalentes? Mesmo que , pela incerteza nas medidas podemos dizer que essa diferença está na margem de erro do experimento.
O método que faz essa comparação é comparar_medidas, que recebe duas Medidas e retorna se elas são:
- EQUIVALENTES
- DIFERENTES
- INCONCLUSIVO
imc1 = Medida(25, 'kg/m²', 0.1)
imc2 = Medida(24.5, 'kg/m²', 0.3)
print(comparar_medidas(imc1, imc2))
# Comparacao.EQUIVALENTES
Perceba que 3 resultados são possíveis, então infelizmente a sintaxe ìmc1==imc2 ou ìmc1!=imc2 não é perfeita, porque no caso inconclusivo temos ìmc1==imc2 (False) e ìmc1!=imc2 (False) ao mesmo tempo, o que creio ser javascript demais pro meu gosto.
O critério usado é o da apostila:
- EQUIVALENTES:
- INCONCLUSIVO:
- DIFERENTES:
Intuitivamente, a comparação é feita pelo quanto os valores nominais são diferentes e quanta incerteza temos nas medidas.
Ordenando Medidas
Em alguns momentos nós queremos usar o max ou min de um conjunto de medidas. Imagine que você quer, por exemplo, determinar a voltagem/corrente máxima atingida por um circuito.
Mesmo que existam incertezas, geralmente o que você se refere como min,max é em relação ao valor nominal. Então a classe Medida implementa comparações < <= > >=, referentes aos valores nominais, assim é possível usar funções do tipo max,min e sort de maneira direta.
voltagens=arrayM([1,4,3],'ampere',0.1)
print(max(voltagens)) #(4,0 ± 0,1) A
print(min(voltagens)) #(1,0 ± 0,1) A
print(sorted(voltagens)) #[(1,0 ± 0,1) A, (3,0 ± 0,1) A, (4,0 ± 0,1) A]``
voltagem_a=voltagens[0]
voltagem_b=voltagens[1]
print(voltagem_a<voltagem_b) #True
print(voltagem_a>voltagem_b) #False
Intervalo de Confiança
Como estamos falando de medidas experimentais, falamos de intervalos e não valores exatos. Objetos da classe Medida possuem um método chamado intervalo_de_confiança. Com ele, podemos especificar uma probabilidade p de estarmos representando os valores possíveis das Medidas.
imc=Medida(24.5,'kg/m²',0.3)
print(imc.intervalo_de_confiança(0.95,'kg/m²'))
#[23.91,25.08]
Convertendo Unidades
Por padrão, a unidade guardada em um objeto Medida é a unidade calculada pela operação realizada na sua geração. Então, se tivéssemos medido a altura usando , teríamos o IMC em .
Como o LabIFSC2 abstrai a conversão de unidades, uma das escolhas de design da biblioteca foi que a unidade em que a Medida é representada é decidida no momento do print, fazendo o print de uma string formatada, as chamadas fstrings (formatted strings) de Python.
print(f"{medida:unidade}")
Um exemplo concreto se encontra abaixo:
print(imc) # (2,45 ± 0,03)x10⁻³ kg/cm²
print(f"{imc:kg/m²}") # (2,45 ± 0,03)x10¹ kg/m²
print(f"{imc:g/cm²}") # (2,45 ± 0,03) g/cm²
print(f"{imc:si}") # (2,45 ± 0,03)x10¹ kg/m²
print(f"{imc}")
Dimensão
Como unidades só são uma característica do print de uma medida, e não algo intrínseco, uma forma independente de unidade para caracterizar o que uma medida é de fato é sua dimensão. Uma velocidade, por exemplo, independente se está em ou , é um comprimento dividido por um tempo. Você pode acessar esse atributo com medida.dimensao.
velocidade=Medida(10,'m/s',0.1)
print(velocidade.dimensao) #[length] / [time]
-
Perceba que o LabIFSC2 tem uma diferença de ordem de argumentos na criação de uma
Medidaem relação ao LabIFSC. Eu decidi colocar as unidades no meio da declaração pois, pessoalmente, acho que uma unidade no meio dos argumentos torna a leitura dos valores nominais e incerteza mais simples. Isso fica mais evidente em funções comolab.linspaceMelab.arrayMem que temos muitos valores numéricos nos seus construtores. ↩ -
A convenção de desvio padrão é a mesma da apostila, ou seja, dividimos os desvios quadráticos por e NÃO por . Isso é chamado de correção de Bessel. Esse detalhe só tem efeito visível para valores pequenos de , mas produz um resultado não enviesado para o desvio padrão. ↩