{"id":28621662,"url":"https://github.com/Dlloydev/sTune","last_synced_at":"2025-06-12T05:06:02.235Z","repository":{"id":44875414,"uuid":"437714576","full_name":"Dlloydev/sTune","owner":"Dlloydev","description":"Open loop PID autotuner using a novel s-curve inflection point test method. Tuning parameters are determined in about ½Tau on a first-order system with time delay. Full 5Tau testing and multiple serial output options are provided.","archived":false,"fork":false,"pushed_at":"2022-07-24T18:29:53.000Z","size":95,"stargazers_count":45,"open_issues_count":4,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2023-03-10T20:30:48.735Z","etag":null,"topics":["arduino","autotune","control","fopdt","inflection","pid","process","sopdt","step","tuner","tuning"],"latest_commit_sha":null,"homepage":"","language":"C++","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/Dlloydev.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}},"created_at":"2021-12-13T02:44:22.000Z","updated_at":"2023-03-01T22:53:48.000Z","dependencies_parsed_at":"2022-08-12T11:40:17.732Z","dependency_job_id":null,"html_url":"https://github.com/Dlloydev/sTune","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"purl":"pkg:github/Dlloydev/sTune","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dlloydev%2FsTune","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dlloydev%2FsTune/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dlloydev%2FsTune/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dlloydev%2FsTune/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dlloydev","download_url":"https://codeload.github.com/Dlloydev/sTune/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dlloydev%2FsTune/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259402054,"owners_count":22851868,"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","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":["arduino","autotune","control","fopdt","inflection","pid","process","sopdt","step","tuner","tuning"],"created_at":"2025-06-12T05:01:59.873Z","updated_at":"2025-06-12T05:06:02.222Z","avatar_url":"https://github.com/Dlloydev.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# sTune    [![arduino-library-badge](https://www.ardu-badge.com/badge/sTune.svg?)](https://www.ardu-badge.com/sTune) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/dlloydev/library/sTune.svg)](https://registry.platformio.org/packages/libraries/dlloydev/sTune)\n\nThis is an open loop PID autotuner using a novel s-curve inflection point test method. Tuning parameters are typically determined in about ½Tau on a first-order system with time delay. Full 5Tau testing and multiple serial output options are provided. See [**WiKi**](https://github.com/Dlloydev/sTune/wiki) for test results and more.\n\n### Inflection Point Tuning Method\n\nThis open-loop tuning method is used when the controller action is set to `directIP` or `reverseIP`. This method works best on processes that respond with an S-shaped reaction curve to a stepped output. Being an open-loop test, there is no setpoint and PID correction involved. The process gain, dead time, time constant and more is determined by doing a shortened step test that ends just after the [inflection point](http://en.wikipedia.org/wiki/Inflection_point) has been reached. From here, the apparent maximum PV (input) is mathematically determined and the  controller's tuning parameters are calculated. Test duration is typically only ½Tau.\n\n#### Inflection Point Discovery\n\nAccurate determination of the inflection point was given high priority for this test method. To accomplish this, a circular buffer for the input readings is created that's sized to 6% of the samples value. The buffer is used as a moving tangent line where the \"head\" of the tangent is based on the average of all readings in the buffer and the \"tail\" is based on the oldest instantaneous value in the buffer. The tangent line moves along the reaction curve one sample at a time. The slope of the tangent line is checked at every sample. When the sign of the change in slope changes (i.e. slope goes from increasing to decreasing or from decreasing to increasing), this is the point of inflection ([where the tangent turns red here](https://en.wikipedia.org/wiki/Inflection_point#/media/File:Animated_illustration_of_inflection_point.gif)). After 1⁄16 samples has occurred with the new slope direction, then it's known that the point of inflection has been reached. Final calculations are made and the test ends.\n\n#### S-shaped Step Response\n\n![Reaction Curve](https://user-images.githubusercontent.com/63488701/151890696-d574d77b-b849-4079-81e2-71e4ee416fa3.png)\n\n#### Configuration\n\n- First, the PID controller is placed in `manual` mode.\n\n- The tuner action is set to `directIP` or `reverseIP`, then configure sTune:\n\n- ```c++\n  tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);\n  ```\n\n- Its expected that the user is already familiar with the controller and can make a rough estimation of what the system's time constant would be. Use this estimate for the `testTimeSec` constant.\n\n- The `samples` constant is used to define the maximum number of samples used to perform the test. To get an accurate representation of the curve, the suggested range is 200-500. \n\n- `settleTimeSec` is used to provide additional settling time prior to starting the test. \n\n- `inputSpan` and `outputSpan` represent the maximum operating range of input and output. Examples:\n\n  - If your input works with temp readings of 20C min and 220C max, then `inputSpan = 200;`\n     If the output uses 8-bit PWM and your using its full range, then `outputSpan = 255;`\n     If the output is digital relay controlled by millis() with window period of 2000ms, then `outputSpan = 2000;`\n\n- `outputStart` is the initial control output value which is used for the `settleTimeSec` duration and sample 0.\n\n- `outputStep` is the stepped output value used for sample 1 to test completion.\n\n- after test completion, the setup can be updated for the next test and `tuner.Configure()` can be called again.\n\n#### Test\n\n- The `outputStep` value is applied at sample 1 and inflection point discovery begins.\n\n- Dead time is determined when the averaged input has increased (or decreased) beyond one resolution value from the starting instantaneous input value.\n- When the point of inflection is reached, the test ends. The apparent `pvMax` is calculated using:\n\n- ```c++\n  pvMax = pvIp + slopeIp * kexp;  // where kexp = 4.3004 = (1 / exp(-1)) / (1 - exp(-1))\n  ```\n\n- The process gain `Ku` and time constant `Tu` are determined and the selected tuning rule's constants are used to determine `Kp, Ki, Kd, Ti and Td`. Also, `controllability` and other details are provided (see comments in `sTune.cpp`).\n- In the user's sketch, the PID controller is set to automatic, the tuning parameters are applied the PID controller is run.\n\n### Full 5T Test\n\nA full test to pvMax is used when the controller action is set to `direct5T` or `reverse5T`. Use this method if the `IP`testing isn't a good fit to the process or if you'd like to get test data for the complete input response. Here, it is assumed the test will complete at about 3.5τ, from which point the apparent `pvMax` is estimated and the tuning parameters are calculated.\n\n![image](https://user-images.githubusercontent.com/63488701/150998367-a1999050-cab4-486f-a3ae-1c9dbdf11060.png)\n\n### Functions\n\n#### sTune Constructor\n\n```c++\nsTune(float *input, float *output, TuningRule tuningRule, Action action, SerialMode serialMode);\n```\n\n- `input` and `output` are pointers to the variables holding these values.\n- `tuningRule` provides selection of 10 various tuning rules as described in the table below.\n- `action` provides choices for controller action (direct or reverse) and whether to perform a fast inflection point test (IP) or a full 5 time constant test (5T). Choices are `directIP`, `direct5T`, `reverseIP` and `reverse5T`.\n- `serialMode` provides 6 choices for serial output.\n\n| Open Loop Tuning Methods | Autotune  Plot (using PWM output)                            | Description                                                  |\n| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |\n| `ZN_PID`                 | [![Click to enlarge](https://user-images.githubusercontent.com/63488701/149276354-fcec7626-4f0a-4ce2-a8a2-078745a84dcd.png)](https://user-images.githubusercontent.com/63488701/149275791-a46f353a-3215-486c-a9ce-d96183897272.PNG) | Open Loop Ziegler-Nichols method with ¼ decay ratio          |\n| `DampedOsc_PID`          | [![Click to enlarge](https://user-images.githubusercontent.com/63488701/149277219-48534317-cf0f-44f0-a5be-12653b2f6e0c.png)](https://user-images.githubusercontent.com/63488701/149275509-68d12ba6-269a-4ce1-b8a7-36037518c49b.PNG) | Damped Oscillation method can solve marginal stability issues |\n| `NoOvershoot_PID`        | [![Click to enlarge](https://user-images.githubusercontent.com/63488701/149277649-7bdf4a72-4de6-41b2-9825-628d4d742423.png)](https://user-images.githubusercontent.com/63488701/149275728-4fca57f0-c975-4350-ab45-56d50b7c2cdf.PNG) | No Overshoot uses the C-H-R method (set point tracking) with 0% overshoot |\n| `CohenCoon_PID`          | [![Click to enlarge](https://user-images.githubusercontent.com/63488701/149278074-6a01584e-0c9b-44bf-b595-f436f653f220.png)](https://user-images.githubusercontent.com/63488701/149275398-69586823-0267-4834-8183-d383713f2d27.PNG) | Open loop Cohen Coon method approximates closed loop response with a ¼ decay ratio |\n| `Mixed_PID`              | [![Click to enlarge](https://user-images.githubusercontent.com/63488701/149278272-5057825c-5d92-4e69-9790-c90fd5235eaf.png)](https://user-images.githubusercontent.com/63488701/149275646-7aa0d8c9-397e-4bc5-8110-85b54a951c4f.PNG) | Mixed method averages the gains for `ZN_PID`, `DampedOsc_PID`, `NoOvershoot_PID` and `CohenCoon_PID` |\n| `ZN_PI`                  |                                                              | Open Loop Ziegler-Nichols method with ¼ decay ratio          |\n| `DampedOsc_PI`           |                                                              | Damped Oscillation method can solve marginal stability issues |\n| `NoOvershoot_PI`         |                                                              | No Overshoot uses the C-H-R method (set point tracking) with 0% overshoot |\n| `CohenCoon_PI`           |                                                              | Open loop Cohen Coon method approximates closed loop response with a ¼ decay ratio |\n| `Mixed_PI`               |                                                              | Mixed method averages the gains for `ZN_PI`, `DampedOsc_PI`, `NoOvershoot_PI` and `CohenCoon_PI` |\n\n| Serial Mode     | Description                                                  |\n| --------------- | ------------------------------------------------------------ |\n| `serialOFF`     | No serial output will occur.                                 |\n| `printALL`      | Prints test data while settling and during the test run. A summary of results is printed when testing completes. |\n| `printSUMMARY`  | A summary of results is printed when testing completes.      |\n| `printDEBUG`    | Same as `printALL`but includes printing diagnostic data during test run. |\n| `printPIDTUNER` | ➩  Prints test data in csv format compatible with [pidtuner.com](https://pidtuner.com). \u003cbr /\u003e➩  Requires the controller `action` being set to `direct5T` or `reverse5T`\u003cbr /\u003e➩  Just copy the serial printer data and import (paste) into PID Tuner for further\u003cbr /\u003e      analysis, model identification, fine PID tuning and experimentation. \u003cbr /\u003e➩  Note that `Kp`, `Ti` and `Td` is also provided for PID Tuner. |\n| `printPLOTTER`  | Plots `pvAvg` data for use with Serial Plotter.              |\n\n#### Instantiate sTune\n\n```c++\nsTune tuner = sTune(\u0026Input, \u0026Output, tuner.ZN_PID, tuner.directIP, tuner.printALL);\n/*                                         ZN_PID           directIP     serialOFF\n                                           DampedOsc_PID    direct5T     printALL\n                                           NoOvershoot_PID  reverseIP    printSUMMARY\n                                           CohenCoon_PID    reverse5T    printDEBUG\n                                           Mixed_PID\n                                           ZN_PI\n                                           DampedOsc_PI\n                                           NoOvershoot_PI\n                                           CohenCoon_PI\n                                           Mixed_PI\n*/\n```\n\n#### Configure\n\nThis function applies the sTune test settings.\n\n```c++\nvoid Configure(const float inputSpan, const float outputSpan, float outputStart, float outputStep,\nuint32_t testTimeSec, uint32_t settleTimeSec, const uint16_t samples);\n```\n\n#### Set Functions\n\n```c++\nvoid SetEmergencyStop(float e_Stop);\nvoid SetControllerAction(Action Action);\nvoid SetSerialMode(SerialMode SerialMode);\nvoid SetTuningMethod(TuningMethod TuningMethod);\n```\n\n#### Query Functions\n\n```c++\nfloat GetKp();                  // proportional gain\nfloat GetKi();                  // integral gain\nfloat GetKd();                  // derivative gain\nfloat GetTi();                  // integral time\nfloat GetTd();                  // derivative time\nfloat GetProcessGain();         // process gain\nfloat GetDeadTime();            // process dead time (seconds)\nfloat GetTau();                 // process time constant (seconds)\nuint8_t GetControllerAction();\nuint8_t GetSerialMode();\nuint8_t GetTuningMethod();\nvoid GetAutoTunings(float * kp, float * ki, float * kd);\n\n```\n\n#### Controllability of the process\n\nWhen the test ends, sTune determines [how difficult](https://blog.opticontrols.com/wp-content/uploads/2011/06/td-versus-tau.png) the process is to control.\n\n```c++\nfloat controllability = _Tu / _td + epsilon;\n```\n\n#### References\n\n- [Comparison of PID Controller Tuning Methods](http://maulana.lecture.ub.ac.id/files/2014/12/Jurnal-PID_Tunning_Comparison.pdf)\n- [Ziegler-Nichols Open-Loop Tuning Rules](https://blog.opticontrols.com/archives/477)\n- [Inflection point](https://en.wikipedia.org/wiki/Inflection_point)\n- [Time Constant (Re: Step response with arbitrary initial conditions)](https://en.wikipedia.org/wiki/Time_constant)\n- [Sample Time is a Fundamental Design and Tuning Specification](https://controlguru.com/sample-time-is-a-fundamental-design-and-tuning-specification/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDlloydev%2FsTune","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDlloydev%2FsTune","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDlloydev%2FsTune/lists"}