184 lines
3.7 KiB
Go
184 lines
3.7 KiB
Go
package lrls
|
|
|
|
import (
|
|
"gonum.org/v1/gonum/mat"
|
|
)
|
|
|
|
func recursive(u, y []float64) ([][]float64, []float64, error) {
|
|
dl := len(u)
|
|
if len(y) < dl {
|
|
dl = len(y)
|
|
}
|
|
|
|
// number of params.
|
|
p := 4
|
|
e := make([]float64, dl)
|
|
|
|
covMs, err := covMatrices(dl, p)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
theta, err := newTheta(dl, p)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
phi, err := newPhi(dl, p)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// the guts.
|
|
// in matlab:
|
|
// phi(:, k) = [-y(k-1) -y(k-2) u(k-1) u(k-2)]';
|
|
// e(k) = y(k) - phi(:, k)' * thm(:, k-1);
|
|
// C(:,:,k) = C(:,:,k-1) - (C(:,:,k-1)*phi(:,k)*phi(:,k)'*C(:,:,k-1))/(1+phi(:,k)'*C(:,:,k-1)*phi(:,k));
|
|
// thm(:,k) = thm(:,k-1) + C(:,:,k)*phi(:,k)*e(k);
|
|
for k := 2; k <= dl-1; k++ {
|
|
// phi[k] = []float64{-1.0 * y[k-1], -1 * y[k-2], -1 * u[k-1], -1 * u[k-2]}
|
|
// phi[k] = []float64{y[k-1], y[k-2], u[k-1], u[k-2]}
|
|
phi[k] = []float64{-1 * (y[k-1]), -1 * (y[k-2]), u[k-1], u[k-2]}
|
|
phiK := phi[k]
|
|
th := theta[k-1]
|
|
|
|
// phiT[k].theta[k-1].
|
|
phiThetaDotProd := phiThetaDotProd(p, phiK, th)
|
|
|
|
// get current error.
|
|
currentError := y[k] - phiThetaDotProd
|
|
|
|
// save current error.
|
|
e[k] = currentError
|
|
|
|
// next CM:
|
|
// cm(k) = cm(k-1) - [cm(k-1).phi(k).phiT(k).cm(k-1) / 1 + phiT(k).cm(k-1).phi(k)]
|
|
// next theta:
|
|
// theta(k) = theta(k-1) + cm(k).phi(k).e(k)
|
|
|
|
cmPrev := &mat.Dense{}
|
|
cmPrev.CloneFrom(covMs[k-1])
|
|
|
|
cmK := nextCM(p, cmPrev, phiK)
|
|
|
|
covMs[k] = cmK
|
|
|
|
tmp := &mat.Dense{}
|
|
phiVec := mat.NewVecDense(p, phiK)
|
|
|
|
tmp.Mul(cmK, phiVec)
|
|
|
|
// tmp.Scale(currentError, cmK) // -> this errs with dimens mismatch.
|
|
for i := range tmp.RawMatrix().Data {
|
|
tmp.RawMatrix().Data[i] *= currentError
|
|
}
|
|
|
|
tmpV := mat.NewVecDense(p, tmp.RawMatrix().Data)
|
|
|
|
thVec := mat.NewVecDense(p, th)
|
|
nuTh := mat.NewVecDense(p, nil)
|
|
|
|
nuTh.AddVec(thVec, tmpV)
|
|
|
|
theta[k] = nuTh.RawVector().Data
|
|
}
|
|
|
|
return theta, e, nil
|
|
}
|
|
|
|
func phiThetaDotProd(p int, phi, th []float64) float64 {
|
|
var res float64
|
|
|
|
for i := 0; i < p; i++ {
|
|
res += phi[i] * th[i]
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
// nextCM calculates the value of the next Covariance Matrix.
|
|
// cm(k) = cm(k-1) - [ cm(k-1).phi(k).phiT(k).cm(k-1) / 1 + phiT(k).cm(k-1).phi(k) ]
|
|
// matlab:
|
|
// C(k) = C(k-1) - (C(:,:,k-1)*phi(:,k)*phi(:,k)'*C(:,:,k-1))/(1+phi(:,k)'*C(:,:,k-1)*phi(:,k)).
|
|
func nextCM(p int, cmPrev *mat.Dense, phi []float64) *mat.Dense {
|
|
phiVec := mat.NewVecDense(p, phi)
|
|
phiVecTransposed := phiVec.TVec()
|
|
cmTmp := &mat.Dense{}
|
|
|
|
// r, c := cmPrev.Dims()
|
|
// log.Printf("cmPrev dims: %d, %d", r, c)
|
|
// r, c = phiVec.Dims()
|
|
// log.Printf("phiVec dims: %d, %d", r, c)
|
|
|
|
cmTmp.Mul(phiVec, phiVecTransposed)
|
|
|
|
cmTmp.Mul(cmTmp, cmPrev)
|
|
|
|
cmTmp.Mul(cmPrev, cmTmp)
|
|
|
|
// -----
|
|
|
|
cmTmp2 := &mat.Dense{}
|
|
|
|
cmTmp2.Mul(phiVecTransposed, cmPrev)
|
|
|
|
vecTmp := mat.NewVecDense(p, cmTmp2.RawMatrix().Data)
|
|
|
|
denominator := 1 + doVector(
|
|
vecTmp.RawVector().Data,
|
|
phiVec.RawVector().Data,
|
|
)
|
|
|
|
for i := range cmTmp.RawMatrix().Data {
|
|
cmTmp.RawMatrix().Data[i] /= denominator
|
|
}
|
|
|
|
cm := &mat.Dense{}
|
|
|
|
cm.Sub(cmPrev, cmTmp)
|
|
cm = subMat(cmPrev, cmTmp)
|
|
|
|
return cm
|
|
}
|
|
|
|
// doVector returns a scalar product of column vector `cv` and regular vector
|
|
// `rv`.
|
|
func doVector(cv, rv []float64) float64 {
|
|
var res float64
|
|
|
|
for i := range cv {
|
|
res += cv[i] * rv[i]
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func subMat(m1, m2 *mat.Dense) *mat.Dense {
|
|
r, c := m1.Dims()
|
|
m := mat.NewDense(r, c, nil)
|
|
|
|
for i := range m1.RawMatrix().Data {
|
|
m.RawMatrix().Data[i] = m1.RawMatrix().Data[i] - m2.RawMatrix().Data[i]
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
func TransposeTheta(theta [][]float64) [][]float64 {
|
|
thLen := len(theta)
|
|
elemLen := len(theta[0])
|
|
nuTheta := make([][]float64, elemLen)
|
|
|
|
for i := range theta[0] {
|
|
p := make([]float64, thLen)
|
|
|
|
for j := range theta {
|
|
p[j] = theta[j][i]
|
|
}
|
|
|
|
nuTheta[i] = p
|
|
}
|
|
|
|
return nuTheta
|
|
}
|