├── .gitignore ├── LICENSE ├── README.md ├── TcMatrix.sln ├── TcMatrix ├── LibraryCategory.libcat.xml ├── TcMatrix.tspproj ├── TcMatrix.tspproj.bak └── TcMatrix │ ├── POUs │ ├── Array2DStaticMatrix.TcPOU │ ├── Csv │ │ ├── MatrixCsvReader.TcPOU │ │ └── MatrixCsvWriter.TcPOU │ ├── DynamicMatrix.TcPOU │ ├── ExternalStaticMatrix.TcPOU │ ├── Functions │ │ ├── Arrays │ │ │ ├── Array2D_Cols.TcPOU │ │ │ ├── Array2D_Rows.TcPOU │ │ │ ├── Array2D_To_Matrix.TcPOU │ │ │ ├── Matrix_SameSizeAs_Array2D.TcPOU │ │ │ └── Matrix_To_Array2D.TcPOU │ │ ├── Matrix │ │ │ ├── Matrix_CanMult.TcPOU │ │ │ ├── Matrix_Copy.TcPOU │ │ │ ├── Matrix_DeterminateSquare.TcPOU │ │ │ ├── Matrix_ElementDifference.TcPOU │ │ │ ├── Matrix_ElementProduct.TcPOU │ │ │ ├── Matrix_ElementSum.TcPOU │ │ │ ├── Matrix_Grow.TcPOU │ │ │ ├── Matrix_InvertSquare.TcPOU │ │ │ ├── Matrix_Product.TcPOU │ │ │ ├── Matrix_Scale.TcPOU │ │ │ ├── Matrix_Shrink.TcPOU │ │ │ ├── Matrix_SubMatrix.TcPOU │ │ │ ├── Matrix_Transpose.TcPOU │ │ │ └── Matrix_TransposeSquare.TcPOU │ │ └── Vector │ │ │ ├── Vector_CrossProduct.TcPOU │ │ │ ├── Vector_DotProduct.TcPOU │ │ │ ├── Vector_Magnitude.TcPOU │ │ │ └── Vector_Normalize.TcPOU │ ├── Matrix.TcPOU │ ├── MatrixAccessors │ │ ├── MatrixAccessor.TcPOU │ │ ├── ShrunkMatrixAccessor.TcPOU │ │ ├── SubMatrixAccessor.TcPOU │ │ └── TransposeMatrixAccessor.TcPOU │ └── StaticMatrix.TcPOU │ ├── TcMatrix.plcproj │ └── Version │ └── Global_Version.TcGVL └── TcMatrixTest ├── TcMatrixTest.tsproj └── TcMatrixTest ├── PlcTask.TcTTO ├── TESTs ├── FB_Array_Test.TcPOU ├── FB_CsvReadWrite_Test.TcPOU ├── FB_DynamicMatrix_Test.TcPOU ├── FB_MatrixDeterminate_Test.TcPOU ├── FB_MatrixElementProduct_Test.TcPOU ├── FB_MatrixElementSum_Test.TcPOU ├── FB_MatrixGetMagicSquare_Test.TcPOU ├── FB_MatrixGrow_Test.TcPOU ├── FB_MatrixInvert_Test.TcPOU ├── FB_MatrixMatrixProduct_Test.TcPOU ├── FB_MatrixShrink_Test.TcPOU ├── FB_MatrixSubMatrix_Test.TcPOU ├── FB_MatrixTranspose_Test.TcPOU ├── FB_StaticMatrix_Test.TcPOU ├── FB_VectorCrossProduct_Test.TcPOU └── PRG_TEST.TcPOU ├── TcMatrixTest.plcproj └── Version └── Global_Version.TcGVL /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore template for TwinCAT3 2 | # website: https://www.beckhoff.com/twincat3/ 3 | # 4 | # Recommended: VisualStudio.gitignore 5 | 6 | # TwinCAT files 7 | *.tpy 8 | *.tclrs 9 | *.compiled-library 10 | *.compileinfo 11 | *.tmc 12 | *.tmcRefac 13 | *.library 14 | *.project.~u 15 | *.tsproj.bak 16 | *.xti.bak 17 | LineIDs.dbg 18 | LineIDs.dbg.bak 19 | _Boot/ 20 | _CompileInfo/ 21 | _Libraries/ 22 | 23 | ## Ignore Visual Studio temporary files, build results, and 24 | ## files generated by popular Visual Studio add-ons. 25 | ## 26 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 27 | 28 | # User-specific files 29 | *.rsuser 30 | *.suo 31 | *.user 32 | *.userosscache 33 | *.sln.docstates 34 | 35 | # User-specific files (MonoDevelop/Xamarin Studio) 36 | *.userprefs 37 | 38 | # Mono auto generated files 39 | mono_crash.* 40 | 41 | # Build results 42 | [Dd]ebug/ 43 | [Dd]ebugPublic/ 44 | [Rr]elease/ 45 | [Rr]eleases/ 46 | x64/ 47 | x86/ 48 | [Aa][Rr][Mm]/ 49 | [Aa][Rr][Mm]64/ 50 | bld/ 51 | [Bb]in/ 52 | [Oo]bj/ 53 | [Ll]og/ 54 | [Ll]ogs/ 55 | 56 | # Visual Studio 2015/2017 cache/options directory 57 | .vs/ 58 | # Uncomment if you have tasks that create the project's static files in wwwroot 59 | #wwwroot/ 60 | 61 | # Visual Studio 2017 auto generated files 62 | Generated\ Files/ 63 | 64 | # MSTest test Results 65 | [Tt]est[Rr]esult*/ 66 | [Bb]uild[Ll]og.* 67 | 68 | # NUnit 69 | *.VisualState.xml 70 | TestResult.xml 71 | nunit-*.xml 72 | 73 | # Build Results of an ATL Project 74 | [Dd]ebugPS/ 75 | [Rr]eleasePS/ 76 | dlldata.c 77 | 78 | # Benchmark Results 79 | BenchmarkDotNet.Artifacts/ 80 | 81 | # .NET Core 82 | project.lock.json 83 | project.fragment.lock.json 84 | artifacts/ 85 | 86 | # StyleCop 87 | StyleCopReport.xml 88 | 89 | # Files built by Visual Studio 90 | *_i.c 91 | *_p.c 92 | *_h.h 93 | *.ilk 94 | *.meta 95 | *.obj 96 | *.iobj 97 | *.pch 98 | *.pdb 99 | *.ipdb 100 | *.pgc 101 | *.pgd 102 | *.rsp 103 | *.sbr 104 | *.tlb 105 | *.tli 106 | *.tlh 107 | *.tmp 108 | *.tmp_proj 109 | *_wpftmp.csproj 110 | *.log 111 | *.vspscc 112 | *.vssscc 113 | .builds 114 | *.pidb 115 | *.svclog 116 | *.scc 117 | 118 | # Chutzpah Test files 119 | _Chutzpah* 120 | 121 | # Visual C++ cache files 122 | ipch/ 123 | *.aps 124 | *.ncb 125 | *.opendb 126 | *.opensdf 127 | *.sdf 128 | *.cachefile 129 | *.VC.db 130 | *.VC.VC.opendb 131 | 132 | # Visual Studio profiler 133 | *.psess 134 | *.vsp 135 | *.vspx 136 | *.sap 137 | 138 | # Visual Studio Trace Files 139 | *.e2e 140 | 141 | # TFS 2012 Local Workspace 142 | $tf/ 143 | 144 | # Guidance Automation Toolkit 145 | *.gpState 146 | 147 | # ReSharper is a .NET coding add-in 148 | _ReSharper*/ 149 | *.[Rr]e[Ss]harper 150 | *.DotSettings.user 151 | 152 | # TeamCity is a build add-in 153 | _TeamCity* 154 | 155 | # DotCover is a Code Coverage Tool 156 | *.dotCover 157 | 158 | # AxoCover is a Code Coverage Tool 159 | .axoCover/* 160 | !.axoCover/settings.json 161 | 162 | # Visual Studio code coverage results 163 | *.coverage 164 | *.coveragexml 165 | 166 | # NCrunch 167 | _NCrunch_* 168 | .*crunch*.local.xml 169 | nCrunchTemp_* 170 | 171 | # MightyMoose 172 | *.mm.* 173 | AutoTest.Net/ 174 | 175 | # Web workbench (sass) 176 | .sass-cache/ 177 | 178 | # Installshield output folder 179 | [Ee]xpress/ 180 | 181 | # DocProject is a documentation generator add-in 182 | DocProject/buildhelp/ 183 | DocProject/Help/*.HxT 184 | DocProject/Help/*.HxC 185 | DocProject/Help/*.hhc 186 | DocProject/Help/*.hhk 187 | DocProject/Help/*.hhp 188 | DocProject/Help/Html2 189 | DocProject/Help/html 190 | 191 | # Click-Once directory 192 | publish/ 193 | 194 | # Publish Web Output 195 | *.[Pp]ublish.xml 196 | *.azurePubxml 197 | # Note: Comment the next line if you want to checkin your web deploy settings, 198 | # but database connection strings (with potential passwords) will be unencrypted 199 | *.pubxml 200 | *.publishproj 201 | 202 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 203 | # checkin your Azure Web App publish settings, but sensitive information contained 204 | # in these scripts will be unencrypted 205 | PublishScripts/ 206 | 207 | # NuGet Packages 208 | *.nupkg 209 | # NuGet Symbol Packages 210 | *.snupkg 211 | # The packages folder can be ignored because of Package Restore 212 | **/[Pp]ackages/* 213 | # except build/, which is used as an MSBuild target. 214 | !**/[Pp]ackages/build/ 215 | # Uncomment if necessary however generally it will be regenerated when needed 216 | #!**/[Pp]ackages/repositories.config 217 | # NuGet v3's project.json files produces more ignorable files 218 | *.nuget.props 219 | *.nuget.targets 220 | 221 | # Microsoft Azure Build Output 222 | csx/ 223 | *.build.csdef 224 | 225 | # Microsoft Azure Emulator 226 | ecf/ 227 | rcf/ 228 | 229 | # Windows Store app package directories and files 230 | AppPackages/ 231 | BundleArtifacts/ 232 | Package.StoreAssociation.xml 233 | _pkginfo.txt 234 | *.appx 235 | *.appxbundle 236 | *.appxupload 237 | 238 | # Visual Studio cache files 239 | # files ending in .cache can be ignored 240 | *.[Cc]ache 241 | # but keep track of directories ending in .cache 242 | !?*.[Cc]ache/ 243 | 244 | # Others 245 | ClientBin/ 246 | ~$* 247 | *~ 248 | *.dbmdl 249 | *.dbproj.schemaview 250 | *.jfm 251 | *.pfx 252 | *.publishsettings 253 | orleans.codegen.cs 254 | 255 | # Including strong name files can present a security risk 256 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 257 | #*.snk 258 | 259 | # Since there are multiple workflows, uncomment next line to ignore bower_components 260 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 261 | #bower_components/ 262 | 263 | # RIA/Silverlight projects 264 | Generated_Code/ 265 | 266 | # Backup & report files from converting an old project file 267 | # to a newer Visual Studio version. Backup files are not needed, 268 | # because we have git ;-) 269 | _UpgradeReport_Files/ 270 | Backup*/ 271 | UpgradeLog*.XML 272 | UpgradeLog*.htm 273 | ServiceFabricBackup/ 274 | *.rptproj.bak 275 | 276 | # SQL Server files 277 | *.mdf 278 | *.ldf 279 | *.ndf 280 | 281 | # Business Intelligence projects 282 | *.rdl.data 283 | *.bim.layout 284 | *.bim_*.settings 285 | *.rptproj.rsuser 286 | *- [Bb]ackup.rdl 287 | *- [Bb]ackup ([0-9]).rdl 288 | *- [Bb]ackup ([0-9][0-9]).rdl 289 | 290 | # Microsoft Fakes 291 | FakesAssemblies/ 292 | 293 | # GhostDoc plugin setting file 294 | *.GhostDoc.xml 295 | 296 | # Node.js Tools for Visual Studio 297 | .ntvs_analysis.dat 298 | node_modules/ 299 | 300 | # Visual Studio 6 build log 301 | *.plg 302 | 303 | # Visual Studio 6 workspace options file 304 | *.opt 305 | 306 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 307 | *.vbw 308 | 309 | # Visual Studio LightSwitch build output 310 | **/*.HTMLClient/GeneratedArtifacts 311 | **/*.DesktopClient/GeneratedArtifacts 312 | **/*.DesktopClient/ModelManifest.xml 313 | **/*.Server/GeneratedArtifacts 314 | **/*.Server/ModelManifest.xml 315 | _Pvt_Extensions 316 | 317 | # Paket dependency manager 318 | .paket/paket.exe 319 | paket-files/ 320 | 321 | # FAKE - F# Make 322 | .fake/ 323 | 324 | # CodeRush personal settings 325 | .cr/personal 326 | 327 | # Python Tools for Visual Studio (PTVS) 328 | __pycache__/ 329 | *.pyc 330 | 331 | # Cake - Uncomment if you are using it 332 | # tools/** 333 | # !tools/packages.config 334 | 335 | # Tabs Studio 336 | *.tss 337 | 338 | # Telerik's JustMock configuration file 339 | *.jmconfig 340 | 341 | # BizTalk build output 342 | *.btp.cs 343 | *.btm.cs 344 | *.odx.cs 345 | *.xsd.cs 346 | 347 | # OpenCover UI analysis results 348 | OpenCover/ 349 | 350 | # Azure Stream Analytics local run output 351 | ASALocalRun/ 352 | 353 | # MSBuild Binary and Structured Log 354 | *.binlog 355 | 356 | # NVidia Nsight GPU debugger configuration file 357 | *.nvuser 358 | 359 | # MFractors (Xamarin productivity tool) working folder 360 | .mfractor/ 361 | 362 | # Local History for Visual Studio 363 | .localhistory/ 364 | 365 | # BeatPulse healthcheck temp database 366 | healthchecksdb 367 | 368 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 369 | MigrationBackup/ 370 | 371 | # Ionide (cross platform F# VS Code tools) working folder 372 | .ionide/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 BurksEngineering 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TcMatrix 2 | 3 | ## Description 4 | 5 | A TwinCAT 3 library for manipulating 2D data sets of LREAL. 6 | 7 | Features include: 8 | 9 | * Element-wise setting, getting, summing, scaling, and power functions 10 | * Initialization as copies, zeros, trapezoidal, and other pre-defined matrix types 11 | * Matrix operations like multiplication, transposition, and inversion 12 | * Vector operations for 1D matricies like dot/cross product and normalization 13 | * Complex access operations similar to ['slicing'](https://en.wikipedia.org/wiki/Array_slicing) 14 | * Options to use static or dynamically allocated memory 15 | * Reading/Writing with CSV files, output to the ADS message logger 16 | 17 | Compare to: 18 | 19 | * [CODESYS Matrix Library](https://us.store.codesys.com/matrix-library.html) ([docs](https://store.codesys.com/media/n98_media_assets/files/2111000003-D/4/Matrix%20Bibliothek_en.pdf)) 20 | * [Siemens Library of General Functions](https://support.industry.siemens.com/cs/document/109479728/library-of-general-functions-(lgf)-for-simatic-step-7-(tia-portal)-and-simatic-s7-1200-s7-1500) ([docs](https://cache.industry.siemens.com/dl/files/728/109479728/att_1019474/v3/109479728_LGF_TIAV16_DOC_V5_0_0_en.pdf)) 21 | 22 | ## Contents 23 | 24 | * [Installation](#twincat-3-installation) 25 | * [Usage](#usage) 26 | * [Quick Start](#quick-start) 27 | * [Matrix](#base-matrix-class) 28 | * [DynamicMatrix](#dynamicmatrix-class) 29 | * [StaticMatrix](#static-memory-matrix) 30 | * [MatrixAccessor](#matrix-accessors) 31 | * [Examples](#examples) 32 | * [Projects](#projects-with-implementations) 33 | 34 | ## TwinCAT 3 Installation 35 | 36 | ### From Binary 37 | 38 | 1. Go to the [releases page](https://github.com/BurksEngineering/TcMatrix/releases) and download the *.library file from the latest release, saving it to a temporary directory somewhere on the computer running TwinCAT. 39 | 1. Follow the [library installation instructions](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/4189333259.html) from Beckhoff, using the 'Install' option and browsing for the local copy you had just downloaded. 40 | 1. After installtion, you may delete the local copy of the library that you had downloaded. Beckhoff has likely copied it to a version-specific folder in `C:\TwinCAT\3.1\Components\Plc\Managed Libraries\Burks Engineering\TcMatrix\` 41 | 42 | ### From Source 43 | 44 | Preconditions: 45 | 46 | * TwinCAT 3.1.4024 XAE 47 | * TwinCAT 3.1.4024 XAR, ideally configured with an isolated core 48 | * Visual Studio Community or Shell, 2019 or higher 49 | * [TcUnit](https://github.com/tcunit/TcUnit) v1.2 or higher 50 | 51 | Compilation: 52 | 53 | 1. Clone the repository to a computer running TwinCAT 3 54 | 1. Open the [main solution file](TcMatrix.sln) in Visual Studio 55 | 1. Within the Visual Studio *TcMatrix* project, right click on the *TcMatrix/TcMatrix Project* item and select *Rebuild* 56 | 1. There should be no compile errors, although there may be warnings 57 | 1. Right click on the *TcMatrix/TcMatrix Project* item again and select *Save as library and install* 58 | 1. The file can be saved anywhere, but a local *Builds* folder is always a good choice 59 | 60 | Test: 61 | 62 | 1. Within the Visual Studio *TcMatrixTest* project, right click on the *PLC/TcMatrixTest/TcMatrixTest Project* item and select *Rebuild* 63 | 1. There should be no compile errors, although there may be warnings 64 | 1. Open the *SYSTEM/Real-Time* item and click *Read From Target*, then assign all tasks to an isolated core from your system 65 | 1. In the Visual Studio toolbar (or TwinCAT file menu) click *Activate Configuration* 66 | 1. When prompted, agree to start the project in run mode and auto-start the boot project 67 | 1. After a few seconds the TcUnit results should be visible in the Error List window. Verify that all tests have passed. 68 | 69 | ## Usage 70 | 71 | ### Quick Start 72 | 73 | Example showing vector multiplication with the identity matrix. 74 | See TcMatrixTest.FB_Array_Test.MarkdownExample1 75 | ``` 76 | VAR 77 | M : Array2DStaticMatrix; //This instance is the matrix that the code will interact with 78 | M_Data : ARRAY[1..3,1..3] OF LREAL; //This array will act as the memory for the matrix 79 | V : Array2DStaticMatrix; //This instance is the initial column vector 80 | V_Data : ARRAY[1..3,1..1] OF LREAL := [1, 2, 3]; //This array will act as the memory for the initial column vector, prepopulated 81 | Res : Array2DStaticMatrix; //This instance is the resulting column vector 82 | Res_Data : ARRAY[1..3,1..1] OF LREAL := [1, 2, 3]; //This array will act as the memory for the resulting column vector 83 | success : BOOL; //records success or failure of the matrix multiplication 84 | equal : BOOL; //records success if the resulting vector is equal to the first 85 | END_VAR 86 | 87 | M(Data := M_Data); //Connect the memory to the matrix and initialize it 88 | V(Data := V_Data); //Connect the memory to the initial column vector and initialize it (retaining declared values) 89 | Res(Data := Res_Data); //Connect the memory to the resulting column vector and initialize it 90 | 91 | M.FillTrapezoidal(Diagonal := 1, UpperRight := 0, LowerLeft := 0); //Transforms the matrix from all zeros into the identity matrix 92 | success := Matrix_Product(M,V,Res); //perform the matrix multiplication 93 | equal := V.IsEqual(Res); //the result of the multiplication should be equal to the initial value because of the identity matrix 94 | 95 | ``` 96 | 97 | ### Base Matrix Class 98 | 99 | This abstract FB is the basis for all other matrix FBs. 100 | It represents a 2D array of LREAL elements. 101 | It provides dozens of methods and properties useful for manipulating itself, calculating values, and comparing to other matricies. 102 | Critically, this base class does not actually contain any mechanism for storing the values of the matrix (that is the responsibility of the specific inheriting sub-class). 103 | 104 | --- 105 | **NOTE** 106 | 107 | Because *Matrix* is an abstract FB it cannot be assigned (`:=`) directly. 108 | Instead, each *Matrix* is always passed in and out of a function *AS REFERENCE*. 109 | This also allows interactions with inhereted sub-classes of *Matrix* more easily. 110 | 111 | --- 112 | 113 | Below are some (but not all) of the functions and methods within the base Matrix FB. All functions and methods are documented within the library and can be explored within TwinCAT. 114 | 115 | #### Element Access 116 | 117 | Fundamentally the matrix is just a 2D array of LREAL data. These simple methods and functions form the backbone of the entire class. 118 | 119 | * __Rows__ : returns the number of rows in the matrix 120 | * __Cols__ : Returns the number of columns in the matrix 121 | * __Size(dim)__ : Returns the length of the matrix in the specified dimension (0=rows, 1=cols) 122 | * __GetRC(R,C)__ : Returns the value of the element at the specified (0-indexed) position within the matrix 123 | * __SetRC(R,C,Val)__ : Sets the value of the element at the specified (0-indexed) position within the matrix 124 | * __IsEmpty__ : Returns TRUE if *Rows*=0 OR *Cols*=0 125 | * __IsSquare__ : Returns TRUE if *Rows*=*Cols* and the matrix is not empty 126 | * __IsVector__ : Returns TRUE if *Rows*=1 OR *Cols*=1 and the matrix is not empty 127 | 128 | Every *Matrix* is considered as a 1D array of LREAL data types under the hood. 129 | This 1D view of data can be particularly useful when considering the matrix as a vector, but not caring whether it is a row vector or column vector. 130 | 131 | * __Length__ : The length of the 1D array (equal to *Rows* x *Cols*) 132 | * __GetI(I)__ : Returns the value of the element at the specified (0-based) position in the 1D array 133 | * __SetI(I,Val)__ : Sets the value of the element at the specified (0-based) position in the 1D array 134 | 135 | #### Initializers 136 | 137 | * __Clear()__ : Sets the value of every element to 0.0 138 | * __CopyFrom(Matrix)__ : Only if the supplied matrix is exactly the same size as this matrix, copy all elements to this matrix 139 | * __FillFrom(Matrix)__ : Copy every element from the supplied matrix which exists in both this amtrix and the supplied matrix 140 | * __FillTrapezoidal(D,UR,LL)__ : Copy one value into the main diagonal of this matrix, copy another value into all elements to the upper-right of the main diagonal, and copy another value into all elements to the lower-left of the main diagonal 141 | 142 | #### Modifiers 143 | 144 | * __ElementSum(Matrix)__ : Sets each element of this matrix to the value of its sum with the corresponding element in the supplied matrix 145 | * __ElementDifference(Matrix)__ : Sets each element of this matrix (as subtrahend) to the value of its difference with the corresponding element in the supplied matrix (as minuend) 146 | * __ElementProduct(Matrix)__ : Sets each element of this matrix to the value of its product with the corresponding element in the supplied matrix 147 | * __Scale(Scalar)__ : Sets each element of this matrix to the value of its product with the specified scalar 148 | * __Power(Exponent)__ : Sets each element of this matrix to the value of itsself raised to the supplied exponent 149 | * __TransposeSquare()__ : (Works on square matricies only) Swaps each element at (R,C) with a corresponding element at (C,R) 150 | * __InvertSquare(Tolerance)__ : Transforms this matrix into its inverse, if possible. The supplied Tolerance is used as a limit for any number used as a denominator (1E-12 is a good value to use). 151 | * __SortByColAsc(C)__ : Sorts the matrix by swapping entire rows around until the specified column is in ascending order. The relative position of equal rows will remain unchanged so as to allow tiered sorting. 152 | 153 | #### Comparators 154 | 155 | * __IsEqualSize__ : Returns TRUE if this matrix is the same size (*Rows* and *Cols*) as the supplied matrix 156 | * __IsEqual__ : Returns TRUE if *IsEqualSize* is true AND every element in this matrix is equal to its corresponding element in the supplied matrix 157 | * __IsNearlyEqual(Tolerance)__ : Returns TRUE if *IsEqualSize* AND every element in this matrix is equal (within the specified tolerance) to its corresponding element in the supplied matrix 158 | 159 | #### Calculators 160 | 161 | * __Sum__ : A property that returns the sum of every element in the matrix 162 | * __MaxVal__ : A property that returns the maximum value contained in the matrix 163 | * __MinVal__ : A property that returns the minimum value contained in the matrix 164 | * __Average__ : A property that returns the average of all values contained in the matrix 165 | * __GetDeterminate()__ : Calculates the determinate of the matrix if it is square 166 | * __GetVectorMagnitude()__ : Calculates the magnitude (square root of the sum of the squares) of the matrix if it is a vector 167 | 168 | #### External Functions 169 | 170 | These functions compartmentalize simple matrix operations outside of any specific FB. 171 | For some operations, like matrix multiplication, the dimensions of every *Matrix* involved can be different which makes using an external function more convenient for non-resizeable matricies. 172 | They all take in *REFERENCE TO Matrix* as both the inputs and outputs to their arithmatic operation. 173 | Be careful when using a reference to the same *Matrix* instance as both an input and an output! 174 | 175 | A non-exhaustive list of included external functions (see documentation within TwinCAT for the full list): 176 | 177 | * __Matrix_Product__ 178 | * __Matrix_Transpose__ 179 | * __Matrix_Grow__ 180 | * __Matrix_Shrink__ 181 | * __Matrix_SubMatrix__ 182 | * __Vector_CrossProduct__ 183 | 184 | #### Inheritance Guide 185 | 186 | To make a concrete matrix class as a sub-class of the *Matrix* FB the following properties and methods must be implemented: 187 | 188 | * __Rows__ : *UINT* 189 | * __Cols__ : *UINT* 190 | * __GetI(I)__ : *LREAL* 191 | * __SetI(I,Val)__ : *BOOL* 192 | 193 | Because everything comes back to representing a 1D array of LREALs as a 2D array of LREALs all you need are these four functions. 194 | The *Rows* and *Cols* together define the length of the 1D array and the size of the 2D array. 195 | The *GetI* and *SetI* functions define the transformation between the 1D and 2D array, as well as access to the source of the 1D data. 196 | This type of interface also allows for a *Matrix* itself to be the source data for another *Matrix*! (see [Matrix Accessors](#matrix-accessors)) 197 | 198 | Example Inheritance: 199 | * __*DynamicMatrix*__ uses a *POINTER TO LREAL* assigned from dynamic memory allocation to track the 1D data 200 | * __*ExternalStaticMatrix*__ uses a *POINTER TO LREAL* assigned at initialization based on some external *ARRAY [] OF LREAL* 201 | * __*MatrixAccessor*__ uses a *REFERENCE TO Matrix* assigned at runtime as the basis for the memory and structure 202 | 203 | #### CSV File Interaction 204 | 205 | The *MatrixCsvReader* and *MatrixCsvWriter* FBs exist to help read/write data from/to CSV files on the disk of the local IPC. 206 | Headers must be supplied externally when writing, and are ignored when reading. 207 | When reading a CSV file the destination matrix must be large enough to fit the entire contents of the file. 208 | The functions take multiple PLC cycles to complete, and work like a standard multi-cylce FB (bExecute, bError, etc). 209 | See the included documentaiton within TwinCAT for details. 210 | 211 | ### DynamicMatrix Class 212 | 213 | The *DynamicMatrix* class uses the *FB_DynMem_Manager2* to dynamically allocate as much memory as required for the given operation. 214 | This amazing flexibility comes at the cost of some restrictions on use in order to avoid memory leaks. 215 | 216 | --- 217 | **WARNING** 218 | 219 | Using the assignment operator (`:=`) to copy a *DynamicMatrix* will result in the new matrix retaining a pointer to the data of the old matrix! 220 | For this reason, the pragma `{attribute 'no_assign'}` is used to block assignment at compile-time, but inheriting sub-classes will need to include this pragma themselves. 221 | Note that using *DynamicMatrix* as the return value of a function is essentially an assignment operation and will also not work. 222 | Therefore, it is recommended to always pass *DynamicMatrix* objects in and out of functions using the *REFERENCE TO* keyword. 223 | To alleviate the pain of these assignment rules there are a ton of '[Resultant](#resultants)' helper functions available to use which initialize a new *DynamicMatrix* as the result of some operation on other matrix objects. 224 | 225 | --- 226 | 227 | The *DynamicMatrix* FB will automatically free its memory when an instance of the class is created, or goes out of scope. 228 | This prevents memory leaks and page faults, but it also prevents you from instantiating a *DynamicMatrix* inside of a function and then passing a *REFERENCE TO* it back up the call chain. 229 | Another consequnce is that a *DynamicMatrix* cannot be retained after power-loss. 230 | A *DynamicMatrix* within a GVL will free its memory when the program terminates. 231 | 232 | #### Initializers 233 | 234 | All of these functions destroy any data already in the matrix and replace it with the new data. 235 | 236 | * __Free()__ : Frees all dynamically allocated memory and resets the size of the matrix to 0x0 237 | * __Init(R,C)__ : Initializes a *R*x*C* matrix, with potentially random non-zero values 238 | * __InitZeros(R,C)__ : Initializes a *R*x*C* matrix where every element is equal to 0.0 239 | * __InitVector(L,Val,Inc)__ : Initializes an *L*x1 column vector where the 0th element is equal to *Val* and every subsequent element is *Inc* larger than the previous 240 | * __InitCopy(Matrix)__ : Initializes a matrix with the exact size and contents of the supplied matrix 241 | * __InitIdentity(L)__ : Initializes a square identity matrix of size *L*x*L* 242 | * __InitConstant(R,C,Val)__ : Initializes a *R*x*C* matrix where every element is equal to the supplied value 243 | * __InitTrapezoidal(R,C,D,UR,LL)__ : Initializes a *R*x*C* matrix then fills is using *FillTrapezoidal()* 244 | 245 | #### Dynamic Modifiers 246 | 247 | All of these function change the dimensions *Rows* and *Cols*) of the matrix without destroying the data within the matrix. 248 | 249 | * __Resize(R,C,Retain?,Init?)__ : Changes the total number of *Rows* and *Cols* in the matrix. 250 | If Retain is seleced then any element within the bounds of both the initial and resulting matrix will have its value retained. 251 | If Init is selected then any newly created element will have its value set to zero. 252 | * __Transpose()__ : Similar to *TransposeSquare()*, however it works on rectangular matricies (swapping *Rows* and *Cols*) 253 | * __Shrink(R,C)__ : Removes the specified Row and Column from the matrix, resuling in a new size of (*Rows*-1,*Cols*-1). No dimension can be shrunk from 1 to 0 (therefore vectors only shrink in one direction). 254 | * __Grow(R,C,Dval,Rval,Cval)__ : Adds a row and column in the specified positions. The value of the new element at the intersection is specified by DVal, while the values in the newly created Row and Column are specified by Rval and Cval, respectively. 255 | 256 | #### Resultants 257 | 258 | There are many functions available that initialzie the size and contents of a *DynamicMatrix* to the result of another function (typically a [modifier](#modifiers) or an [external function](#external-functions)) 259 | 260 | A non-exhaustive list of resultant functions (see documentation within TwinCAT for the full list): 261 | 262 | * __AsElementSum__ 263 | * __AsInverse__ 264 | * __AsMatrixProduct__ 265 | * __AsVectorCrossProduct__ 266 | * __AsSubMatrix__ 267 | * __AsRowVector__ 268 | * __AsColVector__ 269 | 270 | ### Static Memory Matrix 271 | 272 | This type of matrix has the number of rows and columns set during initialization and then they cannot be changed. 273 | 274 | #### Base StaticMatrix Class 275 | 276 | This simple abstract class sets the rules for all static memory matricies by creating a protected *Init_(R,C)* method that must be called to set the initial size of the matrix. 277 | It also implements the required *Rows* and *Cols* properties to return the values that were set during initialization. 278 | 279 | #### ExternalStaticMatrix Class 280 | 281 | This simple concrete derivative of the StaticMatrix class uses an external *ARRAY OF LREAL* as the memory source for the matrix data. 282 | It is accessed in row-major order based on the logic in the *GetI* and *SetI* functions. 283 | It is most useful when someone doesn't trust dynamically allocated memory, but also doesn't want to make multiple size-specific custom derived FBs just to set up a single complex matrix operation. 284 | 285 | * __Init(R,C,pD)__ : Must be called in order to setup the matrix (it will be empty until this method is called). 286 | 287 | #### Array2DStaticMatrix Class 288 | 289 | This simple concrete derivative of the StaticMatrix class uses an external *2D ARRAY OF LREAL* as the memory source for the matrix data. 290 | It is most useful when someone is already interfacing with data in a native 2D array, but wants to quickly utilize some matrix functions. 291 | 292 | * To set up the matrix, the main FB must be called with the __Data__ parameter pointing at the external 2D array of LREAL that will be treated like a matrix. 293 | 294 | --- 295 | **WARNING** 296 | 297 | It is the callers responsibility to ensure that the pointer provided to the initializer is valid: 298 | 299 | * The length of the data structure pointed to (probably an array of LREAL) is at least as long as *Rows* x *Cols* 300 | * The scope of the data structure pointed to is the same as the scope of the corresponding *ExternalStaticMatrix* (probably declared adjacent to eachother as a VAR or GVL) 301 | 302 | Additionally, direct assignment (`:=`) should not be used with this type of matrix because a second copy of the Matrix, but with a pointer to the original's data source, would be created. 303 | For this reason, the pragma `{attribute 'no_assign'}` is used to block assignment at compile-time. 304 | Keep in mind that returning a value from a function is also a form of assignment and is not allowed. 305 | 306 | --- 307 | 308 | ### Matrix Accessors 309 | 310 | Matrix accessors are a way of interacting with the data of a parent *Matrix* through a special lens, without copying the data into a new *Matrix* and then back again. 311 | This type of *Matrix* works by creating a function that converts the I-based indexing of the accessor matrix into the I-based indexing of the parent matrix, then using it to intercept calls to *GetI* and *SetI*. 312 | Concrete Matrix Accessor Classes can be easily created from the parent MatrixAccessor abstract class by implementing the This2Parent method in order to define the index conversion. 313 | Note that matrix accessor allow **both read and write access** to the parent matrix! 314 | 315 | Included Matrix Accessors: 316 | 317 | * __SubMatrixAccessor__ : Allows access to a rectangular subset of the parent matrix as if it were a standalone matrix 318 | * __TransposeMatrixAccessor__ : Allows access to the elements of the parent matrix as if it were transposed 319 | * __ShrunkMatrixAccessor__ : Allows access to the parent matrix as if the [*Shrink* function](#dynamic-modifiers) had been called 320 | 321 | --- 322 | **WARNING** 323 | 324 | Matrix Accessors inherently store a pointer (*BY REFERENCE*) to their parent matrix. 325 | If the parent matrix goes out of scope (through function return) or is moved (through an online change) then the Matrix Accessor will no longer work. 326 | Therefore, they are best used quickly then destroyed, all within the scope of a single F or FB. 327 | 328 | --- 329 | 330 | ## Examples 331 | 332 | ### Projects With Implementations 333 | 334 | * [TcTransform](https://github.com/BurksEngineering/TcTransform): Static memory 3x1, 3x3, and 4x4 matricies for common 3D coordinate system transformations 335 | * The unit tests within this project provide a large number of simple examples and usages 336 | * The ExternalStaticMatrix is one example of how to implement the StaticMatrix base class -------------------------------------------------------------------------------- /TcMatrix.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31605.320 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{B1E792BE-AA5F-4E3C-8C82-674BF9C0715B}") = "TcMatrixTest", "TcMatrixTest\TcMatrixTest.tsproj", "{E21DD48F-97CD-43F0-AA17-4340951B180B}" 7 | EndProject 8 | Project("{DFBE7525-6864-4E62-8B2E-D530D69D9D96}") = "TcMatrix", "TcMatrix\TcMatrix.tspproj", "{85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CFB45DAA-19B9-4B68-BFD0-1FD493283908}" 11 | ProjectSection(SolutionItems) = preProject 12 | LICENSE = LICENSE 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|TwinCAT CE7 (ARMV7) = Debug|TwinCAT CE7 (ARMV7) 19 | Debug|TwinCAT OS (ARMT2) = Debug|TwinCAT OS (ARMT2) 20 | Debug|TwinCAT RT (x64) = Debug|TwinCAT RT (x64) 21 | Debug|TwinCAT RT (x86) = Debug|TwinCAT RT (x86) 22 | Release|TwinCAT CE7 (ARMV7) = Release|TwinCAT CE7 (ARMV7) 23 | Release|TwinCAT OS (ARMT2) = Release|TwinCAT OS (ARMT2) 24 | Release|TwinCAT RT (x64) = Release|TwinCAT RT (x64) 25 | Release|TwinCAT RT (x86) = Release|TwinCAT RT (x86) 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7) 29 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7) 30 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2) 31 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2) 32 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64) 33 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64) 34 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86) 35 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86) 36 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7) 37 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7) 38 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2) 39 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2) 40 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64) 41 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64) 42 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86) 43 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86) 44 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7) 45 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7) 46 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2) 47 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2) 48 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64) 49 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64) 50 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86) 51 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86) 52 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7) 53 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7) 54 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2) 55 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2) 56 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64) 57 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64) 58 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86) 59 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86) 60 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7) 61 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7) 62 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2) 63 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2) 64 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64) 65 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64) 66 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86) 67 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86) 68 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7) 69 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7) 70 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2) 71 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2) 72 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64) 73 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64) 74 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86) 75 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86) 76 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7) 77 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7) 78 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2) 79 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2) 80 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64) 81 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64) 82 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86) 83 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86) 84 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7) 85 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7) 86 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2) 87 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2) 88 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64) 89 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64) 90 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86) 91 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86) 92 | EndGlobalSection 93 | GlobalSection(SolutionProperties) = preSolution 94 | HideSolutionNode = FALSE 95 | EndGlobalSection 96 | GlobalSection(ExtensibilityGlobals) = postSolution 97 | SolutionGuid = {63919060-1A7C-4886-96B2-69C3753079AE} 98 | EndGlobalSection 99 | EndGlobal 100 | -------------------------------------------------------------------------------- /TcMatrix/LibraryCategory.libcat.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | d5875a41-817d-44f3-8af7-6c59eaddc95f 5 | 1.0.0.0 6 | Burks 7 | 8 | 9 | 426a88ee-bb19-4918-8554-e1c9c24621f9 10 | 1.0.0.0 11 | 12 | d5875a41-817d-44f3-8af7-6c59eaddc95f 13 | 14 | Matrix 15 | 16 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix.tspproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix.tspproj.bak: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Array2DStaticMatrix.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 21 | 22 | 25 | 26 | 27 | 28 | 42 | 43 | Ri,Col => Ci); 49 | IF Ri <0 OR Ri >= Rows OR Ci < 0 OR Ci >= Cols THEN 50 | GetI := 0.0; 51 | LogWarning('%s: Attempted I access outside of bounds of array'); 52 | ELSE 53 | //add lower bound offset before fetching from array 54 | GetI := Data[R0+Ri,C0+Ci]; 55 | END_IF 56 | END_IF]]> 57 | 58 | 59 | 60 | 72 | 73 | Ri,Col => Ci); 79 | IF Ri <0 OR Ri >= Rows OR Ci < 0 OR Ci >= Cols THEN 80 | SetI := FALSE; 81 | LogWarning('%s: Attempted I access outside of bounds of array'); 82 | ELSE 83 | SetI := TRUE; 84 | Data[R0+Ri,C0+Ci] := Val; 85 | END_IF 86 | END_IF]]> 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Csv/MatrixCsvReader.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 54 | 55 | = M.Rows OR Ci >= M.Cols THEN 148 | bError := TRUE; 149 | nErrId :=1; 150 | nErrStep := step; 151 | step := stepCloseFile; 152 | RETURN; 153 | END_IF 154 | M.SetRC(Ri,Ci,STRING_TO_LREAL(CsvRead.getValue)); 155 | Ci := Ci + 1; 156 | nVals := NVals + 1; 157 | IF CsvRead.bCRLF THEN 158 | Ri := Ri + 1; 159 | Ci := 0; 160 | nRows := Ri; 161 | END_IF 162 | IF Ci > nCols THEN 163 | nCols := Ci; 164 | END_IF 165 | END_IF 166 | END_IF 167 | UNTIL 168 | NOT(CsvRead.bOk) 169 | END_REPEAT 170 | IF readEOF THEN//this probably will never happen because EOF seems to be mutually exclusive with reading bytes 171 | step := stepCloseFile; 172 | ELSE 173 | //move pointer backwards to where it was before the read, then forward based on how much data was read from the CSV buffer. This re-reads any partial cells that were not parsed 174 | FileSeek.nSeekPos := bytesParsed - bytesRead; 175 | IF FileSeek.nSeekPos <> 0 THEN 176 | step := stepMovePointer; 177 | ELSE 178 | step := stepFillBuffer; 179 | END_IF; 180 | END_IF 181 | 182 | 183 | 184 | stepMovePointer: 185 | IF FileSeek.bError AND NOT bError THEN 186 | bError := TRUE; 187 | nErrId := FileSeek.nErrId; 188 | nErrStep := step; 189 | step := stepDone; 190 | ELSIF NOT(FileSeek.bBusy) THEN 191 | step := stepFillBuffer; 192 | END_IF 193 | 194 | stepCloseFile: 195 | 196 | IF FileClose.bError AND NOT bError THEN 197 | bError := TRUE; 198 | nErrId := FileClose.nErrId; 199 | nErrStep := step; 200 | step := stepDone; 201 | ELSIF NOT(FileClose.bBusy) THEN 202 | step := stepDone; 203 | END_IF 204 | 205 | 206 | stepDone: 207 | bBusy := FALSE; 208 | END_CASE 209 | 210 | IF NOT bExecute THEN 211 | step := stepReady; 212 | bBusy := FALSE; 213 | END_IF 214 | ]]> 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Csv/MatrixCsvWriter.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 48 | 49 | 0 AND cbHeaderLen > 0 THEN 93 | step := stepWriteHeader; 94 | FileWrite.pWriteBuff := pHeader; 95 | FileWrite.cbWriteLen := cbHeaderLen; 96 | ELSE 97 | step := stepFillBuffer; 98 | END_IF; 99 | END_IF 100 | 101 | stepWriteHeader: 102 | IF FileWrite.bError THEN 103 | bError := TRUE; 104 | nErrId := FileWrite.nErrId; 105 | nErrStep := step; 106 | step := stepCloseFile; 107 | ELSIF NOT(FileWrite.bBusy) THEN 108 | step := stepFillBuffer; 109 | END_IF 110 | 111 | 112 | stepFillBuffer: 113 | //add field divider manually at the beginning of the write block 114 | IF Ci > 0 THEN 115 | buffer[0] := DEFAULT_CSV_FIELD_SEP; 116 | bufferOffset := 1; 117 | ELSE 118 | bufferOffset := 0; 119 | END_IF 120 | 121 | BuffCmd := E_EnumCmdType.eEnumCmd_First; 122 | REPEAT 123 | CsvWrite(eCmd := BuffCmd, 124 | putValue := LREAL_TO_STRING(M.GetRC(Ri,Ci)), 125 | bCRLF := M.Cols = Ci+1, 126 | pBuffer := ADR(buffer)+bufferOffset, 127 | cbBuffer := bufferSize-bufferOffset); 128 | 129 | IF NOT(CsvWrite.bOk) THEN 130 | bError := TRUE; 131 | nErrId := 1; 132 | nErrStep := step; 133 | step := stepCloseFile; 134 | RETURN; 135 | END_IF 136 | 137 | BuffCmd := E_EnumCmdType.eEnumCmd_Next; 138 | Ci := Ci + 1; 139 | IF Ci >= M.Cols THEN 140 | Ci := 0; 141 | Ri := Ri + 1; 142 | END_IF 143 | UNTIL 144 | Ri >= M.Rows OR CsvWrite.cbFree < dataSize 145 | END_REPEAT 146 | step := stepWriteBuffer; 147 | FileWrite.pWriteBuff := ADR(buffer); 148 | FileWrite.cbWriteLen := CsvWrite.cbSize+bufferOffset; 149 | 150 | 151 | stepWriteBuffer: 152 | 153 | IF FileWrite.bError THEN 154 | bError := TRUE; 155 | nErrId := FileWrite.nErrId; 156 | nErrStep := step; 157 | step := stepDone; 158 | ELSIF NOT(FileWrite.bBusy) THEN 159 | IF Ri >= M.Rows THEN 160 | step := stepCloseFile; 161 | ELSE 162 | step := stepFillBuffer; 163 | END_IF 164 | END_IF 165 | 166 | stepCloseFile: 167 | 168 | IF FileClose.bError AND NOT bError THEN 169 | bError := TRUE; 170 | nErrId := FileClose.nErrId; 171 | nErrStep := step; 172 | step := stepDone; 173 | ELSIF NOT(FileClose.bBusy) THEN 174 | step := stepDone; 175 | END_IF 176 | 177 | 178 | stepDone: 179 | bBusy := FALSE; 180 | END_CASE 181 | 182 | IF NOT bExecute THEN 183 | step := stepReady; 184 | bBusy := FALSE; 185 | END_IF 186 | ]]> 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/ExternalStaticMatrix.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 32 | 33 | = Length THEN 37 | GetI := 0.0; 38 | LogWarning('%s: Attempted I access of out-of-bounds Matrix data'); 39 | ELSE 40 | GetI := Data[I]; 41 | END_IF]]> 42 | 43 | 44 | 45 | 52 | 53 | 55 | 56 | 57 | 58 | 66 | 67 | = Length THEN 71 | SetI := FALSE; 72 | LogWarning('%s: Attempt to set data using I access when I is out of bounds'); 73 | ELSE 74 | SetI := TRUE; 75 | Data[I] := Val; 76 | END_IF]]> 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_Cols.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_Rows.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_To_Matrix.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 17 | 18 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Arrays/Matrix_SameSizeAs_Array2D.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Arrays/Matrix_To_Array2D.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 17 | 18 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_CanMult.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Copy.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_DeterminateSquare.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 18 | 19 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementDifference.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 17 | 18 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementProduct.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementSum.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Grow.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 25 | 26 | M_To.Rows-1 THEN 27 | Matrix_Grow := FALSE; 28 | RETURN; 29 | END_IF 30 | IF M_From.Cols <> M_To.Cols-1 THEN 31 | Matrix_Grow := FALSE; 32 | RETURN; 33 | END_IF 34 | 35 | IF Row < 0 OR Row > M_From.Rows THEN 36 | Matrix_Grow := FALSE; 37 | RETURN; 38 | END_IF 39 | 40 | IF Col < 0 OR Col > M_From.Cols THEN 41 | Matrix_Grow := FALSE; 42 | RETURN; 43 | END_IF 44 | 45 | Matrix_Grow := TRUE; 46 | 47 | //loop backwards to avoid possible overwriting the input if the same matrix is both inputs. 48 | //in order to ensure the final decrement breaks the loop condition the final valid value must be 1, not zero. So just offset all indexes by 1... 49 | FOR Ri := 0 TO M_To.Rows-1 DO 50 | FOR Ci := 0 TO M_To.Cols-1 DO 51 | IF Ri = Row AND Ci = Col THEN 52 | M_To.SetRC(Ri,Ci,DiagVal); 53 | ELSIF Ri = Row THEN 54 | M_To.SetRC(Ri,Ci,RowVal); 55 | ELSIF Ci = Col THEN 56 | M_To.SetRC(Ri,Ci,ColVal); 57 | ELSE 58 | //note that if Ri or Ci is their lowest value (1), then the BOOL condition must be false because 0 cannot be greater than any UINT. 59 | //This guarantees that the lowest RC indexes are zero. 60 | M_To.SetRC(Ri,Ci,M_From.GetRC(Ri - BOOL_TO_UINT((Ri)>Row),Ci - BOOL_TO_UINT((Ci)>Col))); 61 | END_IF 62 | END_FOR 63 | END_FOR 64 | ]]> 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_InvertSquare.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 19 | 20 | Mi THEN 42 | FOR Ci := 0 TO M.Cols-1 DO 43 | IF Ci <> Mi THEN 44 | M.SetRC(Ri,Ci,M.GetRC(Ri,Ci) - M.GetRC(Ri,Mi)*M.GetRC(Mi,Ci)/temp); 45 | END_IF 46 | END_FOR 47 | END_IF; 48 | END_FOR 49 | 50 | temp := -1/temp; 51 | M.SetRC(Mi,Mi,temp); 52 | FOR Ni := 0 TO M.Cols-1 DO 53 | IF Ni <> Mi THEN 54 | M.SetRC(Mi,Ni,M.GetRC(Mi,Ni)*temp); 55 | M.SetRC(Ni,Mi,M.GetRC(Ni,Mi)*temp); 56 | END_IF; 57 | END_FOR 58 | 59 | END_FOR 60 | 61 | M.Scale(-1); 62 | ]]> 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Product.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 19 | 20 | Res.Rows OR B.Cols <> Res.Cols THEN 26 | Matrix_Product := FALSE; 27 | RETURN; 28 | END_IF 29 | 30 | Matrix_Product := TRUE; 31 | 32 | FOR Ri := 0 TO Res.Rows-1 DO 33 | FOR Ci := 0 TO Res.Cols-1 DO 34 | Sum := 0; 35 | FOR I := 0 TO A.Cols-1 DO 36 | Sum := Sum + A.GetRC(Ri,I) * B.GetRC(I,Ci); 37 | END_FOR 38 | Res.SetRC(Ri,Ci,Sum); 39 | END_FOR 40 | END_FOR]]> 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Scale.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Shrink.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 22 | 23 | MAX(1,M_From.Rows-1) OR M_To.Cols <> MAX(1,M_From.Cols-1) THEN 29 | Matrix_Shrink := FALSE; 30 | RETURN; 31 | END_IF 32 | 33 | IF Row >= M_From.Rows OR Col >= M_From.Cols THEN 34 | Matrix_Shrink := FALSE; 35 | RETURN; 36 | END_IF 37 | 38 | Matrix_Shrink := TRUE; 39 | 40 | FOR Ri := 0 TO M_To.Rows-1 DO 41 | FOR Ci := 0 TO M_To.Cols-1 DO 42 | M_To.SetRC(Ri,Ci,M_From.GetRC(Ri + BOOL_TO_UINT(Ri >= Row AND M_From.Rows <> M_To.Rows),Ci + BOOL_TO_UINT(Ci >= Col AND M_From.Cols <> M_To.Cols))); 43 | END_FOR 44 | END_FOR]]> 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_SubMatrix.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 24 | 25 | M_Super.Rows OR ColStart + ColCount > M_Super.Cols THEN 26 | Matrix_SubMatrix := FALSE; 27 | RETURN; 28 | END_IF 29 | IF M_Sub.Rows <> RowCount OR M_Sub.Cols <> ColCount THEN 30 | Matrix_SubMatrix := FALSE; 31 | RETURN; 32 | END_IF 33 | 34 | Matrix_SubMatrix := TRUE; 35 | 36 | IF RowCount = 0 OR ColCount = 0 THEN 37 | RETURN;//valid to get a zero-len matrix as the result, but indexing below will cause a pagefault due to creating 32k+ warning messages for invalid access 38 | END_IF 39 | 40 | FOR Ri := 0 TO RowCount-1 DO 41 | FOR Ci := 0 TO ColCount-1 DO 42 | M_Sub.SetRC(Ri,Ci,M_Super.GetRC(RowStart+Ri,ColStart+Ci)); 43 | END_FOR 44 | END_FOR]]> 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Transpose.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | M_To.Cols OR M_From.Cols <> M_to.Rows THEN 18 | Matrix_Transpose := FALSE; 19 | RETURN; 20 | END_IF 21 | 22 | Matrix_Transpose := TRUE; 23 | 24 | FOR Ri := 0 TO M_From.Rows-1 DO 25 | FOR Ci := 0 TO M_From.Cols-1 DO 26 | M_To.SetRC(Ci,Ri,M_From.GetRC(Ri,Ci)); 27 | END_FOR 28 | END_FOR]]> 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_TransposeSquare.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14 | 15 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_CrossProduct.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 22 | 23 | Res.Length - 1 THEN 27 | Vector_CrossProduct := FALSE; 28 | RETURN; 29 | END_IF 30 | 31 | FOR I := LOWER_BOUND(Vectors,1) TO UPPER_BOUND(Vectors,1) DO 32 | IF Vectors[I] = 0 THEN 33 | Vector_CrossProduct := FALSE; 34 | RETURN; 35 | END_IF 36 | IF NOT(Vectors[I]^.IsVector) OR Vectors[I]^.Length <> Res.Length THEN 37 | Vector_CrossProduct := FALSE; 38 | RETURN; 39 | END_IF 40 | END_FOR 41 | 42 | 43 | IF NOT(M_Vectors.Init(Res.Length,Res.Length)) THEN 44 | Vector_CrossProduct := FALSE; 45 | RETURN; 46 | END_IF 47 | 48 | 49 | //build aggregate matrix 50 | FOR Ri := 0 TO M_Vectors.Rows-1 DO 51 | FOR Ci := 0 TO M_Vectors.Cols-1 DO 52 | IF Ri = 0 THEN 53 | M_Vectors.SetRC(Ri,Ci,1); 54 | ELSE 55 | I := LOWER_BOUND(Vectors,1)-1 + Ri; 56 | M_Vectors.SetRC(Ri,Ci,Vectors[I]^.GetI(Ci)); 57 | END_IF 58 | END_FOR 59 | END_FOR 60 | 61 | //if some vectors are parallel or whatever there is no 'one' cross product, so return false 62 | IF M_Vectors.GetDeterminant() = 0 THEN 63 | Vector_CrossProduct := FALSE; 64 | RETURN; 65 | END_IF 66 | 67 | Vector_CrossProduct := TRUE; 68 | 69 | //take determiantes 70 | FOR Ci := 0 TO M_Vectors.Cols-1 DO 71 | M_Det.Init(M_Vectors,0,Ci); 72 | IF NOT(Matrix_DeterminateSquare(M_Det, Res=>Det)) THEN 73 | Vector_CrossProduct := FALSE; 74 | RETURN; 75 | END_IF 76 | Sign := ((UINT_TO_INT(Ci)+1) MOD 2)*2 -1;//even columns are positive, odd columns are negative 77 | Res.SetI(Ci,Det*Sign); 78 | END_FOR 79 | 80 | ]]> 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_DotProduct.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 17 | 18 | B.Length OR A.IsEmpty THEN 19 | Vector_DotProduct := FALSE; 20 | Res := 0; 21 | RETURN; 22 | END_IF 23 | 24 | Vector_DotProduct := TRUE; 25 | 26 | Sum := 0; 27 | FOR I := 0 TO A.Length-1 DO 28 | Sum := Sum + A.GetI(I)*B.GetI(I); 29 | END_FOR 30 | Res := SUM;]]> 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_Magnitude.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_Normalize.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | Res.Length THEN 18 | Vector_Normalize := FALSE; 19 | RETURN; 20 | END_IF 21 | 22 | IF NOT(Vector_Magnitude(In,Res=>Mag)) THEN 23 | Vector_Normalize := FALSE; 24 | RETURN; 25 | END_IF 26 | 27 | //dont use copy because vectors might be in different orientations 28 | FOR I:= 0 TO Res.Length-1 DO 29 | Res.SetI(I,In.GetI(I)*Mag); 30 | END_FOR]]> 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/MatrixAccessors/MatrixAccessor.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 31 | 32 | = Length THEN 39 | GetI := 0.0; 40 | LogWarning('%s: Attempted I access beyond limits of Matrix Accessor'); 41 | ELSE 42 | GetI := M_.GetI(This2Parent(I)); 43 | END_IF]]> 44 | 45 | 46 | 47 | 52 | 53 | 54 | 55 | 56 | 57 | 65 | 66 | = Length THEN 73 | SetI := FALSE; 74 | LogWarning('%s: Attempted I access beyond limits of Matrix Accessor'); 75 | ELSE 76 | SetI := M_.SetI(This2Parent(I),Val); 77 | END_IF]]> 78 | 79 | 80 | 81 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/MatrixAccessors/ShrunkMatrixAccessor.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 26 | 27 | 0 THEN 31 | Cols := M_.Cols-1; 32 | ELSE 33 | Cols := 0; 34 | END_IF]]> 35 | 36 | 37 | 38 | 39 | 46 | 47 | 50 | 51 | 52 | 53 | 55 | 56 | 59 | 60 | 0 THEN 64 | Rows := M_.Rows-1; 65 | ELSE 66 | Rows := 0; 67 | END_IF]]> 68 | 69 | 70 | 71 | 72 | 81 | 82 | ThisR, Col => ThisC); 89 | 90 | This2Parent := RCC2I(ThisR+BOOL_TO_UINT(RowRemoved_<=ThisR),ThisC+BOOL_TO_UINT(ColRemoved_<=ThisC),M_.Cols);]]> 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/MatrixAccessors/SubMatrixAccessor.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 28 | 29 | M_.Cols THEN 33 | Cols := 0; 34 | ELSE 35 | Cols := ColCount_; 36 | END_IF]]> 37 | 38 | 39 | 40 | 41 | 50 | 51 | 56 | 57 | 58 | 59 | 61 | 62 | 65 | 66 | M_.Rows THEN 70 | Rows := 0; 71 | ELSE 72 | Rows := RowCount_; 73 | END_IF]]> 74 | 75 | 76 | 77 | 78 | 87 | 88 | ThisR, Col => ThisC); 95 | This2Parent := RCC2I(ThisR+RowStart_,ThisC+ColStart_,M_.Cols);]]> 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/MatrixAccessors/TransposeMatrixAccessor.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 73 | 74 | ThisR, Col => ThisC); 81 | 82 | This2Parent := RCC2I(ThisC,ThisR,M_.Cols);]]> 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/POUs/StaticMatrix.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 49 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/TcMatrix.plcproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0.0 4 | 2.0 5 | {c0f4bef7-55d3-4b7e-a92a-8580425ecfb1} 6 | True 7 | true 8 | true 9 | false 10 | TcMatrix 11 | 3.1.4023.0 12 | {8ec408c3-a544-4a75-9918-b9e0bcde03c0} 13 | {a002c4ff-eb8a-4723-9b5c-4867c37c6d11} 14 | {55280038-9b8d-402f-b14c-4fb127dddb5c} 15 | {bbd717dd-a9af-4f58-9010-62c8b0afd061} 16 | {0530cbe7-771f-4e48-bb43-655369b89363} 17 | {696e4867-e7af-4d84-8e99-6d19d1fc0070} 18 | Burks Engineering 19 | false 20 | TcMatrix 21 | 1.4.3 22 | TcMatrix 23 | Andrew Burks 24 | Matrix arithmatic library 25 | true 26 | true 27 | reStructuredText 28 | 29 | 30 | {d5875a41-817d-44f3-8af7-6c59eaddc95f} 31 | 1.0.0.0 32 | Burks 33 | 34 | 35 | {426a88ee-bb19-4918-8554-e1c9c24621f9} 36 | 1.0.0.0 37 | 38 | {d5875a41-817d-44f3-8af7-6c59eaddc95f} 39 | 40 | Matrix 41 | 42 | 43 | 44 | {426a88ee-bb19-4918-8554-e1c9c24621f9} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Code 60 | 61 | 62 | Code 63 | 64 | 65 | Code 66 | 67 | 68 | Code 69 | 70 | 71 | Code 72 | 73 | 74 | Code 75 | 76 | 77 | Code 78 | 79 | 80 | Code 81 | 82 | 83 | Code 84 | 85 | 86 | Code 87 | 88 | 89 | Code 90 | 91 | 92 | Code 93 | 94 | 95 | Code 96 | 97 | 98 | Code 99 | 100 | 101 | Code 102 | 103 | 104 | Code 105 | 106 | 107 | Code 108 | 109 | 110 | Code 111 | 112 | 113 | Code 114 | 115 | 116 | Code 117 | 118 | 119 | Code 120 | 121 | 122 | Code 123 | 124 | 125 | Code 126 | 127 | 128 | Code 129 | 130 | 131 | Code 132 | 133 | 134 | Code 135 | 136 | 137 | Code 138 | 139 | 140 | Code 141 | 142 | 143 | Code 144 | 145 | 146 | Code 147 | 148 | 149 | Code 150 | 151 | 152 | Code 153 | 154 | 155 | Code 156 | 157 | 158 | Code 159 | 160 | 161 | Code 162 | 163 | 164 | 165 | 166 | Tc2_Standard, * (Beckhoff Automation GmbH) 167 | Tc2_Standard 168 | 169 | 170 | Tc2_System, * (Beckhoff Automation GmbH) 171 | Tc2_System 172 | 173 | 174 | Tc2_Utilities, * (Beckhoff Automation GmbH) 175 | Tc2_Utilities 176 | 177 | 178 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH) 179 | Tc3_DynamicMemory 180 | 181 | 182 | 183 | 184 | Content 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | "<ProjectRoot>" 193 | 194 | {192FAD59-8248-4824-A8DE-9177C94C195A} 195 | 196 | "{192FAD59-8248-4824-A8DE-9177C94C195A}" 197 | 198 | 199 | 200 | {29BD8D0C-3586-4548-BB48-497B9A01693F} 201 | 202 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}" 203 | 204 | Rules 205 | 206 | "Rules" 207 | 208 | 209 | 210 | 211 | 212 | 213 | {40450F57-0AA3-4216-96F3-5444ECB29763} 214 | 215 | "{40450F57-0AA3-4216-96F3-5444ECB29763}" 216 | 217 | 218 | ActiveVisuProfile 219 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA= 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | System.Collections.Hashtable 228 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861} 229 | System.String 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /TcMatrix/TcMatrix/Version/Global_Version.TcGVL: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 13 | 14 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest.tsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | PlcTask 11 | 12 | 13 | 14 | 15 | 16 | 17 | TcMatrixTest Instance 18 | {08500001-0000-0000-F000-000000000064} 19 | 20 | 21 | 0 22 | PlcTask 23 | 24 | #x02010030 25 | 26 | 20 27 | 10000000 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/PlcTask.TcTTO: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10000 6 | 20 7 | 8 | PRG_TEST 9 | 10 | {9b75a233-b2fa-4356-b033-b3a5400daf73} 11 | {6076d168-c44a-407b-aeea-77de7f1456ee} 12 | {2a2da5c4-7b4e-4691-9c70-8a2799caae79} 13 | {8d1d71c3-4d2f-47ab-827c-37893fb4fe4d} 14 | {8f2a9d96-a8d2-4504-801c-5af985aa447a} 15 | 16 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_Array_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 16 | 17 | 18 | 35 | 36 | 59 | 60 | 61 | 62 | 80 | 81 | 111 | 112 | 113 | 114 | 130 | 131 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_CsvReadWrite_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 37 | 38 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_DynamicMatrix_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 17 | 18 | 19 | 20 | 29 | 30 | 43 | 44 | 45 | 46 | 55 | 56 | 71 | 72 | 73 | 74 | 83 | 84 | 98 | 99 | 100 | 101 | 110 | 111 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixDeterminate_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 15 | 16 | 17 | 26 | 27 | Actual); 32 | 33 | // @TEST-ASSERT 34 | AssertTrue(Result,'Main function call was not successful'); 35 | AssertEquals(Expected,Actual,'Determinate value was incorrect'); 36 | 37 | TEST_FINISHED();]]> 38 | 39 | 40 | 41 | 50 | 51 | Actual); 56 | 57 | // @TEST-ASSERT 58 | AssertFalse(Result,'Main function call was unexpectedly successful'); 59 | AssertEquals(Expected,Actual,'Determinate value was incorrect'); 60 | 61 | TEST_FINISHED();]]> 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixElementProduct_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 15 | 16 | 17 | 26 | 27 | 38 | 39 | 40 | 41 | 50 | 51 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixElementSum_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 15 | 16 | 17 | 26 | 27 | 38 | 39 | 40 | 41 | 50 | 51 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixGetMagicSquare_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixGrow_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 16 | 17 | 18 | 26 | 27 | 37 | 38 | 39 | 40 | 49 | 50 | 62 | 63 | 64 | 65 | 73 | 74 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixInvert_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 17 | 18 | 19 | 27 | 28 | 40 | 41 | 42 | 43 | 51 | 52 | 62 | 63 | 64 | 65 | 75 | 76 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixMatrixProduct_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 17 | 18 | 19 | 28 | 29 | 40 | 41 | 42 | 43 | 52 | 53 | 67 | 68 | 69 | 70 | 79 | 80 | 94 | 95 | 96 | 97 | 106 | 107 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixShrink_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 15 | 16 | 17 | 25 | 26 | 36 | 37 | 38 | 39 | 48 | 49 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixSubMatrix_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixTranspose_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 16 | 17 | 18 | 27 | 28 | 41 | 42 | 43 | 44 | 53 | 54 | 67 | 68 | 69 | 70 | 82 | 83 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_StaticMatrix_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/FB_VectorCrossProduct_Test.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12 | 13 | 16 | 17 | 18 | 30 | 31 | 50 | 51 | 52 | 53 | 65 | 66 | 84 | 85 | 86 | 87 | 97 | 98 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TESTs/PRG_TEST.TcPOU: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/TcMatrixTest.plcproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0.0 4 | 2.0 5 | {d894bf7b-783c-4a82-8af1-3d395565c311} 6 | True 7 | true 8 | true 9 | false 10 | TcMatrixTest 11 | 3.1.4023.0 12 | {7e72f38d-c49a-4167-a7df-3d3d3c1a22d3} 13 | {a9df0001-c2d5-4050-8f34-930bd6c91f07} 14 | {e8f56aa0-def9-4aea-8fa5-31071a156ee5} 15 | {7b9b3f09-514f-456f-9be3-5742f173d1ff} 16 | {79cc4822-ca77-4885-a1fc-84c408e29968} 17 | {fcb5c87e-e41c-422e-9ee7-2814e0fa659f} 18 | Burks Engineering 19 | false 20 | TcMatrix Unit Tests 21 | 0.0.0 22 | true 23 | true 24 | Andrew Burks 25 | Unit Tests for the TcMatrix Library 26 | 27 | 28 | 29 | Code 30 | 31 | 32 | Code 33 | 34 | 35 | Code 36 | 37 | 38 | Code 39 | 40 | 41 | Code 42 | 43 | 44 | Code 45 | 46 | 47 | Code 48 | 49 | 50 | Code 51 | 52 | 53 | Code 54 | 55 | 56 | Code 57 | 58 | 59 | Code 60 | 61 | 62 | Code 63 | 64 | 65 | Code 66 | 67 | 68 | Code 69 | 70 | 71 | Code 72 | 73 | 74 | Code 75 | 76 | 77 | Code 78 | 79 | 80 | Code 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Tc2_Standard, * (Beckhoff Automation GmbH) 91 | Tc2_Standard 92 | 93 | 94 | Tc2_System, * (Beckhoff Automation GmbH) 95 | Tc2_System 96 | 97 | 98 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH) 99 | Tc3_DynamicMemory 100 | 101 | 102 | Tc3_Module, * (Beckhoff Automation GmbH) 103 | Tc3_Module 104 | 105 | 106 | TcMatrix, * (Burks Engineering) 107 | TcMatrix 108 | 109 | 110 | 111 | 112 | TcUnit 113 | 114 | 115 | 116 | 117 | Content 118 | 119 | 120 | 121 | 122 | TcMatrix, * (Burks Engineering) 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | "<ProjectRoot>" 131 | 132 | {192FAD59-8248-4824-A8DE-9177C94C195A} 133 | 134 | "{192FAD59-8248-4824-A8DE-9177C94C195A}" 135 | 136 | 137 | 138 | {29BD8D0C-3586-4548-BB48-497B9A01693F} 139 | 140 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}" 141 | 142 | Rules 143 | 144 | "Rules" 145 | 146 | 147 | 148 | 149 | 150 | 151 | {8F99A816-E488-41E4-9FA3-846536012284} 152 | 153 | "{8F99A816-E488-41E4-9FA3-846536012284}" 154 | 155 | 156 | DisabledWarningIds 157 | 394 158 | 159 | 160 | {40450F57-0AA3-4216-96F3-5444ECB29763} 161 | 162 | "{40450F57-0AA3-4216-96F3-5444ECB29763}" 163 | 164 | 165 | ActiveVisuProfile 166 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA= 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | System.Collections.Hashtable 175 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861} 176 | System.String 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /TcMatrixTest/TcMatrixTest/Version/Global_Version.TcGVL: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 13 | 14 | --------------------------------------------------------------------------------