code: def update(self, z, R=None, H=None):
          
  
          if H is None:
              H = self.H
  
          # new probability is recursively defined as prior * likelihood
          for i, f in enumerate(self.filters):
              f.update(z, R, H)
              self.p[i] *= f.likelihood
  
          self.p /= sum(self.p) # normalize
  
          # compute estimated state and covariance of the bank of filters.
          self.P = np.zeros(self.filters[0].P.shape)
  
          # state can be in form [x,y,z,...] or [[x, y, z,...]].T
          is_row_vector = (self.filters[0].x.ndim == 1)
          if is_row_vector:
              self.x = np.zeros(self.dim_x)
              for f, p in zip(self.filters, self.p):
                  self.x += np.dot(f.x, p)
          else:
              self.x = np.zeros((self.dim_x, 1))
              for f, p in zip(self.filters, self.p):
                  self.x = np.zeros((self.dim_x, 1))
                  self.x += np.dot(f.x, p)
  
          for x, f, p in zip(self.x, self.filters, self.p):
              y = f.x - x
              self.P += p*(np.outer(y, y) + f.P)
  
  
          # save measurement and posterior state
          self.z = deepcopy(z)
          self.x_post = self.x.copy()
          self.P_post = self.P.copy()
docs: Add a new measurement (z) to the Kalman filter. If z is None, nothing
          is changed.
  
          Parameters
          ----------
  
          z : np.array
              measurement for this update.
  
          R : np.array, scalar, or None
              Optionally provide R to override the measurement noise for this
              one call, otherwise  self.R will be used.
  
          H : np.array,  or None
              Optionally provide H to override the measurement function for this
              one call, otherwise  self.H will be used.