yaflpy.pyx 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635
  1. # -*- coding: utf-8 -*-
  2. """
  3. Copyright 2020 anonimous <shkolnick-kun@gmail.com> and contributors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing,
  9. software distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions
  12. and limitations under the License.
  13. """
  14. #==============================================================================
  15. # YAFL C API
  16. #==============================================================================
  17. #cython: language_level=3
  18. #distutils: language=c
  19. from libc cimport stdint
  20. #------------------------------------------------------------------------------
  21. cdef extern from "yafl_config.h":
  22. ctypedef double yaflFloat
  23. ctypedef stdint.int32_t yaflInt
  24. #------------------------------------------------------------------------------
  25. cdef extern from "yafl_math.c":
  26. ctypedef enum yaflStatusEn:
  27. #Warning flag masks
  28. YAFL_ST_MSK_REGULARIZED = 0x01 #YAFL_ST_R
  29. YAFL_ST_MSK_GLITCH_SMALL = 0x02 #YAFL_ST_S
  30. YAFL_ST_MSK_GLITCH_LARGE = 0x04 #YAFL_ST_L
  31. YAFL_ST_MSK_ANOMALY = 0x08 #YAFL_ST_A
  32. #Everthing is OK
  33. YAFL_ST_OK = 0x00
  34. #Wagnings
  35. YAFL_ST_R = 0x01
  36. YAFL_ST_S = 0x02
  37. YAFL_ST_SR = 0x03
  38. YAFL_ST_L = 0x04
  39. YAFL_ST_LR = 0x05
  40. YAFL_ST_SL = 0x06
  41. YAFL_ST_SLR = 0x07
  42. YAFL_ST_A = 0x08
  43. YAFL_ST_AR = 0x09
  44. YAFL_ST_SA = 0x0a
  45. YAFL_ST_SAR = 0x0b
  46. YAFL_ST_LA = 0x0c
  47. YAFL_ST_LAR = 0x0d
  48. YAFL_ST_SLA = 0x0e
  49. YAFL_ST_SLAR = 0x0f
  50. # Error threshold value (greater values are errors)
  51. YAFL_ST_ERR_THR = 0x010
  52. # Invalid argument numer
  53. YAFL_ST_INV_ARG_1 = 0x100
  54. YAFL_ST_INV_ARG_2 = 0x110
  55. YAFL_ST_INV_ARG_3 = 0x120
  56. YAFL_ST_INV_ARG_4 = 0x130
  57. YAFL_ST_INV_ARG_5 = 0x140
  58. YAFL_ST_INV_ARG_6 = 0x150
  59. YAFL_ST_INV_ARG_7 = 0x160
  60. YAFL_ST_INV_ARG_8 = 0x170
  61. YAFL_ST_INV_ARG_9 = 0x180
  62. YAFL_ST_INV_ARG_10 = 0x190
  63. YAFL_ST_INV_ARG_11 = 0x1a0
  64. #--------------------------------------------------------------------------
  65. #cdef yaflStatusEn yafl_math_set_u(yaflInt sz, yaflFloat *res, yaflFloat *u)
  66. #------------------------------------------------------------------------------
  67. cdef extern from "yafl.c":
  68. ctypedef _yaflKalmanBaseSt yaflKalmanBaseSt
  69. ctypedef yaflStatusEn (* yaflKalmanFuncP)(yaflKalmanBaseSt *, \
  70. yaflFloat *, yaflFloat *)
  71. ctypedef yaflStatusEn (* yaflKalmanResFuncP)(yaflKalmanBaseSt *, \
  72. yaflFloat *, yaflFloat *, \
  73. yaflFloat *)
  74. ctypedef yaflStatusEn (* yaflKalmanScalarUpdateP)(yaflKalmanBaseSt *, \
  75. yaflInt)
  76. ctypedef yaflFloat (* yaflKalmanRobFuncP)(yaflKalmanBaseSt *, yaflFloat)
  77. ctypedef struct _yaflKalmanBaseSt:
  78. yaflKalmanFuncP f #
  79. yaflKalmanFuncP h #
  80. yaflKalmanResFuncP zrf #
  81. yaflFloat * x #
  82. yaflFloat * y #
  83. yaflFloat * Up #
  84. yaflFloat * Dp #
  85. yaflFloat * Uq #
  86. yaflFloat * Dq #
  87. yaflFloat * Ur #
  88. yaflFloat * Dr #
  89. yaflInt Nx #
  90. yaflInt Nz #
  91. #==========================================================================
  92. # UD-factorized EKF definitions
  93. #==========================================================================
  94. ctypedef struct yaflEKFBaseSt:
  95. yaflKalmanBaseSt base
  96. yaflKalmanFuncP jf #
  97. yaflKalmanFuncP jh #
  98. yaflFloat * H #
  99. yaflFloat * W #
  100. yaflFloat * D #
  101. cdef yaflStatusEn yafl_ekf_base_predict(yaflKalmanBaseSt * self)
  102. cdef yaflStatusEn \
  103. yafl_ekf_base_update(yaflKalmanBaseSt * self, yaflFloat * z, \
  104. yaflKalmanScalarUpdateP scalar_update)
  105. #--------------------------------------------------------------------------
  106. cdef yaflStatusEn \
  107. yafl_ekf_bierman_update_scalar(yaflKalmanBaseSt * self, yaflInt i)
  108. #--------------------------------------------------------------------------
  109. cdef yaflStatusEn \
  110. yafl_ekf_joseph_update_scalar(yaflKalmanBaseSt * self, yaflInt i)
  111. #==========================================================================
  112. ctypedef struct yaflEKFAdaptiveSt:
  113. yaflEKFBaseSt base
  114. yaflFloat chi2
  115. #--------------------------------------------------------------------------
  116. cdef yaflStatusEn \
  117. yafl_ekf_adaptive_bierman_update_scalar(yaflKalmanBaseSt * self, \
  118. yaflInt i)
  119. #--------------------------------------------------------------------------
  120. cdef yaflStatusEn \
  121. yafl_ekf_adaptive_joseph_update_scalar(yaflKalmanBaseSt * self, \
  122. yaflInt i)
  123. #--------------------------------------------------------------------------
  124. # For demonstration purposes only
  125. cdef yaflStatusEn \
  126. yafl_ekf_do_not_use_this_update_scalar(yaflKalmanBaseSt * self, yaflInt i)
  127. #==========================================================================
  128. ctypedef struct yaflEKFRobustSt:
  129. yaflEKFBaseSt base
  130. yaflKalmanRobFuncP g
  131. yaflKalmanRobFuncP gdot
  132. #--------------------------------------------------------------------------
  133. cdef yaflStatusEn \
  134. yafl_ekf_robust_bierman_update_scalar(yaflKalmanBaseSt * self, \
  135. yaflInt i)
  136. #--------------------------------------------------------------------------
  137. cdef yaflStatusEn \
  138. yafl_ekf_robust_joseph_update_scalar(yaflKalmanBaseSt * self, \
  139. yaflInt i)
  140. #==========================================================================
  141. ctypedef struct yaflEKFAdaptiveRobustSt:
  142. yaflEKFRobustSt base
  143. yaflFloat chi2
  144. #--------------------------------------------------------------------------
  145. cdef yaflStatusEn \
  146. yafl_ekf_adaptive_robust_bierman_update_scalar(yaflKalmanBaseSt * self, \
  147. yaflInt i)
  148. #--------------------------------------------------------------------------
  149. cdef yaflStatusEn \
  150. yafl_ekf_adaptive_robust_joseph_update_scalar(yaflKalmanBaseSt * self, \
  151. yaflInt i)
  152. #==========================================================================
  153. # UD-factorized UKF definitions
  154. #==========================================================================
  155. ctypedef _yaflUKFBaseSt yaflUKFBaseSt
  156. ctypedef yaflStatusEn (* yaflUKFSigmaAddP)(yaflUKFBaseSt *, yaflFloat *, \
  157. yaflFloat *, yaflFloat)
  158. ctypedef struct yaflUKFSigmaSt:
  159. yaflInt np
  160. yaflUKFSigmaAddP addf
  161. #--------------------------------------------------------------------------
  162. ctypedef yaflStatusEn (* yaflUKFSigmaGenWeigthsP)(yaflUKFBaseSt *)
  163. ctypedef yaflStatusEn (* yaflUKFSigmaGenSigmasP)(yaflUKFBaseSt *)
  164. ctypedef struct yaflUKFSigmaMethodsSt:
  165. yaflUKFSigmaGenWeigthsP wf
  166. yaflUKFSigmaGenSigmasP spgf
  167. #--------------------------------------------------------------------------
  168. ctypedef struct _yaflUKFBaseSt:
  169. yaflKalmanBaseSt base
  170. yaflUKFSigmaSt * sp_info
  171. const yaflUKFSigmaMethodsSt * sp_meth
  172. yaflKalmanFuncP xmf
  173. yaflKalmanResFuncP xrf
  174. yaflKalmanFuncP zmf
  175. yaflFloat * zp
  176. yaflFloat * Sx
  177. yaflFloat * Pzx
  178. yaflFloat * sigmas_x
  179. yaflFloat * sigmas_z
  180. yaflFloat * wm
  181. yaflFloat * wc
  182. #--------------------------------------------------------------------------
  183. cdef yaflStatusEn yafl_ukf_post_init(yaflUKFBaseSt * self) #static inline
  184. cdef yaflStatusEn yafl_ukf_gen_sigmas(yaflUKFBaseSt * self) #static inline
  185. cdef yaflStatusEn yafl_ukf_base_predict(yaflUKFBaseSt * self)
  186. cdef yaflStatusEn \
  187. yafl_ukf_base_update(yaflUKFBaseSt * self, yaflFloat * z, \
  188. yaflKalmanScalarUpdateP scalar_update)
  189. #==========================================================================
  190. cdef yaflStatusEn \
  191. yafl_ukf_bierman_update_scalar(yaflKalmanBaseSt * self, yaflInt i)
  192. #==========================================================================
  193. ctypedef struct yaflUKFAdaptivedSt:
  194. yaflUKFBaseSt base
  195. yaflFloat chi2
  196. cdef yaflStatusEn \
  197. yafl_ukf_adaptive_bierman_update_scalar(yaflKalmanBaseSt * self, \
  198. yaflInt i)
  199. #==========================================================================
  200. ctypedef struct yaflUKFRobustSt:
  201. yaflUKFBaseSt base
  202. yaflKalmanRobFuncP g
  203. yaflKalmanRobFuncP gdot
  204. #--------------------------------------------------------------------------
  205. cdef yaflStatusEn \
  206. yafl_ukf_robust_bierman_update_scalar(yaflKalmanBaseSt * self, \
  207. yaflInt i)
  208. #==========================================================================
  209. ctypedef struct yaflUKFAdaptiveRobustSt:
  210. yaflUKFRobustSt base
  211. yaflFloat chi2
  212. #--------------------------------------------------------------------------
  213. cdef yaflStatusEn \
  214. yafl_ukf_adaptive_robust_bierman_update_scalar(yaflKalmanBaseSt * self, \
  215. yaflInt i)
  216. #==========================================================================
  217. ctypedef struct yaflUKFSt:
  218. yaflUKFBaseSt base
  219. yaflFloat * Us
  220. yaflFloat * Ds
  221. #--------------------------------------------------------------------------
  222. cdef yaflStatusEn yafl_ukf_update(yaflUKFBaseSt * self, yaflFloat * z)
  223. #==========================================================================
  224. ctypedef struct yaflUKFFullAdapiveSt:
  225. yaflUKFSt base
  226. yaflFloat chi2
  227. yaflStatusEn yafl_ukf_adaptive_update(yaflUKFBaseSt * self, yaflFloat * z)
  228. #==========================================================================
  229. # Van der Merwe sigma point generator
  230. #==========================================================================
  231. ctypedef struct yaflUKFMerweSt:
  232. yaflUKFSigmaSt base
  233. yaflFloat alpha
  234. yaflFloat beta
  235. yaflFloat kappa
  236. cdef const yaflUKFSigmaMethodsSt yafl_ukf_merwe_spm
  237. #==============================================================================
  238. #Extension API
  239. #==============================================================================
  240. # We need numpy for Pythonic interfaces
  241. cimport numpy as np
  242. import numpy as np#WTF??
  243. import scipy.stats as st
  244. # We need traceback to print pythonic callback exceptions
  245. import traceback as tb
  246. #==============================================================================
  247. #Status masks
  248. ST_MSK_REGULARIZED = YAFL_ST_MSK_REGULARIZED
  249. ST_MSK_GLITCH_SMALL = YAFL_ST_MSK_GLITCH_SMALL
  250. ST_MSK_GLITCH_LARGE = YAFL_ST_MSK_GLITCH_LARGE
  251. ST_MSK_ANOMALY = YAFL_ST_MSK_ANOMALY
  252. ST_MSK_ERROR = 0xFF0
  253. ST_MSK_WARNING = 0xF
  254. #Everthing is OK
  255. ST_OK = YAFL_ST_OK
  256. #Error threshold
  257. ST_ERR_THR = YAFL_ST_ERR_THR
  258. #Errors:
  259. # Invalid argument numer
  260. ST_INV_ARG_1 = YAFL_ST_INV_ARG_1
  261. ST_INV_ARG_2 = YAFL_ST_INV_ARG_2
  262. ST_INV_ARG_3 = YAFL_ST_INV_ARG_3
  263. ST_INV_ARG_4 = YAFL_ST_INV_ARG_4
  264. ST_INV_ARG_5 = YAFL_ST_INV_ARG_5
  265. ST_INV_ARG_6 = YAFL_ST_INV_ARG_6
  266. ST_INV_ARG_7 = YAFL_ST_INV_ARG_7
  267. ST_INV_ARG_8 = YAFL_ST_INV_ARG_8
  268. ST_INV_ARG_9 = YAFL_ST_INV_ARG_9
  269. ST_INV_ARG_10 = YAFL_ST_INV_ARG_10
  270. ST_INV_ARG_11 = YAFL_ST_INV_ARG_11
  271. #==============================================================================
  272. # UD-factorized EKF API
  273. #==============================================================================
  274. #------------------------------------------------------------------------------
  275. # Kalman filter basic union
  276. #------------------------------------------------------------------------------
  277. ctypedef union yaflPyKalmanBaseUn:
  278. yaflKalmanBaseSt base
  279. yaflEKFBaseSt ekf
  280. yaflEKFAdaptiveSt ekf_adaptive
  281. yaflEKFRobustSt ekf_robust
  282. yaflEKFAdaptiveRobustSt ekf_ada_rob
  283. yaflUKFBaseSt ukf
  284. yaflUKFAdaptivedSt ukf_adaptive
  285. yaflUKFRobustSt ukf_robust
  286. yaflUKFAdaptiveRobustSt ukf_ada_rob
  287. yaflUKFSt ukf_full
  288. yaflUKFFullAdapiveSt ukf_full_adaptive
  289. #------------------------------------------------------------------------------
  290. # Kalman filter C-structure with Python callback
  291. #------------------------------------------------------------------------------
  292. ctypedef struct yaflPyKalmanBaseSt:
  293. # Kalman filter base union
  294. yaflPyKalmanBaseUn base
  295. # Python/Cython self
  296. void * py_self
  297. #------------------------------------------------------------------------------
  298. cdef int _U_sz(int dim_u):
  299. return max(1, (dim_u * (dim_u - 1))//2)
  300. #------------------------------------------------------------------------------
  301. # Basic Filter class
  302. #------------------------------------------------------------------------------
  303. cdef class yaflKalmanBase:
  304. # Kalman filter C-self
  305. cdef yaflPyKalmanBaseSt c_self
  306. # Kalman filter memory views
  307. cdef yaflFloat [::1] v_x
  308. cdef yaflFloat [::1] v_y
  309. cdef yaflFloat [::1] v_z
  310. cdef yaflFloat [::1] v_Up
  311. cdef yaflFloat [::1] v_Dp
  312. cdef yaflFloat [::1] v_Uq
  313. cdef yaflFloat [::1] v_Dq
  314. cdef yaflFloat [::1] v_Ur
  315. cdef yaflFloat [::1] v_Dr
  316. # Kalman filter numpy arrays
  317. cdef np.ndarray _x
  318. cdef np.ndarray _y
  319. cdef np.ndarray _z
  320. cdef np.ndarray _Up
  321. cdef np.ndarray _Dp
  322. cdef np.ndarray _Uq
  323. cdef np.ndarray _Dq
  324. cdef np.ndarray _Ur
  325. cdef np.ndarray _Dr
  326. # Callback info
  327. cdef yaflFloat _dt
  328. cdef dict _fx_args
  329. cdef object _fx
  330. cdef dict _hx_args
  331. cdef object _hx
  332. cdef object _residual_z
  333. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  334. fx, hx, residual_z = None):
  335. #Store dimensions
  336. self.c_self.base.base.Nx = dim_x
  337. self.c_self.base.base.Nz = dim_z
  338. #Setup callbacks
  339. self.c_self.py_self = <void *>self
  340. self._dt = dt
  341. self._fx_args = {}
  342. self._hx_args = {}
  343. if not callable(fx):
  344. raise ValueError('fx must be callable!')
  345. self.c_self.base.base.f = <yaflKalmanFuncP>yafl_py_kalman_fx
  346. self._fx = fx
  347. if not callable(hx):
  348. raise ValueError('hx must be callable!')
  349. self.c_self.base.base.h = <yaflKalmanFuncP>yafl_py_kalman_hx
  350. self._hx = hx
  351. if residual_z:
  352. if not callable(residual_z):
  353. raise ValueError('residual_z must be callable!')
  354. self.c_self.base.base.zrf = <yaflKalmanResFuncP>yafl_py_kalman_zrf
  355. self._residual_z = residual_z
  356. else:
  357. self.c_self.base.base.zrf = <yaflKalmanResFuncP>0
  358. self._residual_z = None
  359. # Allocate memories and setup the rest of c_self
  360. self._z = np.zeros((dim_z,), dtype=np.float64)
  361. self.v_z = self._z
  362. self._x = np.zeros((dim_x,), dtype=np.float64)
  363. self.v_x = self._x
  364. self.c_self.base.base.x = &self.v_x[0]
  365. self._y = np.zeros((dim_z,), dtype=np.float64)
  366. self.v_y = self._y
  367. self.c_self.base.base.y = &self.v_y[0]
  368. self._Up = np.zeros((_U_sz(dim_x),), dtype=np.float64)
  369. self.v_Up = self._Up
  370. self.c_self.base.base.Up = &self.v_Up[0]
  371. self._Dp = np.ones((dim_x,), dtype=np.float64)
  372. self.v_Dp = self._Dp
  373. self.c_self.base.base.Dp = &self.v_Dp[0]
  374. self._Uq = np.zeros((_U_sz(dim_x),), dtype=np.float64)
  375. self.v_Uq = self._Uq
  376. self.c_self.base.base.Uq = &self.v_Uq[0]
  377. self._Dq = np.ones((dim_x,), dtype=np.float64)
  378. self.v_Dq = self._Dq
  379. self.c_self.base.base.Dq = &self.v_Dq[0]
  380. self._Ur = np.zeros((_U_sz(dim_z),), dtype=np.float64)
  381. self.v_Ur = self._Ur
  382. self.c_self.base.base.Ur = &self.v_Ur[0]
  383. self._Dr = np.ones((dim_z,), dtype=np.float64)
  384. self.v_Dr = self._Dr
  385. self.c_self.base.base.Dr = &self.v_Dr[0]
  386. #==========================================================================
  387. #Decorators
  388. @property
  389. def x(self):
  390. return self._x
  391. @x.setter
  392. def x(self, value):
  393. self._x[:] = value
  394. #--------------------------------------------------------------------------
  395. @property
  396. def y(self):
  397. return self._y
  398. @y.setter
  399. def y(self, value):
  400. raise AttributeError('yaflKalmanBase does not support this!')
  401. #--------------------------------------------------------------------------
  402. @property
  403. def Up(self):
  404. return self._Up
  405. @Up.setter
  406. def Up(self, value):
  407. self._Up[:] = value
  408. #--------------------------------------------------------------------------
  409. @property
  410. def Dp(self):
  411. return self._Dp
  412. @Dp.setter
  413. def Dp(self, value):
  414. self._Dp[:] = value
  415. #--------------------------------------------------------------------------
  416. @property
  417. def Uq(self):
  418. return self._Uq
  419. @Uq.setter
  420. def Uq(self, value):
  421. self._Uq[:] = value
  422. #--------------------------------------------------------------------------
  423. @property
  424. def Dq(self):
  425. return self._Dq
  426. @Dq.setter
  427. def Dq(self, value):
  428. self._Dq[:] = value
  429. #--------------------------------------------------------------------------
  430. @property
  431. def Ur(self):
  432. return self._Ur
  433. @Ur.setter
  434. def Ur(self, value):
  435. self._Ur[:] = value
  436. #--------------------------------------------------------------------------
  437. @property
  438. def Dr(self):
  439. return self._Dr
  440. @Dr.setter
  441. def Dr(self, value):
  442. self._Dr[:] = value
  443. #==========================================================================
  444. def _predict(self):
  445. raise NotImplementedError('yaflKalmanBase is the base class!')
  446. def predict(self, dt=None, **fx_args):
  447. old_dt = self._dt
  448. if dt:
  449. if np.isnan(dt):
  450. raise ValueError('Invalid dt value (nan)!')
  451. self._dt = <yaflFloat>dt
  452. self._fx_args = fx_args
  453. res = self._predict()
  454. if res > YAFL_ST_ERR_THR:
  455. raise ValueError('Bad return value on yaflKalmanBase.predict!')
  456. self._dt = old_dt
  457. return res
  458. #==========================================================================
  459. def _update(self):
  460. raise NotImplementedError('yaflKalmanBase is the base class!')
  461. def update(self, z, **hx_args):
  462. self._z[:] = z
  463. self._hx_args = hx_args
  464. res = self._update()
  465. if res > YAFL_ST_ERR_THR:
  466. raise ValueError('Bad return value on yaflKalmanBase.update!')
  467. return res
  468. #------------------------------------------------------------------------------
  469. cdef yaflStatusEn yafl_py_kalman_fx(yaflPyKalmanBaseSt * self, \
  470. yaflFloat * new_x, yaflFloat * old_x):
  471. try:
  472. if not isinstance(<object>(self.py_self), yaflKalmanBase):
  473. raise ValueError('Invalid py_self type (must be subclass of yaflKalmanBase)!')
  474. py_self = <yaflKalmanBase>(self.py_self)
  475. fx = py_self._fx
  476. if not callable(fx):
  477. raise ValueError('fx must be callable!')
  478. dt = py_self._dt
  479. if np.isnan(dt):
  480. raise ValueError('Invalid dt value (nan)!')
  481. fx_args = py_self._fx_args
  482. if not isinstance(fx_args, dict):
  483. raise ValueError('Invalid fx_args type (must be dict)!')
  484. nx = self.base.base.Nx
  485. if nx <= 0:
  486. raise ValueError('nx must be > 0!')
  487. _new_x = np.asarray(<yaflFloat[:nx]> new_x) #np.float64_t
  488. _old_x = np.asarray(<yaflFloat[:nx]> old_x) #np.float64_t
  489. _new_x[:] = fx(_old_x, dt, **fx_args)
  490. return YAFL_ST_OK
  491. except Exception as e:
  492. print(tb.format_exc())
  493. return YAFL_ST_INV_ARG_1
  494. #------------------------------------------------------------------------------
  495. cdef yaflStatusEn yafl_py_kalman_hx(yaflPyKalmanBaseSt * self, \
  496. yaflFloat * z, yaflFloat * x):
  497. try:
  498. if not isinstance(<object>(self.py_self), yaflKalmanBase):
  499. raise ValueError('Invalid py_self type (must be subclass of yaflKalmanBase)!')
  500. py_self = <yaflKalmanBase>(self.py_self)
  501. hx = py_self._hx
  502. if not callable(hx):
  503. raise ValueError('hx must be callable!')
  504. hx_args = py_self._hx_args
  505. if not isinstance(hx_args, dict):
  506. raise ValueError('Invalid hx_args type (must be dict)!')
  507. nx = self.base.base.Nx
  508. if nx <= 0:
  509. raise ValueError('nx must be > 0!')
  510. nz = self.base.base.Nz
  511. if nx <= 0:
  512. raise ValueError('nz must be > 0!')
  513. _x = np.asarray(<yaflFloat[:nx]> x) #np.float64_t
  514. _z = np.asarray(<yaflFloat[:nz]> z) #np.float64_t
  515. _z[:] = hx(_x, **hx_args)
  516. return YAFL_ST_OK
  517. except Exception as e:
  518. print(tb.format_exc())
  519. return YAFL_ST_INV_ARG_1
  520. #------------------------------------------------------------------------------
  521. cdef yaflStatusEn yafl_py_kalman_zrf(yaflPyKalmanBaseSt * self, yaflFloat * res, \
  522. yaflFloat * sigma, yaflFloat * pivot):
  523. try:
  524. if not isinstance(<object>(self.py_self), yaflKalmanBase):
  525. raise ValueError('Invalid py_self type (must be subclass of yaflKalmanBase)!')
  526. py_self = <yaflKalmanBase>(self.py_self)
  527. residual_z = py_self._residual_z
  528. if not callable(residual_z):
  529. raise ValueError('residual_z must be callable!')
  530. nz = self.base.base.Nz
  531. if nz <= 0:
  532. raise ValueError('nx must be > 0!')
  533. _res = np.asarray(<yaflFloat[:nz]> res) #np.float64_t
  534. _sigma = np.asarray(<yaflFloat[:nz]> sigma) #np.float64_t
  535. _pivot = np.asarray(<yaflFloat[:nz]> pivot) #np.float64_t
  536. _res[:] = residual_z(_sigma, _pivot)
  537. return YAFL_ST_OK
  538. except Exception as e:
  539. print(tb.format_exc())
  540. return YAFL_ST_INV_ARG_1
  541. #==============================================================================
  542. # Basic Filter class
  543. #==============================================================================
  544. cdef class yaflExtendedBase(yaflKalmanBase):
  545. # Kalman filter memory views
  546. cdef yaflFloat [:, ::1] v_H
  547. cdef yaflFloat [:, ::1] v_W
  548. cdef yaflFloat [::1] v_D
  549. # Kalman filter numpy arrays
  550. cdef np.ndarray _H
  551. cdef np.ndarray _W
  552. cdef np.ndarray _D
  553. # Callback info
  554. cdef object _jfx
  555. cdef object _jhx
  556. #The object will be Extensible
  557. cdef dict __dict__
  558. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  559. fx, jfx, hx, jhx, residual_z = None):
  560. super().__init__(dim_x, dim_z, dt, fx, hx, residual_z)
  561. if not callable(jfx):
  562. raise ValueError('jfx must be callable!')
  563. self.c_self.base.ekf.jf = <yaflKalmanFuncP>yafl_py_ekf_jfx
  564. self._jfx = jfx
  565. if not callable(jhx):
  566. raise ValueError('jhx must be callable!')
  567. self.c_self.base.ekf.jh = <yaflKalmanFuncP>yafl_py_ekf_jhx
  568. self._jhx = jhx
  569. # Allocate memories and setup the rest of c_self
  570. self._H = np.zeros((dim_z, dim_x), dtype=np.float64)
  571. self.v_H = self._H
  572. self.c_self.base.ekf.H = &self.v_H[0, 0]
  573. self._W = np.zeros((dim_x, 2 * dim_x), dtype=np.float64)
  574. self.v_W = self._W
  575. self.c_self.base.ekf.W = &self.v_W[0,0]
  576. self._D = np.ones((2 * dim_x,), dtype=np.float64)
  577. self.v_D = self._D
  578. self.c_self.base.ekf.D = &self.v_D[0]
  579. #==========================================================================
  580. def _predict(self):
  581. return yafl_ekf_base_predict(&(self.c_self.base.base))
  582. #==========================================================================
  583. def _update(self):
  584. raise NotImplementedError('yaflExtendedBase is the base class!')
  585. #------------------------------------------------------------------------------
  586. # State transition function Jacobian
  587. cdef yaflStatusEn yafl_py_ekf_jfx(yaflPyKalmanBaseSt * self, yaflFloat * w, \
  588. yaflFloat * x):
  589. try:
  590. if not isinstance(<object>(self.py_self), yaflExtendedBase):
  591. raise ValueError('Invalid py_self type (must be subclass of yaflExtendedBase)!')
  592. py_self = <yaflExtendedBase>(self.py_self)
  593. jfx = py_self._jfx
  594. if not callable(jfx):
  595. raise ValueError('jfx must be callable!')
  596. dt = py_self._dt
  597. if np.isnan(dt):
  598. raise ValueError('Invalid dt value (nan)!')
  599. fx_args = py_self._fx_args
  600. if not isinstance(fx_args, dict):
  601. raise ValueError('Invalid fx_args type (must be dict)!')
  602. #How about handling exceptions here???
  603. py_self._W[:, :self.base.base.Nx] = jfx(py_self._x, dt, **fx_args)
  604. return YAFL_ST_OK
  605. except Exception as e:
  606. print(tb.format_exc())
  607. return YAFL_ST_INV_ARG_1
  608. #------------------------------------------------------------------------------
  609. # State transition function Jacobian
  610. cdef yaflStatusEn yafl_py_ekf_jhx(yaflPyKalmanBaseSt * self, yaflFloat * h, \
  611. yaflFloat * x):
  612. try:
  613. if not isinstance(<object>(self.py_self), yaflExtendedBase):
  614. raise ValueError('Invalid py_self type (must be subclass of yaflExtendedBase)!')
  615. py_self = <yaflExtendedBase>(self.py_self)
  616. jhx = py_self._jhx
  617. if not callable(jhx):
  618. raise ValueError('jhx must be callable!')
  619. hx_args = py_self._hx_args
  620. if not isinstance(hx_args, dict):
  621. raise ValueError('Invalid hx_args type (must be dict)!')
  622. #How about handling exceptions here???
  623. py_self._H[:,:] = jhx(py_self._x, **hx_args)
  624. return YAFL_ST_OK
  625. except Exception as e:
  626. print(tb.format_exc())
  627. return YAFL_ST_INV_ARG_1
  628. #==============================================================================
  629. cdef class Bierman(yaflExtendedBase):
  630. def _update(self):
  631. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  632. yafl_ekf_bierman_update_scalar)
  633. #------------------------------------------------------------------------------
  634. cdef class Joseph(yaflExtendedBase):
  635. def _update(self):
  636. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  637. yafl_ekf_joseph_update_scalar)
  638. #==============================================================================
  639. # Adaptive filter basic class
  640. #==============================================================================
  641. cdef class yaflAdaptiveBase(yaflExtendedBase):
  642. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  643. fx, jfx, hx, jhx, **kwargs):
  644. super().__init__(dim_x, dim_z, dt, fx, jfx, hx, jhx, **kwargs)
  645. #Init chi2 with scipy.stats.chi2.ppf(0.999, 1)
  646. self.c_self.base.ekf_adaptive.chi2 = 10.8275662
  647. #==========================================================================
  648. #Decorators
  649. @property
  650. def chi2(self):
  651. return self.c_self.base.ekf_adaptive.chi2
  652. @chi2.setter
  653. def chi2(self, value):
  654. self.c_self.base.ekf_adaptive.chi2 = <yaflFloat>value
  655. #==============================================================================
  656. cdef class AdaptiveBierman(yaflAdaptiveBase):
  657. def _update(self):
  658. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  659. yafl_ekf_adaptive_bierman_update_scalar)
  660. #------------------------------------------------------------------------------
  661. cdef class AdaptiveJoseph(yaflAdaptiveBase):
  662. def _update(self):
  663. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  664. yafl_ekf_adaptive_joseph_update_scalar)
  665. #------------------------------------------------------------------------------
  666. cdef class DoNotUseThisFilter(yaflAdaptiveBase):
  667. """
  668. WARNING!!!
  669. DO NOT USE THIS variant of Adaptive Joseph filter !!!
  670. It was implemented to show some flaws of the corresponding algorithm!
  671. """
  672. def _update(self):
  673. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  674. yafl_ekf_do_not_use_this_update_scalar)
  675. ###########
  676. #==============================================================================
  677. # Robust filter basic class
  678. #==============================================================================
  679. cdef class yaflRobustBase(yaflExtendedBase):
  680. cdef object _gz
  681. cdef object _gdotz
  682. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  683. fx, jfx, hx, jhx, gz=None, gdotz=None, **kwargs):
  684. super().__init__(dim_x, dim_z, dt, fx, jfx, hx, jhx, **kwargs)
  685. if gz:
  686. if not callable(gz):
  687. raise ValueError('gz must be callable!')
  688. if not gdotz:
  689. raise ValueError('gdotz must be passed!')
  690. if not callable(gdotz):
  691. raise ValueError('gdotz must be callable!')
  692. self._gz = gz
  693. self._gdotz = gdotz
  694. self.c_self.base.ekf_robust.g = <yaflKalmanRobFuncP>yafl_py_ekf_rob_gz
  695. self.c_self.base.ekf_robust.gdot = <yaflKalmanRobFuncP>yafl_py_ekf_rob_gdotz
  696. else:
  697. self.c_self.base.ekf_robust.g = <yaflKalmanRobFuncP>0
  698. self.c_self.base.ekf_robust.gdot = <yaflKalmanRobFuncP>0
  699. #------------------------------------------------------------------------------
  700. # Influence limiting function
  701. cdef yaflFloat yafl_py_ekf_rob_gz(yaflPyKalmanBaseSt * self, yaflFloat nu):
  702. try:
  703. if not isinstance(<object>(self.py_self), yaflRobustBase):
  704. raise ValueError('Invalid py_self type (must be subclass of yaflRobustBase)!')
  705. py_self = <yaflRobustBase>(self.py_self)
  706. gz = py_self._gz
  707. if not callable(gz):
  708. raise ValueError('gz must be callable!')
  709. hx_args = py_self._hx_args
  710. if not isinstance(hx_args, dict):
  711. raise ValueError('Invalid hx_args type (must be dict)!')
  712. #How about handling exceptions here???
  713. ret = gz(nu, **hx_args)
  714. if type(ret) != float:
  715. raise ValueError('gz must return float!')
  716. return <yaflFloat>ret
  717. except Exception as e:
  718. print(tb.format_exc())
  719. return <yaflFloat>0.0
  720. #------------------------------------------------------------------------------
  721. # Influence limiting function derivative
  722. cdef yaflFloat yafl_py_ekf_rob_gdotz(yaflPyKalmanBaseSt * self, yaflFloat nu):
  723. try:
  724. if not isinstance(<object>(self.py_self), yaflRobustBase):
  725. raise ValueError('Invalid py_self type (must be subclass of yaflRobustBase)!')
  726. py_self = <yaflRobustBase>(self.py_self)
  727. gdotz = py_self._gdotz
  728. if not callable(gdotz):
  729. raise ValueError('gdotz must be callable!')
  730. hx_args = py_self._hx_args
  731. if not isinstance(hx_args, dict):
  732. raise ValueError('Invalid hx_args type (must be dict)!')
  733. #How about handling exceptions here???
  734. ret = gdotz(nu, **hx_args)
  735. if type(ret) != float:
  736. raise ValueError('gdotz must return float!')
  737. return <yaflFloat>ret
  738. except Exception as e:
  739. print(tb.format_exc())
  740. return <yaflFloat>0.0
  741. #==============================================================================
  742. cdef class RobustBierman(yaflRobustBase):
  743. def _update(self):
  744. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  745. yafl_ekf_robust_bierman_update_scalar)
  746. #------------------------------------------------------------------------------
  747. cdef class RobustJoseph(yaflRobustBase):
  748. def _update(self):
  749. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  750. yafl_ekf_robust_joseph_update_scalar)
  751. #==============================================================================
  752. # Adaptive robust filter basic class
  753. #==============================================================================
  754. cdef class yaflAdaptiveRobustBase(yaflRobustBase):
  755. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  756. fx, jfx, hx, jhx, **kwargs):
  757. super().__init__(dim_x, dim_z, dt, fx, jfx, hx, jhx, **kwargs)
  758. #Init chi2 with scipy.stats.chi2.ppf(0.997, 1)
  759. self.c_self.base.ekf_ada_rob.chi2 = 8.807468393511947
  760. #==========================================================================
  761. #Decorators
  762. @property
  763. def chi2(self):
  764. return self.c_self.base.ekf_ada_rob.chi2
  765. @chi2.setter
  766. def chi2(self, value):
  767. self.c_self.base.ekf_ada_rob.chi2 = <yaflFloat>value
  768. #==============================================================================
  769. cdef class AdaptiveRobustBierman(yaflAdaptiveRobustBase):
  770. def _update(self):
  771. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  772. yafl_ekf_adaptive_robust_bierman_update_scalar)
  773. #------------------------------------------------------------------------------
  774. cdef class AdaptiveRobustJoseph(yaflAdaptiveRobustBase):
  775. def _update(self):
  776. return yafl_ekf_base_update(&self.c_self.base.base, &self.v_z[0], \
  777. yafl_ekf_adaptive_robust_joseph_update_scalar)
  778. #==============================================================================
  779. # UD-factorized UKF API
  780. #==============================================================================
  781. # Sigma points generator basic definitions
  782. #------------------------------------------------------------------------------
  783. ctypedef union yaflPySigmaBaseUn:
  784. yaflUKFSigmaSt base
  785. yaflUKFMerweSt merwe
  786. #------------------------------------------------------------------------------
  787. ctypedef struct yaflPySigmaSt:
  788. # Sigma point generator base structure
  789. yaflPySigmaBaseUn base
  790. # Python/Cython self
  791. void * py_self
  792. #------------------------------------------------------------------------------
  793. cdef class yaflSigmaBase:
  794. # Sigma point generator C-self
  795. cdef yaflPySigmaSt c_self
  796. # Callback info
  797. cdef object _addf
  798. #The object will be Extensible
  799. cdef dict __dict__
  800. def __init__(self, yaflInt dim_x, addf=None):
  801. #Setup callbacks
  802. self.c_self.py_self = <void *>self
  803. if addf:
  804. if not callable(addf):
  805. raise ValueError('addf must be callable!')
  806. self.c_self.base.base.addf = <yaflUKFSigmaAddP>yafl_py_sigma_addf
  807. self._addf = addf
  808. else:
  809. self.c_self.base.base.addf = <yaflUKFSigmaAddP>0
  810. pnum = self.get_np(dim_x)
  811. self.c_self.base.base.np = pnum
  812. cdef yaflInt get_np(self, int dim_x):
  813. raise NotImplementedError('yaflSigmaBase is the base class!')
  814. cdef const yaflUKFSigmaMethodsSt * get_spm(self):
  815. raise NotImplementedError('yaflSigmaBase is the base class!')
  816. @property
  817. def pnum(self):
  818. return self.c_self.base.base.np
  819. @pnum.setter
  820. def pnum(self, value):
  821. raise AttributeError('yaflSigmaBase does not support this!')
  822. #------------------------------------------------------------------------------
  823. # UD-factorized UKF definitions
  824. #------------------------------------------------------------------------------
  825. cdef class yaflUnscentedBase(yaflKalmanBase):
  826. # Kalman filter memory views
  827. cdef yaflFloat [::1] v_zp
  828. cdef yaflFloat [::1] v_Sx
  829. cdef yaflFloat [:, ::1] v_Pzx
  830. cdef yaflFloat [:, ::1] v_sigmas_x
  831. cdef yaflFloat [:, ::1] v_sigmas_z
  832. cdef yaflFloat [::1] v_wm
  833. cdef yaflFloat [::1] v_wc
  834. # Kalman filter numpy arrays
  835. cdef np.ndarray _zp
  836. cdef np.ndarray _Sx
  837. cdef np.ndarray _Pzx
  838. cdef np.ndarray _sigmas_x
  839. cdef np.ndarray _sigmas_z
  840. cdef np.ndarray _wm
  841. cdef np.ndarray _wc
  842. # Callback info
  843. cdef object _points
  844. cdef object _mean_x
  845. cdef object _resudual_x
  846. cdef object _mean_z
  847. #The object will be Extensible
  848. cdef dict __dict__
  849. def __init__(self, int dim_x, int dim_z, yaflFloat dt, hx, fx, points,\
  850. x_mean_fn=None, z_mean_fn=None, \
  851. residual_x=None, residual_z=None):
  852. super().__init__(dim_x, dim_z, dt, fx, hx, residual_z)
  853. if x_mean_fn:
  854. if not callable(x_mean_fn):
  855. raise ValueError('x_mean_fn must be callable!')
  856. self.c_self.base.ukf.xmf = <yaflKalmanFuncP>yafl_py_ukf_xmf
  857. self._mean_x = x_mean_fn
  858. else:
  859. self.c_self.base.ukf.xmf = <yaflKalmanFuncP>0
  860. self._mean_x = None
  861. if residual_x:
  862. if not callable(residual_x):
  863. raise ValueError('residual_x must be callable!')
  864. self.c_self.base.ukf.xrf = <yaflKalmanResFuncP>yafl_py_ukf_xrf
  865. self._residual_x = residual_x
  866. else:
  867. self.c_self.base.ukf.xrf = <yaflKalmanResFuncP>0
  868. self._residual_x = None
  869. if z_mean_fn:
  870. if not callable(z_mean_fn):
  871. raise ValueError('z_mean_fn must be callable!')
  872. self.c_self.base.ukf.zmf = <yaflKalmanFuncP>yafl_py_ukf_zmf
  873. self._mean_z = z_mean_fn
  874. else:
  875. self.c_self.base.ukf.zmf = <yaflKalmanFuncP>0
  876. self._mean_z = None
  877. #Setup sigma points generator
  878. if not isinstance(points, yaflSigmaBase):
  879. raise ValueError('Invalid points type (must be subclass of yaflSigmaBase)!')
  880. _points = <yaflSigmaBase>points
  881. self._points = _points
  882. self.c_self.base.ukf.sp_info = &_points.c_self.base.base
  883. self.c_self.base.ukf.sp_meth = _points.get_spm()
  884. # Allocate memories and setup the rest of c_self
  885. # Sigma points and weights
  886. pnum = _points.pnum
  887. self._wm = np.zeros((pnum,), dtype=np.float64)
  888. self.v_wm = self._wm
  889. self.c_self.base.ukf.wm = &self.v_wm[0]
  890. self._wc = np.zeros((pnum,), dtype=np.float64)
  891. self.v_wc = self._wc
  892. self.c_self.base.ukf.wc = &self.v_wc[0]
  893. self._sigmas_x = np.zeros((pnum, dim_x), dtype=np.float64)
  894. self.v_sigmas_x = self._sigmas_x
  895. self.c_self.base.ukf.sigmas_x = &self.v_sigmas_x[0, 0]
  896. self._sigmas_z = np.zeros((pnum, dim_z), dtype=np.float64)
  897. self.v_sigmas_z = self._sigmas_z
  898. self.c_self.base.ukf.sigmas_z = &self.v_sigmas_z[0, 0]
  899. #Rest of rhe UKF
  900. self._zp = np.zeros((dim_z,), dtype=np.float64)
  901. self.v_zp = self._zp
  902. self.c_self.base.ukf.zp = &self.v_zp[0]
  903. self._Pzx = np.zeros((dim_z, dim_x), dtype=np.float64)
  904. self.v_Pzx = self._Pzx
  905. self.c_self.base.ukf.Pzx = &self.v_Pzx[0, 0]
  906. self._Sx = np.zeros((dim_x,), dtype=np.float64)
  907. self.v_Sx = self._Sx
  908. self.c_self.base.ukf.Sx = &self.v_Sx[0]
  909. #Call C-post init
  910. yafl_ukf_post_init(&self.c_self.base.ukf)
  911. #==========================================================================
  912. #Decorators
  913. @property
  914. def Pzx(self):
  915. return self._Pzx
  916. #--------------------------------------------------------------------------
  917. @property
  918. def zp(self):
  919. return self._zp
  920. #--------------------------------------------------------------------------
  921. @property
  922. def sigmas_x(self):
  923. return self._sigmas_x
  924. @sigmas_x.setter
  925. def sigmas_x(self, value):
  926. raise AttributeError('yaflUnscentedBase does not support this!')
  927. #--------------------------------------------------------------------------
  928. @property
  929. def sigmas_z(self):
  930. return self._sigmas_z
  931. @sigmas_z.setter
  932. def sigmas_z(self, value):
  933. raise AttributeError('yaflUnscentedBase does not support this!')
  934. #--------------------------------------------------------------------------
  935. @property
  936. def wc(self):
  937. return self._wc
  938. @wc.setter
  939. def wc(self, value):
  940. raise AttributeError('yaflUnscentedBase does not support this!')
  941. #--------------------------------------------------------------------------
  942. @property
  943. def wm(self):
  944. return self._wm
  945. @wm.setter
  946. def wm(self, value):
  947. raise AttributeError('yaflUnscentedBase does not support this!')
  948. #==========================================================================
  949. def _predict(self):
  950. return yafl_ukf_base_predict(&self.c_self.base.ukf)
  951. #==========================================================================
  952. def _update(self):
  953. raise NotImplementedError('yaflUnscentedBase is the base class!')
  954. #==============================================================================
  955. cdef yaflStatusEn yafl_py_sigma_addf(yaflPyKalmanBaseSt * self, yaflFloat * delta, \
  956. yaflFloat * pivot, yaflFloat mult):
  957. try:
  958. if not isinstance(<object>(self.py_self), yaflUnscentedBase):
  959. raise ValueError('Invalid py_self type (must be subclass of yaflUnscentedBase)!')
  960. py_self = <yaflUnscentedBase>(self.py_self)
  961. _addf = py_self._points._addf
  962. if not callable(_addf):
  963. raise ValueError('_addf must be callable!')
  964. nx = self.base.base.Nx
  965. if nx <= 0:
  966. raise ValueError('nx must be > 0!')
  967. _delta = np.asarray(<yaflFloat[:nx]> delta) #np.float64_t
  968. _pivot = np.asarray(<yaflFloat[:nx]> pivot) #np.float64_t
  969. _delta[:] = _addf(_delta, _pivot, mult)
  970. return YAFL_ST_OK
  971. except Exception as e:
  972. print(tb.format_exc())
  973. return YAFL_ST_INV_ARG_1
  974. #------------------------------------------------------------------------------
  975. cdef yaflStatusEn yafl_py_ukf_xmf(yaflPyKalmanBaseSt * self, \
  976. yaflFloat * res, yaflFloat * sigmas):
  977. try:
  978. if not isinstance(<object>(self.py_self), yaflUnscentedBase):
  979. raise ValueError('Invalid py_self type (must be subclass of yaflUnscentedBase)!')
  980. py_self = <yaflUnscentedBase>(self.py_self)
  981. mean_x = py_self._mean_x
  982. if not callable(mean_x):
  983. raise ValueError('mean_x must be callable!')
  984. nx = self.base.base.Nx
  985. if nx <= 0:
  986. raise ValueError('nx must be > 0!')
  987. _points = py_self._points
  988. if not isinstance(py_self, yaflSigmaBase):
  989. raise ValueError('Invalid _points type (must be subclass of yaflSigmaBase)!')
  990. pnum = _points.base.base.np
  991. if pnum <= 0:
  992. raise ValueError('pnum must be > 0!')
  993. _sigmas = np.asarray(<yaflFloat[:pnum, :nx]> sigmas) #np.float64_t
  994. _res = np.asarray(<yaflFloat[:nx]> res) #np.float64_t
  995. _res[:] = mean_x(_sigmas, _points._wm)
  996. return YAFL_ST_OK
  997. except Exception as e:
  998. print(tb.format_exc())
  999. return YAFL_ST_INV_ARG_1
  1000. #------------------------------------------------------------------------------
  1001. cdef yaflStatusEn yafl_py_ukf_xrf(yaflPyKalmanBaseSt * self, yaflFloat * res, \
  1002. yaflFloat * sigma, yaflFloat * pivot):
  1003. try:
  1004. if not isinstance(<object>(self.py_self), yaflUnscentedBase):
  1005. raise ValueError('Invalid py_self type (must be subclass of yaflUnscentedBase)!')
  1006. py_self = <yaflUnscentedBase>(self.py_self)
  1007. residual_x = py_self._residual_x
  1008. if not callable(residual_x):
  1009. raise ValueError('residual_x must be callable!')
  1010. nx = self.base.base.Nx
  1011. if nx <= 0:
  1012. raise ValueError('nx must be > 0!')
  1013. _res = np.asarray(<yaflFloat[:nx]> res) #np.float64_t
  1014. _sigma = np.asarray(<yaflFloat[:nx]> sigma) #np.float64_t
  1015. _pivot = np.asarray(<yaflFloat[:nx]> pivot) #np.float64_t
  1016. _res[:] = residual_x(_sigma, _pivot)
  1017. return YAFL_ST_OK
  1018. except Exception as e:
  1019. print(tb.format_exc())
  1020. return YAFL_ST_INV_ARG_1
  1021. #------------------------------------------------------------------------------
  1022. cdef yaflStatusEn yafl_py_ukf_zmf(yaflPyKalmanBaseSt * self, \
  1023. yaflFloat * res, yaflFloat * sigmas):
  1024. try:
  1025. if not isinstance(<object>(self.py_self), yaflUnscentedBase):
  1026. raise ValueError('Invalid py_self type (must be subclass of yaflUnscentedBase)!')
  1027. py_self = <yaflUnscentedBase>(self.py_self)
  1028. mean_z = py_self._mean_z
  1029. if not callable(mean_z):
  1030. raise ValueError('mean_z must be callable!')
  1031. nz = self.base.base.Nz
  1032. if nz <= 0:
  1033. raise ValueError('nz must be > 0!')
  1034. _points = py_self._points
  1035. if not isinstance(py_self, yaflSigmaBase):
  1036. raise ValueError('Invalid _points type (must be subclass of yaflSigmaBase)!')
  1037. pnum = _points.base.base.np
  1038. if pnum <= 0:
  1039. raise ValueError('pnum must be > 0!')
  1040. _sigmas = np.asarray(<yaflFloat[:pnum, :nz]> sigmas) #np.float64_t
  1041. _res = np.asarray(<yaflFloat[:nz]> res) #np.float64_t
  1042. _res[:] = mean_z(_sigmas, _points._wm)
  1043. return YAFL_ST_OK
  1044. except Exception as e:
  1045. print(tb.format_exc())
  1046. return YAFL_ST_INV_ARG_1
  1047. #==============================================================================
  1048. cdef class UnscentedBierman(yaflUnscentedBase):
  1049. """
  1050. UD-factorized UKF implementation
  1051. """
  1052. def _update(self):
  1053. return yafl_ukf_base_update(&self.c_self.base.ukf, &self.v_z[0], \
  1054. yafl_ukf_bierman_update_scalar)
  1055. #==============================================================================
  1056. cdef class UnscentedAdaptiveBierman(yaflUnscentedBase):
  1057. def __init__(self, int dim_x, int dim_z, yaflFloat dt, hx, fx, points, \
  1058. **kwargs):
  1059. super().__init__(dim_x, dim_z, dt, hx, fx, points, **kwargs)
  1060. #Init chi2 with scipy.stats.chi2.ppf(0.99999, 1)
  1061. self.c_self.base.ukf_adaptive.chi2 = 19.511420964666268
  1062. #==========================================================================
  1063. #Decorators
  1064. @property
  1065. def chi2(self):
  1066. return self.c_self.base.ukf_adaptive.chi2
  1067. @chi2.setter
  1068. def chi2(self, value):
  1069. self.c_self.base.ukf_adaptive.chi2 = <yaflFloat>value
  1070. """
  1071. UD-factorized UKF implementation
  1072. """
  1073. def _update(self):
  1074. return yafl_ukf_base_update(&self.c_self.base.ukf, &self.v_z[0], \
  1075. yafl_ukf_adaptive_bierman_update_scalar)
  1076. #==============================================================================
  1077. # Robust filter basic class
  1078. #==============================================================================
  1079. cdef class yaflRobustUKFBase(yaflUnscentedBase):
  1080. cdef object _gz
  1081. cdef object _gdotz
  1082. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  1083. hx, fx, points, gz=None, gdotz=None, **kwargs):
  1084. super().__init__(dim_x, dim_z, dt, hx, fx, points, **kwargs)
  1085. if gz:
  1086. if not callable(gz):
  1087. raise ValueError('gz must be callable!')
  1088. if not gdotz:
  1089. raise ValueError('gdotz must be passed!')
  1090. if not callable(gdotz):
  1091. raise ValueError('gdotz must be callable!')
  1092. self._gz = gz
  1093. self._gdotz = gdotz
  1094. self.c_self.base.ukf_robust.g = <yaflKalmanRobFuncP>yafl_py_ukf_rob_gz
  1095. self.c_self.base.ukf_robust.gdot = <yaflKalmanRobFuncP>yafl_py_ukf_rob_gdotz
  1096. else:
  1097. self.c_self.base.ukf_robust.g = <yaflKalmanRobFuncP>0
  1098. self.c_self.base.ukf_robust.gdot = <yaflKalmanRobFuncP>0
  1099. #------------------------------------------------------------------------------
  1100. # Influence limiting function
  1101. cdef yaflFloat yafl_py_ukf_rob_gz(yaflPyKalmanBaseSt * self, yaflFloat nu):
  1102. try:
  1103. if not isinstance(<object>(self.py_self), yaflRobustUKFBase):
  1104. raise ValueError('Invalid py_self type (must be subclass of yaflRobustBase)!')
  1105. py_self = <yaflRobustUKFBase>(self.py_self)
  1106. gz = py_self._gz
  1107. if not callable(gz):
  1108. raise ValueError('gz must be callable!')
  1109. hx_args = py_self._hx_args
  1110. if not isinstance(hx_args, dict):
  1111. raise ValueError('Invalid hx_args type (must be dict)!')
  1112. #How about handling exceptions here???
  1113. ret = gz(nu, **hx_args)
  1114. if type(ret) != float:
  1115. raise ValueError('gz must return float!')
  1116. return <yaflFloat>ret
  1117. except Exception as e:
  1118. print(tb.format_exc())
  1119. return <yaflFloat>0.0
  1120. #------------------------------------------------------------------------------
  1121. # Influence limiting function derivative
  1122. cdef yaflFloat yafl_py_ukf_rob_gdotz(yaflPyKalmanBaseSt * self, yaflFloat nu):
  1123. try:
  1124. if not isinstance(<object>(self.py_self), yaflRobustUKFBase):
  1125. raise ValueError('Invalid py_self type (must be subclass of yaflRobustBase)!')
  1126. py_self = <yaflRobustUKFBase>(self.py_self)
  1127. gdotz = py_self._gdotz
  1128. if not callable(gdotz):
  1129. raise ValueError('gdotz must be callable!')
  1130. hx_args = py_self._hx_args
  1131. if not isinstance(hx_args, dict):
  1132. raise ValueError('Invalid hx_args type (must be dict)!')
  1133. #How about handling exceptions here???
  1134. ret = gdotz(nu, **hx_args)
  1135. if type(ret) != float:
  1136. raise ValueError('gdotz must return float!')
  1137. return <yaflFloat>ret
  1138. except Exception as e:
  1139. print(tb.format_exc())
  1140. return <yaflFloat>0.0
  1141. #==============================================================================
  1142. cdef class UnscentedRobustBierman(yaflRobustUKFBase):
  1143. def _update(self):
  1144. return yafl_ukf_base_update(&self.c_self.base.ukf, &self.v_z[0], \
  1145. yafl_ukf_robust_bierman_update_scalar)
  1146. #==============================================================================
  1147. # Adaptive robust UKF base
  1148. #==============================================================================
  1149. cdef class yaflAdaptiveRobustUKFBase(yaflRobustUKFBase):
  1150. def __init__(self, int dim_x, int dim_z, yaflFloat dt, \
  1151. hx, fx, points, **kwargs):
  1152. super().__init__(dim_x, dim_z, dt, hx, fx, points, **kwargs)
  1153. #Init chi2 with scipy.stats.chi2.ppf(0.997, 1)
  1154. self.c_self.base.ukf_ada_rob.chi2 = 8.807468393511947
  1155. #==========================================================================
  1156. #Decorators
  1157. @property
  1158. def chi2(self):
  1159. return self.c_self.base.ukf_ada_rob.chi2
  1160. @chi2.setter
  1161. def chi2(self, value):
  1162. self.c_self.base.ukf_ada_rob.chi2 = <yaflFloat>value
  1163. #==============================================================================
  1164. cdef class UnscentedAdaptiveRobustBierman(yaflAdaptiveRobustUKFBase):
  1165. def _update(self):
  1166. return yafl_ukf_base_update(&self.c_self.base.ukf, &self.v_z[0], \
  1167. yafl_ukf_adaptive_robust_bierman_update_scalar)
  1168. #==============================================================================
  1169. # Full UKF, not sequential square root version of UKF
  1170. #==============================================================================
  1171. cdef class Unscented(yaflUnscentedBase):
  1172. cdef yaflFloat [::1] v_Us
  1173. cdef yaflFloat [::1] v_Ds
  1174. def __init__(self, int dim_x, int dim_z, yaflFloat dt, hx, fx, points, \
  1175. **kwargs):
  1176. super().__init__(dim_x, dim_z, dt, hx, fx, points, **kwargs)
  1177. self._Us = np.zeros((_U_sz(dim_z),), dtype=np.float64)
  1178. self.v_Us = self._Us
  1179. self.c_self.base.ukf_full.Us = &self.v_Us[0]
  1180. self._Ds = np.ones((dim_z,), dtype=np.float64)
  1181. self.v_Ds = self._Ds
  1182. self.c_self.base.ukf_full.Ds = &self.v_Ds[0]
  1183. #==========================================================================
  1184. #Decorators
  1185. @property
  1186. def Us(self):
  1187. return self._Us
  1188. @Us.setter
  1189. def Us(self, value):
  1190. raise AttributeError('Unscented does not support this!')
  1191. #--------------------------------------------------------------------------
  1192. @property
  1193. def Ds(self):
  1194. return self._Ds
  1195. @Ds.setter
  1196. def Ds(self, value):
  1197. raise AttributeError('Unscented does not support this!')
  1198. #==========================================================================
  1199. """
  1200. UD-factorized UKF implementation
  1201. """
  1202. def _update(self):
  1203. return yafl_ukf_update(&self.c_self.base.ukf, &self.v_z[0])
  1204. #==============================================================================
  1205. # Full adaptive UKF, not sequential square root version of UKF
  1206. #==============================================================================
  1207. cdef class UnscentedAdaptive(Unscented):
  1208. def __init__(self, int dim_x, int dim_z, yaflFloat dt, hx, fx, points, \
  1209. aplha = 0.000001, **kwargs):
  1210. super().__init__(dim_x, dim_z, dt, hx, fx, points, **kwargs)
  1211. self.c_self.base.ukf_full_adaptive.chi2 = \
  1212. st.chi2.ppf(1.0 - aplha, dim_z)
  1213. #==========================================================================
  1214. #Decorators
  1215. @property
  1216. def chi2(self):
  1217. return self.c_self.base.ukf_full_adaptive.chi2
  1218. @chi2.setter
  1219. def chi2(self, value):
  1220. self.c_self.base.ukf_full_adaptive.chi2 = <yaflFloat>value
  1221. #==========================================================================
  1222. """
  1223. UD-factorized UKF implementation
  1224. """
  1225. def _update(self):
  1226. return yafl_ukf_adaptive_update(&self.c_self.base.ukf, &self.v_z[0])
  1227. #==============================================================================
  1228. cdef class MerweSigmaPoints(yaflSigmaBase):
  1229. """
  1230. Van der Merwe sigma point generator implementation
  1231. """
  1232. def __init__(self, yaflInt dim_x, yaflFloat alpha, yaflFloat beta, \
  1233. yaflFloat kappa=0.0, **kwargs):
  1234. super().__init__(dim_x, **kwargs)
  1235. self.c_self.base.merwe.alpha = alpha
  1236. self.c_self.base.merwe.beta = beta
  1237. self.c_self.base.merwe.kappa = kappa
  1238. cdef yaflInt get_np(self, int dim_x):
  1239. return (2 * dim_x + 1)
  1240. cdef const yaflUKFSigmaMethodsSt * get_spm(self):
  1241. return &yafl_ukf_merwe_spm
  1242. #==========================================================================
  1243. #Decorators
  1244. @property
  1245. def alpha(self):
  1246. return self.c_self.base.merwe.alpha
  1247. @alpha.setter
  1248. def alpha(self, value):
  1249. raise AttributeError('MerweSigmaPoints does not support this!')
  1250. @property
  1251. def beta(self):
  1252. return self.c_self.base.merwe.beta
  1253. @beta.setter
  1254. def beta(self, value):
  1255. raise AttributeError('MerweSigmaPoints does not support this!')
  1256. @property
  1257. def kappa(self):
  1258. return self.c_self.base.merwe.kappa
  1259. @kappa.setter
  1260. def kappa(self, value):
  1261. raise AttributeError('MerweSigmaPoints does not support this!')