-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Addition of Efficient/Lagrangian Point-Mass Filter #1052
Closed
Closed
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
c78f2a4
added lagrangian pmf and tan in its raw form
pesslovany a586b46
refact
pesslovany 08f9394
Merge branch 'dstl:main' into main
pesslovany 13ac8e8
Update nonlinear.py
pesslovany 1dc8e5a
flake8 changes
pesslovany 1442c8b
flake8
pesslovany 1baf1bf
added test for functions and pointmass
pesslovany 77273c3
adding tests
pesslovany 714a78a
fixed deletion of plotter
pesslovany 870ccb6
added test for updater points mass
pesslovany 8eb51da
Added test for predictor
pesslovany bb58d1a
Added lines to tests. Reverted plotter.
pesslovany 7af6e21
Fixed flake 8
pesslovany 9900128
Added documentation
pesslovany e3933a7
Removing inwanted files
pesslovany 60bd143
Merge branch 'main' into main
pesslovany 18c27ad
Changes based on review. Making the code work again and fixing pep8 i…
pesslovany c6c9450
Merge branch 'main' into main
pesslovany 0645cc3
Fixing flake8 issues after merge
pesslovany a7f3bc6
Changed names of the functions to maintain python naming convetions
pesslovany File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,3 +18,6 @@ htmlcov/ | |
|
||
#Animation plotting example | ||
docs/examples/plotting/example_animation.gif | ||
|
||
#Mac files | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import numpy as np | ||
from scipy.stats import mvn | ||
import itertools | ||
from numpy import linalg as LA | ||
import scipy.special as sciSpec | ||
from scipy.interpolate import RegularGridInterpolator | ||
from scipy.signal import fftconvolve | ||
|
||
|
||
def boxvertex(n, bound): | ||
bound = np.flipud(bound) | ||
vertices = np.zeros((2**n, n)) | ||
for k in range(2**n): | ||
for d in range(n): | ||
if k & (1 << d): | ||
vertices[k, d] = bound[d] | ||
else: | ||
vertices[k, d] = -bound[d] | ||
return vertices | ||
|
||
|
||
|
||
def measPdfPrepFFT(measPdf, gridDimOld, predMeanEst, predVarEst, F, sFactor, nx, Npa, k): | ||
# Setup the measurement grid | ||
eigVal, eigVect = np.linalg.eig(predVarEst) # eigenvalue and eigenvectors, for setting up the grid | ||
gridBoundWant = np.sqrt(eigVal) * sFactor # Wanted boundaries of pred grid | ||
gridBoundWantCorners = np.dot(boxvertex(nx, gridBoundWant), eigVect.T).T + predMeanEst # Wanted corner of predictive grid | ||
gridBoundWantCorners = np.dot(np.linalg.inv(F), gridBoundWantCorners) # Back to filtering space | ||
maxF = np.max(gridBoundWantCorners, axis=1) # Min/Max meas corners | ||
minF = np.min(gridBoundWantCorners, axis=1) | ||
gridDim = [] | ||
gridStep = np.zeros((nx, 1)) | ||
for ind3 in range(nx): # Creation of filtering grid so that it creates wanted predictive grid | ||
gridDim.append(np.linspace(minF[ind3], maxF[ind3], Npa)) | ||
gridStep[ind3] = abs(gridDim[ind3][0] - gridDim[ind3][1]) | ||
measGridNew = np.array(np.meshgrid(*gridDim)).reshape(nx, -1, order='C') | ||
|
||
|
||
GridDelta = gridStep # Grid step size | ||
GridDelta = np.squeeze(GridDelta) | ||
|
||
# Interpolation | ||
Fint = RegularGridInterpolator(gridDimOld, measPdf.reshape(Npa, Npa, order='F'), method="linear", bounds_error=False, fill_value=0) | ||
if k == 0: | ||
filtGridInterpInvTrsf = measGridNew.T | ||
else: | ||
filtGridInterpInvTrsf = np.dot(np.linalg.inv(F), measGridNew).T | ||
measPdf = Fint(filtGridInterpInvTrsf) | ||
|
||
gridDimOld = gridDim | ||
|
||
# # Unpack x, y coordinates from measGrid | ||
# x_coords, y_coords = measGridNew | ||
|
||
# # Plot the data as a scatter plot | ||
# plt.figure() | ||
# plt.scatter(x_coords, y_coords, c=measPdf, cmap='viridis') | ||
|
||
|
||
return measPdf, gridDimOld, GridDelta, measGridNew | ||
|
||
|
||
|
||
def pmfUpdateFFT(F, measPdf, measGridNew, GridDelta, k, Npa, invQ, predDenDenomW, nx): | ||
# Predictive grid | ||
predGrid = np.dot(F, measGridNew) | ||
|
||
# Grid step size | ||
GridDelta[:, k+1] = np.dot(F, GridDelta[:, k]) | ||
|
||
# ULTRA FAST PMF | ||
filtDenDOTprodDeltas = np.dot(measPdf, np.prod(GridDelta[:, k])) # measurement PDF * measurement PDF step size | ||
filtDenDOTprodDeltasCub = np.reshape(filtDenDOTprodDeltas, (Npa, Npa), order='C') # Into physical space | ||
|
||
halfGrid = (np.ceil(predGrid.shape[1] / 2)-1).astype(int) | ||
|
||
pom = np.transpose(predGrid[:, halfGrid][:, np.newaxis] - predGrid) # Middle row of the TPM matrix | ||
TPMrow = (np.exp(np.sum(-0.5 * pom @ invQ * pom, axis=1)) / predDenDenomW).reshape(1, -1, order='C') # Middle row of the TPM matrix | ||
TPMrowCubPom = np.reshape(TPMrow, (Npa, Npa), order='F') # Into physical space | ||
|
||
# Compute the convolution using scipy.signal.fftconvolve | ||
convolution_result_complex = fftconvolve(filtDenDOTprodDeltasCub, TPMrowCubPom, mode='same') | ||
|
||
# Take the real part of the convolution result to get a real-valued result | ||
convolution_result_real = np.real(convolution_result_complex).T | ||
|
||
|
||
predDensityProb = np.reshape(convolution_result_real, (-1,1), order='F') | ||
predDensityProb = predDensityProb / (np.sum(predDensityProb) * np.prod(GridDelta[:, k+1])) # Normalization (theoretically not needed) | ||
|
||
|
||
return predDensityProb, predGrid, GridDelta | ||
|
||
|
||
def ukfUpdate(measVar,nx,kappa,measMean,ffunct,k,Q): | ||
# UKF prediction for grid placement | ||
S = np.linalg.cholesky(measVar) #lower choleski | ||
decomp = np.sqrt(nx+kappa)*S | ||
rep = np.matlib.repmat(measMean.T,2*nx,1).T + np.c_[decomp,-decomp] #concatenate | ||
chi = np.c_[measMean, rep] | ||
wUKF = np.array(np.c_[kappa,np.matlib.repmat(0.5,1,2*nx)])/(nx+kappa) #weights | ||
|
||
Y = ffunct(chi, np.zeros((nx,1)),k) | ||
xp_aux = Y @ wUKF.T | ||
Ydiff = Y - xp_aux | ||
Pp_aux = np.multiply(Ydiff,np.matlib.repmat(wUKF,nx,1))@Ydiff.T+Q.T # UKF prediction var | ||
return xp_aux,Pp_aux | ||
|
||
|
||
def gridCreationFFT(xp_aux, Pp_aux, sFactor, nx, Npa): | ||
# Boundaries of grid | ||
gridBound = np.sqrt(np.diag(Pp_aux)) * sFactor | ||
|
||
# Creation of propagated grid | ||
gridDim = [] | ||
gridStep = np.zeros((nx, 1)) | ||
for ind3 in range(nx): | ||
gridDim.append(np.linspace(-gridBound[ind3], gridBound[ind3], Npa) + xp_aux[ind3]) | ||
gridStep[ind3] = abs(gridDim[ind3][0] - gridDim[ind3][1]) | ||
|
||
# Grid rotation by eigenvectors and translation to the counted unscented mean | ||
predGrid = np.array(np.meshgrid(*gridDim)).reshape(nx, -1, order='C') | ||
|
||
# Grid step size | ||
predGridDelta = np.squeeze(gridStep) | ||
|
||
return predGrid, gridDim, predGridDelta | ||
|
||
|
||
def gridCreation(xp_aux,Pp_aux,sFactor,nx,Npa): | ||
gridDim = np.zeros((nx,Npa)) | ||
gridStep = np.zeros(nx) | ||
eigVal,eigVect = LA.eig(Pp_aux) # eigenvalue and eigenvectors for setting up the grid | ||
gridBound = np.sqrt(eigVal)*sFactor #Boundaries of grid | ||
|
||
for ind3 in range(0,nx): #Creation of propagated grid | ||
gridDim[ind3] = np.linspace(-gridBound[ind3], gridBound[ind3], Npa) #New grid with middle in 0 | ||
gridStep[ind3] = np.absolute(gridDim[ind3][0] - gridDim[ind3][1]) #Grid step | ||
|
||
combvec_predGrid = np.array(list(itertools.product(*gridDim))) | ||
predGrid_pom = np.dot(combvec_predGrid,eigVect).T | ||
size_pom = np.size(predGrid_pom,1) | ||
predGrid = predGrid_pom + np.matlib.repmat(xp_aux,1,size_pom) #Grid rotation by eigenvectors and traslation to the counted unscented mean | ||
predGridDelta = gridStep # Grid step size | ||
return predGrid,predGridDelta | ||
|
||
|
||
def pmfMeas(predGrid,nz,k,z,invR,predDenDenomV,predDensityProb,predGridDelta,hfunct): | ||
predThrMeasEq = hfunct(predGrid,np.zeros((nz,1)),k+1) #Prediction density grid through measurement EQ | ||
pom = np.matlib.repmat(z,np.size(predThrMeasEq.T,0),1)-predThrMeasEq.T #Measurement - measurementEQ(Grid) | ||
citatel = np.exp(np.sum(-0.5*np.multiply(pom @ invR,pom),1)) | ||
filterDensityNoNorm = np.multiply(citatel / predDenDenomV ,predDensityProb.T) | ||
filterDensityNoNorm = filterDensityNoNorm.T | ||
measPdf = (filterDensityNoNorm / np.sum(np.prod(predGridDelta)*filterDensityNoNorm,0)) | ||
return measPdf | ||
|
||
def pmfUpdateSTD(measGrid,measPdf,predGridDelta,ffunct,predGrid,nx,k,invQ,predDenDenomW,N): | ||
fitDenDOTprodDeltas = measPdf*np.prod(predGridDelta[:,k]) # measurement PDF * measurement PDF step size | ||
gridNext = ffunct(measGrid,np.zeros((nx,1)),k+1) # Old grid through dynamics | ||
|
||
predDensityProb = np.zeros((N,1)) | ||
for ind2 in range(0,N): #Over number of state of prediction grid | ||
pom = (predGrid[:,ind2].T-(gridNext).T) | ||
suma = np.sum(-0.5*np.multiply(pom@invQ,pom),1) | ||
predDensityProb[ind2,0] = (np.exp(suma)/predDenDenomW).T@fitDenDOTprodDeltas | ||
predDensityProb = predDensityProb/(np.sum(predDensityProb)*np.prod(predGridDelta[:,k+1])) # Normalizaton (theoretically not needed) | ||
return predDensityProb | ||
|
||
|
||
def pmfUpdateDWC(invF,predGrid,measGrid,predGridDelta,Qa,cnormHere,measPdf,N,k): | ||
predDensityProb = np.zeros((N,N)) | ||
for i in range(0,N): # Unecessary for cycle, for clearer understanding | ||
ma = invF @ predGrid[:,i] | ||
for n in range(0,N): | ||
lowerBound = np.array([measGrid[:,n]-predGridDelta[:,k]/2]).T # boundary of rectangular region M | ||
upperBound = np.array([measGrid[:,n]+predGridDelta[:,k]/2]).T | ||
cdfAct = mvn.mvnun(lowerBound,upperBound,ma,Qa)[0] #Integral calculation | ||
predDensityProb[i,n] = cnormHere*cdfAct*measPdf[n] # Predictive density | ||
predDensityProb = np.sum(predDensityProb,1) | ||
predDensityProb = predDensityProb/(np.sum(predDensityProb)*np.prod(predGridDelta[:,k+1])) # Normalizaton (theoretically not needed) | ||
return predDensityProb | ||
|
||
|
||
def pmfUpdateDiagDWC(measGrid,N,predGridDelta,F,predGrid,Q,s2,measPdf,normDiagDWC,k): | ||
predDensityProb = np.zeros((N,N)) | ||
bound = np.zeros((np.size(measGrid,0),np.size(measGrid,0))) # boundary of rectangular region M | ||
|
||
for i in range(0,N): | ||
for n in range(0,N): | ||
bound = np.array([measGrid[:,n]-predGridDelta[:,k]/2,measGrid[:,n]+ predGridDelta[:,k]/2]).T | ||
pom = np.array([ np.divide(-F@bound[:,0] + predGrid[:,i],np.sqrt(np.diag(Q))), np.divide(-F@bound[:,1] + predGrid[:,i],np.sqrt(np.diag(Q))) ]).T # NESEDI DIMENZE!!!!!!!!!! | ||
erfAct = np.prod((0.5 - 0.5*sciSpec.erf(pom[:,1]/s2)) - (0.5 - 0.5*sciSpec.erf(pom[:,0]/s2))) | ||
predDensityProb[i,n] = measPdf[n] * normDiagDWC * erfAct # Predictive density | ||
predDensityProb = np.sum(predDensityProb,1) | ||
predDensityProb = predDensityProb/(np.sum(predDensityProb)*np.prod(predGridDelta[:,k+1])) # Normalizaton (theoretically not needed) | ||
return predDensityProb | ||
|
||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file required? Looks like added functionality from the file e.g. gridCreation has been added to functions/init.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have deleted the file.