├── .gitattributes ├── .gitignore ├── LICENSE ├── Linear Quadratic Regulators.pdf ├── Matavecontrol.prj ├── Model Predictive Control for an artifical pancreas - Matias Sørensen og Simon Kristiansen.pdf ├── README.md ├── Table of functions.odt ├── Table of functions.pdf ├── examples ├── bodeExample.m ├── bodeExampleMATLAB.png ├── bodeExampleOctave.png ├── c2dExample.m ├── c2dExampleMATLAB.png ├── c2dExampleOctave.png ├── examples.md ├── kf_qmpcExample.m ├── kf_qmpcExampleMATLAB.png ├── mpcExample.m ├── mpcExampleMATLAB.png ├── nyquistExample.m ├── nyquistExampleMATLAB.png ├── nyquistExampleOctave.png ├── stateSpaceExample.m ├── stateSpaceExampleMATLAB.png ├── stateSpaceExampleOctave.png ├── stepExample.m ├── stepExampleMATLAB.png ├── stepExampleOctave.png ├── transferFunctionExmaple.m ├── transferFunctionExmapleMATLAB.png └── transferFunctionExmapleOctave.png ├── listOfFunctions ├── matave ├── +mc │ ├── acker.m │ ├── allmargin.m │ ├── append.m │ ├── are.m │ ├── arma.m │ ├── balreal.m │ ├── bode.m │ ├── bodemag.m │ ├── c2d.m │ ├── c2dt.m │ ├── chirp.m │ ├── conv2fft.m │ ├── covar.m │ ├── ctrb.m │ ├── d2c.m │ ├── d2d.m │ ├── damp.m │ ├── db2mag.m │ ├── dbdrop.m │ ├── dcgain.m │ ├── evalfr.m │ ├── feedback.m │ ├── findmaxgain.m │ ├── fminsearch.m │ ├── freqresp.m │ ├── gensig.m │ ├── gram.m │ ├── hsvd.m │ ├── imc.m │ ├── impulse.m │ ├── initial.m │ ├── kf_qmpc.m │ ├── linprog.m │ ├── listOfFunctions │ ├── lmpc.m │ ├── loop.m │ ├── lqe.m │ ├── lqgreg.m │ ├── lqi.m │ ├── lqr.m │ ├── lsim.m │ ├── lyap.m │ ├── mag2db.m │ ├── margin.m │ ├── minreal.m │ ├── modred.m │ ├── nlsim.m │ ├── nyquist.m │ ├── obsv.m │ ├── pade.m │ ├── parallel.m │ ├── pid.m │ ├── pipd.m │ ├── pole.m │ ├── pzmap.m │ ├── qmpc.m │ ├── quadprog.m │ ├── ramp.m │ ├── referencegain.m │ ├── reg.m │ ├── rlocfind.m │ ├── rlocus.m │ ├── satlsim.m │ ├── sensitivity.m │ ├── series.m │ ├── sgrid.m │ ├── sigma.m │ ├── smithpredict.m │ ├── ss.m │ ├── ss2tf.m │ ├── step.m │ ├── tf.m │ ├── tf2ss.m │ ├── tzero.m │ ├── updatematavecontrol.m │ ├── zero.m │ └── zpk.m └── README.md └── resources └── project ├── EEtUlUb-dLAdf0KpMVivaUlztwA ├── yjq8T9-gQYy0f2NhORonQUngnPgd.xml └── yjq8T9-gQYy0f2NhORonQUngnPgp.xml ├── NjSPEMsIuLUyIpr2u1Js5bVPsOs ├── 2kj09UetkV_lru3gvSPXnY6-nM4d.xml ├── 2kj09UetkV_lru3gvSPXnY6-nM4p.xml ├── KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml ├── KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml ├── QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml ├── QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml ├── R1RggVhA72agIvELiuhWPRS8F0Id.xml ├── R1RggVhA72agIvELiuhWPRS8F0Ip.xml ├── aEHSZBIY-yve10yGis12Zr5DLZod.xml ├── aEHSZBIY-yve10yGis12Zr5DLZop.xml ├── j4xwF_j8iFTVayUMfxLgMnTbencd.xml ├── j4xwF_j8iFTVayUMfxLgMnTbencp.xml ├── r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml └── r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml ├── OfxnnyUcu5GSELEDRUyOXcMZW0c ├── 0svTqDZyxKsHr8tr9l_5tqIMcqwd.xml ├── 0svTqDZyxKsHr8tr9l_5tqIMcqwp.xml ├── 0tLh2TRaHNLS2qzQDqexHEHLXVMd.xml ├── 0tLh2TRaHNLS2qzQDqexHEHLXVMp.xml ├── 96SFBJ-bIQLnHvDLQUTQfLO8XDod.xml ├── 96SFBJ-bIQLnHvDLQUTQfLO8XDop.xml ├── _MRJWxV8DfREsKhDtvTq3Jjm_RQd.xml ├── _MRJWxV8DfREsKhDtvTq3Jjm_RQp.xml ├── icQfkkI3t1PC4Ek0YY0fHihS5Yod.xml ├── icQfkkI3t1PC4Ek0YY0fHihS5Yop.xml ├── oSQ_nBKlxRWiL15nEg7_Rn5-agId.xml ├── oSQ_nBKlxRWiL15nEg7_Rn5-agIp.xml ├── qzR9VwkbUp-oa5a1uN0CPiHvfNId.xml ├── qzR9VwkbUp-oa5a1uN0CPiHvfNIp.xml ├── ySuCV85gsbuVjl71P1huo8omBFQd.xml └── ySuCV85gsbuVjl71P1huo8omBFQp.xml ├── Project.xml ├── Y0MXjQcTETsDYSfZOITJxehWTOQ ├── -CoAOABvy9cuGUC38ZyaKbdeLOwd.xml ├── -CoAOABvy9cuGUC38ZyaKbdeLOwp.xml ├── -SbeBzw66TzYB4FU3szMFT_cuxAd.xml ├── -SbeBzw66TzYB4FU3szMFT_cuxAp.xml ├── -uWRYmmAnEkaEOZhJsoOtba7DlEd.xml ├── -uWRYmmAnEkaEOZhJsoOtba7DlEp.xml ├── 11XmEjI_K5BBZNuXErv9HOmoVb4d.xml ├── 11XmEjI_K5BBZNuXErv9HOmoVb4p.xml ├── 1KTluOp16-oR5v3JUK0UHA8e6WUd.xml ├── 1KTluOp16-oR5v3JUK0UHA8e6WUp.xml ├── 1w-nJuyPlyAftYmX_f8A0UO2RoYd.xml ├── 1w-nJuyPlyAftYmX_f8A0UO2RoYp.xml ├── 2-za1lJr8fVK3PJ1MHlXunw5Oskd.xml ├── 2-za1lJr8fVK3PJ1MHlXunw5Oskp.xml ├── 2rEj_f0GPdtD554fpQNmyoBcu3Id.xml ├── 2rEj_f0GPdtD554fpQNmyoBcu3Ip.xml ├── 4DRfx5bQIrL3zJNHm7GLriyLfqUd.xml ├── 4DRfx5bQIrL3zJNHm7GLriyLfqUp.xml ├── 4PanJm-mPEJlkWhsC591LHn6aiYd.xml ├── 4PanJm-mPEJlkWhsC591LHn6aiYp.xml ├── 54Nzb97VcU2zBkaWOgRp2fge9pcd.xml ├── 54Nzb97VcU2zBkaWOgRp2fge9pcp.xml ├── 5623OBuXkEpLP79xKtBFRnkKHTwd.xml ├── 5623OBuXkEpLP79xKtBFRnkKHTwp.xml ├── 6Bh2D-xMzXRKqe6s6nncGX_LLq4d.xml ├── 6Bh2D-xMzXRKqe6s6nncGX_LLq4p.xml ├── 6oFg1XfxuDHhfjP4t4s5xOHzcrsd.xml ├── 6oFg1XfxuDHhfjP4t4s5xOHzcrsp.xml ├── 7IW8qVfB6kZF63giXtxVXReB9SUd.xml ├── 7IW8qVfB6kZF63giXtxVXReB9SUp.xml ├── 7oOVoMxiTqU8K6QQ4sUkZO9RP2Ud.xml ├── 7oOVoMxiTqU8K6QQ4sUkZO9RP2Up.xml ├── 7zY7EuVRFOGx43YZ-Y9TIffdlRMd.xml ├── 7zY7EuVRFOGx43YZ-Y9TIffdlRMp.xml ├── B67JrGieaCPkkHupmiFqKtCE6pUd.xml ├── B67JrGieaCPkkHupmiFqKtCE6pUp.xml ├── BWbN1hILgy2Xnv7NeEd_GOhnYVkd.xml ├── BWbN1hILgy2Xnv7NeEd_GOhnYVkp.xml ├── BdYYMugAhyen8aTKF0WVSC5CJMYd.xml ├── BdYYMugAhyen8aTKF0WVSC5CJMYp.xml ├── BrnqdsK_ogt7Lib0tBOndoDjD_Yd.xml ├── BrnqdsK_ogt7Lib0tBOndoDjD_Yp.xml ├── Cn9iMC8MNPNB5JDsln6zVltnWPYd.xml ├── Cn9iMC8MNPNB5JDsln6zVltnWPYp.xml ├── Cr5mcv7j6DQanwB6ElyAlI8bUJsd.xml ├── Cr5mcv7j6DQanwB6ElyAlI8bUJsp.xml ├── FFPwQdZhJJjzWviOr_Y8ow76HHEd.xml ├── FFPwQdZhJJjzWviOr_Y8ow76HHEp.xml ├── IdnWZbYNeczTHna-1KgMBVw3dTkd.xml ├── IdnWZbYNeczTHna-1KgMBVw3dTkp.xml ├── ItT4tYcXdZiwyGq2gNplYIZi-5kd.xml ├── ItT4tYcXdZiwyGq2gNplYIZi-5kp.xml ├── JyUYT_XYg4otoIQ8t01K4919hBUd.xml ├── JyUYT_XYg4otoIQ8t01K4919hBUp.xml ├── K73qDanDhcbDYKqjaFwytbLwGKgd.xml ├── K73qDanDhcbDYKqjaFwytbLwGKgp.xml ├── Ks44_1yuOlA02cwQtl9Hj_VSmGQd.xml ├── Ks44_1yuOlA02cwQtl9Hj_VSmGQp.xml ├── KyuCQK9P5YV7bEjabcSd4q48gY8d.xml ├── KyuCQK9P5YV7bEjabcSd4q48gY8p.xml ├── KzeaGeO1UH_COx-dXm2_DAEReEcd.xml ├── KzeaGeO1UH_COx-dXm2_DAEReEcp.xml ├── N2RPtkh5ZI7i2sSZ9SOs-pP9cw0d.xml ├── N2RPtkh5ZI7i2sSZ9SOs-pP9cw0p.xml ├── Q0mF6K2JACo0hwfoTHRiZIIs0UUd.xml ├── Q0mF6K2JACo0hwfoTHRiZIIs0UUp.xml ├── SeEYVLuQTDVvsjYSRnAtdr_2NhQd.xml ├── SeEYVLuQTDVvsjYSRnAtdr_2NhQp.xml ├── V0cZFTBU3_EpgkWw_Io5Y6jlFZgd.xml ├── V0cZFTBU3_EpgkWw_Io5Y6jlFZgp.xml ├── W-Du79i4Ko3EezEp2M74qz5SYusd.xml ├── W-Du79i4Ko3EezEp2M74qz5SYusp.xml ├── Yb-7rgk-EbjB7wP6z2IdIPPvUlAd.xml ├── Yb-7rgk-EbjB7wP6z2IdIPPvUlAp.xml ├── YopdEcictGnkIQ_5prpSJs34qMkd.xml ├── YopdEcictGnkIQ_5prpSJs34qMkp.xml ├── Yvbp9FUZKCSQJncgLoI5reinE8gd.xml ├── Yvbp9FUZKCSQJncgLoI5reinE8gp.xml ├── ZSr63X3mMNEhpHVxHT_0ldMLNqYd.xml ├── ZSr63X3mMNEhpHVxHT_0ldMLNqYp.xml ├── _K78ptPkoib18O_M5mDAripZWUkd.xml ├── _K78ptPkoib18O_M5mDAripZWUkp.xml ├── _dBbd0q9a5geL--6i8vH8WvsZbEd.xml ├── _dBbd0q9a5geL--6i8vH8WvsZbEp.xml ├── _yABYToFV-Vjbphro5wtF2zF0NAd.xml ├── _yABYToFV-Vjbphro5wtF2zF0NAp.xml ├── bhnlN9XOEJ1B6NEw30i-8lD3XSwd.xml ├── bhnlN9XOEJ1B6NEw30i-8lD3XSwp.xml ├── cVDmIEZqQ6RuSQlM-GFDxsJK8Fcd.xml ├── cVDmIEZqQ6RuSQlM-GFDxsJK8Fcp.xml ├── cj0dX_uC53Jt6gPqFnKbLR1-iJMd.xml ├── cj0dX_uC53Jt6gPqFnKbLR1-iJMp.xml ├── crViRB3JW-vZT9LEYWdXpvxIyIEd.xml ├── crViRB3JW-vZT9LEYWdXpvxIyIEp.xml ├── jMspD52-8pQRDJM84VawTeYB670d.xml ├── jMspD52-8pQRDJM84VawTeYB670p.xml ├── jXytGzI4O2iQkm5Iid_M99e7kl8d.xml ├── jXytGzI4O2iQkm5Iid_M99e7kl8p.xml ├── jegMYt-Jgzo1xmWNIPX-xdbhG18d.xml ├── jegMYt-Jgzo1xmWNIPX-xdbhG18p.xml ├── kFa7fP1qhyzvenZPkkRfV8neELgd.xml ├── kFa7fP1qhyzvenZPkkRfV8neELgp.xml ├── k_LDNoMhWM_ftCTzKT4LUnl8z1Id.xml ├── k_LDNoMhWM_ftCTzKT4LUnl8z1Ip.xml ├── kdyNwcW_EV1D4OcQHOT0h5ui6oUd.xml ├── kdyNwcW_EV1D4OcQHOT0h5ui6oUp.xml ├── lTNcbFF3WgZbJrqXWWqgs1AlWFUd.xml ├── lTNcbFF3WgZbJrqXWWqgs1AlWFUp.xml ├── mLjyaWT3h9G6pnHN4E1ZmZnWDDwd.xml ├── mLjyaWT3h9G6pnHN4E1ZmZnWDDwp.xml ├── nxHIvmYl91RxdSAAehuvNMiMvM0d.xml ├── nxHIvmYl91RxdSAAehuvNMiMvM0p.xml ├── q0SFswbWjtAqBsGhTVKi6kBxqmAd.xml ├── q0SFswbWjtAqBsGhTVKi6kBxqmAp.xml ├── qOqHwCrRHme4LTDtVseEt6L5eN8d.xml ├── qOqHwCrRHme4LTDtVseEt6L5eN8p.xml ├── qY_esZacgV_-CBdwSlj-x3tae5cd.xml ├── qY_esZacgV_-CBdwSlj-x3tae5cp.xml ├── qn_WO7trpHLQ8MBDNf14xTjUXv8d.xml ├── qn_WO7trpHLQ8MBDNf14xTjUXv8p.xml ├── sZsojGNj1Xsew2r2cjrxgTtJiz4d.xml ├── sZsojGNj1Xsew2r2cjrxgTtJiz4p.xml ├── t6G0dleSjZRdaE0mqOxDKu4M8xsd.xml ├── t6G0dleSjZRdaE0mqOxDKu4M8xsp.xml ├── t6Xz-myNiIJid1uOQBu3M-Z_hf4d.xml ├── t6Xz-myNiIJid1uOQBu3M-Z_hf4p.xml ├── tmzg2FyGbnUr4U5BapcMKI6CS7Ed.xml ├── tmzg2FyGbnUr4U5BapcMKI6CS7Ep.xml ├── utwGE9hQzpXV3PZxiEjFjWMyMeAd.xml ├── utwGE9hQzpXV3PZxiEjFjWMyMeAp.xml ├── x-l6L7vAJyYBtn-SDFTmhDDN-MAd.xml ├── x-l6L7vAJyYBtn-SDFTmhDDN-MAp.xml ├── x4GzzdUEvl5vK1S2qWPJ8s1NfPYd.xml ├── x4GzzdUEvl5vK1S2qWPJ8s1NfPYp.xml ├── xNX7uGtM_e36nIF5tMGLJYQgs_4d.xml ├── xNX7uGtM_e36nIF5tMGLJYQgs_4p.xml ├── xi57K6yo7qEW6cfchYEdjcWGnkcd.xml ├── xi57K6yo7qEW6cfchYEdjcWGnkcp.xml ├── xyaFs-562jwpSMpoHmrjkNpXI3kd.xml ├── xyaFs-562jwpSMpoHmrjkNpXI3kp.xml ├── yMp73CpOLXJfFwcL5zbkVD1Dgpod.xml ├── yMp73CpOLXJfFwcL5zbkVD1Dgpop.xml ├── yvnfTAHHm4btVWqLUrENzD5XMNsd.xml ├── yvnfTAHHm4btVWqLUrENzD5XMNsp.xml ├── zDJYuT22rAyRg0WvG1AdowAaXN4d.xml ├── zDJYuT22rAyRg0WvG1AdowAaXN4p.xml ├── zgQIfZQSIp7WL4NSqDq4njhDAOcd.xml ├── zgQIfZQSIp7WL4NSqDq4njhDAOcp.xml ├── zr_37WR-HxanuIcLCVDyLghcKzAd.xml └── zr_37WR-HxanuIcLCVDyLghcKzAp.xml ├── fjRQtWiSIy7hIlj-Kmk87M7s21k ├── NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml └── NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml ├── lPZI5oa5DxrsR-PK7aQQLq3WqrE ├── Miy75s7SKM4dtkSrAQrwPD2Pnvsd.xml ├── Miy75s7SKM4dtkSrAQrwPD2Pnvsp.xml ├── Y0MXjQcTETsDYSfZOITJxehWTOQd.xml ├── Y0MXjQcTETsDYSfZOITJxehWTOQp.xml ├── tzlQc0NLrARVg_2cChAq5muGE2Ud.xml └── tzlQc0NLrARVg_2cChAq5muGE2Up.xml ├── qaw0eS1zuuY1ar9TdPn1GMfrjbQ ├── OfxnnyUcu5GSELEDRUyOXcMZW0cd.xml ├── OfxnnyUcu5GSELEDRUyOXcMZW0cp.xml ├── TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml ├── TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml ├── lPZI5oa5DxrsR-PK7aQQLq3WqrEd.xml ├── lPZI5oa5DxrsR-PK7aQQLq3WqrEp.xml ├── qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml └── qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml ├── root ├── 6x1BhZX_fLnKpcwqra0qFwv1jIgp.xml ├── EEtUlUb-dLAdf0KpMVivaUlztwAp.xml ├── GiiBklLgTxteCEmomM8RCvWT0nQd.xml ├── GiiBklLgTxteCEmomM8RCvWT0nQp.xml ├── KAXfQgCar2Yb8zOxgvf9hdmLP1Ep.xml ├── NmGqIpAwUJcXFyLjFAGnU9uyN5Yp.xml ├── fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml └── qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml ├── rootp.xml └── uuid-f651a9a5-b7b9-4361-b11c-7c91771b35e7.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.fig binary 2 | *.mat binary 3 | *.mdl binary diff merge=mlAutoMerge 4 | *.mdlp binary 5 | *.mex* binary 6 | *.mlapp binary 7 | *.mldatx binary 8 | *.mlproj binary 9 | *.mlx binary 10 | *.p binary 11 | *.sfx binary 12 | *.sldd binary 13 | *.slreqx binary merge=mlAutoMerge 14 | *.slmx binary merge=mlAutoMerge 15 | *.sltx binary 16 | *.slxc binary 17 | *.slx binary merge=mlAutoMerge 18 | *.slxp binary 19 | 20 | ## Other common binary file types 21 | *.docx binary 22 | *.exe binary 23 | *.jpg binary 24 | *.pdf binary 25 | *.png binary 26 | *.xlsx binary 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Autosave files 2 | *.asv 3 | *.m~ 4 | *.autosave 5 | *.slx.r* 6 | *.mdl.r* 7 | 8 | # Derived content-obscured files 9 | *.p 10 | 11 | # Compiled MEX files 12 | *.mex* 13 | 14 | # Packaged app and toolbox files 15 | *.mlappinstall 16 | *.mltbx 17 | 18 | # Deployable archives 19 | *.ctf 20 | 21 | # Generated helpsearch folders 22 | helpsearch*/ 23 | 24 | # Code generation folders 25 | slprj/ 26 | sccprj/ 27 | codegen/ 28 | 29 | # Cache files 30 | *.slxc 31 | 32 | # Cloud based storage dotfile 33 | .MATLABDriveTag 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Daniel Mårtensson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Linear Quadratic Regulators.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/Linear Quadratic Regulators.pdf -------------------------------------------------------------------------------- /Matavecontrol.prj: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Model Predictive Control for an artifical pancreas - Matias Sørensen og Simon Kristiansen.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/Model Predictive Control for an artifical pancreas - Matias Sørensen og Simon Kristiansen.pdf -------------------------------------------------------------------------------- /Table of functions.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/Table of functions.odt -------------------------------------------------------------------------------- /Table of functions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/Table of functions.pdf -------------------------------------------------------------------------------- /examples/bodeExample.m: -------------------------------------------------------------------------------- 1 | G = mc.tf(10,[1 2 3]); 2 | 3 | mc.bode(G,0.01, 100); -------------------------------------------------------------------------------- /examples/bodeExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/bodeExampleMATLAB.png -------------------------------------------------------------------------------- /examples/bodeExampleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/bodeExampleOctave.png -------------------------------------------------------------------------------- /examples/c2dExample.m: -------------------------------------------------------------------------------- 1 | G = mc.tf(10,[1 2 3]) 2 | 3 | Gd = mc.c2d(G,0.5) 4 | 5 | mc.step(Gd); -------------------------------------------------------------------------------- /examples/c2dExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/c2dExampleMATLAB.png -------------------------------------------------------------------------------- /examples/c2dExampleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/c2dExampleOctave.png -------------------------------------------------------------------------------- /examples/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | This folder containts some simple examples. 3 | -------------------------------------------------------------------------------- /examples/kf_qmpcExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/kf_qmpcExampleMATLAB.png -------------------------------------------------------------------------------- /examples/mpcExample.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear all 3 | clc 4 | 5 | sys = mc.ss(0, [0 1; -1 -1], [0;1], [1 0]); % SISO state space model 6 | 7 | sysd = mc.c2d(sys, 0.5); % To discrete 8 | 9 | R = [6]; % Reference for the SISO model. If MIMO -> R need to be a vector 10 | N = 10; % Horizon predict constant 11 | T = 35; % Horizon time constant 12 | lambda = 7; % Regularization for smoother inputs u 13 | 14 | [y, t, x, u] = mc.lmpc(sysd, N, R, T, lambda); % Simulate MPC with linear programming 15 | hold on 16 | plot(t, u) 17 | 18 | I = 0.2; % Integral action constant 19 | Umax = [0.4]; % Maximum input signal vector 20 | S = [2]; % Slack variable says that the output can be +2 over the reference R, in this case: 6+2 = 8 21 | lambda = 0.2; % Regularization for smoother inputs u 22 | figure(2); % New figure 23 | x0 = [-8; 20]; 24 | [y, t, x, u] = mc.qmpc(sysd, N, R, T, lambda, Umax, S, I, x0); % Simulate MPC with quadratic programming 25 | hold on 26 | plot(t, u) 27 | -------------------------------------------------------------------------------- /examples/mpcExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/mpcExampleMATLAB.png -------------------------------------------------------------------------------- /examples/nyquistExample.m: -------------------------------------------------------------------------------- 1 | G = mc.tf(10,[1 2 3]) 2 | 3 | mc.nyquist(G,0.01,100) -------------------------------------------------------------------------------- /examples/nyquistExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/nyquistExampleMATLAB.png -------------------------------------------------------------------------------- /examples/nyquistExampleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/nyquistExampleOctave.png -------------------------------------------------------------------------------- /examples/stateSpaceExample.m: -------------------------------------------------------------------------------- 1 | sys = mc.ss(3,[ 0 1; -2 -3],[0;1],[1 0;0 1],[0;0]) -------------------------------------------------------------------------------- /examples/stateSpaceExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/stateSpaceExampleMATLAB.png -------------------------------------------------------------------------------- /examples/stateSpaceExampleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/stateSpaceExampleOctave.png -------------------------------------------------------------------------------- /examples/stepExample.m: -------------------------------------------------------------------------------- 1 | sys = mc.ss(3,[ 0 1; -2 -3],[0;1],[1 0;0 1],[0;0]) 2 | 3 | mc.step(sys,5); -------------------------------------------------------------------------------- /examples/stepExampleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/stepExampleMATLAB.png -------------------------------------------------------------------------------- /examples/stepExampleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/stepExampleOctave.png -------------------------------------------------------------------------------- /examples/transferFunctionExmaple.m: -------------------------------------------------------------------------------- 1 | G = mc.tf(10,[1 2 3]) -------------------------------------------------------------------------------- /examples/transferFunctionExmapleMATLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/transferFunctionExmapleMATLAB.png -------------------------------------------------------------------------------- /examples/transferFunctionExmapleOctave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/MataveControl/36abe64cc9b00b17f6cff5e9c916321fb74a6d0a/examples/transferFunctionExmapleOctave.png -------------------------------------------------------------------------------- /listOfFunctions: -------------------------------------------------------------------------------- 1 | acker.m 2 | allmargin.m 3 | append.m 4 | are.m 5 | balreal.m 6 | bode.m 7 | bodemag.m 8 | c2d.m 9 | c2dt.m 10 | covar.m 11 | ctrb.m 12 | d2c.m 13 | d2d.m 14 | damp.m 15 | db2mag.m 16 | dbdrop.m 17 | dcgain.m 18 | evalfr.m 19 | feedback.m 20 | findmaxgain.m 21 | freqresp.m 22 | gensig.m 23 | gram.m 24 | hsvd.m 25 | imc.m 26 | impulse.m 27 | initial.m 28 | loop.m 29 | lmpc.m 30 | qmpc.m 31 | lqe.m 32 | lqgreg.m 33 | lqi.m 34 | lqr.m 35 | lsim.m 36 | lyap.m 37 | mag2db.m 38 | margin.m 39 | minreal.m 40 | modred.m 41 | satlsim.m 42 | nyquist.m 43 | obsv.m 44 | pade.m 45 | parallel.m 46 | pid.m 47 | pipd.m 48 | pole.m 49 | pzmap.m 50 | ramp.m 51 | referencegain.m 52 | reg.m 53 | rlocus.m 54 | rlocfind.m 55 | sensitivity.m 56 | series.m 57 | sgrid.m 58 | sigma.m 59 | smithpredict.m 60 | ss.m 61 | ss2tf.m 62 | step.m 63 | tf.m 64 | tf2ss.m 65 | tzero.m 66 | updatematavecontrol.m 67 | zero.m 68 | zpk.m 69 | nlsim.m 70 | fminsearch.m 71 | arma.m 72 | chirp.m 73 | linprog.m 74 | quadprog.m 75 | conv2fft.m 76 | kf_qmpc.m 77 | -------------------------------------------------------------------------------- /matave/+mc/acker.m: -------------------------------------------------------------------------------- 1 | % Generate control law gain matrix L of a state space model by using eigen values vector P 2 | % Input: G, sys, P 3 | % Example 1: [L] = mc.acker(sys, P) 4 | % Author: Daniel Mårtensson, October 2017 5 | % Source from Modern Control Engineering, Ogata, 3th edition. 6 | 7 | function [L] = acker(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get model 18 | sys = varargin{1}; 19 | % Get matrecies 20 | A = sys.A; 21 | B = sys.B; 22 | 23 | % Check if B is SISO 24 | if(size(B, 2) > 1) 25 | error('Only SISO models!') 26 | end 27 | 28 | % Get eigen values 29 | if(length(varargin) >= 2) 30 | P = varargin{2}; 31 | else 32 | error('Missing the closed loop poles') 33 | end 34 | 35 | % Vectorize P 36 | P = P(:); 37 | if(size(A,1) ~= length(P)) 38 | error('Poles need to have the same dimension as matrix A') 39 | end 40 | 41 | % Create the control law gain matrix L 42 | %Formula from Ogata Modern Control Engineering 43 | Cm = mc.ctrb(sys); % Controllability matrix 44 | RealPoly = real(poly(P)); % Real polynomal of P 45 | L = Cm\polyvalm(RealPoly, A); 46 | L = L(size(A,2),:); 47 | 48 | % Check if the user has put in very bad pole locations 49 | P = sort(P); 50 | nonZeroPoles = find(P ~= 0); 51 | P = P(nonZeroPoles); 52 | % Sort the eigen values 53 | eigenvalues = sort(eig(A-B*L)); 54 | % Ge the egenvalues which has non zero poles 55 | eigenvalues = eigenvalues(nonZeroPoles); 56 | % Get the absolute maximum value of P 57 | M = abs(P); 58 | 59 | % Get the difference between pole locations and eigen values 60 | Diff = abs(P-eigenvalues); 61 | if(max(Diff./M) > .05) 62 | disp('Warning: Pole locations are in more that 5% error') 63 | end 64 | 65 | elseif(strcmp(type, 'TF' )) 66 | disp('Only state space models only') 67 | else 68 | error('This is not TF or SS'); 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /matave/+mc/allmargin.m: -------------------------------------------------------------------------------- 1 | % Print out all margins of a state space model or a 2 | % transfer function between frequencies w1 and w2 3 | % Input: sys, G, w1, w2 4 | % Example 1: S = mc.allmargin(sys, w1, w2) 5 | % Example 2: S = mc.allmargin(G, w1, w2) 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | 8 | function [S] = allmargin(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | w2 = varargin{3}; 21 | end 22 | 23 | 24 | % Get the type 25 | type = varargin{1}.type; 26 | % Check if there is a TF or SS model 27 | if(strcmp(type, 'SS' )) 28 | % SS to TF 29 | G = mc.ss2tf(varargin{1}); 30 | % Call allmargin 31 | mc.allmargin(G, w1, w2); 32 | elseif(strcmp(type, 'TF' )) 33 | % If there is a MIMO TF 34 | G = varargin{1}; 35 | for i = 1:size(G,1) 36 | for j = 1:size(G,2) 37 | % Get numerator vector and denomerator vector 38 | a = G(i,j).num; 39 | b = G(i,j).den; 40 | % Get delay 41 | delay = G(i,j).delay; 42 | % Get sample time 43 | sampleTime = G(i,j).sampleTime; 44 | 45 | % Numerator and denomerator need to be the same length 46 | if(length(a) > length(b)) 47 | b = [zeros(1, size(a,2) - size(b,2)) b]; 48 | elseif(length(a) < length(b)) 49 | a = [zeros(1, size(b,2) - size(a,2)) a]; 50 | end 51 | 52 | L = 10000; % Number of frequency elements 53 | N = length(b); % Number of denomerators 54 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 55 | % Evaluate transfer function 56 | H = zeros(1, L); 57 | h = sampleTime; 58 | if(sampleTime > 0) % Discrete model 59 | for k = 1 : L 60 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 61 | end 62 | else 63 | for k = 1 : L 64 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 65 | end 66 | end 67 | % Done! 68 | 69 | % Get wc, phim 70 | wc = inf; 71 | phim = inf; 72 | flag = false; 73 | for k = 1:length(H) 74 | % The dB need to be over 0 for flag = true 75 | if ((20*log10(abs(H(k))) > 0)) 76 | flag = true; 77 | end 78 | % When dB is under 0 and flag = true 79 | if (and(20*log10(abs(H(k))) <= 0, flag == true )) 80 | wc = w(k); 81 | phim = 180 + angle(H(k)) * 180/pi; 82 | break; 83 | end 84 | end 85 | 86 | % Get wpi, Am 87 | wpi = inf; 88 | Am = inf; 89 | for k = 1:length(H) 90 | if (angle(H(k)) * 180/pi <= -180) 91 | wpi = w(k); 92 | Am = 20*log10(abs(H(k))); 93 | break; 94 | end 95 | end 96 | 97 | % Compute the delay margin 98 | Dm = pi*phim/(180*wc); 99 | 100 | % Check if it's stable 101 | p = mc.pole(G(i,j)); 102 | stable = 1; 103 | for k = 1:length(p) 104 | if(real(p(k)) > 0) 105 | stable = 0; % Not stable! We got one positive pole! 106 | break; 107 | end 108 | end 109 | 110 | % Am 111 | Am = abs(Am); 112 | 113 | % Print it out 114 | % DMFrequency(Phidm) is the same as wc 115 | S(i,j) = {sprintf('Transfer function: %ix%i\nGainMargin(Am): %i\nGMFrequency(wpi): %i\nPhaseMargin(Phim): %i\nPMFrequency(Wc): %i\nDelayMargin(Dm): %i\nDMFrequency(Phidm): %i\nStable: %i\n', i, j, Am, wpi, phim, wc, Dm, wc, stable)}; 116 | 117 | 118 | end 119 | end 120 | % Do cell2mat 121 | S = cell2mat(S); 122 | else 123 | error('Only transfer functions and state space models allowed') 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /matave/+mc/append.m: -------------------------------------------------------------------------------- 1 | % Append diffrent models into one large model and get a state space model 2 | % Input: G, sys 3 | % Example 1: sys = mc.append(G1, G2, sys1) 4 | % Example 2: sys = mc.append(sys1, sys2, G1, G2) 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [sys] = append(varargin) 8 | if(isempty(varargin{1})) 9 | error ('Missing model') 10 | end 11 | 12 | % Get type from the first model 13 | type = varargin{1}.type; 14 | 15 | % State space 16 | if(or(strcmp(type, 'SS' ), strcmp(type, 'TF' ))) 17 | for i = 1:length(varargin) 18 | % check if we need to convert that TF to SS 19 | type = varargin{i}.type; 20 | if(strcmp(type, 'TF' )) 21 | % Yes! 22 | sys = mc.tf2ss(varargin{i}, 'OCF'); 23 | else 24 | % No! 25 | sys = varargin{i}; 26 | end 27 | % Get the matrecies 28 | A = sys.A; 29 | B = sys.B; 30 | C = sys.C; 31 | D = sys.D; 32 | 33 | % The first one sets the default delay and sample time 34 | if(i == 1) 35 | firstdelay = sys.delay; 36 | firstsampleTime = sys.sampleTime; 37 | Apast = blkdiag([],A); 38 | Bpast = blkdiag([],B); 39 | Cpast = blkdiag([],C); 40 | Dpast = blkdiag([],D); 41 | else 42 | delay = sys.delay; 43 | sampleTime = sys.sampleTime; 44 | % The delay and sample time needs to be the same as the others 45 | if(and(firstdelay == delay, firstsampleTime == sampleTime)) 46 | Apast = blkdiag(Apast,A); 47 | Bpast = blkdiag(Bpast,B); 48 | Cpast = blkdiag(Cpast,C); 49 | Dpast = blkdiag(Dpast,D); 50 | else 51 | error('Sample time or delay is not equal as the first model') 52 | end 53 | end 54 | end 55 | % Now we are done! Create the SS model now! 56 | sys = mc.ss(firstdelay, Apast, Bpast, Cpast, Dpast); 57 | sys.sampleTime = firstsampleTime; 58 | else 59 | error('No state space model or transfer function') 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /matave/+mc/arma.m: -------------------------------------------------------------------------------- 1 | % Generates a ARMA model from numerator vector and denomerator vector 2 | % Input: numerator, denomerator, sampleTime(optional), delay(optional) 3 | % Example 1: H = mc.arma(num, den) 4 | % Example 2: H = mc.arma(num, den, sampleTime) 5 | % Example 3: H = mc.arma(num, den, sampleTime, delay) 6 | % Author: Daniel Mårtensson, 2022 Oktober 7 | 8 | function [H] = arma(varargin) 9 | % Check if there is some input arguments 10 | if(isempty (varargin)) 11 | error ('Missing arguments') 12 | end 13 | % OK. We have arguments! 14 | 15 | % Get numerator 16 | if(length(varargin) < 1) 17 | error('Missing numerator') 18 | else 19 | numerator = varargin{1}; 20 | end 21 | 22 | % Get denomerator 23 | if(length(varargin) < 2) 24 | error('Missing denomerator') 25 | else 26 | denomerator = varargin{2}; 27 | end 28 | 29 | % Get sampleTime 30 | if(length(varargin) >= 3) 31 | sampleTime = varargin{3}; 32 | else 33 | sampleTime = 0; 34 | end 35 | 36 | % Check if there is some numerators 37 | if(isempty (numerator)) 38 | error('Missing numerator'); 39 | end 40 | % OK. We have numerators! 41 | 42 | % Check if there is some denomerators 43 | if(isempty (denomerator)) 44 | error('Missing denomerator'); 45 | end 46 | % OK. We have denomerator! 47 | 48 | % Make sure that we divide all with denomerator(1) 49 | if(denomerator(1) == 0) 50 | error('First number in the denomerator cannot be 0'); 51 | else 52 | numerator = numerator/denomerator(1); 53 | denomerator = denomerator/denomerator(1); 54 | end 55 | 56 | % Create transfer function 57 | H.num = numerator; 58 | H.den = denomerator; 59 | H.delay = 0; 60 | 61 | % Add numerator 62 | tfnum = ''; 63 | firstNumber = false; 64 | for i = 1:length(numerator) 65 | a = numerator(i); 66 | if(a > 0) 67 | if(or(i == 1, firstNumber == false)) 68 | tfnum = strcat(tfnum, num2str(a), sprintf('z^-%i', i-1)); 69 | firstNumber = true; 70 | else 71 | tfnum = strcat(tfnum, {' + '}, num2str(a), sprintf('z^-%i', i-1)); 72 | end 73 | elseif(a < 0) 74 | tfnum = strcat(tfnum, {' '}, num2str(a), sprintf('z^-%i', i-1)); 75 | end 76 | end 77 | H.tfnum = char(tfnum); 78 | 79 | % Add the dash lines 80 | H.tfdash = '-'; 81 | 82 | % Add denomerator 83 | tfden = '1'; 84 | for i = 2:length(denomerator) 85 | a = denomerator(i); 86 | if(a > 0) 87 | tfden = strcat(tfden, {' + '}, num2str(a), sprintf('z^-%i', i-1)); 88 | elseif(a < 0) 89 | tfden = strcat(tfden, {' '}, num2str(a), sprintf('z^-%i', i-1)); 90 | end 91 | end 92 | H.tfden = char(tfden(1,1)); 93 | 94 | % Update the dash line 95 | H.tfdash = getDashedLine(H.tfnum, H.tfden); 96 | 97 | % Add type and sample time 98 | H.type = 'ARMA'; 99 | H.sampleTime = sampleTime; 100 | end 101 | 102 | 103 | function [dash] = getDashedLine(numeratorString, denomeratorString) 104 | dash = ''; 105 | if(length(numeratorString) <= length(denomeratorString)) 106 | for i = 1:length(denomeratorString) 107 | dash = strcat(dash,'-'); 108 | end 109 | else 110 | for i = 1:length(numeratorString) 111 | dash = strcat(dash,'-'); 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /matave/+mc/balreal.m: -------------------------------------------------------------------------------- 1 | % Generates the balanced realization of a state space model 2 | % Input: sys 3 | % Example 1: model = mc.balreal(sys) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [model] = balreal(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing model') 10 | end 11 | 12 | % Get model type 13 | type = varargin{1}.type; 14 | % Check if there is a TF or SS model 15 | if(strcmp(type, 'SS' )) 16 | % Get sys 17 | sys = varargin{1}; 18 | % Get gramians 19 | Q = mc.gram(sys, 'o'); 20 | P = mc.gram(sys, 'c'); 21 | % Get hankel singular values 22 | E = diag(mc.hsvd(sys)); 23 | 24 | % Begin 25 | Q1 = chol(Q); 26 | U = chol(eye(size(Q))); 27 | E1 = chol(E); 28 | 29 | T = inv(E1)*U'*Q1; 30 | 31 | % Get matrecies 32 | A = sys.A; 33 | B = sys.B; 34 | C = sys.C; 35 | D = sys.D; 36 | delay = sys.delay; 37 | sampleTime = sys.sampleTime; 38 | 39 | model = mc.ss(delay, T*A*inv(T), T*B, C*inv(T), D); 40 | model.sampleTime = sampleTime; 41 | elseif(strcmp(type, 'TF' )) 42 | disp('Only state space model are allowed') 43 | else 44 | error('This is not TF or SS'); 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /matave/+mc/bode.m: -------------------------------------------------------------------------------- 1 | % Plot the bode diagram of a state space model or a 2 | % transfer function between frequencies w1 and w2 3 | % Input: sys, G, w1, w2 4 | % Example 1: [mag, phase, wout] = mc.bode(sys, w1, w2) 5 | % Example 2: [mag, phase, wout] = mc.bode(G, w1, w2) 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | 8 | function [mag, phase, wout] = bode(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | if(w1 == 0) 21 | w1 = 0.001; 22 | end 23 | w2 = varargin{3}; 24 | end 25 | 26 | % Get the type 27 | type = varargin{1}.type; 28 | % Check if there is a TF or SS model 29 | if(strcmp(type, 'SS' )) 30 | % SS to TF 31 | G = mc.ss2tf(varargin{1}); 32 | % Call bode 33 | [mag, phase, wout] = mc.bode(G, w1, w2); 34 | elseif(strcmp(type, 'TF' )) 35 | % If there is a MIMO TF 36 | G = varargin{1}; 37 | for i = 1:size(G,1) 38 | for j = 1:size(G,2) 39 | % Get numerator vector and denomerator vector 40 | a = G(i,j).num; 41 | b = G(i,j).den; 42 | % Get delay 43 | delay = G(i,j).delay; 44 | % Get sample time 45 | sampleTime = G(i,j).sampleTime; 46 | 47 | % Numerator and denomerator need to be the same length 48 | if(length(a) > length(b)) 49 | b = [zeros(1, size(a,2) - size(b,2)) b]; 50 | elseif(length(a) < length(b)) 51 | a = [zeros(1, size(b,2) - size(a,2)) a]; 52 | end 53 | 54 | L = 1000; % Number of frequency elements 55 | N = length(b); % Number of denomerators 56 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 57 | % Evaluate transfer function 58 | H = zeros(1, L); 59 | h = sampleTime; 60 | if(sampleTime > 0) % Discrete model 61 | for k = 1 : L 62 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 63 | end 64 | else 65 | for k = 1 : L 66 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 67 | end 68 | end 69 | 70 | % Done! 71 | % Plot Bode diagram 72 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 73 | subplot(2,1,1) 74 | semilogx(w, 20*log10(abs(H))); 75 | ylabel('Magnitude [dB]'); 76 | grid on 77 | subplot(2,1,2) 78 | 79 | BodeAngles = angle(H) * 180/pi; 80 | semilogx(w, BodeAngles); 81 | ylabel('Phase [deg]'); 82 | xlabel('Frequency [rad/s]'); 83 | grid on 84 | 85 | % Return these values 86 | mag = 20*log10(abs(H)); 87 | phase = BodeAngles; 88 | wout = w; 89 | end 90 | end 91 | else 92 | error('Only transfer functions allowed') 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /matave/+mc/bodemag.m: -------------------------------------------------------------------------------- 1 | % Plot the bode diagram, without phase diagram, of a state space model or a 2 | % transfer function between frequencies w1 and w2 3 | % Input: sys, G, w1, w2 4 | % Example 1: mc.bodemag(sys, w1, w2) 5 | % Example 2: mc.bodemag(G, w1, w2) 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | 8 | function [reval] = bodemag(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | if(w1 == 0) 21 | w1 = 0.001; 22 | end 23 | w2 = varargin{3}; 24 | end 25 | 26 | % Get the type 27 | type = varargin{1}.type; 28 | % Check if there is a TF or SS model 29 | if(strcmp(type, 'SS' )) 30 | % SS to TF 31 | G = mc.ss2tf(varargin{1}); 32 | % Call bode 33 | mc.bode(G, w1, w2); 34 | elseif(strcmp(type, 'TF' )) 35 | % If there is a MIMO TF 36 | G = varargin{1}; 37 | for i = 1:size(G,1) 38 | for j = 1:size(G,2) 39 | % Get numerator vector and denomerator vector 40 | a = G(i,j).num; 41 | b = G(i,j).den; 42 | % Get delay 43 | delay = G(i,j).delay; 44 | % Get sample time 45 | sampleTime = G(i,j).sampleTime; 46 | 47 | % Numerator and denomerator need to be the same length 48 | if(length(a) > length(b)) 49 | b = [zeros(1, size(a,2) - size(b,2)) b]; 50 | elseif(length(a) < length(b)) 51 | a = [zeros(1, size(b,2) - size(a,2)) a]; 52 | end 53 | 54 | L = 1000; % Number of frequency elements 55 | N = length(b); % Number of denomerators 56 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 57 | % Evaluate transfer function 58 | H = zeros(1, L); 59 | h = sampleTime; 60 | if(sampleTime > 0) % Discrete model 61 | for k = 1 : L 62 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 63 | end 64 | else 65 | for k = 1 : L 66 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 67 | end 68 | end 69 | 70 | 71 | % Done! 72 | % Plot Bode diagram 73 | 74 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 75 | semilogx(w, 20*log10(abs(H))); 76 | ylabel('Magnitude [dB]'); 77 | grid on 78 | end 79 | end 80 | else 81 | error('Only transfer functions allowed') 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /matave/+mc/c2d.m: -------------------------------------------------------------------------------- 1 | % Transform continuous time model to discrete model 2 | % Input: sys, G, sampeltime 3 | % Example 1: Gd = mc.c2d(G, sampleTime) 4 | % Example 2: sysd = mc.c2d(sys, sampleTime) 5 | % Author: Daniel Mårtensson, September 2017 6 | 7 | function [model] = c2d(varargin) 8 | if(isempty(varargin{1})) 9 | error ('Missing model') 10 | end 11 | 12 | if(isempty(varargin{2})) 13 | error ('Missing sampeltime') 14 | end 15 | 16 | % State space 17 | if(strcmp(varargin{1}.type, 'SS' )) 18 | % Get info 19 | A = varargin{1}.A; 20 | B = varargin{1}.B; 21 | C = varargin{1}.C; 22 | D = varargin{1}.D; 23 | delay = varargin{1}.delay; 24 | h = varargin{2}; 25 | % Compute sizes 26 | a1 = size(A,2) + size(B,2) - size(A,1); 27 | b1 = size(A,2); 28 | a2 = size(A,2) + size(B,2) - size(B,1); 29 | b2 = size(B,2); 30 | % Compute square matrix 31 | M = [A B; zeros(a1, b1) zeros(a2, b2)]; 32 | M = expm(M*h); 33 | % Find the discrete matrecies 34 | Ad = M(1:size(A,1), 1:size(A,2)); 35 | Bd = M(1:size(B,1), (size(A,2) + 1):(size(A,2) + size(B,2))); 36 | model = mc.ss(delay, Ad, Bd, C, D); 37 | % Don't forget to add sample time 38 | model.sampleTime = h; 39 | 40 | % Transfer function 41 | elseif(strcmp(varargin{1}.type, 'TF' )) 42 | % Transform it to a state space model. 43 | sys = mc.tf2ss(varargin{1}, 'OCF'); 44 | % Turn sys to discrete 45 | h = varargin{2}; 46 | if(and(h > 0, sys.delay > 0)) 47 | error('You cannot turn time continous transfer function with delay into discrete transfer function. Try state space instead: sys = mc.tf2ss(G) -> sysd = c2d(sys)'); 48 | end 49 | model = mc.c2d(sys, h); 50 | % Turn it then into a tf 51 | model = mc.ss2tf(model); 52 | model.sampleTime = h; 53 | % Replace the delaytime to discrete delay time 54 | model.tfdash = strrep(model.tfdash, 'e', 'z'); 55 | model.tfdash = strrep(model.tfdash, 's', ''); 56 | % Remove all s -> s 57 | model.tfnum = strrep(model.tfnum, 's', 'z'); 58 | model.tfden = strrep(model.tfden, 's', 'z'); 59 | else 60 | error('No state space model or transfer function') 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /matave/+mc/c2dt.m: -------------------------------------------------------------------------------- 1 | % Transform a state space model or transfer function to discrete state space model with delay 2 | % Input: G, sys, sampleTime 3 | % Output: sysd(discrete state space model with delay), l(step prediction) 4 | % Example 1: [sysd, l] = mc.c2dt(G, sampleTime) 5 | % Example 2: [sysd, l] = mc.c2dt(sys, sampleTime) 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | % Updated: 2018-03-04 8 | 9 | function [sysd, l] = c2dt(varargin) 10 | if(isempty(varargin{1})) 11 | error ('Missing model') 12 | end 13 | 14 | % Check sample time 15 | if(length(varargin) < 2) 16 | error ('Missing sample time') 17 | end 18 | 19 | % Get delay 20 | if(varargin{1}.delay <= 0) 21 | error('This model has no delay') 22 | end 23 | 24 | % Get type 25 | type = varargin{1}.type; 26 | 27 | % State space 28 | if(strcmp(type, 'SS' )) 29 | % Check if allready discrete 30 | if(varargin{1}.sampleTime > 0) 31 | % The model is allready discrete! Turn it back! 32 | sys = mc.d2c(varargin{1}, varargin{1}.sampleTime); 33 | A = sys.A; 34 | B = sys.B; 35 | C = sys.C; 36 | D = sys.D; 37 | sampleTime = sys.sampleTime; % Over write the sampleTime 38 | delay = sys.delay; % Get delay 39 | else 40 | % No! The model is not discrete! 41 | sys = varargin{1}; 42 | A = sys.A; 43 | B = sys.B; 44 | C = sys.C; 45 | D = sys.D; 46 | sampleTime = varargin{2}; % Get the sample time 47 | delay = sys.delay; 48 | end 49 | 50 | % Original Source: Digital Control Of Dynamic Systems - G.F Franklin 51 | % Modified by me! 52 | 53 | % Get sizes of input and output matrix 54 | [bx,by] = size(B); 55 | [cx,cy] = size(C); 56 | l = ceil(delay/sampleTime); % Check of delay is less that sampleTime - Round up 57 | m = l*sampleTime - delay; 58 | 59 | % Create discrete matrecies s1, s2 s3 etc 60 | s1 = expm([A*m, B*m; zeros(by,bx+by)]); 61 | s2 = expm([A*(sampleTime-m), B*(sampleTime-m); zeros(by,bx+by)]); 62 | s3 = eye((l-1)*by); 63 | s4 = zeros(cy,(l-2)*by); 64 | s5 = zeros((l-1)*by,bx+by); 65 | s6 = zeros(by,bx+l*by); 66 | 67 | P = s1(1:bx, 1:bx)*s2(1:bx, 1:bx); 68 | H1 = s1(1:bx, 1:bx)*s2(1:bx, bx+1:bx+by); 69 | H2 = s1(1:bx, bx+1:bx+by); 70 | if(l == 1) % If the delay is less that sampleTime 71 | A = [P, H1; s6]; 72 | B = [H2; eye(by)]; 73 | C = [C, zeros(cx, by)]; 74 | D = zeros(cx, by); 75 | else % If the delay is more that sampleTime 76 | A = [P, H1, H2, s4; s5, s3; s6]; 77 | B = [zeros(bx+(l-1)*by, by); eye(by)]; 78 | C = [C,zeros(cx, l*by)]; 79 | D = zeros(cx, by); 80 | end 81 | % Get the discrete state space model now 82 | sysd = mc.ss(delay, A, B, C, D); 83 | sysd.sampleTime = sampleTime; % Get the sample time 84 | 85 | elseif(strcmp(type, 'TF' )) 86 | % Check if allready discrete 87 | if(varargin{1}.sampleTime > 0) 88 | % Yes! The model is discrete! Turn it back! 89 | G = mc.d2c(varargin{1}, varargin{1}.sampleTime); 90 | % TF to SS 91 | sys = mc.tf2ss(G, 'OCF'); 92 | % Get the sample time 93 | sampleTime = varargin{1}.sampleTime; 94 | % Call c2dt 95 | [sysd, l] = mc.c2dt(sys, sampleTime); 96 | else 97 | % TF to SS 98 | G = varargin{1}; 99 | sys = mc.tf2ss(G, 'OCF'); 100 | % Get the sample time 101 | sampleTime = varargin{2}; 102 | % Call c2dt 103 | [sysd, l] = mc.c2dt(sys, sampleTime); 104 | end 105 | else 106 | error('No state space model or transfer function') 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /matave/+mc/chirp.m: -------------------------------------------------------------------------------- 1 | 2 | % Chirp - Generates a frequency signal 3 | % Input: t(time), A(amplitude, optional) 4 | % Output: u(signal), fs(sampling frequency) 5 | % Example 1: [u, fs] = mc.chirp(t); 6 | % Example 1: [u, fs] = mc.chirp(t, A); 7 | % Author: Daniel Mårtensson, Oktober 29:e 2022 8 | 9 | function [u, fs] = chirp(varargin) 10 | % Check if there is any input 11 | if(isempty(varargin)) 12 | error('Missing inputs') 13 | end 14 | 15 | % Get time 16 | if(length(varargin) >= 1) 17 | t = varargin{1}; 18 | else 19 | error('Missing time'); 20 | end 21 | 22 | % Get amplitude 23 | if(length(varargin) >= 2) 24 | A = varargin{2}; 25 | else 26 | A = 1; 27 | end 28 | 29 | % Create the length 30 | N = length(t); 31 | 32 | % Create the difference chirp duration 33 | T = t(end) - t(1); 34 | 35 | % Create the sampling frequency 36 | fs = 1/(T/N); 37 | 38 | % Create the start frequency 39 | f0 = 0; 40 | 41 | % Create the final frequency 42 | f1 = fs/2; 43 | 44 | % Create the chirp rate 45 | c = (f1-f0)/T; 46 | 47 | % Create the frequency signal 48 | u = A*sin(2*pi*(c/2*t.^2 + f0*t)); 49 | 50 | end 51 | -------------------------------------------------------------------------------- /matave/+mc/conv2fft.m: -------------------------------------------------------------------------------- 1 | % Convolution via FFT2 2 | % Input: X(Data matrix), K(Kernel matrix) 3 | % Output: C(Filtered data matrix) 4 | % Example 1: [C] = mc.conv2fft(X, K); 5 | % Author: Daniel Mårtensson, 24 September 2023 6 | 7 | function [C] = conv2fft(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error('Missing input') 11 | end 12 | 13 | % Get input matrix X 14 | if(length(varargin) >= 1) 15 | X = varargin{1}; 16 | else 17 | error('Missing input data matrix X') 18 | end 19 | 20 | % Get the sigma 21 | if(length(varargin) >= 2) 22 | K = varargin{2}; 23 | else 24 | error('Missing kernel data matrix K') 25 | end 26 | 27 | % Create kernel 28 | [m, n] = size(X); 29 | kernel = zeros(m, n); 30 | [m, n] = size(K); 31 | 32 | % Compute the sizes 33 | m_middle = ceil(m/2); 34 | n_middle = m_middle; 35 | 36 | % Insert kernel 37 | kernel(1:m_middle, 1:n_middle) = K(m_middle:end, n_middle:end); 38 | kernel(end-m_middle+1:end, 1:n_middle) = K(1:m_middle, n_middle:end); 39 | kernel(1:m_middle, end-n_middle+1:end) = K(m_middle:end, 1:n_middle); 40 | kernel(end-m_middle+1:end, end-n_middle+1:end) = K(1:m_middle, 1:n_middle); 41 | 42 | % Do FFT2 on X and kernel 43 | A = fft2(X); 44 | B = fft2(kernel); 45 | 46 | % Compute the convolutional matrix - real to remove zero imaginary numbers 47 | C = real(ifft2(A.*B)); 48 | end 49 | -------------------------------------------------------------------------------- /matave/+mc/covar.m: -------------------------------------------------------------------------------- 1 | % Get the covariance matrix of a state space model with the intensity of Gaussian white noise matrix 2 | % Input: sys, W 3 | % Example: [P] = mc.covar(sys, W) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [P] = covar(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing model') 10 | end 11 | 12 | % Get model type 13 | type = varargin{1}.type; 14 | % Check if there is a TF or SS model 15 | if(strcmp(type, 'SS' )) 16 | % Get sys 17 | sys = varargin{1}; 18 | % Get sample time 19 | sampleTime = sys.sampleTime; 20 | % Get matrecies 21 | A = sys.A; 22 | B = sys.B; 23 | C = sys.C; 24 | D = sys.D; 25 | 26 | % Get W matrix 27 | if(length(varargin) >= 2) 28 | W = varargin{2}; 29 | else 30 | error('Missing W matrix') 31 | end 32 | 33 | % Check W matrix 34 | if(or(size(B,2) ~= size(W,1), size(W, 1) ~= size(W,2))) 35 | error('W matrix need to be square or B matrix need to have same columns as rows as W matrix') 36 | end 37 | 38 | if(~issymmetric(W)) 39 | error('W-matrix need to be symmetric') 40 | end 41 | 42 | % Check if W matrix is semi-definite 43 | EigenValues = eig(W); 44 | for i = 1:length(EigenValues) 45 | if(EigenValues(i) < 0) 46 | error('W matrix need to have non negative eigen values') 47 | end 48 | end 49 | 50 | % Get lyapunov 51 | if(sampleTime > 0) 52 | opt = 'd'; 53 | else 54 | opt = 't'; 55 | end 56 | 57 | % Get lyapunov solution 58 | X = mc.lyap(A, B*W*B', opt); 59 | 60 | % Get P matrix 61 | P = C*X*C' + D*W*D'; 62 | 63 | 64 | elseif(strcmp(type, 'TF' )) 65 | disp('Only state space model are allowed') 66 | else 67 | error('This is not TF or SS'); 68 | end 69 | 70 | end -------------------------------------------------------------------------------- /matave/+mc/ctrb.m: -------------------------------------------------------------------------------- 1 | % Generates the controllability matrix of a state space model 2 | % Input: sys, n(optinal) 3 | % Example 1: [Cs] = mc.ctrb(sys) 4 | % Example 1: [Cs] = mc.ctrb(sys, n) 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [Cs] = ctrb(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get SS 18 | sys = varargin{1}; 19 | 20 | % Check if we got variable n for minimal realization 21 | if(length(varargin) > 1) 22 | n = varargin{2}; 23 | else 24 | n = size(sys.A, 1); % Else, we only check the dimension of A 25 | end 26 | 27 | % Compute the controllability matrix now! 28 | Cs = []; 29 | for i = 0:(n-1) 30 | Cs = [Cs sys.A^i*sys.B]; 31 | end 32 | 33 | elseif(strcmp(type, 'TF' )) 34 | % Get TF 35 | disp('Only state space models allowed'); 36 | else 37 | error('This is not TF or SS'); 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /matave/+mc/d2c.m: -------------------------------------------------------------------------------- 1 | % Transform discrete transfer function or state space model to continuous time 2 | % transfer function or state space model 3 | % Input: Gd, sysd 4 | % Example 1: G = mc.d2c(Gd) 5 | % Example 2: sys = mc.d2c(sysd) 6 | % Author: Daniel Mårtensson, September 2017 7 | 8 | function [model] = d2c(varargin) 9 | if(isempty(varargin{1})) 10 | error ('Missing model') 11 | end 12 | 13 | % State space 14 | if(strcmp(varargin{1}.type, 'SS' )) 15 | % Get info 16 | A = varargin{1}.A; 17 | B = varargin{1}.B; 18 | C = varargin{1}.C; 19 | D = varargin{1}.D; 20 | delay = varargin{1}.delay; 21 | sampleTime = varargin{1}.sampleTime; 22 | % Compute sizes 23 | a1 = size(A,2) + size(B,2) - size(A,1); 24 | b1 = size(A,2); 25 | a2 = size(A,2) + size(B,2) - size(B,1); 26 | b2 = size(B,2); 27 | % Compute square matrix 28 | M = [A B; zeros(a1, b1) eye(a2, b2)]; 29 | M = round(logm(M)*1/sampleTime*1/1e-6)*1e-6; % Very important to remove small numbers!! 30 | M(abs(M) < 1e-6) = 0; % Very importat to turn -0 to 0. 31 | A = M(1:size(A,1), 1:size(A,2)); 32 | B = M(1:size(B,1), (size(A,2) + 1):(size(A,2) + size(B,2))); 33 | % Return model 34 | model = mc.ss(delay, A, B, C, D); 35 | % Don't forget to add sample time to zero again 36 | model.sampleTime = 0; 37 | elseif(strcmp(varargin{1}.type, 'TF' )) 38 | % Turn TF to SS 39 | sysd = mc.tf2ss(varargin{1}, 'OCF'); 40 | % Call d2c2 41 | G = mc.d2c(sysd); 42 | % SS to SS 43 | model = mc.ss2tf(G); 44 | else 45 | error('No state space model or transfer function') 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /matave/+mc/d2d.m: -------------------------------------------------------------------------------- 1 | % Rediscrete transfer function or state space model 2 | % Input: Gd, sysd, sampleTime 3 | % Example 1: G = mc.d2d(Gd, sampleTime) 4 | % Example 2: sys = mc.d2d(sysd, sampleTime) 5 | % Author: Daniel Mårtensson, September 2017 6 | 7 | function [model] = d2d(varargin) 8 | if(isempty(varargin{1})) 9 | error ('Missing model') 10 | end 11 | 12 | if(isempty(varargin{2})) 13 | error ('Missing sampeltime') 14 | end 15 | 16 | % State space 17 | if(strcmp(varargin{1}.type, 'SS' )) 18 | % To continuous from discrete 19 | sys = mc.d2c(varargin{1}); 20 | % To discrete from continuous 21 | model = mc.c2d(sys, varargin{2}); 22 | elseif(strcmp(varargin{1}.type, 'TF' )) 23 | % To continuous from discrete 24 | G = mc.d2c(varargin{1}); 25 | % To discrete from continuous 26 | model = mc.c2d(G, varargin{2}); 27 | else 28 | error('No state space model or transfer function') 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /matave/+mc/damp.m: -------------------------------------------------------------------------------- 1 | % Generates zeros from transfer functions or state space models 2 | % Input: G, sys 3 | % Example 1: [Frequency, Damping, Poles, TimeConstant] = mc.damp(G) 4 | % Example 2: [Frequency, Damping, Poles, TimeConstant] = mc.damp(sys) 5 | % Author: Daniel Mårtensson, September 2017 6 | 7 | function [Frequency, Damping, Poles] = damp(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Get sampleTime 16 | sampleTime = varargin{1}.sampleTime; 17 | % Check if there is a TF or SS model 18 | if(strcmp(type, 'SS' )) 19 | % Check if it's discrete 20 | if(sampleTime == 0) 21 | Poles = mc.pole(varargin{1}) 22 | Frequency = abs(Poles) 23 | Damping = -cos(angle(Poles)) 24 | TimeConstant = (1./(Frequency.*Damping)) 25 | else 26 | % Discrete 27 | Poles = mc.pole(varargin{1}) 28 | Frequency = abs(log(Poles)/sampleTime) 29 | Damping = -cos(angle(log(Poles))) 30 | TimeConstant = (1./(Frequency.*Damping)) 31 | end 32 | elseif(strcmp(type, 'TF' )) 33 | % Check if it's discrete 34 | if(sampleTime == 0) 35 | Poles = mc.pole(varargin{1}) 36 | Frequency = abs(Poles) 37 | Damping = -cos(angle(Poles)) 38 | TimeConstant = (1./(Frequency.*Damping)) 39 | else 40 | % Discrete 41 | Poles = mc.pole(varargin{1}) 42 | Frequency = abs(log(Poles)/sampleTime) 43 | Damping = -cos(angle(log(Poles))) 44 | TimeConstant = (1./(Frequency.*Damping)) 45 | end 46 | else 47 | error('This is not TF or SS'); 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /matave/+mc/db2mag.m: -------------------------------------------------------------------------------- 1 | % Convert decibel to magnitude 2 | % Input dB 3 | % Example 1: [mag] = mc.db2mag(dB) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | function [mag] = db2mag (dB) 6 | mag = 10.^(dB/20); 7 | end 8 | -------------------------------------------------------------------------------- /matave/+mc/dbdrop.m: -------------------------------------------------------------------------------- 1 | % Plot the nyquist diagram of a state space model or a transfer function to find the 2 | % 3 dB gain drop between frequencies w1 and w2 3 | % Input: G, sys, w1, w2 4 | % Example 1: [drop] = mc.dbdrop(sys, w1, w2) 5 | % Example 2: [drop] = mc.dbdrop(G, w1, w2) 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | 8 | function [drop] = dbdrop(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | if(w1 == 0) 21 | w1 = 0.001; 22 | end 23 | w2 = varargin{3}; 24 | end 25 | 26 | 27 | % Get the type 28 | type = varargin{1}.type; 29 | % Check if there is a TF or SS model 30 | if(strcmp(type, 'SS' )) 31 | % SS to TF 32 | G = mc.ss2tf(varargin{1}); 33 | % Call dBdrop 34 | mc.dbdrop(G, w1, w2); 35 | elseif(strcmp(type, 'TF' )) 36 | % If there is a MIMO TF 37 | G = varargin{1}; 38 | for i = 1:size(G,1) 39 | for j = 1:size(G,2) 40 | % Get numerator vector and denomerator vector 41 | a = G(i,j).num; 42 | b = G(i,j).den; 43 | % Get delay 44 | delay = G(i,j).delay; 45 | % Get sample time 46 | sampleTime = G(i,j).sampleTime; 47 | 48 | % Numerator and denomerator need to be the same length 49 | if(length(a) > length(b)) 50 | b = [zeros(1, size(a,2) - size(b,2)) b]; 51 | elseif(length(a) < length(b)) 52 | a = [zeros(1, size(b,2) - size(a,2)) a]; 53 | end 54 | 55 | L = 1000; % Number of frequency elements 56 | N = length(b); % Number of denomerators 57 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 58 | % Evaluate transfer function 59 | H = zeros(1, L); 60 | h = sampleTime; 61 | if(sampleTime > 0) % Discrete model 62 | for k = 1 : L 63 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 64 | end 65 | else 66 | for k = 1 : L 67 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 68 | end 69 | end 70 | % Done! 71 | % Plot bode diagram 72 | 73 | 74 | dBstatic = 20*log10(abs(mc.freqresp(G(i,j), 0))); % The static G(0) dB gain 75 | dBinitial = dBstatic - 3; 76 | dropWc = NaN; 77 | drop = 0; 78 | for k = 1 : L 79 | if(20*log10(abs(H(k))) <= dBinitial) 80 | drop = w(k); 81 | break; 82 | end 83 | end 84 | 85 | % Check if drop has changed 86 | if(drop == 0) 87 | opts = struct('WindowStyle','modal', 'Interpreter','tex'); 88 | warndlg('\color{blue} No dB drop of 3 dB was found. Try to increase the frequency range.', 'No dB', opts); 89 | return; 90 | end 91 | 92 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 93 | semilogx(w, 20*log10(abs(H)), 'b'); 94 | hold on 95 | h = semilogx([drop drop], [dBinitial (dBinitial + 3)], 'r'); 96 | ylabel('Magnitude [dB]'); 97 | grid on 98 | legend(h,strcat('3 dB drop at: ', num2str(drop), ' rad/s')) 99 | 100 | 101 | end 102 | end 103 | else 104 | error('Only transfer functions and state space models allowed') 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /matave/+mc/dcgain.m: -------------------------------------------------------------------------------- 1 | % Generates the low frequency gain of a state space model or a transfer function 2 | % Input: sys, G 3 | % Example 1: dc = mc.dcgain(sys) 4 | % Example 2: dc = mc.dcgain(G) 5 | % Author: Daniel Mårtensson 2017 September 6 | 7 | function [dc] = dcgain(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get the type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get necessary info 18 | A = varargin{1}.A; 19 | B = varargin{1}.B; 20 | C = varargin{1}.C; 21 | D = varargin{1}.D; 22 | dc = C*inv(-A)*B + D; 23 | elseif(strcmp(type, 'TF' )) 24 | % Get necessary info 25 | for i = 1:size(varargin{1},1) 26 | for j = 1:size(varargin{1},2) 27 | % Get necessary info 28 | G = varargin{1}(i, j); 29 | % Get the static gain 30 | dc(i, j) = G.num(length(G.num))/G.den(length(G.den)); 31 | 32 | % If divided by zero - Is not a number 33 | if isnan(dc(i, j)) 34 | disp(sprintf('Divided my zero - mc.dcgain(%i, %i) set to 0', i, j)) 35 | dc(i, j) = 0; 36 | end 37 | end 38 | end 39 | else 40 | error('This is not TF or SS'); 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /matave/+mc/evalfr.m: -------------------------------------------------------------------------------- 1 | % Computes the frequency response from a transfer function or state space model at single frequency w 2 | % Input: G, sys, w 3 | % Example 1: frsp = mc.evalfr(sys, w) 4 | % Example 2: frsp = mc.evalfr(G, w) 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [frsp] = evalfr(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error('Missing model') 11 | end 12 | 13 | % Check if there is any input 14 | if(length(varargin) < 2) 15 | error('Missing frequencies') 16 | end 17 | 18 | w = varargin{2}; 19 | 20 | % Get the type 21 | type = varargin{1}.type; 22 | % Check if there is a TF or SS model 23 | if(strcmp(type, 'SS' )) 24 | % SS to TF 25 | G = mc.ss2tf(varargin{1}); 26 | % Call evalfr 27 | [frsp] = mc.evalfr(G, w); 28 | elseif(strcmp(type, 'TF' )) 29 | % If there is a MIMO TF 30 | G = varargin{1}; 31 | % Create H 32 | %L = 1000; % Number of frequency elements 33 | H = zeros(size(G,1),size(G,2), 1); 34 | for i = 1:size(G,1) 35 | for j = 1:size(G,2) 36 | % Get numerator vector and denomerator vector 37 | a = G(i,j).num; 38 | b = G(i,j).den; 39 | % Get delay 40 | delay = G(i,j).delay; 41 | 42 | % Numerator and denomerator need to be the same length 43 | if(length(a) > length(b)) 44 | b = [zeros(1, size(a,2) - size(b,2)) b]; 45 | elseif(length(a) < length(b)) 46 | a = [zeros(1, size(b,2) - size(a,2)) a]; 47 | end 48 | 49 | N = length(b); % Number of denomerators 50 | % Evaluate transfer function 51 | for k = 1 : 1 52 | H(i,j,k) = (a*fliplr((w(k)).^(0 : N-1)).')/(b*fliplr((w(k)).^(0 : N-1)).')*exp(-delay*w(k)); 53 | end 54 | 55 | 56 | % Done! 57 | end 58 | end 59 | frsp = H; 60 | else 61 | error('Only transfer functions and state space models allowed') 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /matave/+mc/feedback.m: -------------------------------------------------------------------------------- 1 | % Computes the new transfer function or state space model of serial connection 2 | % Input: G, sys, sign(optinal) 3 | % Example 1: G = mc.feedback(G1, G2) % Negative feedback is used as default 4 | % Example 2: sys = mc.feedback(sys1, sys2) % Negative feedback is used as default 5 | % Example 3: sys = mc.feedback(sys1, sys2, sign) % sign = '+' Positive feedback 6 | % Author: Daniel Mårtensson, Oktober 2017 7 | 8 | function [model] = feedback(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error ('Missing input') 12 | end 13 | 14 | % Check if there is a second input 15 | if(isempty(varargin{2})) 16 | error ('Missing second model') 17 | end 18 | 19 | % Check feedback sign 20 | if(length(varargin) >= 3) 21 | f = varargin{3}; 22 | if(or(strcmp(f,'+'),strcmp(f,'-'))) 23 | f = varargin{3}; 24 | else 25 | error('Unknow feedback sign'); 26 | end 27 | else 28 | f = '-'; 29 | end 30 | 31 | % Get model type 32 | type = varargin{1}.type; 33 | % Check if there is a TF or SS model 34 | if(strcmp(type, 'SS' )) 35 | % Get info 36 | sys1 = varargin{1}; 37 | sys2 = varargin{2}; 38 | if(sys1.sampleTime == sys2.sampleTime) 39 | % Get matrecies 40 | A1 = sys1.A; 41 | A2 = sys2.A; 42 | B1 = sys1.B; 43 | B2 = sys2.B; 44 | C1 = sys1.C; 45 | C2 = sys2.C; 46 | D1 = sys1.D; 47 | D2 = sys2.D; 48 | 49 | % Get feedback state space 50 | if(strcmp(f, '-')) 51 | A = [(A1 - B1*D2*C1) -B1*C2 ; B2*C1 (A2 - B2*D1*C2)]; 52 | B = [B1; B2*D1]; 53 | C = [C1 -D1*C2]; 54 | D = D1; 55 | else % f = '+' 56 | A = [(A1 + B1*D2*C1) B1*C2 ; B2*C1 (A2 + B2*D1*C2)]; 57 | B = [B1; B2*D1]; 58 | C = [C1 D1*C2]; 59 | D = D1; 60 | end 61 | if(sys1.delay ~= sys2.delay) 62 | error('It need to be the same delay for both of the systems') 63 | end 64 | delay = sys1.delay; 65 | model = mc.ss(delay, A, B, C, D); 66 | model.sampleTime = sys1.sampleTime; 67 | else 68 | error('Need to have the same sampling time') 69 | end 70 | elseif(strcmp(type, 'TF' )) 71 | % Get info 72 | G1 = varargin{1}; 73 | G2 = varargin{2}; 74 | if(G1.sampleTime == G2.sampleTime) 75 | % Get num and den for the model down 76 | G_down = mc.series(G1, G2); 77 | num_down = G_down.num; 78 | den_down = G_down.den; 79 | % Get num and den for model above 80 | G_up = G1; 81 | num_up = G_up.num; 82 | den_up = G_up.den; 83 | % Get delay 84 | delay = G1.delay; 85 | 86 | % Need to have same length for the down model 87 | num_down = [zeros(1, length(den_down) - length(num_down)) num_down]; 88 | den_down = [zeros(1, length(num_down) - length(den_down)) den_down]; 89 | 90 | % -1 feedback or +1 feedback 91 | % 1 - a/b = (b-a)/b 92 | % 1 + a/b = (b+a)/b 93 | if(strcmp(f, '-')) 94 | num_down = den_down + num_down; 95 | else % f = '+' 96 | num_down = den_down - num_down; 97 | end 98 | 99 | % (a/b)/(c/d) = a*d/(b*c) 100 | num = conv(num_up, den_down); 101 | den = conv(den_up, num_down); 102 | 103 | if(delay > 0) 104 | model = mc.tf(num, den, delay); 105 | else 106 | model = mc.tf(num, den); 107 | end 108 | model.sampleTime = G1.sampleTime; 109 | 110 | % Discrete or not? 111 | if (model.sampleTime > 0) 112 | % Replace the delaytime to discrete delay time 113 | model.tfdash = strrep(model.tfdash, 'e', 'z'); 114 | model.tfdash = strrep(model.tfdash, 's', ''); 115 | % Remove all s -> s 116 | model.tfnum = strrep(model.tfnum, 's', 'z'); 117 | model.tfden = strrep(model.tfden, 's', 'z'); 118 | end 119 | else 120 | error('Need to have the same sampling time') 121 | end 122 | else 123 | error('This is not TF or SS'); 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /matave/+mc/findmaxgain.m: -------------------------------------------------------------------------------- 1 | % Find the maximum gain limit when the process becomes unstable. 2 | % Input: sys, G, maxgain 3 | % Example 1: [K] = mc.findmaxgain(sys, maxgain) 4 | % Example 2: [K] = mc.findmaxgain(G, maxgain) 5 | % Example 3: [K] = mc.findmaxgain(G) 6 | % Example 4: [K] = mc.findmaxgain(sys) 7 | % Author: Daniel Mårtensson, 2018 Februari 8 | 9 | function [K] = findmaxgain(varargin) 10 | % Check if there is any input 11 | if(isempty(varargin)) 12 | error('Missing model') 13 | end 14 | 15 | % Get the type 16 | type = varargin{1}.type; 17 | % Check if there is a TF or SS model 18 | if(strcmp(type, 'SS' )) 19 | % SS to TF 20 | G = mc.ss2tf(varargin{1}); 21 | if(length(varargin) >= 2) 22 | maxgain = varargin{2}; 23 | else 24 | %disp('Default gain is 1000'); 25 | maxgain = 1000; 26 | end 27 | % Call findmaxgain 28 | mc.findmaxgain(G, maxgain); 29 | elseif(strcmp(type, 'TF' )) 30 | % If there is a MIMO TF 31 | G = varargin{1}; 32 | for i = 1:size(G,1) 33 | for j = 1:size(G,2) 34 | % Get sample time 35 | sampleTime = G(i,j).sampleTime; 36 | % Get num 37 | num = G(i,j).num; 38 | % Get den 39 | den = G(i, j).den; 40 | % Maximum Gain K 41 | if(length(varargin) >= 2) 42 | maxgain = varargin{2}; 43 | else 44 | %disp('Default gain is 1000'); 45 | maxgain = 1000; 46 | end 47 | 48 | % P-controller vector 49 | P = linspace(0, maxgain, 10000); 50 | 51 | % Turn them into equal length 52 | if length(den) < length(num) 53 | den = [zeros(1, length(num) - length(den)) den]; 54 | elseif length(den) > length(num) 55 | num = [zeros(1, length(den) - length(num)) num]; 56 | end 57 | 58 | % Do numerical calculation 59 | for k = 1:length(P) 60 | % Multiply P with num and add with den 61 | polynomal = P(k)*num + den; % Always begin with P(k) = 0. G(s) = K*num + den is the feedback G(s) = K*G/(1 + K*G) 62 | % Find the roots 63 | PolyRoots = roots(polynomal); 64 | % Check if the system is discrete or not 65 | if sampleTime > 0 66 | % Check if PolyRoots are stable - Discrete way 67 | Temp = and(abs(PolyRoots) <= 1, abs(PolyRoots) >= -1); 68 | Stable = prod(Temp); % If someone is 0, then Stable will be 0 69 | else 70 | % Check if PolyRoots are stable - Discrete way 71 | Temp = real(PolyRoots) <= 0; 72 | Stable = prod(Temp); % If someone is 0, then Stable will be 0 73 | end 74 | 75 | 76 | % Check if Stable is 1 or 0 77 | if Stable == 0 78 | K(i, j) = P(k); % Save this K because this is the limit 79 | break; % Break the for-loop for the numerical calculation 80 | end 81 | 82 | end 83 | 84 | end 85 | end 86 | else 87 | error('Only transfer functions and state space models allowed') 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /matave/+mc/freqresp.m: -------------------------------------------------------------------------------- 1 | % Computes the frequency response from a transfer function or state space model with the frequency vector w 2 | % Input: sys, G, w 3 | % Example 1: [H, wout] = mc.freqresp(sys, w) 4 | % Example 2: [H, wout] = mc.freqresp(G, w) 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [H, wout] = freqresp(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error('Missing model') 11 | end 12 | 13 | % Check if there is any input 14 | if(length(varargin) < 2) 15 | error('Missing frequencies') 16 | end 17 | 18 | w = varargin{2}; 19 | 20 | % Get the type 21 | type = varargin{1}.type; 22 | % Check if there is a TF or SS model 23 | if(strcmp(type, 'SS' )) 24 | % SS to TF 25 | G = mc.ss2tf(varargin{1}); 26 | % Call freqresp 27 | [H, wout] = mc.freqresp(G, w); 28 | elseif(strcmp(type, 'TF' )) 29 | % If there is a MIMO TF 30 | G = varargin{1}; 31 | % Create H 32 | L = length(w); % Number of frequency elements 33 | H = zeros(size(G,1),size(G,2), L); 34 | for i = 1:size(G,1) 35 | for j = 1:size(G,2) 36 | % Get numerator vector and denomerator vector 37 | a = G(i,j).num; 38 | b = G(i,j).den; 39 | % Get delay 40 | delay = G(i,j).delay; 41 | % Get sample time 42 | sampleTime = G(i,j).sampleTime; 43 | 44 | % Numerator and denomerator need to be the same length 45 | if(length(a) > length(b)) 46 | b = [zeros(1, size(a,2) - size(b,2)) b]; 47 | elseif(length(a) < length(b)) 48 | a = [zeros(1, size(b,2) - size(a,2)) a]; 49 | end 50 | 51 | N = length(b); % Number of denomerators 52 | wout = w; 53 | % Evaluate transfer function 54 | h = sampleTime; 55 | if(sampleTime > 0) % Discrete model 56 | for k = 1 : L 57 | H(i,j,k) = (a*fliplr((exp(1i*wout(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*wout(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*wout(k)*h)); 58 | end 59 | else % Continous 60 | for k = 1 : L 61 | H(i,j,k) = (a*fliplr((1i*wout(k)).^(0 : N-1)).')/(b*fliplr((1i*wout(k)).^(0 : N-1)).')*exp(-delay*1i*wout(k)); 62 | end 63 | end 64 | 65 | % Done! 66 | end 67 | end 68 | else 69 | error('Only transfer functions and state space models allowed') 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /matave/+mc/gensig.m: -------------------------------------------------------------------------------- 1 | % Generates a signal of sin, square or pulse 2 | % Input: type, amp, Tf, Ts 3 | % Example 1: [u, t] = mc.gensig(type, amp, Tf, Ts) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [u, t] = gensig(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error('Missing input') 10 | end 11 | % Get type 12 | if(length(varargin) > 0) 13 | type = varargin{1}; 14 | else 15 | error('Missing type') 16 | end 17 | % Get the amplitude 18 | if(length(varargin) > 1) 19 | amp = varargin{2}; 20 | else 21 | amp = 1; 22 | end 23 | % Get the Tf 24 | if(length(varargin) > 2) 25 | Tf = varargin{3}; 26 | else 27 | Tf = 1; 28 | end 29 | % Get time 30 | if(length(varargin) > 3) 31 | Ts = varargin{4}; 32 | else 33 | Ts = 10; 34 | end 35 | 36 | 37 | switch type 38 | case 'sin' 39 | t = linspace(0,Ts, 1000); 40 | u = amp*sin(Tf*t + Ts); 41 | case 'square' 42 | t = linspace(0,Ts, 1000); 43 | u = []; 44 | n = 1; 45 | if(Tf == 1) 46 | Tf = 2; 47 | end 48 | for i = 1:length(t) 49 | if(i >= length(t)/(Tf)*n) 50 | u(i) = amp; 51 | if(i >= length(t)/(Tf)*(n + 1)) 52 | n = n + 2; 53 | end 54 | else 55 | u(i) = 0; 56 | end 57 | end 58 | case 'pulse' 59 | t = linspace(0,Ts, 1000); 60 | u = []; 61 | n = 1; 62 | if(Tf == 1) 63 | Tf = 2; 64 | end 65 | for i = 1:length(t) 66 | if(i >= length(t)/(Tf)*n) 67 | u(i) = amp; 68 | n = n + 1; 69 | else 70 | u(i) = 0; 71 | end 72 | end 73 | u(end) = 0; % Remove the last peak 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /matave/+mc/gram.m: -------------------------------------------------------------------------------- 1 | % Generates the gramian a state space model, where opt = 'c' or opt = 'o' 2 | % Input: sys, opt 3 | % Example 1: X = mc.gram(sys, opt) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [X] = gram(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing model') 10 | end 11 | 12 | if(length(varargin) >= 2) 13 | opt = varargin{2}; 14 | else 15 | error('Missing option: ´c´ or ´o´'); 16 | end 17 | 18 | % Get model type 19 | type = varargin{1}.type; 20 | % Check if there is a TF or SS model 21 | if(strcmp(type, 'SS' )) 22 | % Get sys 23 | sys = varargin{1}; 24 | % Get sample time 25 | sampleTime = varargin{1}.sampleTime; 26 | 27 | if(sampleTime > 0) 28 | % Discrete way 29 | A = sys.A; 30 | B = sys.B; 31 | C = sys.C; 32 | 33 | if(strcmp(opt, 'c')) 34 | X = mc.lyap(A, B*B', 'd'); 35 | elseif(strcmp(opt, 'o')) 36 | X = mc.lyap(A', C'*C, 'd'); 37 | else 38 | disp(sprintf('Unknown option: %s', opt)); 39 | end 40 | 41 | else 42 | % Continous way 43 | A = sys.A; 44 | B = sys.B; 45 | C = sys.C; 46 | 47 | if(strcmp(opt, 'c')) 48 | X = mc.lyap(A, B*B'); 49 | elseif(strcmp(opt, 'o')) 50 | X = mc.lyap(A', C'*C); 51 | else 52 | disp(sprintf('Unknown option: %s', opt)); 53 | end 54 | 55 | end 56 | elseif(strcmp(type, 'TF' )) 57 | disp('Only state space model are allowed') 58 | else 59 | error('This is not TF or SS'); 60 | end 61 | 62 | end -------------------------------------------------------------------------------- /matave/+mc/hsvd.m: -------------------------------------------------------------------------------- 1 | % Get the hankel singular values of a state space model 2 | % Input: SS, p(optional) 3 | % Example 1: hsv = mc.hsvd(sys) 4 | % Example 1: hsv = mc.hsvd(sys, p) % p = 'plot' 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [hsv] = hsvd(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing model') 11 | end 12 | 13 | if(length(varargin) >= 2) 14 | p = varargin{2}; 15 | else 16 | p = 'n'; 17 | end 18 | 19 | % Get model type 20 | type = varargin{1}.type; 21 | % Check if there is a TF or SS model 22 | if(strcmp(type, 'SS' )) 23 | % Get sys 24 | sys = varargin{1}; 25 | % Get gramians 26 | P = mc.gram(sys, 'c'); 27 | Q = mc.gram(sys, 'o'); 28 | % Get hankel singular values 29 | hsv = sqrt(eig(P*Q)); 30 | % Plot them too! 31 | if(strcmp(p,'plot')) 32 | bar(hsv) 33 | title('Hankel Singular Values (State Contributions)') 34 | xlabel('State') 35 | ylabel('State Energy') 36 | legend('Stable modes') 37 | end 38 | elseif(strcmp(type, 'TF' )) 39 | disp('Only state space model are allowed') 40 | else 41 | error('This is not TF or SS'); 42 | end 43 | end -------------------------------------------------------------------------------- /matave/+mc/imc.m: -------------------------------------------------------------------------------- 1 | % An IMC controller 2 | % Input: G(System), K(Controller), Go(Forward Model) 3 | % Example 1: [G] = mc.imc(G, K, Go) 4 | % Author: Daniel Mårtensson, Februari 2018 5 | 6 | 7 | function [model] = imc(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Check if there is a second input 14 | if(isempty(varargin{2})) 15 | error ('Missing controller transfer function') 16 | end 17 | 18 | % Check if there is a third input 19 | if(isempty(varargin{3})) 20 | error ('Missing forward Modelr') 21 | end 22 | 23 | % Get model type 24 | type = varargin{1}.type; 25 | % Check if there is a TF or SS model 26 | if(strcmp(type, 'TF' )) 27 | % Get system G 28 | G = varargin{1}; 29 | % Get controller K 30 | K = varargin{2}; 31 | % Get system Go 32 | Go = varargin{3}; 33 | 34 | % They must have the same sample time 35 | if(and(G.sampleTime == K.sampleTime, G.sampleTime == Go.sampleTime)) 36 | % Get num and den 37 | num1 = G.num; 38 | den1 = G.den; 39 | num2 = Go.num; 40 | den2 = Go.den; 41 | 42 | % Extend - pad - Equal length 43 | num1 = [zeros(1, length(num2) - length(num1)) num1]; 44 | den1 = [zeros(1, length(den2) - length(den1)) den1]; 45 | num2 = [zeros(1, length(num1) - length(num2)) num2]; 46 | den2 = [zeros(1, length(den1) - length(den2)) den2]; 47 | 48 | % Substract - Importat to have -conv(num1, den2) + conv(num2, den1) 49 | % because we are doing negative feedback - This is parallel method of two TF's 50 | num = conv(num1, den2) - conv(num2, den1); 51 | den = conv(den1, den2); 52 | 53 | % Create a transfer function of num and den 54 | GGo = mc.tf(num, den); 55 | % Need to have the same sample time as G! 56 | GGo.sampleTime = G.sampleTime; 57 | % Do feedback witg GGo and K. 58 | F = mc.feedback(K, GGo); 59 | % Do serial connection with F and G. 60 | model = mc.series(F, G); 61 | 62 | 63 | else 64 | error('Not the same sample time') 65 | end 66 | else 67 | error('Only transfer functions'); 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /matave/+mc/impulse.m: -------------------------------------------------------------------------------- 1 | % Do a impulse response of a transfer function or a state space model 2 | % Input: G, sys, t(optional) 3 | % Example 1: [y,t,x] = mc.impulse(G, t) 4 | % Example 2: [y,t,x] = mc.impulse(G) 5 | % Example 3: [y,t,x] = mc.impulse(sys, t) 6 | % Author: Daniel Mårtensson, September 2017 7 | % Update 2022-10-08: Simulate ARMA model 8 | 9 | function [y,t,X] = impulse(varargin) 10 | % Check if there is some input arguments or it's not a model 11 | if(isempty(varargin{1})) 12 | error ('Missing input') 13 | end 14 | 15 | % Check if there is a model 16 | if(strcmp(varargin{1}.type,'SS')) 17 | 18 | % Get time 19 | if(length(varargin) >= 2) 20 | t = varargin{2}; 21 | else 22 | disp('Time assumed to be 10 seconds'); 23 | t = 10; 24 | end 25 | 26 | % Get sample time to compute the new time vector 27 | sampleTime = varargin{1}.sampleTime; 28 | if(sampleTime > 0) 29 | t = 0:sampleTime:t; 30 | else 31 | t = 0:0.01:t; % Sample time assumed to be 0.01 32 | end 33 | 34 | % Multiple signals...or not! 35 | u = zeros(size(varargin{1}.B, 2), length(t)); % Creates 1 1 1 1 1 1 1 36 | u(:,1) = ones(size(u,1), 1); 37 | x0 = zeros(size(varargin{1}.A, 1), 1); % Assume x0 = [0; 0; 0; ..... ; 0] 38 | 39 | % Call lsim! 40 | [y,t,X] = mc.lsim(varargin{1}, u, t, x0); 41 | elseif(strcmp(varargin{1}.type,'TF')) 42 | % TF to SS 43 | sys = mc.tf2ss(varargin{1}, 'OCF'); 44 | 45 | % Get time 46 | if(length(varargin) >= 2) 47 | t = varargin{2}; 48 | else 49 | disp('Time assumed to be 10 seconds'); 50 | t = 10; 51 | end 52 | 53 | % Call impulse 54 | [y,t,X] = mc.impulse(sys,t); 55 | elseif(strcmp(varargin{1}.type,'ARMA')) 56 | 57 | % Get end time 58 | if(length(varargin) >= 2) 59 | t = varargin{2}; 60 | else 61 | disp('Time assumed to be 10 seconds'); 62 | t = 10; 63 | end 64 | 65 | % Create time vector 66 | sampleTime = varargin{1}.sampleTime; 67 | if(sampleTime > 0) 68 | t = 0:sampleTime:t; 69 | else 70 | t = 0:0.01:t; % Sample time assumed to be 0.01 71 | end 72 | 73 | % Create input u 74 | u = linspace(0, 0, length(t)); 75 | u(1) = 1; 76 | 77 | % Call lsim! 78 | [y,t,X] = mc.lsim(varargin{1}, u, t); 79 | else 80 | error('Not a state space model or a transfer function') 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /matave/+mc/initial.m: -------------------------------------------------------------------------------- 1 | % Simulate a transfer function or state space model with initial state vector x0 2 | % and time constant t, not time vector 3 | % Input: sys, t, x0 4 | % Example 1: [y,t,x] = mc.initial(sys, t, x0) 5 | % Author: Daniel Mårtensson, September 2017 6 | 7 | function [y,t,X] = initial(varargin) 8 | % Check if there is some input arguments or it's not a model 9 | if(isempty(varargin{1})) 10 | error ('Missing input') 11 | end 12 | 13 | % Check if there is a model 14 | if(strcmp(varargin{1}.type,'SS')) 15 | 16 | % Get time 17 | if(length(varargin) >= 2) 18 | t = varargin{2}; 19 | else 20 | disp('Time assumed to be 10 seconds'); 21 | t = 10; 22 | end 23 | 24 | % Get sample time to compute the new time vector 25 | sampleTime = varargin{1}.sampleTime; 26 | if(sampleTime > 0) 27 | t = 0:sampleTime:t; 28 | else 29 | t = 0:0.01:t; % Sample time assumed to be 0.01 30 | end 31 | 32 | % Multiple signals...or not! 33 | u = zeros(size(varargin{1}.B, 2), length(t)); % Creates 0 0 0 0 0 0 0 34 | 35 | % Get initial conditions 36 | if(length(varargin) >= 3) 37 | x0 = varargin{3}; 38 | x0 = x0(:); % Turn them into a vector 39 | if(size(varargin{1}.A, 1) ~= size(x0, 1)) 40 | error('The initial conditions vector has not the same row length as matrix A') 41 | end 42 | else 43 | error('Missing initial conditions'); 44 | end 45 | 46 | % Call lsim! 47 | [y,t,X] = mc.lsim(varargin{1}, u, t, x0); 48 | elseif(strcmp(varargin{1}.type,'TF')) 49 | error('Only for state space models') 50 | else 51 | error('Not a state space model or a transfer function') 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /matave/+mc/listOfFunctions: -------------------------------------------------------------------------------- 1 | acker.m 2 | allmargin.m 3 | append.m 4 | are.m 5 | balreal.m 6 | bode.m 7 | bodemag.m 8 | c2d.m 9 | c2dt.m 10 | covar.m 11 | ctrb.m 12 | d2c.m 13 | d2d.m 14 | damp.m 15 | db2mag.m 16 | dbdrop.m 17 | dcgain.m 18 | evalfr.m 19 | feedback.m 20 | findmaxgain.m 21 | freqresp.m 22 | gensig.m 23 | gram.m 24 | hsvd.m 25 | imc.m 26 | impulse.m 27 | initial.m 28 | loop.m 29 | lmpc.m 30 | lqe.m 31 | lqgreg.m 32 | lqi.m 33 | lqr.m 34 | lsim.m 35 | lyap.m 36 | mag2db.m 37 | margin.m 38 | intss.m 39 | minreal.m 40 | modred.m 41 | satlsim.m 42 | nyquist.m 43 | obsv.m 44 | pade.m 45 | parallel.m 46 | pid.m 47 | pipd.m 48 | pole.m 49 | pzmap.m 50 | ramp.m 51 | reg.m 52 | rlocus.m 53 | sensitivity.m 54 | series.m 55 | sigma.m 56 | smithpredict.m 57 | ss.m 58 | ss2tf.m 59 | step.m 60 | tf.m 61 | tf2ss.m 62 | tzero.m 63 | updatematavecontrol.m 64 | zero.m 65 | zpk.m 66 | -------------------------------------------------------------------------------- /matave/+mc/loop.m: -------------------------------------------------------------------------------- 1 | % Create the Complementary sensitivity, sensitivity of an open loop transfer function L 2 | % Input: L 3 | % Example 1: [S, T] = mc.loop(L) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | function [S, T] = loop(varargin) 6 | % Check if there is any input 7 | if(isempty(varargin)) 8 | error ('Missing transfer function') 9 | end 10 | 11 | % Get model type 12 | type = varargin{1}.type; 13 | % Check if there is a TF or SS model 14 | if(strcmp(type, 'SS' )) 15 | error('Only loop transfer functions'); 16 | elseif(strcmp(type, 'TF' )) 17 | % Get open loop transfer function 18 | L = varargin{1}; 19 | % Create S 20 | N = mc.tf(1,1); % Create a constant only for sensitivity function 21 | S = mc.feedback(L, N); 22 | % Create T 23 | T = mc.feedback(L, L); 24 | else 25 | error('This is not TF or SS'); 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /matave/+mc/lqe.m: -------------------------------------------------------------------------------- 1 | % Compute the LQE kalman gain matrix with the weighing matricies Q and R and state space model 2 | % Input: SS, Q, R 3 | % Example 1: [K] = mc.lqe(sys, Q, R) 4 | % Author: Daniel Mårtensson, October 2017 5 | 6 | function [K] = lqe(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing model') 10 | end 11 | 12 | % Get Q R 13 | if(length(varargin) >= 2) 14 | Q = varargin{2}; 15 | R = varargin{3}; 16 | else 17 | error('Missing Q or R'); 18 | end 19 | 20 | % Get model type 21 | type = varargin{1}.type; 22 | % Check if there is a TF or SS model 23 | if(strcmp(type, 'SS' )) 24 | % Get model 25 | sys = varargin{1}; 26 | % Change matrecies due to the Kalman Duality! 27 | sys.A = sys.A'; % Transpose 28 | sys.B = sys.C'; % Transpose 29 | K = (mc.lqr(sys, Q, R))'; 30 | elseif(strcmp(type, 'TF' )) 31 | disp('Only state space models only') 32 | else 33 | error('This is not TF or SS'); 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /matave/+mc/lqi.m: -------------------------------------------------------------------------------- 1 | % Compute the LQI integral gain matrix control law L with the weighing matricies Q and R and state space model 2 | % Input: SS, Q, R 3 | % Example 1: [L, Li] = mc.lqi(sys, Q, R) 4 | % Example 2: [L, Li, sysi] = mc.lqi(sys, Q, R) 5 | % Author: Daniel Mårtensson, October 2017 6 | % Update 2019-06-07: Returning the model wth integral action 7 | 8 | function [L, Li, sys] = lqi(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error ('Missing model') 12 | end 13 | 14 | % Get Q R 15 | if(length(varargin) >= 2) 16 | Q = varargin{2}; 17 | R = varargin{3}; 18 | else 19 | error('Missing Q or R'); 20 | end 21 | 22 | % Get model type 23 | type = varargin{1}.type; 24 | % Check if there is a TF or SS model 25 | if(strcmp(type, 'SS' )) 26 | % Get model 27 | sys = varargin{1}; 28 | A = sys.A; 29 | B = sys.B; 30 | C = sys.C; 31 | D = sys.D; 32 | 33 | % Get info 34 | ny = size(C, 1); % Number outputs 35 | nu = size(B, 2); % Number inputs 36 | nx = size(A, 1); % Number states 37 | 38 | % Create the augmented state space model 39 | if(sys.sampleTime > 0) 40 | sys.A = [A zeros(nx, ny); -C ones(ny, ny)]; 41 | sys.B = [B; -D]; 42 | sys.C = [C zeros(ny, ny)]; 43 | sys.D = D; 44 | else 45 | sys.A = [A zeros(nx, ny); -C zeros(ny, ny)]; 46 | sys.B = [B; -D]; 47 | sys.C = [C zeros(ny, ny)]; 48 | sys.D = D; 49 | end 50 | 51 | 52 | % Get the LQR + LQI control law 53 | ControlLaw = mc.lqr(sys, Q, R); 54 | % Important to have a negative sign! 55 | Li = -ControlLaw(:, (1 + size(C, 2)):end); % We add +1 beacuse we want -Li from [L -Li]. 56 | L = ControlLaw(:, 1:size(C, 2)); 57 | 58 | elseif(strcmp(type, 'TF' )) 59 | disp('Only state space models only') 60 | else 61 | error('This is not TF or SS'); 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /matave/+mc/lqr.m: -------------------------------------------------------------------------------- 1 | % Compute the LQR gain matrix control law L with the weighing matricies Q and R and state space model 2 | % Input: sys, Q, R 3 | % Example 1: [L] = mc.lqr(sys, Q, R) 4 | % Author: Daniel Mårtensson, October 2017 5 | 6 | function [L] = lqr(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing model') 10 | end 11 | 12 | % Get Q R 13 | if(length(varargin) >= 2) 14 | Q = varargin{2}; 15 | R = varargin{3}; 16 | else 17 | error('Missing Q or R'); 18 | end 19 | 20 | % Get model type 21 | type = varargin{1}.type; 22 | % Check if there is a TF or SS model 23 | if(strcmp(type, 'SS' )) 24 | % Get model 25 | sys = varargin{1}; 26 | % Solve the Algebraic Riccati Equation 27 | X = mc.are(sys, Q, R); 28 | % Return the control law L 29 | if(sys.sampleTime > 0) 30 | L = inv(sys.B'*X*sys.B + R)*(sys.B'*X*sys.A); 31 | else 32 | L = inv(R)*sys.B'*X; 33 | end 34 | elseif(strcmp(type, 'TF' )) 35 | disp('Only state space models only') 36 | else 37 | error('This is not TF or SS'); 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /matave/+mc/lyap.m: -------------------------------------------------------------------------------- 1 | % Compute solution X of the Lyapunov equation 2 | % Input: A, Q, opt(optinal) 3 | % Example 1: [X] = mc.lyap(A, B*B'); % t = time contious as default 4 | % Example 2: [X] = mc.lyap(A, B*B', 'd'); % d = discrete 5 | % Author: Daniel Mårtensson, Oktober 2017 6 | 7 | function [X] = lyap(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing A, Q') 11 | end 12 | 13 | A = varargin{1}; 14 | Q = varargin{2}; 15 | 16 | if(length(varargin) <= 2) 17 | opt = 't'; 18 | else 19 | opt = varargin{3}; 20 | end 21 | 22 | if(strcmp(opt, 'd')) 23 | p = kron(conj(A), A); 24 | K = eye(size(p)) - p; 25 | X = K\Q(:); 26 | X = reshape(X, size(A)); 27 | elseif(strcmp(opt, 't')) 28 | K = kron(eye(size(A)), A) + kron(conj(A), eye(size(A))); 29 | X = K\-Q(:); 30 | X = reshape(X, size(A)); 31 | else 32 | disp(sprintf('Unknown option: %s', opt)) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /matave/+mc/mag2db.m: -------------------------------------------------------------------------------- 1 | % Convert magnitude to decibel 2 | % Input mag 3 | % Example 1: [dB] = mc.mag2db(mag) 4 | % Author: Daniel Mårtensson 2017, Oktober 5 | function [dB] = mag2db(mag) 6 | mag(mag < 0) = NaN; 7 | dB = 20*log10(mag); 8 | end 9 | -------------------------------------------------------------------------------- /matave/+mc/margin.m: -------------------------------------------------------------------------------- 1 | % Plot the nyquist diagram of a state space model with margins or a transfer function with margins 2 | % between frequencies w1 and w2 3 | % Input: sys, G, w1, w2 4 | % Example 1: [Am, phim, wpi, wc] = mc.margin(sys, w1, w2) 5 | % Example 2: [Am, phim, wpi, wc] = mc.margin(G, w1, w2) 6 | % Author: Daniel Mårtensson 2017, Oktober 7 | 8 | function [Am, phim, wpi, wc] = margin(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | w2 = varargin{3}; 21 | end 22 | 23 | 24 | % Get the type 25 | type = varargin{1}.type; 26 | % Check if there is a TF or SS model 27 | if(strcmp(type, 'SS' )) 28 | % SS to TF 29 | G = mc.ss2tf(varargin{1}); 30 | % Call marin 31 | mc.margin(G, w1, w2); 32 | elseif(strcmp(type, 'TF' )) 33 | % If there is a MIMO TF 34 | G = varargin{1}; 35 | for i = 1:size(G,1) 36 | for j = 1:size(G,2) 37 | % Get numerator vector and denomerator vector 38 | a = G(i,j).num; 39 | b = G(i,j).den; 40 | % Get delay 41 | delay = G(i,j).delay; 42 | % Get sample time 43 | sampleTime = G(i,j).sampleTime; 44 | 45 | % Numerator and denomerator need to be the same length 46 | if(length(a) > length(b)) 47 | b = [zeros(1, size(a,2) - size(b,2)) b]; 48 | elseif(length(a) < length(b)) 49 | a = [zeros(1, size(b,2) - size(a,2)) a]; 50 | end 51 | 52 | L = 10000; % Number of frequency elements 53 | N = length(b); % Number of denomerators 54 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 55 | % Evaluate transfer function 56 | H = zeros(1, L); 57 | h = sampleTime; 58 | if(sampleTime > 0) % Discrete model 59 | for k = 1 : L 60 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 61 | end 62 | else 63 | for k = 1 : L 64 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 65 | end 66 | end 67 | % Done! 68 | % Plot bode diagram 69 | 70 | % Get wc, phim 71 | wc = inf; 72 | phim = inf; 73 | flag = false; 74 | for k = 1:length(H) 75 | % The dB need to be over 0 for flag = true 76 | if ((20*log10(abs(H(k))) > 0)) 77 | flag = true; 78 | end 79 | % When dB is under 0 and flag = true 80 | if (and(20*log10(abs(H(k))) <= 0, flag == true )) 81 | wc = w(k); 82 | phim = 180 + angle(H(k)) * 180/pi; 83 | break; 84 | end 85 | end 86 | 87 | % Get wpi, Am 88 | wpi = inf; 89 | Am = inf; 90 | for k = 1:length(H) 91 | if (angle(H(k)) * 180/pi <= -180) 92 | wpi = w(k); 93 | Am = 20*log10(abs(H(k))); 94 | break; 95 | end 96 | end 97 | 98 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 99 | subplot(2,1,1) 100 | semilogx(w, 20*log10(abs(H)), wc, 0, 'x', linspace(wpi, wpi), linspace(0, Am)); 101 | legend('Mag', 'Wc', 'Am') 102 | ylabel('Magnitude [dB]'); 103 | title(strcat('Am = ', num2str(abs(Am)), ' dB (at ', num2str(wpi), ' rad/s) , ', 'Phim = ', num2str(abs(phim)), ' deg (at ', num2str(wc), ' rad/s)')) 104 | grid on 105 | subplot(2,1,2) 106 | 107 | semilogx(w, angle(H) * 180/pi, linspace(wc, wc), linspace(-180, phim - 180), wpi, -180, 'x'); 108 | ylabel('Phase [deg]'); 109 | xlabel('Frequency [rad/s]'); 110 | grid on 111 | legend('Phase', 'Phim', 'Am') 112 | 113 | % Am 114 | Am = abs(Am); 115 | 116 | end 117 | end 118 | else 119 | error('Only transfer functions and state space models allowed') 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /matave/+mc/minreal.m: -------------------------------------------------------------------------------- 1 | % Generates the minimal realization of a transfer function by cancle out poles against zeros wiht tolerance tol 2 | % Gernerates the minimal Ho-Kalman-Kung realization of a state space model by cansle out 3 | % non-controllable and non-observable states 4 | % The arbitrary variables r and s controlls the dimension of Hankel Matrix 5 | % Input: TF or SS, tol(optinal), r, s 6 | % Example 1: G = mc.minreal(G, tol) 7 | % Example 2: sys = mc.minreal(sys, s, r) 8 | % Author: Daniel Mårtensson, 2017 Oktober 9 | 10 | function [model] = minreal(varargin) 11 | % Check if there is any input 12 | if(isempty(varargin)) 13 | error ('Missing model') 14 | end 15 | 16 | % Get tolerance 17 | if(length(varargin) < 2) 18 | tol = 1e-6; 19 | else 20 | tol = varargin{2}; 21 | end 22 | 23 | % Get model type 24 | type = varargin{1}.type; 25 | % Check if there is a TF or SS model 26 | if(strcmp(type, 'SS' )) 27 | 28 | % Get s and r 29 | if(length(varargin) > 2) 30 | s = varargin{2}; 31 | r = varargin{3}; 32 | else 33 | error('Missing r or s'); 34 | end 35 | 36 | % Create discrete model - Important for minimal realization 37 | if(varargin{1}.sampleTime > 0) % Allready Discrete! 38 | sysd = varargin{1}; 39 | else % Time continous 40 | sysd = mc.c2d(varargin{1}, 0.1); % Sample time is 0.1 second 41 | end 42 | 43 | % Hankel matrix 0 44 | k = 0; 45 | H0 = mc.obsv(sysd, r)*sysd.A^k*mc.ctrb(sysd, s); 46 | [U,E,V] = svd(H0,'econ'); 47 | 48 | % New rank n for finding En, Un, Vn 49 | n = rank(E); 50 | En = E(1:n, 1:n); 51 | Un = U(:, 1:n); 52 | Vn = V(:, 1:n); 53 | 54 | % Create identity matrecies 55 | p = size(sysd.C, 1); % number of outputs 56 | m = size(sysd.B, 2); % number of inputs 57 | Ey = [eye(p,p) zeros(p, (r-1)*p)]'; 58 | Eu = [eye(m,m) zeros(m, (s-1)*m)]'; 59 | 60 | % Hankel matrix 1 61 | k = 1; 62 | H1 = mc.obsv(sysd, r)*sysd.A^k*mc.ctrb(sysd, s); 63 | 64 | % The new minimal state space realization 65 | A = En^(-1/2)*Un'*H1*Vn*En^(-1/2); 66 | B = En^(1/2)*Vn'*Eu; 67 | C = Ey'*Un*En^(1/2); 68 | D = sysd.D; 69 | model = mc.ss(varargin{1}.delay, A, B, C, D); 70 | if(varargin{1}.sampleTime > 0) 71 | % The model was discrete in the input 72 | model.sampleTime = varargin{1}.sampleTime; 73 | else 74 | % The model was continous in the input 75 | model.sampleTime = 0.1; 76 | model = mc.d2c(model); % Turn it back! 77 | end 78 | % Done! 79 | 80 | elseif(strcmp(type, 'TF' )) 81 | % Get poles 82 | model = varargin{1}; 83 | p = mc.pole(model); 84 | % Get zeros 85 | [z, k] = mc.zero(model); 86 | % Get delay 87 | delay = model.delay; 88 | % Get sample time 89 | sampleTime = model.sampleTime; 90 | 91 | % Check in which element they are equal 92 | [a, b, c] = intersect(round(z*1/tol)*tol, round(p*1/tol)*tol); 93 | % Remove zeros and poles if they are equal! 94 | z(b) = []; 95 | p(c) = []; 96 | 97 | % Check if the model has delay 98 | if(delay > 0) 99 | model = mc.zpk(z, p, k, delay); 100 | else 101 | model = mc.zpk(z, p, k); 102 | end 103 | 104 | % Insert sample time 105 | model.sampleTime = sampleTime; 106 | 107 | % Discrete or not? 108 | if (model.sampleTime > 0) 109 | % Replace the delaytime to discrete delay time 110 | model.tfdash = strrep(model.tfdash, 'e', 'z'); 111 | model.tfdash = strrep(model.tfdash, 's', ''); 112 | % Remove all s -> s 113 | model.tfnum = strrep(model.tfnum, 's', 'z'); 114 | model.tfden = strrep(model.tfden, 's', 'z'); 115 | end 116 | 117 | else 118 | error('This is not TF or SS'); 119 | end 120 | 121 | end -------------------------------------------------------------------------------- /matave/+mc/modred.m: -------------------------------------------------------------------------------- 1 | % Generates the balanced recuded state space model of a balanced state space model 2 | % Remove states with the tolerance of Hankel singular values 3 | % Input: SS, tol 4 | % Example 1: model = mc.modred(sys, tol) 5 | % Author: Daniel Mårtensson, 2017 October 6 | 7 | function [model] = modred(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing balanced state space model') 11 | end 12 | 13 | if(length(varargin) >= 2) 14 | tol = varargin{2}; 15 | else 16 | error('Missing tolerance for the hankel signular values'); 17 | end 18 | 19 | % Get model type 20 | type = varargin{1}.type; 21 | % Check if there is a TF or SS model 22 | if(strcmp(type, 'SS' )) 23 | % Get sys 24 | sys = varargin{1}; 25 | A = sys.A; 26 | B = sys.B; 27 | C = sys.C; 28 | D = sys.D; 29 | sampleTime = sys.sampleTime; 30 | delay = sys.delay; 31 | 32 | % Get hankel singular values 33 | hsv = diag(mc.hsvd(sys)); 34 | hsv = hsv(hsv >= tol); 35 | n = size(hsv, 1); % Dimension states 36 | A = A(1:n, 1:n); 37 | B = B(1:n, :); 38 | C = C(:,1:n); 39 | 40 | % Create the state space model 41 | model = mc.ss(delay, A, B, C, D); 42 | model.sampleTime = sampleTime; 43 | 44 | elseif(strcmp(type, 'TF' )) 45 | disp('Only state space model are allowed') 46 | else 47 | error('This is not TF or SS'); 48 | end 49 | 50 | end -------------------------------------------------------------------------------- /matave/+mc/nlsim.m: -------------------------------------------------------------------------------- 1 | % Do a nonlinear simulation of a nonlinear state space model 2 | % Input: model, u(inputs), x0(initial state vector), stepTime, simulationMethod('ode23', 'ode45', 'ode15s', 'ode23s'), options 3 | % Example 1: [x,t] = mc.nlsim(model, u, x0, stepTime); 4 | % Example 2: [x,t] = mc.nlsim(model, u, x0, stepTime, 'ode23'); 5 | % Example 3: [x,t] = mc.nlsim(model, u, x0, stepTime, 'ode23', options); 6 | % Author: Daniel Mårtensson, April 2022 7 | 8 | function [x,t] = nlsim(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing inputs') 12 | end 13 | 14 | % Get model 15 | if(length(varargin) >= 1) 16 | model = varargin{1}; 17 | else 18 | error('Missing model') 19 | end 20 | 21 | % Get inputs 22 | if(length(varargin) >= 2) 23 | u = varargin{2}; 24 | else 25 | error('Missing inputs') 26 | end 27 | 28 | % Get initial state vector 29 | if(length(varargin) >= 3) 30 | x0 = varargin{3}; 31 | else 32 | error('Missing initial state vector') 33 | end 34 | 35 | % Get stepTime 36 | if(length(varargin) >= 4) 37 | stepTime = varargin{4}; 38 | else 39 | error('Missing sample time') 40 | end 41 | 42 | % Get simulation method 43 | if(length(varargin) >= 5) 44 | simulationMethod = varargin{5}; 45 | else 46 | simulationMethod = 'ode45'; 47 | end 48 | 49 | % Get options 50 | if(length(varargin) >= 6) 51 | options = varargin{6}; 52 | else 53 | options = odeset(); 54 | end 55 | 56 | % Savings 57 | L = length(u); 58 | x = zeros(size(x0, 1), L); 59 | t = zeros(1, L); 60 | 61 | % Loop 62 | for i = 1:L 63 | % Save time and output 64 | x(:, i) = x0; 65 | t(i) = stepTime*(i-1); 66 | 67 | % Simulate ode45, ode23, ode15s, ode23s 68 | tspan = [stepTime*(i-1) stepTime*i]; 69 | if(strcmp('ode45', simulationMethod)) 70 | [time, output] = ode45(@(t, x) model(t, x, u(:, i)), tspan, x0, options); 71 | elseif(strcmp('ode23', simulationMethod)) 72 | [time, output] = ode23(@(t, x) model(t, x, u(:, i)), tspan, x0, options); 73 | elseif(strcmp('ode15s', simulationMethod)) 74 | [time, output] = ode15s(@(t, x) model(t, x, u(:, i)), tspan, x0, options); 75 | elseif(strcmp('ode23s', simulationMethod)) 76 | [time, output] = ode23s(@(t, x) model(t, x, u(:, i)), tspan, x0, options); 77 | else 78 | error('Choose simulation method such as ode45, ode23, ode15s, ode23s'); 79 | end 80 | 81 | % Next state 82 | x0 = output(end, :)'; 83 | end 84 | 85 | % This is for the sub plot - How many max rows should we have 86 | rows = max(size(x,1), size(u, 1)); 87 | 88 | % Plot - How many subplots? 89 | for i = 1:size(x,1) 90 | subplot(rows,1,i) 91 | plot(t, x(i,:)); 92 | ylabel(strcat('x', num2str(i))); 93 | xlabel(strcat(num2str(stepTime), ' time unit/step time')); 94 | grid on 95 | end 96 | 97 | % Plot the input signals as well 98 | for i = 1:size(u, 1) 99 | subplot(rows, 1, i) 100 | hold on 101 | plot(t, u(i, :)) 102 | grid on 103 | if(i <= size(x,1)) 104 | legend(strcat('x', num2str(i)), strcat('u', num2str(i))) 105 | else 106 | legend(strcat('u', num2str(i))) 107 | end 108 | end 109 | 110 | end -------------------------------------------------------------------------------- /matave/+mc/nyquist.m: -------------------------------------------------------------------------------- 1 | % Plot the nyquist diagram of a state space model or a transfer function 2 | % between given frequencies w1 and w2 3 | % Input: sys, G 4 | % Example 1: mc.nyquist(sys, w1, w2) 5 | % Example 2: mc.nyquist(G, w1, w2) 6 | % Author: Daniel Mårtensson, 2017 Oktober 7 | 8 | function [reval] = nyquist(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | w2 = varargin{3}; 21 | end 22 | 23 | % Get the type 24 | type = varargin{1}.type; 25 | % Check if there is a TF or SS model 26 | if(strcmp(type, 'SS' )) 27 | % SS to TF 28 | G = mc.ss2tf(varargin{1}); 29 | % Call nyquist 30 | mc.nyquist(G, w1, w2); 31 | elseif(strcmp(type, 'TF' )) 32 | % If there is a MIMO TF 33 | G = varargin{1}; 34 | for i = 1:size(G,1) 35 | for j = 1:size(G,2) 36 | % Get numerator vector and denomerator vector 37 | a = G(i,j).num; 38 | b = G(i,j).den; 39 | % Get delay 40 | delay = G(i,j).delay; 41 | % Get sample time 42 | sampleTime = G(i,j).sampleTime; 43 | 44 | % Numerator and denomerator need to be the same length 45 | if(length(a) > length(b)) 46 | b = [zeros(1, size(a,2) - size(b,2)) b]; 47 | elseif(length(a) < length(b)) 48 | a = [zeros(1, size(b,2) - size(a,2)) a]; 49 | end 50 | 51 | L = 10000; % Number of frequency elements - Need to be 10000 for the nyquist plot 52 | N = length(b); % Number of denomerators 53 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 54 | % Evaluate transfer function 55 | H = zeros(1, L); 56 | h = sampleTime; 57 | if(sampleTime > 0) % Discrete model 58 | for k = 1 : L 59 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 60 | end 61 | else 62 | for k = 1 : L 63 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 64 | end 65 | end 66 | % Done! 67 | % Plot nyquist diagram 68 | 69 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 70 | plot([real(H) nan real(H)], [imag(H) nan -imag(H)],-1, 0 ,'+') 71 | title('Nyquist diagram') 72 | xlabel('Real axis') 73 | ylabel('Imaginary axis') 74 | grid on 75 | end 76 | end 77 | else 78 | error('Only transfer functions and state space models allowed') 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /matave/+mc/obsv.m: -------------------------------------------------------------------------------- 1 | % Generates the observability matrix of a state space model 2 | % Input: sys, n(optinal) 3 | % Example 1: Or = mc.obsv(sys) 4 | % Example 2: Or = mc.obsv(sys, n) 5 | % Author: Daniel Mårtensson, 2017 Oktober 6 | 7 | function [Or] = obsv(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get SS 18 | sys = varargin{1}; 19 | 20 | % If we specify n, that means we are using minreal.m 21 | if(length(varargin) > 1) 22 | n = varargin{2}; 23 | else 24 | n = size(sys.A, 1); % Else, we only check the dimension of A 25 | end 26 | 27 | % Compute the observability matrix now! 28 | Or = []; 29 | for i = 0:(n-1) 30 | Or = [Or; sys.C*sys.A^i]; 31 | end 32 | 33 | elseif(strcmp(type, 'TF' )) 34 | % Get TF 35 | disp('Only state space models allowed'); 36 | else 37 | error('This is not TF or SS'); 38 | end 39 | end -------------------------------------------------------------------------------- /matave/+mc/pade.m: -------------------------------------------------------------------------------- 1 | % Do a pade approximation of a transfer function 2 | % Input: G, n 3 | % Example 1: G = mc.pade(G, n) 4 | % Author: Daniel Mårtensson, Februari 2018 5 | 6 | function [model] = pade(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error('Missing model') 10 | end 11 | 12 | % Check if there is any input 13 | if(length(varargin) < 2) 14 | error('Please, insert the order of Pade Approximation: 1, 2, 3 or 4') 15 | end 16 | 17 | % Get the type 18 | type = varargin{1}.type; 19 | % Check if there is a TF or SS model 20 | if(strcmp(type, 'TF' )) 21 | % If there is a MIMO TF 22 | G = varargin{1}; 23 | PadeOrder = varargin{2}; 24 | for i = 1:size(G,1) 25 | for j = 1:size(G,2) 26 | % Get numerator vector and denomerator vector 27 | a = G(i,j).num; 28 | b = G(i,j).den; 29 | % Get delay 30 | delay = G(i,j).delay; 31 | % Get sample time 32 | sampleTime = G(i,j).sampleTime; 33 | if(and(sampleTime > 0, delay > 0)) 34 | error('You cannot turn time continous transfer function with delay into discrete transfer function. Try state space instead: sys = mc.tf2ss(G) -> sysd = mc.c2d(sys)'); 35 | end 36 | 37 | switch PadeOrder 38 | case 1 39 | TFdelay = mc.tf([-delay 2],[delay 2]); 40 | case 2 41 | TFdelay = mc.tf([delay^2 -6*delay 12],[delay^2 6*delay 12]); 42 | case 3 43 | TFdelay = mc.tf([-delay^3 12*delay^2 -60*delay 120],[delay^3 12*delay^2 60*delay 120]); 44 | case 4 45 | TFdelay = mc.tf([delay^4 -20*delay^3 180*delay^2 -840*delay 1680],[delay^4 20*delay^3 180*delay^2 840*delay 1680]); 46 | otherwise 47 | error('Maximum Pade number is 4') 48 | end 49 | 50 | % Need to have the same sample time. Or else series.m won't work for us 51 | TFdelay.sampleTime = sampleTime; 52 | 53 | % Remove the delay because we don't want e^(-delay*s) notion 54 | G(i,j).delay = 0; 55 | model = mc.series(G(i,j), TFdelay); 56 | % Add sample time 57 | model.sampleTime = sampleTime; 58 | model.delay = delay; 59 | 60 | end 61 | end 62 | else 63 | error('Only transfer functions'); 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /matave/+mc/parallel.m: -------------------------------------------------------------------------------- 1 | % Generates the new transfer function or new state space model of parallel connection 2 | % Input: G, sys 3 | % Example 1: G = mc.parallel(G1, G2) 4 | % Example 2: sys = mc.parallel(sys1, sys2) 5 | % Author: Daniel Mårtensson 2017 Oktober 6 | 7 | function [model] = parallel(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Check if there is a second input 14 | if(isempty(varargin{2})) 15 | error ('Missing second model') 16 | end 17 | 18 | % Get model type 19 | type = varargin{1}.type; 20 | % Check if there is a TF or SS model 21 | if(strcmp(type, 'SS' )) 22 | % Get info 23 | sys1 = varargin{1}; 24 | sys2 = varargin{2}; 25 | if(sys1.sampleTime == sys2.sampleTime) 26 | % Get matrecies 27 | A1 = sys1.A; 28 | A2 = sys2.A; 29 | B1 = sys1.B; 30 | B2 = sys2.B; 31 | C1 = sys1.C; 32 | C2 = sys2.C; 33 | D1 = sys1.D; 34 | D2 = sys2.D; 35 | 36 | % Get big state space 37 | A = [A1 zeros(size(A1, 1), size(A2, 2)); zeros(size(A2, 1), size(A1, 2)) A2]; 38 | B = [B1; B2]; 39 | C = [C1 C2]; 40 | D = (D1 + D2); 41 | delay = max([sys1.delay sys2.delay]); 42 | model = mc.ss(delay, A, B, C, D); 43 | model.sampleTime = sys1.sampleTime; 44 | else 45 | error('Need to have the same sampling time') 46 | end 47 | elseif(strcmp(type, 'TF' )) 48 | % Get info 49 | G1 = varargin{1}; 50 | G2 = varargin{2}; 51 | if(G1.sampleTime == G2.sampleTime) 52 | % Get num and den 53 | num1 = G1.num; 54 | den1 = G1.den; 55 | num2 = G2.num; 56 | den2 = G2.den; 57 | % Get delay 58 | if(G1.delay > G2.delay) 59 | delay = G2.delay; 60 | else 61 | delay = G1.delay; 62 | end 63 | 64 | 65 | % Extend - pad 66 | num1 = [zeros(1, length(num2) - length(num1)) num1]; 67 | den1 = [zeros(1, length(den2) - length(den1)) den1]; 68 | num2 = [zeros(1, length(num1) - length(num2)) num2]; 69 | den2 = [zeros(1, length(den1) - length(den2)) den2]; 70 | 71 | % Sum 72 | num = conv(num1, den2) + conv(num2, den1); 73 | den = conv(den1, den2); 74 | 75 | if(delay > 0) 76 | model = mc.tf(num, den, delay); 77 | else 78 | model = mc.tf(num, den); 79 | end 80 | model.sampleTime = G1.sampleTime; 81 | 82 | % Discrete or not? 83 | if (model.sampleTime > 0) 84 | % Replace the delaytime to discrete delay time 85 | model.tfdash = strrep(model.tfdash, 'e', 'z'); 86 | model.tfdash = strrep(model.tfdash, 's', ''); 87 | % Remove all s -> s 88 | model.tfnum = strrep(model.tfnum, 's', 'z'); 89 | model.tfden = strrep(model.tfden, 's', 'z'); 90 | end 91 | else 92 | error('Need to have the same sampling time') 93 | end 94 | else 95 | error('This is not TF or SS'); 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /matave/+mc/pid.m: -------------------------------------------------------------------------------- 1 | % Generates the parallel PID controller as a transfer function 2 | % Input: Kp, Ti(Integrator, Optinal), Td(Derivative, Optional), Tf(Low pass filter, Optinal), Ts(Sample time, Optinal) 3 | % Example 1: [Gpid] = mc.pid(Kp, Ti, Td, Tf, Ts) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [Gpid] = pid(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing parameters') 10 | end 11 | 12 | % Input the parameters 13 | if(length(varargin) >= 1) 14 | Kp = mc.tf(varargin{1}, 1); 15 | Gpid = Kp; 16 | else 17 | error('Need to have at least Kp'); 18 | end 19 | 20 | % Integrator 21 | if(length(varargin) >= 2) 22 | Ki = mc.tf(varargin{2}, [1 0]); 23 | Gpid = mc.parallel(Kp, Ki); 24 | else 25 | Ti = 0; 26 | end 27 | 28 | % Derivative 29 | if(length(varargin) >= 3) 30 | Td = varargin{3}; 31 | else 32 | Td = 0; 33 | end 34 | 35 | % Low pass filter for derivative 36 | if(length(varargin) >= 4) 37 | Tf = varargin{4}; 38 | Kd = mc.tf([Td 0], [Tf 1]); 39 | else 40 | Tf = 0; 41 | Kd = mc.tf([Td 0], [1]); 42 | end 43 | 44 | % Sampling time 45 | if(length(varargin) >= 5) 46 | Ts = varargin{5}; 47 | else 48 | Ts = 0; 49 | end 50 | 51 | % Build the PID 52 | % Check if derivative was 0 53 | if Td > 0 54 | Gpid = mc.parallel(Gpid, Kd); 55 | end 56 | 57 | % Else - Just return Gpid as it is 58 | 59 | % Convert to discrete if needed 60 | if(Ts > 0) 61 | Gpid = mc.c2d(Gpid, Ts); 62 | end 63 | 64 | end 65 | -------------------------------------------------------------------------------- /matave/+mc/pipd.m: -------------------------------------------------------------------------------- 1 | % Generates the serial PID controller as a transfer function 2 | % Input: Kp, Ti(optinal), Td(optional), b(optinal), Ts(optinal) 3 | % Example 1: [Gpipd] = mc.pipd(Kp, Ti, Td, b, Ts) 4 | % Author: Daniel Mårtensson, Oktober 2017 5 | 6 | function [Gpipd] = pipd(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing parameters') 10 | end 11 | 12 | % Input the parameters 13 | if(length(varargin) >= 1) 14 | Kp = varargin{1}; 15 | else 16 | error('Need to have at least Kp'); 17 | end 18 | 19 | % Integrator 20 | if(length(varargin) >= 2) 21 | Ti = varargin{2}; 22 | else 23 | Ti = 0; 24 | end 25 | 26 | % Derivative 27 | if(length(varargin) >= 3) 28 | Td = varargin{3}; 29 | else 30 | Td = 0; 31 | end 32 | 33 | % High pass filter 34 | if(length(varargin) >= 4) 35 | b = varargin{4}; 36 | else 37 | b = 0; 38 | end 39 | 40 | % Sampling time 41 | if(length(varargin) >= 5) 42 | Ts = varargin{5}; 43 | else 44 | Ts = 0; 45 | end 46 | 47 | % Build the PIPD 48 | Gpipd = mc.tf([Kp*Ti*Td Kp*(Ti+Td) Kp],[Ti*Td/b Ti 0]); 49 | 50 | % Convert to discrete if needed 51 | if(Ts > 0) 52 | Gpipd = mc.c2d(Gpipd, Ts); 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /matave/+mc/pole.m: -------------------------------------------------------------------------------- 1 | % Generates poles from transfer functions or state space models 2 | % Input: TF or SS 3 | % Example 1: p = mc.pole(G) 4 | % Example 2: p = mc.pole(sys) 5 | % Author: Daniel Mårtensson 2017 September 6 | 7 | function [p] = pole(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get poles 18 | A = varargin{1}.A; 19 | p = eig(A); % Eigenvalues 20 | elseif(strcmp(type, 'TF' )) 21 | % Get poles 22 | G = varargin{1}; 23 | p = roots(G.den); 24 | else 25 | error('This is not TF or SS'); 26 | end 27 | 28 | end -------------------------------------------------------------------------------- /matave/+mc/pzmap.m: -------------------------------------------------------------------------------- 1 | % Plot poles and zeros of a transfer function or of a state space model 2 | % Input: G, sys 3 | % Example 1: [p, z] = mc.pzmap(G) 4 | % Example 2: [p, z] = mc.pzmap(sys) 5 | % Author: Daniel Mårtensson, 2017 September 6 | 7 | function [p, z] = pzmap(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get poles 18 | p = mc.pole(varargin{1}) 19 | z = mc.tzero(varargin{1}) 20 | plot(real(p), imag(p), 'o', real(z), imag(z), 'x'); 21 | grid on 22 | title('Pole-Zero Map') 23 | xlabel('Real axis'); 24 | ylabel('Imaginary axis'); 25 | 26 | % If we have no zeros - It can happen! 27 | if isempty(z) 28 | legend('poles'); 29 | else 30 | legend('poles', 'zeros'); 31 | end 32 | elseif(strcmp(type, 'TF' )) 33 | % Get G 34 | G = varargin{1}; 35 | % Get poles and zeros 36 | z = roots(G.num); 37 | p = roots(G.den); 38 | plot(real(p), imag(p), 'o', real(z), imag(z), 'x'); 39 | grid on 40 | title('Pole-Zero Map') 41 | xlabel('Real axis'); 42 | ylabel('Imaginary axis'); 43 | 44 | % If we have no zeros - It can happen! 45 | if isempty(z) 46 | legend('poles'); 47 | else 48 | legend('poles', 'zeros'); 49 | end 50 | else 51 | error('This is not TF or SS'); 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /matave/+mc/quadprog.m: -------------------------------------------------------------------------------- 1 | % This is quadratic programming with Hildreth's method 2 | % Min 1/2x^TQx + c^Tx 3 | % S.t Ax <= b 4 | % 5 | % If you want to do maximization, then turn Q and c negative. The constraints are the same 6 | % 7 | % Max 1/2x^T(-Q)x + (-c)^Tx 8 | % S.t Ax <= b 9 | % 10 | % Input: Q(Symmetric matrix), c(Objective function), A(Constraint matrix), b(Constraint vector) 11 | % Output: x(Solution vector), solution(boolean flag) 12 | % Example 1: [x, solution] = mc.quadprog(Q, c, A, b) 13 | % Author: Daniel Mårtensson 2022 September 3 14 | 15 | function [x, solution] = quadprog(Q, c, A, b) 16 | % Assume that the solution is true 17 | solution = true; 18 | 19 | % Same as in C code for Functions.h at CControl 20 | MIN_VALUE = 1e-11; 21 | MAX_ITERATIONS = 10000; 22 | 23 | % Unconstrained solution 24 | x = -linsolve(Q, c); 25 | 26 | % Constraints difference 27 | K = b - A*x; 28 | 29 | % Check if all the constraints are satisfied 30 | if(sum(K < 0) == 0) 31 | return; % All satisfied 32 | end 33 | 34 | % Create P 35 | P = linsolve(Q, A'); 36 | 37 | % Create H = A*Q*A' 38 | H = A*P; 39 | 40 | % Solve lambda from H*lambda = -K, where lambda >= 0 41 | [m, n] = size(K); 42 | lambda = zeros(m, n); 43 | for km = 1:MAX_ITERATIONS 44 | lambda_p = lambda; 45 | 46 | % Use Gauss Seidel 47 | for i = 1:m 48 | w = -1.0/H(i,i)*(K(i) + H(i,:)*lambda - H(i,i)*lambda(i)); 49 | lambda(i) = max(0, w); 50 | end 51 | 52 | % Check if the minimum convergence has been reached 53 | w = (lambda - lambda_p)'*(lambda - lambda_p); 54 | if (w < MIN_VALUE) 55 | break; 56 | end 57 | 58 | % Check if the maximum iteration have been reached 59 | if(km == MAX_ITERATIONS) 60 | solution = false; 61 | return; 62 | end 63 | end 64 | 65 | % Find the solution: x = -inv(Q)*c - inv(Q)*A'*lambda 66 | x = x - P*lambda; 67 | end 68 | -------------------------------------------------------------------------------- /matave/+mc/ramp.m: -------------------------------------------------------------------------------- 1 | % Ramp a state space model or a transfer function 2 | % Input: sys, G, t(optinal) 3 | % Example 1: [y,t,x] = mc.ramp(G, t) 4 | % Example 2: [y,t,x] = mc.ramp(G) 5 | % Example 3: [y,t,x] = mc.ramp(sys, t) 6 | % Author: Daniel Mårtensson, 2017 September 7 | 8 | function [y,t,X] = ramp(varargin) 9 | % Check if there is some input arguments or it's not a model 10 | if(isempty(varargin{1})) 11 | error ('Missing input') 12 | end 13 | 14 | % Check if there is a model 15 | if(strcmp(varargin{1}.type,'SS')) 16 | 17 | % Get time 18 | if(length(varargin) >= 2) 19 | t = varargin{2}; 20 | else 21 | disp('Time assumed to be 10 seconds'); 22 | t = 10; 23 | end 24 | 25 | % Get sample time to compute the new time vector 26 | sampleTime = varargin{1}.sampleTime; 27 | if(sampleTime > 0) 28 | t = 0:sampleTime:t; 29 | else 30 | t = 0:0.01:t; % Sample time assumed to be 0.01 31 | end 32 | 33 | % Multiple signals...or not! 34 | u = linspace(0,1, length(t)); 35 | u = repmat(u, size(varargin{1}.B, 2), 1); % Creates 0 -> 1 36 | x0 = zeros(size(varargin{1}.A, 1), 1); % Assume x0 = [0; 0; 0; ..... ; 0] 37 | % Call lsim! 38 | [y,t,X] = mc.lsim(varargin{1}, u, t, x0); 39 | elseif(strcmp(varargin{1}.type,'TF')) 40 | % TF to SS 41 | sys = mc.tf2ss(varargin{1}, 'OCF'); 42 | 43 | % Get time 44 | if(length(varargin) >= 2) 45 | t = varargin{2}; 46 | else 47 | disp('Time assumed to be 10 seconds'); 48 | t = 10; 49 | end 50 | 51 | % Call ramp 52 | [y,t,X] = mc.ramp(sys,t); 53 | else 54 | error('Not a state space model or a transfer function') 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /matave/+mc/referencegain.m: -------------------------------------------------------------------------------- 1 | % Computes the reference gain Kr and give back a state space model with including the reference gain 2 | % Input: sys 3 | % Example 1: [sys_kr, Kr] = mc.referencegain(sys) 4 | % Author: Daniel Mårtensson, September 2018 5 | 6 | function [sys_kr, Kr] = referencegain(varargin) 7 | % Check if there is any input 8 | if(isempty(varargin)) 9 | error ('Missing input') 10 | end 11 | % Get model type 12 | type = varargin{1}.type; 13 | % Check if there is a TF or SS model 14 | if(strcmp(type, 'SS' )) 15 | % Get A, B, C, D matrecies 16 | sys = varargin{1}; 17 | A = sys.A; 18 | B = sys.B; 19 | C = sys.C; 20 | D = sys.D; 21 | delay = sys.delay; 22 | sampleTime = sys.sampleTime; 23 | 24 | if sampleTime > 0 25 | Kr = 1./(C*inv(eye(size(A)) - A)*B); 26 | else 27 | Kr = 1./(C*inv(-A)*B); 28 | end 29 | % Now create B matrix with precompensator factor - For better tracking 30 | B = B*Kr; 31 | 32 | sys_kr = mc.ss(delay, A, B, C, D); 33 | sys_kr.sampleTime = sampleTime; 34 | 35 | elseif(strcmp(type, 'TF' )) 36 | disp('Only state space models') 37 | else 38 | error('This is not TF or SS'); 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /matave/+mc/reg.m: -------------------------------------------------------------------------------- 1 | % Generates the state feedback controler with the control law L and with integral action law Li 2 | % Input: sys, L, Li(optional), Kr(optional) 3 | % Example 1: [regsys] = mc.reg(sys, L) 4 | % Example 2: [regsys] = mc.reg(sys, L, Li) 5 | % Example 3: [regsys] = mc.reg(sys, L, Li) 6 | % Author: Daniel Mårtensson, November 2017 7 | 8 | function [regsys] = reg(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error ('Missing input') 12 | end 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | 18 | % Get the control law L; 19 | if(length(varargin) >= 2) 20 | L = varargin{2}; 21 | else 22 | error('Missing the control law L'); 23 | end 24 | 25 | % Get the integral control law Li 26 | if(length(varargin) >= 3) 27 | Li = varargin{3}; 28 | end 29 | 30 | % Check if what feedback controller you should use 31 | regulatorNumber = length(varargin); 32 | 33 | % Get A, B, C, D matrecies 34 | sys = varargin{1}; 35 | A = sys.A; 36 | B = sys.B; 37 | C = sys.C; 38 | D = sys.D; 39 | delay = sys.delay; 40 | sampleTime = sys.sampleTime; 41 | 42 | % Create new feedback model 43 | switch regulatorNumber 44 | case 2 % Standard LQR 45 | 46 | %{ 47 | From this: 48 | dx = Ax + Bu 49 | y = Cx + Du 50 | u = -uf + r = -Lx + r % Feedback control law 51 | To this: 52 | dx = (A-BL)x + Br 53 | [y;uf] = [C; L]x + [D;0]r 54 | %} 55 | 56 | % Create the A matrix 57 | A = (A-B*L); 58 | %B matrix is the same 59 | C = [C;L]; % This is for the uf = L*x control law 60 | D = [D; D*0]; % D need to have the same row length as C 61 | 62 | regsys = mc.ss(delay, A, B, C, D); 63 | regsys.sampleTime = sampleTime; 64 | 65 | case 3 % LQR with integral action LQI 66 | % Create A matrix 67 | A = [(A-B*L) B*Li; (D*L-C) -D*Li]; 68 | 69 | % Create B matrix 70 | ny = size(C, 1); % Number outputs 71 | nu = size(B, 2); % Number inputs 72 | B = [0*B; ones(ny, nu)]; % <- precompensator for reference = 0 73 | 74 | % Create C matrix 75 | C = [(C-D*L) D*Li]; 76 | 77 | % Matrix D will be created by it self 78 | 79 | regsys = mc.ss(delay, A, B, C, D); 80 | regsys.sampleTime = sampleTime; 81 | case 4 % LQR with integral action LQI + precompensator for reference 82 | % Create A matrix 83 | A = [(A-B*L) B*Li; (D*L-C) -D*Li]; 84 | 85 | % Create B matrix 86 | ny = size(C, 1); % Number outputs 87 | nu = size(B, 2); % Number inputs 88 | B = [B; ones(ny, nu)]; 89 | 90 | % Create C matrix 91 | C = [(C-D*L) D*Li]; 92 | 93 | % Matrix D will be created by it self 94 | 95 | regsys = mc.ss(delay, A, B, C, D); 96 | regsys.sampleTime = sampleTime; 97 | end 98 | 99 | elseif(strcmp(type, 'TF' )) 100 | disp('Only state space models') 101 | else 102 | error('This is not TF or SS'); 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /matave/+mc/rlocfind.m: -------------------------------------------------------------------------------- 1 | 2 | function [K] = rlocfind (varargin) 3 | % Check if there is any input 4 | if(isempty(varargin)) 5 | error ('Missing input') 6 | end 7 | 8 | % Get pole location 9 | if(length(varargin) >= 2) 10 | p = varargin{2}; 11 | else 12 | error('Missing pole location'); 13 | end 14 | 15 | % Get model type 16 | type = varargin{1}.type; 17 | % Check if there is a TF or SS model 18 | if(strcmp(type, 'SS' )) 19 | % SS to TF 20 | G = mc.ss2tf(varargin{1}); 21 | [k, poles] = mc.rlocfind(G, p); 22 | elseif(strcmp(type, 'TF' )) 23 | % If there is a MIMO TF 24 | G = varargin{1}; 25 | K = zeros(size(G,1), size(G,2)); 26 | 27 | for i = 1:size(G,1) 28 | for j = 1:size(G,2) 29 | % Get numerator vector and denomerator vector 30 | a = G(i,j).num; 31 | b = G(i,j).den; 32 | % Get delay 33 | delay = G(i,j).delay; 34 | % Get sample time 35 | sampleTime = G(i,j).sampleTime; 36 | 37 | % Numerator and denomerator need to be the same length 38 | if(length(a) > length(b)) 39 | b = [zeros(1, size(a,2) - size(b,2)) b]; 40 | elseif(length(a) < length(b)) 41 | a = [zeros(1, size(b,2) - size(a,2)) a]; 42 | end 43 | 44 | N = length(b); 45 | h = sampleTime; 46 | % Notice that a and b has been switched, compared to bode.m 47 | if sampleTime > 0 48 | K(i,j) = abs((b*fliplr((exp(p*h)).^(0 : N-1)).')/(a*fliplr((exp(p*h)).^(0 : N-1)).')*exp(-delay*exp(p*h))); 49 | else 50 | K(i,j) = abs(b*fliplr((p).^(0 : N-1)).'/(a*fliplr(p.^(0 : N-1)).')*exp(-delay*p)); 51 | end 52 | 53 | end 54 | end 55 | 56 | else 57 | error('Error model structure - Unknow'); 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /matave/+mc/rlocus.m: -------------------------------------------------------------------------------- 1 | % Plot root locus plot from a transfer function or state space model at given vector of gains gainvector 2 | % Input: sys, G, gainvector 3 | % Example 1: mc.rlocus(sys, gainvector) 4 | % Example 2: mc.rlocus(G, gainvector) 5 | % Author: Daniel Mårtensson, 2017 Oktober 6 | 7 | function [retval] = rlocus(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error('Missing model') 11 | end 12 | 13 | % Get the type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % SS to TF 18 | G = mc.ss2tf(varargin{1}); 19 | if(length(varargin) >= 2) 20 | Kvector = varargin{2}; 21 | else 22 | error('Missing K gain vector'); 23 | end 24 | % Call rlocus 25 | mc.rlocus(G, Kvector); 26 | elseif(strcmp(type, 'TF' )) 27 | % If there is a MIMO TF 28 | G = varargin{1}; 29 | for i = 1:size(G,1) 30 | for j = 1:size(G,2) 31 | % Get sample time 32 | sampleTime = G(i,j).sampleTime; 33 | % Gain K vector 34 | if(length(varargin) >= 2) 35 | Kvector = varargin{2}; 36 | else 37 | error('Missing K gain vector'); 38 | end 39 | 40 | % Size of the pole and zeros 41 | [npole,mpole] = size(mc.pole(G)); 42 | [nzero,mzero] = size(mc.zero(G)); 43 | % Create empty vectors for storeing the zeros and poles 44 | pvector = [];%zeros(npole, length(Kvector)); 45 | zvector = [];%zeros(nzero, length(Kvector)); 46 | for k = 1:length(Kvector) 47 | if(sampleTime > 0) % Discret 48 | GK = mc.tf(Kvector(k),1); 49 | GKd = mc.c2d(GK, sampleTime); % Sampleing time need to be the same 50 | Gfeedback = mc.feedback(G(i,j), GKd); 51 | else 52 | GK = mc.tf(Kvector(k),1); 53 | Gfeedback = mc.feedback(G(i,j), GK); 54 | end 55 | pvector(:,k) = mc.pole(Gfeedback); 56 | zvector(:,k) = mc.zero(Gfeedback); 57 | end 58 | % Done! Plot it now! 59 | 60 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 61 | plot(real(pvector), imag(pvector), '.r', real(zvector), imag(zvector), 'bo'); 62 | grid on 63 | 64 | % Scale plot 65 | xlim([-10 10]) 66 | ylim([-10 10]) 67 | 68 | % Title 69 | title('Root Locus'); 70 | xlabel('Real Axsis (Seconds^-1)'); 71 | ylabel('Imaginary Axis (Seconds^-1)'); 72 | 73 | end 74 | end 75 | else 76 | error('Only transfer functions and state space models allowed') 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /matave/+mc/sensitivity.m: -------------------------------------------------------------------------------- 1 | % Plot the nyquist diagram of a state space model or a transfer function 2 | % between given frequencies w1 and w2 3 | % Input: G, sys, w1, w2 4 | % Example 1: [Margin_Sensitivity] = mc.sensitivity(sys, w1, w2) 5 | % Example 2: [Margin_Sensitivity] = mc.sensitivity(G, w1, w2) 6 | % Author: Daniel Mårtensson, 2017 Oktober 7 | 8 | function [Ms] = sensitivity(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | w2 = varargin{3}; 21 | end 22 | 23 | 24 | % Get the type 25 | type = varargin{1}.type; 26 | % Check if there is a TF or SS model 27 | if(strcmp(type, 'SS' )) 28 | % SS to TF 29 | G = mc.ss2tf(varargin{1}); 30 | % Call sensitivity 31 | Ms = mc.sensitivity(G, w1, w2); 32 | elseif(strcmp(type, 'TF' )) 33 | % If there is a MIMO TF 34 | G = varargin{1}; 35 | Ms = zeros(size(G,1), size(G,2)); % The return matrix 36 | for i = 1:size(G,1) 37 | for j = 1:size(G,2) 38 | % Get numerator vector and denomerator vector 39 | a = G(i,j).num; 40 | b = G(i,j).den; 41 | % Get delay 42 | delay = G(i,j).delay; 43 | % Get sample time 44 | sampleTime = G(i,j).sampleTime; 45 | 46 | % Numerator and denomerator need to be the same length 47 | if(length(a) > length(b)) 48 | b = [zeros(1, size(a,2) - size(b,2)) b]; 49 | elseif(length(a) < length(b)) 50 | a = [zeros(1, size(b,2) - size(a,2)) a]; 51 | end 52 | 53 | L = 10000; % Number of frequency elements - Need to be 10000 for the nyquist plot 54 | N = length(b); % Number of denomerators 55 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 56 | % Evaluate transfer function 57 | H = zeros(1, L); 58 | h = sampleTime; 59 | if(sampleTime > 0) % Discrete model 60 | for k = 1 : L 61 | H(k) = (a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)); 62 | end 63 | else 64 | for k = 1 : L 65 | H(k) = (a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)); 66 | end 67 | end 68 | % Done! 69 | % Plot nyquist diagram 70 | % Done! 71 | % Plot nyquist diagram 72 | 73 | % Get Ms 74 | Ms = min(1+H); 75 | Mt = 1.3; 76 | x0 = -Mt^2/(Mt^2 + 1); 77 | y0 = 0; 78 | r = Mt/(Mt^2+1); 79 | 80 | % Get the Mt circle 81 | ang = 0:0.01:2*pi; 82 | xp = r*cos(ang); 83 | yp = r*sin(ang); 84 | 85 | figure('Name', sprintf(strcat('Transfer function: ', num2str(i), 'x', num2str(j)))) 86 | plot([real(H)], [imag(H)],-1, 0 ,'+', linspace(-1, -abs(1-real(Ms))), linspace(0, imag(Ms)), x0 + xp, y0 + yp) 87 | title('Nyquist diagram') 88 | xlabel('Real axis') 89 | ylabel('Imaginary axis') 90 | grid on 91 | legend('real imag', 'instability point', 'max(S(jw))', 'max(T(jw)) = 1.3') 92 | 93 | %Ms(i,j) = abs(min(1/1+H)); 94 | Ms(i,j) = abs(Ms); 95 | end 96 | end 97 | else 98 | error('Only transfer functions and state space models allowed') 99 | end 100 | end 101 | 102 | -------------------------------------------------------------------------------- /matave/+mc/series.m: -------------------------------------------------------------------------------- 1 | % Do a serial connection of transfer functions or state space models 2 | % Input: G, sys 3 | % Example 1: G = mc.series(G1, G2) 4 | % Example 2: sys = mc.series(sys1, sys2) 5 | % Author: Daniel Mårtensson, 2017 Oktober 6 | 7 | function [model] = series(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Check if there is a second input 14 | if(isempty(varargin{2})) 15 | error ('Missing second model') 16 | end 17 | 18 | % Get model type 19 | type = varargin{1}.type; 20 | % Check if there is a TF or SS model 21 | if(strcmp(type, 'SS' )) 22 | % Get info 23 | sys1 = varargin{1}; 24 | sys2 = varargin{2}; 25 | if(sys1.sampleTime == sys2.sampleTime) 26 | % Get matrecies 27 | A1 = sys1.A; 28 | A2 = sys2.A; 29 | B1 = sys1.B; 30 | B2 = sys2.B; 31 | C1 = sys1.C; 32 | C2 = sys2.C; 33 | D1 = sys1.D; 34 | D2 = sys2.D; 35 | 36 | % Get big state space 37 | A = [A1 zeros(size(A1, 1), size(A2, 2)); B2*C1 A2]; 38 | B = [B1; B2*D1]; 39 | C = [D2*C1 C2]; 40 | D = D2*D1; 41 | delay = sys1.delay + sys2.delay; 42 | model = mc.ss(delay, A, B, C, D); 43 | model.sampleTime = sys1.sampleTime; 44 | else 45 | error('Need to have the same sampling time') 46 | end 47 | elseif(strcmp(type, 'TF' )) 48 | % Get TF 49 | G1 = varargin{1}; 50 | G2 = varargin{2}; 51 | if(G1.sampleTime == G2.sampleTime) 52 | % Get num and den 53 | num1 = G1.num; 54 | den1 = G1.den; 55 | num2 = G2.num; 56 | den2 = G2.den; 57 | % Get delay 58 | delay = G1.delay + G2.delay; 59 | num = conv(num1, num2); 60 | den = conv(den1, den2); 61 | if(delay > 0) 62 | model = mc.tf(num, den, delay); 63 | else 64 | model = mc.tf(num, den); 65 | end 66 | model.sampleTime = G1.sampleTime; 67 | 68 | % Discrete or not? 69 | if (model.sampleTime > 0) 70 | % Replace the delaytime to discrete delay time 71 | model.tfdash = strrep(model.tfdash, 'e', 'z'); 72 | model.tfdash = strrep(model.tfdash, 's', ''); 73 | % Remove all s -> s 74 | model.tfnum = strrep(model.tfnum, 's', 'z'); 75 | model.tfden = strrep(model.tfden, 's', 'z'); 76 | end 77 | else 78 | error('Need to have the same sampling time') 79 | end 80 | else 81 | error('This is not TF or SS'); 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /matave/+mc/sgrid.m: -------------------------------------------------------------------------------- 1 | function sgrid(z, wn) 2 | % Do the circle 3 | ang=0:0.01:2*pi; 4 | xp=wn*cos(ang); 5 | yp=wn*sin(ang); 6 | 7 | % Do the slope lines 8 | y1 = [0 wn*sqrt(1-z^2)]; 9 | y2 = [0 -wn*sqrt(1-z^2)]; 10 | x1 = [0 -z*wn]; 11 | x2 = [0 -z*wn]; 12 | 13 | % Plot now 14 | hold on 15 | plot(xp, yp,'.-', x1, y1, '.-', x2, y2, '.-') 16 | end -------------------------------------------------------------------------------- /matave/+mc/sigma.m: -------------------------------------------------------------------------------- 1 | % Plot sigma diagram from a transfer function or state space model 2 | % between given frequencies w1 and w2 3 | % Input: G, sys, w1, w2 4 | % Example 1: mc.sigma(sys, w1, w2) 5 | % Example 2: mc.sigma(G, w1, w2) 6 | % Author: Daniel Mårtensson, 2017 Oktober 7 | 8 | function [retval] = sigma(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error('Missing model') 12 | end 13 | 14 | % Check if there is any input 15 | if(length(varargin) < 3) 16 | w1 = 0.01; 17 | w2 = 100; 18 | else 19 | w1 = varargin{2}; 20 | w2 = varargin{3}; 21 | end 22 | 23 | % Get the type 24 | type = varargin{1}.type; 25 | % Check if there is a TF or SS model 26 | if(strcmp(type, 'SS' )) 27 | % SS to TF 28 | G = mc.ss2tf(varargin{1}); 29 | % Call sigma 30 | mc.sigma(G, w1, w2); 31 | elseif(strcmp(type, 'TF' )) 32 | % If there is a MIMO TF 33 | G = varargin{1}; 34 | % Create H 35 | L = 1000; % Number of frequency elements 36 | H = zeros(size(G,1),size(G,2), L); 37 | for i = 1:size(G,1) 38 | for j = 1:size(G,2) 39 | % Get numerator vector and denomerator vector 40 | a = G(i,j).num; 41 | b = G(i,j).den; 42 | % Get delay 43 | delay = G(i,j).delay; 44 | % Get sample time 45 | sampleTime = G(i,j).sampleTime; 46 | 47 | % Numerator and denomerator need to be the same length 48 | if(length(a) > length(b)) 49 | b = [zeros(1, size(a,2) - size(b,2)) b]; 50 | elseif(length(a) < length(b)) 51 | a = [zeros(1, size(b,2) - size(a,2)) a]; 52 | end 53 | 54 | N = length(b); % Number of denomerators 55 | w = logspace(log10(w1), log10(w2), L); % Angular frequencies 56 | % Evaluate transfer function 57 | % norm(A,2) = max(SVD(A)) 58 | h = sampleTime; 59 | if(sampleTime > 0) % Discrete model 60 | for k = 1 : L 61 | H(i,j,k) = norm((a*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')/(b*fliplr((exp(1i*w(k)*h)).^(0 : N-1)).')*exp(-delay*exp(1i*w(k)*h)), 2); 62 | end 63 | else 64 | for k = 1 : L 65 | H(i,j,k) = norm((a*fliplr((1i*w(k)).^(0 : N-1)).')/(b*fliplr((1i*w(k)).^(0 : N-1)).')*exp(-delay*1i*w(k)), 2); 66 | end 67 | end 68 | 69 | % Done! 70 | end 71 | end 72 | % Plot now! 73 | legendStr = ['']; % Need to have '', or else legendStr is numeric 74 | for i = 1:size(H,1) 75 | for j = 1:size(H,2) 76 | y = H(i,j,:); 77 | semilogx(w, 20*log10(abs(y(:))), 'color', rand(1,3)); 78 | grid on 79 | ylabel('Magnitude [dB]'); 80 | xlabel('Frequency [rad/s]'); 81 | title('Singular Values'); 82 | legendStr = [legendStr strcat('TF:', num2str(i), 'x', num2str(j)), '#']; % # is there beacuse we need to split the string later 83 | hold on 84 | end 85 | end 86 | % Remove last # 87 | legendStr = strsplit(legendStr(1,1:end-1), '#'); 88 | % Now plot the legendStr 89 | legend(legendStr); 90 | % Done! 91 | else 92 | error('Only transfer functions and state space models allowed') 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /matave/+mc/smithpredict.m: -------------------------------------------------------------------------------- 1 | % An Otto Smith predictor 2 | % Input: G(System with delay), K(Controller), n(Pade Approximation number) 3 | % Example 1: [G] = mc.smithpredict(G, K, n) 4 | % Author: Daniel Mårtensson, Februari 2018 5 | % Important! Discrete system may be very sensitive with Otto Smith predictor! 6 | 7 | function [model] = smithpredict(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Check if there is a second input 14 | if(isempty(varargin{2})) 15 | error ('Missing controller transfer function') 16 | end 17 | 18 | % Check if there is a third input 19 | if(isempty(varargin{3})) 20 | error ('Missing pade approximation number') 21 | end 22 | 23 | % Get model type 24 | type = varargin{1}.type; 25 | % Check if there is a TF or SS model 26 | if(strcmp(type, 'TF' )) 27 | % Get system G 28 | Gsystem = varargin{1}; 29 | 30 | % Check if the system has delay 31 | if Gsystem.delay <= 0 32 | error('System missing delay.'); 33 | end 34 | 35 | % Get pade approximation number 36 | n = varargin{3}; 37 | 38 | % Create the system with delay 39 | Gdelaysystem = mc.pade(Gsystem, n); 40 | 41 | % Get the controller transfer function 42 | Gcontroller = varargin{2}; 43 | 44 | % Check if the Gcontroller has a delay too! 45 | if Gcontroller.delay > 0 46 | error('The controller has delay.'); 47 | end 48 | 49 | % They must have the same sample time 50 | if(Gsystem.sampleTime == Gcontroller.sampleTime) 51 | % Get num and den 52 | num1 = Gdelaysystem.num; 53 | den1 = Gdelaysystem.den; 54 | num2 = Gsystem.num; 55 | den2 = Gsystem.den; 56 | 57 | % Extend - pad - Equal length 58 | num1 = [zeros(1, length(num2) - length(num1)) num1]; 59 | den1 = [zeros(1, length(den2) - length(den1)) den1]; 60 | num2 = [zeros(1, length(num1) - length(num2)) num2]; 61 | den2 = [zeros(1, length(den1) - length(den2)) den2]; 62 | 63 | % Substract - Importat to have -conv(num1, den2) + conv(num2, den1) 64 | % because we are doing negative feedback 65 | num = -conv(num1, den2) + conv(num2, den1); 66 | den = conv(den1, den2); 67 | 68 | % Create a transfer function of num and den 69 | Gdelaysubstractsystem = mc.tf(num, den); 70 | % Need to have the same sample time as Gdelaysystem! 71 | Gdelaysubstractsystem.sampleTime = Gdelaysystem.sampleTime; 72 | % Create the predicive controller now 73 | predictController = mc.feedback(Gcontroller, Gdelaysubstractsystem); 74 | % Connect predictController with Gdelay 75 | Looptransferfunction = mc.series(Gdelaysystem, predictController); 76 | 77 | % This is only for scalar 1 in the feedback 78 | if Gsystem.sampleTime > 0 79 | M = mc.tf(1,1); % Just a scalar 1 of TF 80 | M = mc.c2d(M, Gsystem.sampleTime); 81 | else 82 | M = mc.tf(1,1); % Just a scalar 1 of TF 83 | end 84 | 85 | % Our smitth predictor system! 86 | model = mc.feedback(Looptransferfunction, M); 87 | else 88 | error('Not the same sample time') 89 | end 90 | else 91 | error('Only transfer functions'); 92 | end 93 | 94 | end 95 | -------------------------------------------------------------------------------- /matave/+mc/ss.m: -------------------------------------------------------------------------------- 1 | % Generates a state space model from matrix A, B, C, D 2 | % Input: delay, A, B, C(optional), D(optional) 3 | % Example 1: sys = mc.ss(delay, A, B) % C set to diagnoal matrix 4 | % Example 2: sys = mc.ss(delay, A, B, C) % D set to zero matrix 5 | % Example 3: sys = mc.ss(delay, A, B, C, D) 6 | % Author: Daniel Mårtensson, 2017 September 7 | 8 | function [sys] = ss(varargin) 9 | 10 | if(length(varargin) < 1) 11 | error('Missing delaytime, A-matrix and B-matrix') 12 | end 13 | 14 | if(length(varargin) < 2) 15 | error('Missing A-matrix and B-matrix') 16 | else 17 | sys.A = varargin{2}; 18 | % Check if sys.A is square matrix 19 | if(size(sys.A,1) ~= size(sys.A,2)) 20 | error('A is not a square'); 21 | end 22 | end 23 | 24 | if(length(varargin) < 3) 25 | error('Missing B-matrix') 26 | else 27 | sys.B = varargin{3}; 28 | % Check if sys.A and sys.B have the same lenght of rows 29 | if(size(sys.A, 1) ~= size(sys.B, 1)) 30 | error('A and B have not the same row length'); 31 | end 32 | end 33 | 34 | if(length(varargin) < 4) 35 | sprintf('C matrix assumed to be a diagonal %ix%i matrix', size(varargin{2}, 1),size(varargin{2}, 2)) 36 | sys.C = eye(size(varargin{2}, 1)); 37 | else 38 | sys.C = varargin{4}; 39 | % Check if sys.A and sys.C have the same lenght of columns 40 | if(size(sys.A, 2) ~= size(sys.C, 2)) 41 | error('A and C have not the same column length'); 42 | end 43 | end 44 | 45 | if(length(varargin) < 5) 46 | sprintf('D matrix assumed to be a zero %ix%i matrix', size(sys.C, 1), size(sys.B, 2)) 47 | sys.D = zeros(size(sys.C, 1), size(sys.B, 2)); 48 | else 49 | sys.D = varargin{5}; 50 | % Check if sys.C and sys.D have the same lenght of rows 51 | if(size(sys.C, 1) ~= size(sys.D, 1)) 52 | error('C and D have not the same row length'); 53 | end 54 | % and check if sys.B and sys.D have the same lenght of columns 55 | if(size(sys.B, 2) ~= size(sys.D, 2)) 56 | error('D and B have not the same columns length'); 57 | end 58 | end 59 | 60 | % Delay time 61 | sys.delay = varargin{1}; 62 | sys.type = 'SS'; 63 | %Sampel time 64 | sys.sampleTime = 0; 65 | 66 | 67 | end -------------------------------------------------------------------------------- /matave/+mc/ss2tf.m: -------------------------------------------------------------------------------- 1 | % Transform state space model to transfer function 2 | % Input: sys 3 | % Example 1: G = mc.ss2tf(sys) 4 | % Author: Daniel Mårtensson, 2017 September 5 | 6 | function [G] = ss2tf(varargin) 7 | % Check if there is some input arguments or it's not a state space model 8 | if(or(isempty(varargin{1}), ~strcmp(varargin{1}.type, 'SS' ))) 9 | error ('Missing state space model') 10 | end 11 | 12 | % Get the matrecies 13 | A = varargin{1}.A; 14 | B = varargin{1}.B; 15 | C = varargin{1}.C; 16 | D = varargin{1}.D; 17 | % Get the delay 18 | delay = varargin{1}.delay; 19 | % Get sampleTime 20 | sampleTime = varargin{1}.sampleTime; 21 | % Get the dc gain 22 | dc = mc.dcgain(varargin{1}); 23 | % Get the poles 24 | p = mc.pole(varargin{1}); 25 | 26 | % Create SISO state space models and convert them into a TF 27 | for i = 1:size(B,2) 28 | for j = 1:size(C,1) 29 | partialSys = mc.ss(delay, A, B(:,i), C(j,:), D(j,i)); 30 | % Get the z,p,k values 31 | [z, gain] = mc.tzero(partialSys); 32 | % Get the numerators and denomerators 33 | partialG = mc.zpk(z, p, gain); 34 | partialnum = partialG.num; 35 | partialden = partialG.den; 36 | % Get TF with delay 37 | if(delay > 0) 38 | G(j,i) = mc.tf(partialnum, partialden, delay); 39 | else 40 | G(j,i) = mc.tf(partialnum, partialden); 41 | end 42 | 43 | % Get sample time 44 | G(j,i).sampleTime = sampleTime; 45 | % If the model is discrete - do this! 46 | if(sampleTime > 0) 47 | % Replace the delaytime to discrete delay time 48 | G(j,i).tfdash = strrep(G(j,i).tfdash, 'e', 'z'); 49 | G(j,i).tfdash = strrep(G(j,i).tfdash, 's', ''); 50 | % Remove all s -> s 51 | G(j,i).tfnum = strrep(G(j,i).tfnum, 's', 'z'); 52 | G(j,i).tfden = strrep(G(j,i).tfden, 's', 'z'); 53 | end 54 | % Done! 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /matave/+mc/step.m: -------------------------------------------------------------------------------- 1 | % Simulate continuous time model of a state space model or transfer function 2 | % Input: G, sys, t(optional) 3 | % Example 1: [y,t,x] = mc.step(G, t) 4 | % Example 2: [y,t,x] = mc.step(G) 5 | % Example 3: [y,t,x] = mc.step(sys, t) 6 | % Author: Daniel Mårtensson, 2017 September 7 | % Update 2022-10-08: Simulate ARMA model 8 | 9 | function [y,t,X] = step(varargin) 10 | % Check if there is some input arguments or it's not a model 11 | if(isempty(varargin{1})) 12 | error ('Missing input') 13 | end 14 | 15 | % Check if there is a model 16 | if(strcmp(varargin{1}.type,'SS')) 17 | 18 | % Get time 19 | if(length(varargin) >= 2) 20 | t = varargin{2}; 21 | else 22 | disp('Time assumed to be 10 seconds'); 23 | t = 10; 24 | end 25 | 26 | % Get sample time to compute the new time vector 27 | sampleTime = varargin{1}.sampleTime; 28 | if(sampleTime > 0) 29 | t = 0:sampleTime:t; 30 | else 31 | t = 0:0.01:t; % Sample time assumed to be 0.01 32 | end 33 | 34 | % Multiple signals...or not! 35 | u = ones(size(varargin{1}.B, 2), length(t)); % Creates 1 1 1 1 1 1 1 36 | x0 = zeros(size(varargin{1}.A, 1), 1); % Assume x0 = [0; 0; 0; ..... ; 0] 37 | 38 | % Call lsim! 39 | [y,t,X] = mc.lsim(varargin{1}, u, t, x0); 40 | elseif(strcmp(varargin{1}.type,'TF')) 41 | % TF to SS 42 | sys = mc.tf2ss(varargin{1}, 'OCF'); 43 | 44 | % Get time 45 | if(length(varargin) >= 2) 46 | t = varargin{2}; 47 | else 48 | disp('Time assumed to be 10 seconds'); 49 | t = 10; 50 | end 51 | 52 | % Call step 53 | [y,t,X] = mc.step(sys,t); 54 | elseif(strcmp(varargin{1}.type,'ARMA')) 55 | 56 | % Get end time 57 | if(length(varargin) >= 2) 58 | t = varargin{2}; 59 | else 60 | disp('Time assumed to be 10 seconds'); 61 | t = 10; 62 | end 63 | 64 | % Create time 65 | sampleTime = varargin{1}.sampleTime; 66 | if(sampleTime > 0) 67 | t = 0:sampleTime:t; 68 | else 69 | t = 0:0.01:t; % Sample time assumed to be 0.01 70 | end 71 | 72 | % Create input u 73 | u = linspace(1, 1, length(t)); 74 | 75 | % Call lsim! 76 | [y,t,X] = mc.lsim(varargin{1}, u, t); 77 | else 78 | error('Not a state space model or a transfer function') 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /matave/+mc/tf.m: -------------------------------------------------------------------------------- 1 | % Generates a transfer function from numerator vector and denomerator vector 2 | % Input: numerator, denomerator, delay(optional) 3 | % Example 1: G = mc.tf(num, den, delay) 4 | % Example 2: G = mc.tf(num, den) 5 | % Author: Daniel Mårtensson, 2017 September 6 | % Update: Added padé approximation 2020-06-29 7 | 8 | function [G] = tf(varargin) 9 | % Check if there is some input arguments 10 | if(isempty (varargin)) 11 | error ('Missing arguments') 12 | end 13 | % OK. We have arguments! 14 | 15 | % Get numerator 16 | if(length(varargin) < 1) 17 | error('Missing numerator') 18 | else 19 | numerator = varargin{1}; 20 | end 21 | % Get denomerator 22 | if(length(varargin) < 2) 23 | error('Missing denomerator') 24 | else 25 | denomerator = varargin{2}; 26 | end 27 | 28 | % Check if there is some numerators 29 | if(isempty (numerator)) 30 | error('Missing numerator'); 31 | end 32 | % OK. We have numerators! 33 | 34 | % Check if there is some denomerators 35 | if(isempty (denomerator)) 36 | error('Missing denomerator'); 37 | end 38 | % OK. We have denomerator! 39 | 40 | % Remove the first 0's in the numerator and denomerator 41 | % Begin with the numerator 42 | for i = 1:length(numerator) 43 | % Find the first value which is larger that 0 or less that 0 44 | if(or(numerator(i) > 0, numerator(i) < 0)) 45 | % Found it! 46 | numerator = numerator(1,i:length(numerator)); 47 | break; 48 | end 49 | end 50 | 51 | % Then with the denomerator 52 | for i = 1:length(denomerator) 53 | % Find the first value which is larger that 0 or less that 0 54 | if(or(denomerator(i) > 0, denomerator(i) < 0)) 55 | % Found it! 56 | denomerator = denomerator(1,i:length(denomerator)); 57 | break; 58 | end 59 | end 60 | 61 | % Build the transfer function 62 | numeratorString = stringPoly(numerator); % Get the numerator string 63 | denomeratorString = stringPoly(denomerator); % Get the denomerator string 64 | dash = getDashedLine(numeratorString, denomeratorString); % Get the dashed line 65 | 66 | % Save the vale 67 | G.num = numerator; 68 | G.den = denomerator; 69 | % Delaytime 70 | if(length(varargin) >= 3) 71 | % Get dashed line delay 72 | delay = varargin{3}; 73 | if(delay > 0) 74 | dash = strcat(dash, 'e^(', num2str(-delay), 's', ')'); 75 | % Remove 1 to '' if delay = 1 76 | if delay == 1 77 | dash = regexprep(dash,'[1]',''); 78 | end 79 | G.delay = delay; 80 | else 81 | G.delay = 0; 82 | end 83 | else 84 | G.delay = 0; 85 | end 86 | % Save 87 | G.tfnum = numeratorString; 88 | G.tfdash = dash; 89 | G.tfden = denomeratorString; 90 | G.type = 'TF'; 91 | G.sampleTime = 0; 92 | 93 | % Padé approximation 94 | if(G.delay > 0) 95 | G = mc.pade(G, 4); 96 | end 97 | end 98 | 99 | % Get a dashed line with dynamical length depending on denomeratorString or numeratorString 100 | function [dash] = getDashedLine(numeratorString, denomeratorString) 101 | dash = ''; 102 | if(length(numeratorString) <= length(denomeratorString)) 103 | for i = 1:length(denomeratorString) 104 | dash = strcat(dash,'-'); 105 | end 106 | else 107 | for i = 1:length(numeratorString) 108 | dash = strcat(dash,'-'); 109 | end 110 | end 111 | end 112 | 113 | function [returnString] = stringPoly(array) 114 | polyString = {}; % Begin with empty cell string 115 | 116 | % Get all to a string cell 117 | for i = 1:length(array) 118 | if(and(array(i) ~= 0, length(array) - i ~= 0)) 119 | if(length(array) - i > 1) 120 | if(and(array(i) <= 1.000001, array(i) >= 0.999999)) 121 | polyString(1, i) = {strcat('s^', num2str(length(array) - i))}; 122 | elseif(and(array(i) >= -1.000001, array(i) <= -0.999999)) 123 | polyString(1, i) = {strcat('-s^', num2str(length(array) - i))}; 124 | else 125 | polyString(1, i) = {strcat(num2str(array(i)), 's^', num2str(length(array) - i))}; 126 | end 127 | else 128 | if(and(array(i) <= 1.000001, array(i) >= 0.999999)) 129 | polyString(1, i) = {strcat('s')}; 130 | elseif(and(array(i) >= -1.000001, array(i) <= -0.999999)) 131 | polyString(1, i) = {strcat('-s')}; 132 | else 133 | polyString(1, i) = {strcat(num2str(array(i)), 's')}; 134 | end 135 | end 136 | else 137 | polyString(1, i) = {strcat(num2str(array(i)))}; 138 | end 139 | end 140 | 141 | % Transform that string cell to a complete string 142 | returnString = ''; 143 | for i = 1:length(polyString) 144 | % No only-zeros are allowed 145 | if(and(~strcmp(char(polyString(1,i)), '0'), ~strcmp(char(polyString(1,i)), '-0'))) 146 | if(length(strfind(char(polyString(1,i)), '-')) > 0) 147 | returnString = [returnString,' ', char(polyString(1,i))]; 148 | else 149 | if(length(returnString) == 0) 150 | returnString = [returnString,' ', char(polyString(1,i))]; 151 | else 152 | returnString = [returnString,' + ', char(polyString(1,i))]; 153 | end 154 | end 155 | end 156 | end 157 | end 158 | -------------------------------------------------------------------------------- /matave/+mc/tzero.m: -------------------------------------------------------------------------------- 1 | % Generates the MIMO zeros from a transfer function or state space model 2 | % Input: G, sys 3 | % Example 1: [z, gain] = mc.tzero(G) 4 | % Example 2: [z, gain] = mc.tzero(sys) 5 | % Author: Daniel Mårtensson, 2017 Oktober 6 | 7 | function [z, gain] = tzero(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | % Get necessary info 18 | A = varargin{1}.A; 19 | sizeOrginalA = size(A, 2); 20 | B = varargin{1}.B; 21 | C = varargin{1}.C; 22 | D = varargin{1}.D; 23 | % Increase A at maximum size 24 | column = [size(B,2) size(C,2) size(D,2)]; 25 | row = [size(B,1) size(C,1) size(D,1)]; 26 | A = [A zeros(size(A,1), max(column) - size(A,2))]; 27 | A = [A; zeros(max(row) - size(A,1), size(A,2))]; 28 | % Make sure so matrix B, C, D have the same size as A 29 | C = rechange(A,C); 30 | B = rechange(A,B); 31 | D = rechange(A,D); 32 | % Compute the zeros 33 | M = [A B; C D]; 34 | I = [eye(size(A,1), size(A,2)) B*0; C*0 D*0]; 35 | z = eig(M, I); 36 | z = z(isfinite(z)); % Remove the inf and zero values from z 37 | % check the lengt of z so we can remove some 0 0 0 from z 38 | if(length(z) - sizeOrginalA > 0) 39 | % Ok! We have more zeros that orginal size of A 40 | % Remove all 0 0 0 41 | z = z(z ~= 0); 42 | % Then add new one! 43 | % if sizeOrginalA - length(z) <= 0, then it will be no change 44 | z = [z zeros(1, sizeOrginalA - length(z))]; % add 0 if needed 45 | end 46 | p = mc.pole(varargin{1}); 47 | dc = mc.dcgain(varargin{1}); 48 | gain = dc*prod(-p)/prod(-z); 49 | elseif(strcmp(type, 'TF' )) 50 | error('Only for state space models!') 51 | else 52 | error('This is not TF or SS'); 53 | end 54 | 55 | end 56 | % Make sure so matrix B, C, D have the same size as A 57 | function [matrix] = rechange(A, mat) 58 | if(size(A, 1) - size(mat, 1) >= 0) 59 | matrix = [mat; zeros(size(A, 1) - size(mat, 1), size(mat,2))]; 60 | end 61 | if(size(A, 2) - size(matrix, 2) >= 0) 62 | matrix = [matrix zeros(size(matrix,1), size(A, 2) - size(matrix, 2))]; 63 | end 64 | end -------------------------------------------------------------------------------- /matave/+mc/updatematavecontrol.m: -------------------------------------------------------------------------------- 1 | % Update the whole matavecontrol library by downloading from GitHub 2 | % Author: Daniel Mårtensson, Februari 2018 3 | % Update 2023-05-15 for MATLAB Control System Toolbox portability 4 | 5 | function updatematavecontrol() 6 | % Get the current working dictionary 7 | currentFolder = pwd; 8 | 9 | % Just update matavecontrol 10 | A = what('matave'); % Importat that it must stand 'matave'. Nothing else! 11 | 12 | % Get the information about where the files are 13 | path = strcat(A.path, '\', '+mc'); % File path 14 | 15 | % Go to path dictionary 16 | cd(path); 17 | 18 | % Downloading listOfFunctions 19 | if(exist('OCTAVE_VERSION', 'builtin') ~= 0) 20 | urlwrite('https://raw.githubusercontent.com/DanielMartensson/matavecontrol/master/listOfFunctions', 'listOfFunctions'); 21 | else 22 | websave('https://raw.githubusercontent.com/DanielMartensson/matavecontrol/master/listOfFunctions', 'listOfFunctions'); 23 | end 24 | 25 | % Read the listOfFunctions 26 | fid = fopen('listOfFunctions'); 27 | txt = textscan(fid, '%s', 'delimiter', '\n'); % Importat to have the delimiter = '\n' 28 | % Remove this double struct 29 | fileList = txt{1,1}; 30 | 31 | % Downloading all the other files 32 | [m, n] = size(fileList); 33 | for i = 1:m 34 | % Downloading 35 | nameOfFile = fileList{i, 1}; 36 | URL = strcat('https://raw.githubusercontent.com/DanielMartensson/matavecontrol/master/matave/+mc/', nameOfFile) 37 | [saveplace, Success] = urlwrite(URL, nameOfFile); 38 | saveplace 39 | Success 40 | end 41 | 42 | disp('Matavecontrol is updated!') 43 | 44 | % Get to the current working dictionary 45 | cd(currentFolder); 46 | 47 | end 48 | -------------------------------------------------------------------------------- /matave/+mc/zero.m: -------------------------------------------------------------------------------- 1 | % Generates zeros from SISO transfer function or SISO state space model 2 | % Input: G, sys 3 | % Example 1: [z, gain] = mc.zero(G) 4 | % Example 2: [z, gain] = mc.zero(sys) 5 | % Author: Daniel Mårtensson, 2017 September 6 | 7 | function [z, gain] = zero(varargin) 8 | % Check if there is any input 9 | if(isempty(varargin)) 10 | error ('Missing input') 11 | end 12 | 13 | % Get model type 14 | type = varargin{1}.type; 15 | % Check if there is a TF or SS model 16 | if(strcmp(type, 'SS' )) 17 | A = varargin{1}.A; 18 | sizeOrginalA = size(A, 2); 19 | B = varargin{1}.B; 20 | C = varargin{1}.C; 21 | D = varargin{1}.D; 22 | % Check if it's SISO system 23 | if(or(size(B, 2) > 1, size(C, 1) > 1)) 24 | error('This is only for SISO system, try to use tzero insted') 25 | end 26 | z = eig([A B; C D], [eye(size(A,1)) B*0; C*0 D*0]); % Get zeros 27 | z = z(isfinite(z)); % Remove the inf and zero values from z 28 | % check the lengt of z so we can remove some 0 0 0 from z 29 | if(length(z) - sizeOrginalA > 0) 30 | % Ok! We have more zeros that orginal size of A 31 | % Remove all 0 0 0 32 | z = z(z ~= 0); 33 | % Then add new one! 34 | % if sizeOrginalA - length(z) <= 0, then it will be no change 35 | z = [z zeros(1, sizeOrginalA - length(z))]; % add 0 if needed 36 | end 37 | p = mc.pole(varargin{1}); 38 | dc = mc.dcgain(varargin{1}); 39 | gain = dc*prod(-p)/prod(-z); 40 | elseif(strcmp(type, 'TF' )) 41 | % Get z, p, k 42 | G = varargin{1}; 43 | if(or(size(G,1) > 1, size(G,2) > 1)) 44 | error('This is only for SISO system, try to use tzero insted') 45 | end 46 | z = roots(G.num); 47 | p = roots(G.den); 48 | dc = mc.dcgain(G); 49 | gain = dc*prod(-p)/prod(-z); 50 | else 51 | error('This is not TF or SS'); 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /matave/+mc/zpk.m: -------------------------------------------------------------------------------- 1 | % Generate a transfer function from vector of zero, vector of poles and vectior of gain 2 | % Input: z, p , k, delay(optional) 3 | % Example 1: G = mc.zpk(z, p, k) 4 | % Example 2: G = mc.zpk(z, p, k, delay) 5 | % Author: Daniel Mårtensson, 2017 September 6 | 7 | 8 | function [G] = zpk(varargin) 9 | % Check if there is any input 10 | if(isempty(varargin)) 11 | error ('Missing input') 12 | end 13 | 14 | % Get zeros 15 | if(length(varargin) < 1) 16 | error('Missing zeros') 17 | else 18 | z = varargin{1}; 19 | end 20 | % Get poles 21 | if(length(varargin) < 2) 22 | error('Missing zeros') 23 | else 24 | p = varargin{2}; 25 | end 26 | 27 | % Get gain 28 | if(length(varargin) < 3) 29 | error('Missing gain') 30 | else 31 | k = varargin{3}; 32 | end 33 | 34 | % Check if values are cells 35 | if(~iscell(z)) 36 | z = {z}; 37 | end 38 | 39 | if(~iscell(p)) 40 | p = {p}; 41 | end 42 | 43 | % The gain k is never cell 44 | 45 | % Get numerator and denomerator 46 | num = cellfun (@(zer, gain) real (gain * poly (zer)), z, num2cell(k), 'uniformoutput', false); 47 | den = cellfun (@(pol) real (poly (pol)), p, 'uniformoutput', false); 48 | 49 | % Get delay 50 | if(length(varargin) >= 4) 51 | delay = varargin{4}; 52 | G = mc.tf(round(cell2mat(num)*1/1e-6)*1e-6, round(cell2mat(den)*1/1e-6)*1e-6, delay); % Tar bort alla 000000 på slutet 53 | else 54 | G = mc.tf(cell2mat(num), cell2mat(den)); 55 | end 56 | 57 | 58 | end 59 | -------------------------------------------------------------------------------- /matave/README.md: -------------------------------------------------------------------------------- 1 | This is the folder where all the matavecontrol files are. 2 | 3 | Books which has been used are: 4 | * Grundläggande reglerteknik, 2002, edition 4, ISBN: 91-44-02416-9 - Bengt Lennartsson, Chalmers, Sverige 5 | * System Modeling and Identification, 2017, edition 2, ISBN: 0-13-482308-7, Can be purchased at http://kfsab.se/, - Rolf Johansson, Lund, Sverige 6 | -------------------------------------------------------------------------------- /resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/yjq8T9-gQYy0f2NhORonQUngnPgd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/yjq8T9-gQYy0f2NhORonQUngnPgp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/0svTqDZyxKsHr8tr9l_5tqIMcqwd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/0svTqDZyxKsHr8tr9l_5tqIMcqwp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/0tLh2TRaHNLS2qzQDqexHEHLXVMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/0tLh2TRaHNLS2qzQDqexHEHLXVMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/96SFBJ-bIQLnHvDLQUTQfLO8XDod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/96SFBJ-bIQLnHvDLQUTQfLO8XDop.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/_MRJWxV8DfREsKhDtvTq3Jjm_RQd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/_MRJWxV8DfREsKhDtvTq3Jjm_RQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/icQfkkI3t1PC4Ek0YY0fHihS5Yod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/icQfkkI3t1PC4Ek0YY0fHihS5Yop.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/oSQ_nBKlxRWiL15nEg7_Rn5-agId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/oSQ_nBKlxRWiL15nEg7_Rn5-agIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/qzR9VwkbUp-oa5a1uN0CPiHvfNId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/qzR9VwkbUp-oa5a1uN0CPiHvfNIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/ySuCV85gsbuVjl71P1huo8omBFQd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/OfxnnyUcu5GSELEDRUyOXcMZW0c/ySuCV85gsbuVjl71P1huo8omBFQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-CoAOABvy9cuGUC38ZyaKbdeLOwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-CoAOABvy9cuGUC38ZyaKbdeLOwp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-SbeBzw66TzYB4FU3szMFT_cuxAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-SbeBzw66TzYB4FU3szMFT_cuxAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-uWRYmmAnEkaEOZhJsoOtba7DlEd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/-uWRYmmAnEkaEOZhJsoOtba7DlEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/11XmEjI_K5BBZNuXErv9HOmoVb4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/11XmEjI_K5BBZNuXErv9HOmoVb4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/1KTluOp16-oR5v3JUK0UHA8e6WUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/1KTluOp16-oR5v3JUK0UHA8e6WUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/1w-nJuyPlyAftYmX_f8A0UO2RoYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/1w-nJuyPlyAftYmX_f8A0UO2RoYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/2-za1lJr8fVK3PJ1MHlXunw5Oskd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/2-za1lJr8fVK3PJ1MHlXunw5Oskp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/2rEj_f0GPdtD554fpQNmyoBcu3Id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/2rEj_f0GPdtD554fpQNmyoBcu3Ip.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/4DRfx5bQIrL3zJNHm7GLriyLfqUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/4DRfx5bQIrL3zJNHm7GLriyLfqUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/4PanJm-mPEJlkWhsC591LHn6aiYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/4PanJm-mPEJlkWhsC591LHn6aiYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/54Nzb97VcU2zBkaWOgRp2fge9pcd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/54Nzb97VcU2zBkaWOgRp2fge9pcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/5623OBuXkEpLP79xKtBFRnkKHTwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/5623OBuXkEpLP79xKtBFRnkKHTwp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/6Bh2D-xMzXRKqe6s6nncGX_LLq4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/6Bh2D-xMzXRKqe6s6nncGX_LLq4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/6oFg1XfxuDHhfjP4t4s5xOHzcrsd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/6oFg1XfxuDHhfjP4t4s5xOHzcrsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7IW8qVfB6kZF63giXtxVXReB9SUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7IW8qVfB6kZF63giXtxVXReB9SUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7oOVoMxiTqU8K6QQ4sUkZO9RP2Ud.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7oOVoMxiTqU8K6QQ4sUkZO9RP2Up.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7zY7EuVRFOGx43YZ-Y9TIffdlRMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/7zY7EuVRFOGx43YZ-Y9TIffdlRMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/B67JrGieaCPkkHupmiFqKtCE6pUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/B67JrGieaCPkkHupmiFqKtCE6pUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BWbN1hILgy2Xnv7NeEd_GOhnYVkd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BWbN1hILgy2Xnv7NeEd_GOhnYVkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BdYYMugAhyen8aTKF0WVSC5CJMYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BdYYMugAhyen8aTKF0WVSC5CJMYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BrnqdsK_ogt7Lib0tBOndoDjD_Yd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/BrnqdsK_ogt7Lib0tBOndoDjD_Yp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Cn9iMC8MNPNB5JDsln6zVltnWPYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Cn9iMC8MNPNB5JDsln6zVltnWPYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Cr5mcv7j6DQanwB6ElyAlI8bUJsd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Cr5mcv7j6DQanwB6ElyAlI8bUJsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/FFPwQdZhJJjzWviOr_Y8ow76HHEd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/FFPwQdZhJJjzWviOr_Y8ow76HHEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/IdnWZbYNeczTHna-1KgMBVw3dTkd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/IdnWZbYNeczTHna-1KgMBVw3dTkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/ItT4tYcXdZiwyGq2gNplYIZi-5kd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/ItT4tYcXdZiwyGq2gNplYIZi-5kp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/JyUYT_XYg4otoIQ8t01K4919hBUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/JyUYT_XYg4otoIQ8t01K4919hBUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/K73qDanDhcbDYKqjaFwytbLwGKgd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/K73qDanDhcbDYKqjaFwytbLwGKgp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Ks44_1yuOlA02cwQtl9Hj_VSmGQd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Ks44_1yuOlA02cwQtl9Hj_VSmGQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/KyuCQK9P5YV7bEjabcSd4q48gY8d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/KyuCQK9P5YV7bEjabcSd4q48gY8p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/KzeaGeO1UH_COx-dXm2_DAEReEcd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/KzeaGeO1UH_COx-dXm2_DAEReEcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/N2RPtkh5ZI7i2sSZ9SOs-pP9cw0d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/N2RPtkh5ZI7i2sSZ9SOs-pP9cw0p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Q0mF6K2JACo0hwfoTHRiZIIs0UUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Q0mF6K2JACo0hwfoTHRiZIIs0UUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/SeEYVLuQTDVvsjYSRnAtdr_2NhQd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/SeEYVLuQTDVvsjYSRnAtdr_2NhQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/V0cZFTBU3_EpgkWw_Io5Y6jlFZgd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/V0cZFTBU3_EpgkWw_Io5Y6jlFZgp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/W-Du79i4Ko3EezEp2M74qz5SYusd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/W-Du79i4Ko3EezEp2M74qz5SYusp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Yb-7rgk-EbjB7wP6z2IdIPPvUlAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Yb-7rgk-EbjB7wP6z2IdIPPvUlAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/YopdEcictGnkIQ_5prpSJs34qMkd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/YopdEcictGnkIQ_5prpSJs34qMkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Yvbp9FUZKCSQJncgLoI5reinE8gd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/Yvbp9FUZKCSQJncgLoI5reinE8gp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/ZSr63X3mMNEhpHVxHT_0ldMLNqYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/ZSr63X3mMNEhpHVxHT_0ldMLNqYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_K78ptPkoib18O_M5mDAripZWUkd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_K78ptPkoib18O_M5mDAripZWUkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_dBbd0q9a5geL--6i8vH8WvsZbEd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_dBbd0q9a5geL--6i8vH8WvsZbEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_yABYToFV-Vjbphro5wtF2zF0NAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/_yABYToFV-Vjbphro5wtF2zF0NAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/bhnlN9XOEJ1B6NEw30i-8lD3XSwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/bhnlN9XOEJ1B6NEw30i-8lD3XSwp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/cVDmIEZqQ6RuSQlM-GFDxsJK8Fcd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/cVDmIEZqQ6RuSQlM-GFDxsJK8Fcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/cj0dX_uC53Jt6gPqFnKbLR1-iJMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/cj0dX_uC53Jt6gPqFnKbLR1-iJMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/crViRB3JW-vZT9LEYWdXpvxIyIEd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/crViRB3JW-vZT9LEYWdXpvxIyIEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jMspD52-8pQRDJM84VawTeYB670d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jMspD52-8pQRDJM84VawTeYB670p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jXytGzI4O2iQkm5Iid_M99e7kl8d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jXytGzI4O2iQkm5Iid_M99e7kl8p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jegMYt-Jgzo1xmWNIPX-xdbhG18d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/jegMYt-Jgzo1xmWNIPX-xdbhG18p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/kFa7fP1qhyzvenZPkkRfV8neELgd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/kFa7fP1qhyzvenZPkkRfV8neELgp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/k_LDNoMhWM_ftCTzKT4LUnl8z1Id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/k_LDNoMhWM_ftCTzKT4LUnl8z1Ip.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/kdyNwcW_EV1D4OcQHOT0h5ui6oUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/kdyNwcW_EV1D4OcQHOT0h5ui6oUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/lTNcbFF3WgZbJrqXWWqgs1AlWFUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/lTNcbFF3WgZbJrqXWWqgs1AlWFUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/mLjyaWT3h9G6pnHN4E1ZmZnWDDwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/mLjyaWT3h9G6pnHN4E1ZmZnWDDwp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/nxHIvmYl91RxdSAAehuvNMiMvM0d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/nxHIvmYl91RxdSAAehuvNMiMvM0p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/q0SFswbWjtAqBsGhTVKi6kBxqmAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/q0SFswbWjtAqBsGhTVKi6kBxqmAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qOqHwCrRHme4LTDtVseEt6L5eN8d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qOqHwCrRHme4LTDtVseEt6L5eN8p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qY_esZacgV_-CBdwSlj-x3tae5cd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qY_esZacgV_-CBdwSlj-x3tae5cp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qn_WO7trpHLQ8MBDNf14xTjUXv8d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/qn_WO7trpHLQ8MBDNf14xTjUXv8p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/sZsojGNj1Xsew2r2cjrxgTtJiz4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/sZsojGNj1Xsew2r2cjrxgTtJiz4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/t6G0dleSjZRdaE0mqOxDKu4M8xsd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/t6G0dleSjZRdaE0mqOxDKu4M8xsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/t6Xz-myNiIJid1uOQBu3M-Z_hf4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/t6Xz-myNiIJid1uOQBu3M-Z_hf4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/tmzg2FyGbnUr4U5BapcMKI6CS7Ed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/tmzg2FyGbnUr4U5BapcMKI6CS7Ep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/utwGE9hQzpXV3PZxiEjFjWMyMeAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/utwGE9hQzpXV3PZxiEjFjWMyMeAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/x-l6L7vAJyYBtn-SDFTmhDDN-MAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/x-l6L7vAJyYBtn-SDFTmhDDN-MAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/x4GzzdUEvl5vK1S2qWPJ8s1NfPYd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/x4GzzdUEvl5vK1S2qWPJ8s1NfPYp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xNX7uGtM_e36nIF5tMGLJYQgs_4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xNX7uGtM_e36nIF5tMGLJYQgs_4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xi57K6yo7qEW6cfchYEdjcWGnkcd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xi57K6yo7qEW6cfchYEdjcWGnkcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xyaFs-562jwpSMpoHmrjkNpXI3kd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/xyaFs-562jwpSMpoHmrjkNpXI3kp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/yMp73CpOLXJfFwcL5zbkVD1Dgpod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/yMp73CpOLXJfFwcL5zbkVD1Dgpop.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/yvnfTAHHm4btVWqLUrENzD5XMNsd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/yvnfTAHHm4btVWqLUrENzD5XMNsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zDJYuT22rAyRg0WvG1AdowAaXN4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zDJYuT22rAyRg0WvG1AdowAaXN4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zgQIfZQSIp7WL4NSqDq4njhDAOcd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zgQIfZQSIp7WL4NSqDq4njhDAOcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zr_37WR-HxanuIcLCVDyLghcKzAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /resources/project/Y0MXjQcTETsDYSfZOITJxehWTOQ/zr_37WR-HxanuIcLCVDyLghcKzAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/Miy75s7SKM4dtkSrAQrwPD2Pnvsd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/Miy75s7SKM4dtkSrAQrwPD2Pnvsp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/Y0MXjQcTETsDYSfZOITJxehWTOQd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/Y0MXjQcTETsDYSfZOITJxehWTOQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/tzlQc0NLrARVg_2cChAq5muGE2Ud.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/lPZI5oa5DxrsR-PK7aQQLq3WqrE/tzlQc0NLrARVg_2cChAq5muGE2Up.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/OfxnnyUcu5GSELEDRUyOXcMZW0cd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/OfxnnyUcu5GSELEDRUyOXcMZW0cp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/lPZI5oa5DxrsR-PK7aQQLq3WqrEd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/lPZI5oa5DxrsR-PK7aQQLq3WqrEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/6x1BhZX_fLnKpcwqra0qFwv1jIgp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/KAXfQgCar2Yb8zOxgvf9hdmLP1Ep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/NmGqIpAwUJcXFyLjFAGnU9uyN5Yp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/rootp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/project/uuid-f651a9a5-b7b9-4361-b11c-7c91771b35e7.xml: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------