Outliers Kalman Filtering This might not be the right place to ask this questions, but I figured it's more of a machine learning question. I am also asking on the pyro forum for brevity.
I'm working with the simple extended Kalman filtering tutorial in Pyro and I want to understand how I can use a Kalman filter to track a measurement series while ignoring outliers. I have found theoretical research on the subject but little in the way of actual implementations. The tutorial shows how to track a particle in 2d space with a Kalman Filter. The problem is this tracker will follow outliers...

I used numpy to generate some outliers:
# probability of an outlier
p_outl = .15
# scale outlier
scale_outl = .01
# create boolean array for location of outliers
outl_msk = np.random.binomial(1, p_outl, (num_frames,))
# create array for outliers. these will be added to measurement y
outl = np.ones((num_frames,)) * outl_msk
outl[np.argwhere(outl_msk).reshape(-1)] = \
outl[np.argwhere(outl_msk).reshape(-1)] * \
np.where(np.random.binomial(1, .5, (np.sum(outl_msk),)), -1, 1) * scale_outl

I added them to the measurements random noise tensor:
# Measurements
mean = torch.zeros(2)
# no correlations
cov = torch.tensor([1e-5, 1e-5]) * torch.eye(2)
# create measurements
with torch.no_grad():
    # sample independent measurement noise from a multivariate normal
    dzs = pyro.sample('dzs', dist.MultivariateNormal(mean, cov).expand((num_frames,)))
    # add outlier to y
    dzs[:, 1] = dzs[:, 1] + torch.tensor(outl).float()
    # compute measurement means
    zs = xs_truth[:, :2] + dzs

This produced the outliers you see in the plot above. This is a demo with 10 frames but I'd hope with any number of frames we see the Kalman Filter follow the actual trajectory not the measurements.
To reproduce the plot, you will need the plotting code. This is not included in the tutorial so here is my plotting code...
plt.plot(xs_truth[:, 0], xs_truth[:, 1], markersize=1.5, lw=2.0)
plt.plot(zs[:, 0], zs[:, 1],
    'o-', color='#00bfff', markersize=5, markerfacecolor='y',
    markeredgewidth=1.0, markeredgecolor='k', label='measurement',
    zorder=4)
for measurement in xs_truth:
    sts.plot_error_ellipse(
        mean=measurement[:2].numpy(), cov=cov.numpy(),
        num_points=30, edgecolor='k', facecolor='m', alpha=0.5,
        linewidth=2.0, linestyle='solid', zorder=0)

plt.plot([s.mean[0].item() for s in states], [s.mean[1].item() for s in states], 'o-',
    color='#ffb818', mec='w', mfc='k', ms=8, lw=2.0, label='track',
    zorder=3)
for state in states:
    sts.plot_error_ellipse(
        mean=state.mean[:2].detach().numpy(), cov=state.cov[:2, :2].detach().numpy(),
        num_points=30, edgecolor='k', facecolor='k', alpha=0.6,
        linewidth=2.0, linestyle='solid', zorder=1)


# Plot aesthetics.
ax = plt.gca()
ax.set_aspect('equal')
plt.title('EKF Demo', fontsize=16, fontweight='bold')
plt.xlabel('x', fontsize=14, fontweight='bold')
plt.ylabel('y', fontsize=14, fontweight='bold')
legend = plt.legend(bbox_to_anchor=(.6, -.2), loc='upper left', numpoints=1)
plt.setp(legend.get_texts(), fontsize='14', fontweight='bold')
# plt.xlim((-0.02, 0.12))
# plt.ylim((-0.02, 0.02))
plt.grid(True)
plt.show()

 A: What you need to do is use a noise model that includes outliers, i.e., a heavy-tailed noise model instead of the Gaussian one. Unfortunately, all the nice properties of classical Kalman filtering break down in this case, so one has to use different algorithms. (But the EKF is only a very crude approximation anyways.)
I have never used pyro, but from a brief look at its documentation, it appears that maybe you could implement an outlier-robust linear state-space filtering method by using the LinerHMM distribution with some heavy-tailed noise distribution. As I said above, the inference algorithm will then be very different from the classical Kalman filter.
If you want to do nonlinear outlier-robust state-space filtering, this is more involved and I am not sure if this is currently supported in pyro; at least I could not find anything that could be used for this in the documentation. You would need a function that allows the specification of an arbitrary deterministic nonlinear transformation of a random variable. pymc3, for example allows this.
