{"id":20480501,"url":"https://github.com/rruiter87/tccontrol","last_synced_at":"2025-10-12T06:40:58.168Z","repository":{"id":133425164,"uuid":"546627175","full_name":"rruiter87/TcControl","owner":"rruiter87","description":"TwinCAT library for PID control and signal filtering","archived":false,"fork":false,"pushed_at":"2024-02-19T12:52:07.000Z","size":1125,"stargazers_count":34,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-14T21:35:55.263Z","etag":null,"topics":["beckhoff","control","iir-filters","industrial-automation","pid-control","plc","twincat","twincat3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rruiter87.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-10-06T11:39:17.000Z","updated_at":"2025-08-04T05:37:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"37d6e367-f344-48bd-9c00-5ac2442b7f3d","html_url":"https://github.com/rruiter87/TcControl","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/rruiter87/TcControl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rruiter87%2FTcControl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rruiter87%2FTcControl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rruiter87%2FTcControl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rruiter87%2FTcControl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rruiter87","download_url":"https://codeload.github.com/rruiter87/TcControl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rruiter87%2FTcControl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279010525,"owners_count":26084759,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["beckhoff","control","iir-filters","industrial-automation","pid-control","plc","twincat","twincat3"],"created_at":"2024-11-15T15:50:22.134Z","updated_at":"2025-10-12T06:40:58.123Z","avatar_url":"https://github.com/rruiter87.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TcControl\n\nTwinCAT library for PID control and signal filtering.\n\n## Examples\n\n### `Signal`\n\nThe basic unit of this library is the `Signal` function block. The most basic usage would be the following where a new value is added and can be retrieved.\n\n```\nPROGRAM MAIN\nVAR\n    signal : Signal;\n    value : LREAL;\nEND_VAR\n\nsignal.Update(value:=5); // Add new value to signal\nvalue := signal.Out; // Retrieve the current value, in this case it would be 5\n```\n\nThe power of signal becomes clear when combined with `.Differentiate`\n\n```\nPROGRAM MAIN\nVAR\n    signal : Signal;\n    value : LREAL;\nEND_VAR\n\nsignal.Update(value:=1).Differentiate(deltaTime:=1);\nvalue := signal.Update(value:=2).Differentiate(deltaTime:=1).Out; // 1\n```\n\nOr `.Iir`\n\n```\nPROGRAM MAIN\nVAR\n    signal : Signal;\n    value : LREAL;\nEND_VAR\n\nsignal.Update(value:=1.4).Iir(decay:=0.5);\nvalue := signal.Update(value:=8.6).Iir(decay:=0.5).Out; // 4.65\n```\n\nOr combining both\n\n```\nPROGRAM MAIN\nVAR\n    signal : Signal;\nEND_VAR\n\nsignal.Update(value:=7).Differentiate(deltaTime:=1).Iir(decay:=0.5); // singal.Out = 0\nsignal.Update(value:=8).Differentiate(deltaTime:=1).Iir(decay:=0.5); // signal.Out = 0.5\nsignal.Update(value:=9).Differentiate(deltaTime:=1).Iir(decay:=0.5); // signal.Out = 0.75\n```\n\nFinally the differentiated/filtered signal can be put into a controller. Currently the library only contains the simple `PidController`\n\n```\nPROGRAM MAIN\nVAR\n    signal : Signal;\n    parameters : PidParameters := (Kp:=2, Ki:=0.25, Kd:=0.5);\n    pid : PidController;\nEND_VAR\n\npid(parameters:=parameters, cycleTime:=1);\nsignal.Controller := pid;\nsignal.Update(3).Control(setpoint:=4); // signal.Out = 2.75\nsignal.Update(3.5).Control(setpoint:=4); // signal.Out = 1.125\n```\n\nSee the unit tests `Singal_Tests` for more examples.\n\n## Custom controller\n\nYou can define your own controller, as long as it implements the `IController` interface. Then you pass it to your signal instance via `signal.Controller := customController;`.\n\n## Other function blocks\n\nThe function blocks used in `Signal` can also be used as stand-alone function blocks. The following function blocks are defined.\n\n- `Derivative`: Take derivative of a value.\n- `InfiniteImpulseResponse`: Infinite impulse response (IIR) filter.\n- `Pid`: PID controller\n  - `Pid.DifferentialPartLimit`: Limit the differential part. Convenient when the output is calculated for the first time. The limit prevents it from having a very large value after the first call.\n  - `Pid.PreviousIntegralPart`: Set previous integral part on first call. Prevents integrator term for needing to build up.\n\n### `Derivative`\n\n```\nPROGRAM MAIN\nVAR\n    derivative : Derivative;\nEND_VAR\n\nderivative(value:=1, deltatime:=1); // derivative.Out = 0 (derivative is always 0 on the initial call)\nderivative(value:=2, deltatime:=1); // derivative.Out = 1\n```\n\nSee `Derivative_Tests` for more examples.\n\n### `InfiniteImpulseResponse`\n\n```\nPROGRAM MAIN\nVAR\n    iir : InfiniteImpulseResponse;\nEND_VAR\n\niir(new:=5, decay:=0.95); // iir.Out = 0.25\niir(new:=5, decay:=0.95); // iir.Out = 0.4875\niir(new:=5, decay:=0.95); // iir.Out = 0.71313\n```\n\nSee `InfiniteImpulseResponse_Tests` for more examples.\n\n### `PidController`\n\n```\nPROGRAM MAIN\nVAR\n    pid : PidController;\n    parameters : PidParameters := (Kp:=0.1, Ki:=0, Kd:=0.01);\nEND_VAR\n\n// limits the difference on the initial call\npid.DifferentialPartLimit := 3;\n// pass the pid parameters (only need to be done once, unless you change them)\npid(parameters:=parameters, cycleTime:=1);\n// Cyclicly call Update\npid.Update(setpoint:=10, actual:=6); // pid.Out = 0.4\npid.Update(setpoint:=10, actual:=8); // pid.Out = 0.18\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frruiter87%2Ftccontrol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frruiter87%2Ftccontrol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frruiter87%2Ftccontrol/lists"}