The observation model is the science
The dynamics half of a state-space model (A, W) is generic physics of movement. The observation model (C, Q, or a firing-rate law) is where actual neuroscience lives — it is your claim about how motor cortex encodes intention. If that claim is wrong, no amount of clever filtering rescues the decoder. So this guide slows down on the encoding side.
Cosine tuning and the linear observation
The classic finding is that many motor-cortex neurons fire in proportion to the cosine of the angle between the reach direction and the cell's preferred direction. Written as a dot product with the velocity vector, that tuning is exactly linear in the state — which is what lets the Kalman filter's C matrix exist.
\lambda_i(\mathbf{v}) = b_i + m_i \cos(\theta - \theta_i) = b_i + \mathbf{d}_i^{\top}\mathbf{v}Baseline b_i, modulation depth m_i, preferred direction theta_i; d_i is the preferred-direction vector, giving the row of C for neuron i.
Many motor neurons fire fastest when movement goes in their favorite direction and slow off it — a cosine curve. That neat shape makes the firing rate a simple linear function of velocity, which is exactly the observation matrix the filter needs.
- b_i
- The neuron's baseline firing rate.
- m_i
- Modulation depth — how strongly it is tuned to direction.
- \theta_i
- The neuron's preferred direction.
- \mathbf{d}_i
- The preferred-direction vector, forming neuron i's row of C.
This cosine tuning curve is what turns motor-cortex spikes into a linear-Gaussian observation model.
The oldest decoder, the population vector, just sums each cell's preferred direction weighted by its firing — no noise model, no regularization. The OLE adds a least-squares inverse; the Kalman filter adds dynamics and running uncertainty. Same tuning assumption, increasingly principled inversion.
Spikes are not Gaussian: the point-process filter
The Kalman filter assumes Gaussian measurement noise. But if your observation is a spike count in a short bin, it is a small non-negative integer — far better modelled as Poisson. The point-process filter replaces the linear-Gaussian observation with a Poisson likelihood whose log-rate is (usually) linear in the state.
\Pr(\Delta N_i = n \mid x_k) = \frac{\big(\lambda_i(x_k)\,\Delta\big)^{n} e^{-\lambda_i(x_k)\,\Delta}}{n!}, \qquad \log \lambda_i(x_k) = \alpha_i + \boldsymbol{\beta}_i^{\top} x_kA Poisson observation with a log-linear (GLM) firing-rate model; the filter keeps a Gaussian posterior but updates it with this non-Gaussian likelihood.
Spikes are discrete counts, not smooth Gaussian signals. Model the count in each tiny time bin as Poisson with a rate that rises log-linearly with the state. The filter keeps a Gaussian belief but corrects it with this spike likelihood.
- \Delta N_i
- The spike count of neuron i in the time bin.
- \lambda_i(x_k)
- The instantaneous firing rate given the current state.
- \Delta
- The width of the time bin.
- \alpha_i,\ \boldsymbol{\beta}_i
- Baseline and tuning weights in the log-rate (GLM) model.
This is the point-process filter, the right tool when you decode from individual spikes rather than smoothed rates.
Learning the parameters
During calibration the participant watches or attempts guided movements, giving paired (x_k, y_k). You then fit C by regressing firing on kinematics and Q from the residuals; A, W come from the kinematics themselves. When part of the state is genuinely hidden — latent factors, unobserved intent — you cannot regress directly and instead use expectation–maximization to learn the parameters by maximum likelihood.
\hat{C} = \Big(\textstyle\sum_k y_k\,x_k^{\top}\Big)\Big(\textstyle\sum_k x_k\,x_k^{\top}\Big)^{-1}, \qquad \hat{Q} = \frac{1}{K}\sum_k (y_k - \hat{C}x_k)(y_k - \hat{C}x_k)^{\top}Ordinary least squares for the tuning matrix and the residual covariance; shrink Q when channels outnumber training samples.
Learn the tuning matrix by ordinary least squares — regress observed neural activity on known states — and estimate the leftover noise from the residuals. Shrink the noise estimate when data is scarce.
- \hat{C}
- The fitted tuning / observation matrix.
- \sum_k y_k\,x_k^{\top}
- The cross-correlation of neural activity with state.
- \big(\sum_k x_k\,x_k^{\top}\big)^{-1}
- Inverse of the state covariance, which normalizes the fit.
- \hat{Q}
- The residual (unexplained) noise covariance.
This fits the observation model; iterating with the hidden state gives EM state-space learning.
Encoding is not decoding
A parameter set that describes the neural code well (C fits the training firing) is not automatically the one that decodes best in closed loop. The encoding model is an assumption baked at calibration time, but tuning drifts across a session and changes the moment the user starts steering feedback. That mismatch is precisely what motivates the nonlinear filters and, above all, the closed-loop retraining of the next guide.