Source code for optbayesexpt.obe_noiseparam
from optbayesexpt.obe_base import OptBayesExpt
import numpy as np
[docs]
class OptBayesExptNoiseParameter(OptBayesExpt):
"""OptBayesExpt adding measurement uncertainty as an unknown parameter.
OptBayesExptNoiseParameter is designed for cases where the experimental
uncertainty / standard deviation of the measurement noise is an unknown.
The standard deviation of the measurement
noise is included as one of the parameters.
The methods rely on several assumptions:
- The noise in measurement data is well-described by additive,
normally-distributed (Gaussian) noise.
- The noise is independent of settings and other parameters.
Arguments:
measurement_model (function): A function accepting (settings,
parameters, constants) arguments and returning model values of
experiment outputs. See the ``model_function`` arg of
``OptBayesExpt``.
setting_values (tuple of arrays): Arrays of allowed values for each
setting. See the ``setting_values`` arg of ``OptBayesExpt``.
parameter_samples (tuple of arrays): random draws of each model
parameter representing the prior probability distribution.
See the ``parameter_samples`` arg of ``OptBayesExpt``. One of the
parameter_sample arrays must be the standard deviation of the
measurement noise, idendified by the ``noise_parameter_index`` arg.
constants (tuple): settings or parameters that are assumed constant.
See the ``constants`` arg of ``OptBayesExpt``.
noise_parameter_index (int or tuple): identifies which of the arrays
in the ``paramter_samples`` input are uncertainty parameters.
For multi-channel measurements, the tuple identifies uncertainty
parameters corresponding to measurement channels. In cases where
channels have the same noise characteristics, indices may be
repeated in the tuple.
\*\*kwargs: Keyword arguments passed to the parent classes.
**Attributes:**
"""
def __init__(self, measurement_model, setting_values, parameter_samples,
constants, noise_parameter_index=None, **kwargs):
OptBayesExpt.__init__(self, measurement_model, setting_values,
parameter_samples, constants, **kwargs)
# identify the measurement noise parameter.
#: int: Stores the noise_parameter_index argument
self.noise_parameter_index = np.atleast_1d(noise_parameter_index)
if len(self.noise_parameter_index) != self.n_channels:
raise RuntimeError(f'noise_parameter_index is not compatible with'
f' {self.n_channels} measurement channels')
[docs]
def enforce_parameter_constraints(self):
"""Detects and nullifies disallowed parameter values
Constrains the noise parameter to be positive. Negative
uncertainties lead to negative likelihoods, negative particle
weights and other abominations. Overwrites the ``OptBayesExpt`` stub
method.
"""
changes = False
# np.nonzero identifies negative values
for param in self.parameters[self.noise_parameter_index]:
bad_ones, = np.nonzero(param <= 0)
if len(bad_ones) > 0:
changes = True
self.particle_weights[bad_ones] = 0
#
# other parameter checks may be added here
#
# renormalize ``particle_weights`` if weights have been changed.
if changes is True:
# rescale the particle weights
self.particle_weights = self.particle_weights \
/ np.sum(self.particle_weights)
[docs]
def likelihood(self, y_model, measurement_record):
"""
Calculates the likelihood of a measurement result.
For each parameter combination, estimate the probability of
obtaining the results provided in :code:`measurement_result`.
Under these assumptions, and model values :math:`y_{model}` as a
function of parameters, the likelihood is a Gaussian function
proportional to :math:`\sigma^{-1} \exp [-(y_{model} - y_{meas})^2
/ (2 \sigma^2)]`.
Args:
y_model (:obj:`ndarray`): ``model_function()`` results evaluated
for all parameters.
measurement_record (:obj:`tuple`): The measurement conditions
and results, supplied by the user to ``update_pdf()``. The
first two elements of ``measurement_record`` are:
- settings (tuple)
- measurement value (float or tuple)
further entries in the measurement_record are ignored.
Returns:
an array of probabilities corresponding to the parameters in
:code:`self.allparameters`.
"""
# unpack the measurement_record
onesetting, y_meas = measurement_record[:2]
lky = 1.0
sigma = self.parameters[self.noise_parameter_index]
for y_m, y, s in zip(y_model,
np.atleast_1d(y_meas), sigma):
lky *= self._gauss_noise_likelihood(y_m, y, s)
if self.choke is not None:
return np.power(lky, self.choke)
else:
return lky
[docs]
def yvar_noise_model(self):
"""Calculates the mean variance from the noise parameter.
Overwrites OptBayesExpt method, replacing :code:`default_noise_std **
2` with the mean variance calculated from the noise parameter. Used
in calculating utility.
Returns: (float) average variance.
"""
# square the sigma samples
sigma_squared = self.parameters[self.noise_parameter_index] ** 2
# weighted average
yvars = np.average(sigma_squared, weights=self.particle_weights,
axis=1)
return yvars.reshape((self.n_channels, 1))