| 1 | #!/bin/bash |
| 2 | |
| 3 | #==BEGIN function definition== |
| 4 | yell() { echo "$0: $*" >&2; } # print script path and all args to stderr |
| 5 | die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status |
| 6 | try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails |
| 7 | update_pi() { |
| 8 | # Desc: Calculates control variable (CV) given setpoint (SP) and |
| 9 | # process variable (PV). Uses proportional integral (PI) |
| 10 | # control. |
| 11 | # Usage: update_pi arg1 arg2 arg3 arg4 arg5 arg6 |
| 12 | # Version: 0.1.3 |
| 13 | # Input: arg1: path_loop_name (control loop name path) |
| 14 | # arg2: var_pv (process variable) |
| 15 | # arg3: var_sp (set point) |
| 16 | # arg4: tune_p (proportional tuning factor) |
| 17 | # arg5: tune_i (integral tuning factor) |
| 18 | # arg6: var_cv_bias (control variable bias; prevents initial jerk) |
| 19 | # Output: stdout: var_cv (control variable) |
| 20 | # file: path_var_pv |
| 21 | # file: path_var_sp |
| 22 | # file: path_tune_p |
| 23 | # file: path_tune_i |
| 24 | # file: path_var_cv |
| 25 | # file: path_sum (saves updated sum state) |
| 26 | # Example: update_pi /dev/shm/DC1.AC 1.0 3.0 2.0 3.0 |
| 27 | # Depends: bc, gnu coreutils 8.30, yell(), try() |
| 28 | local var_sp var_pv var_cv; |
| 29 | local tune_p tune_i; |
| 30 | local term_p term_i; |
| 31 | local error sum sum_cand; |
| 32 | local path_sum path_var_sp path_var_pv path_tune_p path_tune_i; |
| 33 | |
| 34 | path_loop_name="$1"; |
| 35 | |
| 36 | path_var_pv="$path_loop_name".pv |
| 37 | var_pv="$2"; # read provided process variable |
| 38 | |
| 39 | path_var_sp="$path_loop_name".sp |
| 40 | if [[ -f "$path_var_sp" ]]; then |
| 41 | var_sp="$(cat "$path_var_sp" | head -n1)"; |
| 42 | else |
| 43 | var_sp="$3"; |
| 44 | fi; |
| 45 | |
| 46 | path_tune_p="$path_loop_name".tune_p |
| 47 | if [[ -f "$path_tune_p" ]]; then |
| 48 | tune_p="$(cat "$path_tune_p" | head -n1)"; |
| 49 | else |
| 50 | tune_p="$4"; |
| 51 | fi; |
| 52 | |
| 53 | path_tune_i="$path_loop_name".tune_i |
| 54 | if [[ -f "$path_tune_i" ]]; then |
| 55 | tune_i="$(cat "$path_tune_i" | head -n1)"; |
| 56 | else |
| 57 | tune_i="$5"; |
| 58 | fi; |
| 59 | |
| 60 | path_var_cv="$path_loop_name".cv |
| 61 | |
| 62 | path_var_cv_bias="$path_loop_name".cv_bias |
| 63 | var_cv_bias="$6"; |
| 64 | |
| 65 | path_sum="$path_loop_name".sum |
| 66 | if [[ -f "$path_sum" ]]; then |
| 67 | sum="$(cat "$path_sum" | head -n1)"; |
| 68 | else |
| 69 | sum=0; |
| 70 | fi; |
| 71 | |
| 72 | #yell "DEBUG:path_loop_name:$path_loop_name"; |
| 73 | #yell "DEBUG:var_pv:$var_pv"; |
| 74 | #yell "DEBUG:var_sp:$var_sp"; |
| 75 | #yell "DEBUG:var_cv:$var_cv"; |
| 76 | #yell "DEBUG:var_cv_bias:$var_cv_bias"; |
| 77 | #yell "DEBUG:tune_p:$tune_p"; |
| 78 | #yell "DEBUG:tune_i:$tune_i"; |
| 79 | |
| 80 | error="$(try echo "$var_sp - $var_pv" | bc -l)"; |
| 81 | #yell "DEBUG:error:$error"; |
| 82 | sum_cand="$(try echo "$sum + $error" | bc -l)"; |
| 83 | #yell "DEBUG:sum:$sum"; |
| 84 | if [[ "$(try echo "$sum_cand > 2 * $sum " | bc -l)" -eq 1 ]]; then |
| 85 | sum="$(try echo "$sum + l($error + 1)" | bc -l)"; # dampen integral sum spikes |
| 86 | else |
| 87 | sum="$sum_cand"; |
| 88 | fi; |
| 89 | term_p="$(try echo "$tune_p * $error" | bc -l)"; |
| 90 | #yell "DEBUG:term_p:$term_p"; |
| 91 | term_i="$(try echo "$tune_i * $sum" | bc -l)"; |
| 92 | #yell "DEBUG:term_i:$term_i"; |
| 93 | var_cv="$(try echo "$term_p + $term_i + $var_cv_bias" | bc -l)"; |
| 94 | #yell "DEBUG:var_cv:$var_cv"; |
| 95 | |
| 96 | # Write variables to memory |
| 97 | echo "$sum" > "$path_sum"; |
| 98 | echo "$var_sp" > "$path_var_sp"; |
| 99 | echo "$var_pv" > "$path_var_pv"; |
| 100 | echo "$tune_p" > "$path_tune_p"; |
| 101 | echo "$tune_i" > "$path_tune_i"; |
| 102 | echo "$var_cv" > "$path_var_cv"; |
| 103 | echo "$var_cv_bias" > "$path_var_cv_bias"; |
| 104 | |
| 105 | # Output control variable to stdout |
| 106 | echo "$var_cv"; |
| 107 | |
| 108 | #yell "DEBUG:=============END_ROUND==============="; |
| 109 | } # update specified PI loop |
| 110 | #==END function definition== |
| 111 | |
| 112 | #==BEGIN Example code== |
| 113 | path_loop_name="/tmp/DC1.AC"; |
| 114 | var_pv=1.0; |
| 115 | var_sp=2.0; |
| 116 | tune_p=1.0; |
| 117 | tune_i=0.1; |
| 118 | var_cv_init=1000; |
| 119 | try rm "$path_loop_name"* |
| 120 | |
| 121 | var_pv=4.0; |
| 122 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 123 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 124 | yell "DEBUG:output:$output"; |
| 125 | var_pv=4.0; |
| 126 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 127 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 128 | yell "DEBUG:output:$output"; |
| 129 | var_pv=4.0; |
| 130 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 131 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 132 | yell "DEBUG:output:$output"; |
| 133 | var_pv=4.0; |
| 134 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 135 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 136 | yell "DEBUG:output:$output"; |
| 137 | var_pv=4.0; |
| 138 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 139 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 140 | yell "DEBUG:output:$output"; |
| 141 | var_pv=1.0; |
| 142 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 143 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 144 | yell "DEBUG:output:$output"; |
| 145 | var_pv=1.0; |
| 146 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 147 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 148 | yell "DEBUG:output:$output"; |
| 149 | var_pv=1.0; |
| 150 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 151 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 152 | yell "DEBUG:output:$output"; |
| 153 | var_pv=1.0; |
| 154 | output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; |
| 155 | yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; |
| 156 | yell "DEBUG:output:$output"; |
| 157 | #==END Example code== |
| 158 | |
| 159 | # Author: Steven Baltakatei Sandoval |
| 160 | # License: GPLv3+ |