From dbee4a4b26e10e4aac686ed7e01c8f8165e851e7 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 8 Aug 2021 07:48:32 +0000 Subject: [PATCH 01/16] feat(u/p/bktemp-parseArgs):Add example parseArgs python3 script - note: made using sleepRand.py as template --- unitproc/python/bktemp-parseArgs | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100755 unitproc/python/bktemp-parseArgs diff --git a/unitproc/python/bktemp-parseArgs b/unitproc/python/bktemp-parseArgs new file mode 100755 index 0000000..de287cd --- /dev/null +++ b/unitproc/python/bktemp-parseArgs @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# Usage: python3 ./bktemp-parseArgs -vv 3 + +import argparse, logging; + +# Setup argument parser (see https://docs.python.org/3.7/library/argparse.html ) +parser = argparse.ArgumentParser( + description='Perform some work.', + epilog="Author: Steven Baltakatei Sandoval. License: GPLv3+"); +parser = argparse.ArgumentParser( + description='(example description) Delay activity for a random number of seconds. Delays sampled from an inverse gaussian distribution.', + epilog="(example epilog) Author: Steven Baltakatei Sandoval. License: GPLv3+"); +parser.add_argument('-v','--verbose', + action='count', + dest='verbosity', + default=0, + help='(example help) Verbose output. (repeat for increased verbosity)'); +parser.add_argument('mean', + action='store', + metavar='SECONDS', + nargs=1, + default=1, + type=float, + help='(example help) Mean seconds of delay. Is the mean of the inverse gaussian distribution.'); +args = parser.parse_args(); + +# Define functions +def setup_logging(verbosity): + # Depends: module: argparse + # Ref/Attrib: Haas, Florian; Configure logging with argparse; https://xahteiwi.eu/resources/hints-and-kinks/python-cli-logging-options/ + base_loglevel = 30; + verbosity = min(verbosity, 2); + loglevel = base_loglevel - (verbosity * 10); + logging.basicConfig(level=loglevel, + format='%(message)s'); + +## Start up logger +setup_logging(args.verbosity); +logging.debug('DEBUG:Debug logging output enabled.'); +logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); +logging.debug('DEBUG:args:' + str(args)); -- 2.30.2 From 252ebb00f5568d5fa53cc890b08642e453585f79 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 8 Aug 2021 07:51:55 +0000 Subject: [PATCH 02/16] chore(u/p/bktemp-parseArgs):Add version number --- unitproc/python/bktemp-parseArgs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unitproc/python/bktemp-parseArgs b/unitproc/python/bktemp-parseArgs index de287cd..ec8185d 100755 --- a/unitproc/python/bktemp-parseArgs +++ b/unitproc/python/bktemp-parseArgs @@ -1,5 +1,7 @@ #!/usr/bin/env python3 # Usage: python3 ./bktemp-parseArgs -vv 3 +# Version: 0.0.1 +# Note: is example tempalte for setting up use of logging module import argparse, logging; -- 2.30.2 From a967b286845c5754d4fbfd1fab2cff6ff56be352 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 8 Aug 2021 08:04:30 +0000 Subject: [PATCH 03/16] chore(u/p/sleepRand.py):Update comments --- unitproc/python/sleepRand.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/unitproc/python/sleepRand.py b/unitproc/python/sleepRand.py index 3917506..7a9b2b7 100755 --- a/unitproc/python/sleepRand.py +++ b/unitproc/python/sleepRand.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 # Desc: Pauses a random amount of time. Random distribution is inverse gaussian. -# Version: 0.0.4 +# Version: 0.0.5 # Depends: python 3.7.3 -# Usage: ./sleepRand.py [-v] [-p L] SECONDS +# Usage: ./sleepRand.py [-v] [-p P] SECONDS # Input: SECONDS: float seconds (mean of inverse gaussian distribution) -# L: precision (lambda of inverse gaussian distribution) +# P: precision (lambda of inverse gaussian distribution) # Example: python3 sleepRand.py -vv -p 8.0 60.0 import argparse; @@ -38,6 +38,7 @@ args = parser.parse_args(); # Define functions def setup_logging(verbosity): + '''Sets up logging''' # Depends: module: argparse # Ref/Attrib: Haas, Florian; Configure logging with argparse; https://xahteiwi.eu/resources/hints-and-kinks/python-cli-logging-options/ base_loglevel = 30; @@ -71,6 +72,7 @@ setup_logging(args.verbosity); logging.debug('DEBUG:Debug logging output enabled.'); logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); logging.debug('DEBUG:args:' + str(args)); + ## Reject negative floats. try: ### Get desired mean -- 2.30.2 From 31322bd99a1db51281a33446f58cd9e15b29195d Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Mon, 9 Aug 2021 12:15:38 +0000 Subject: [PATCH 04/16] feat(u/p/sleepRand.py):Add --upper bound option - note: option added in case user wishes to limit maximum possible delay generated. --- unitproc/python/sleepRand.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/unitproc/python/sleepRand.py b/unitproc/python/sleepRand.py index 7a9b2b7..016e9f3 100755 --- a/unitproc/python/sleepRand.py +++ b/unitproc/python/sleepRand.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # Desc: Pauses a random amount of time. Random distribution is inverse gaussian. -# Version: 0.0.5 +# Version: 0.0.6 # Depends: python 3.7.3 # Usage: ./sleepRand.py [-v] [-p P] SECONDS # Input: SECONDS: float seconds (mean of inverse gaussian distribution) @@ -34,6 +34,13 @@ parser.add_argument('--precision','-p', default=[4.0], type=float, help='How concentrated delays are around the mean (default: 4.0). Must be a positive integer or floating point value. Is the lambda factor in the inverse gaussian distribution. High values (e.g. > 10.0) cause random delays to rarely stray far from MEAN. Small values (e.g. < 0.10) result in many small delays plus occasional long delays.'); +parser.add_argument('--upper','-u', + action='store', + metavar='U', + nargs=1, + default=[None], + type=float, + help='Upper bound for possible delays (default: no bound). Without bound, extremely high delays are unlikely but possible.'); args = parser.parse_args(); # Define functions @@ -73,14 +80,28 @@ logging.debug('DEBUG:Debug logging output enabled.'); logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); logging.debug('DEBUG:args:' + str(args)); -## Reject negative floats. +## Receive input arguments try: ### Get desired mean desMean = args.mean[0]; logging.debug('DEBUG:Desired mean:' + str(desMean)); + ### Get lambda precision factor lambdaFactor = args.precision[0]; logging.debug('DEBUG:Lambda precision factor:' + str(lambdaFactor)); + + ### Get upper bound + if isinstance(args.upper[0], float): + logging.debug('DEBUG:args.upper[0] is float:' + str(args.upper[0])); + upperBound = args.upper[0]; + elif args.upper[0] is None: + logging.debug('DEBUG:args.upper[0] is None:' + str(args.upper[0])); + upperBound = None; + else: + raise TypeError('Upper bound not set correctly.'); + logging.debug('DEBUG:Upper bound:' + str(upperBound)); + + ### Reject negative floats. if desMean < 0: logging.error('ERROR:Desired mean is negative:' + str(desMean)); raise ValueError('Negative number error.'); @@ -91,8 +112,13 @@ except ValueError: sys.exit(1); # Calculate delay -delay = randInvGau(desMean, desMean * lambdaFactor); -logging.debug('delay:' + str(delay)); +rawDelay = randInvGau(desMean, desMean * lambdaFactor); +logging.debug('DEBUG:rawDelay(seconds):' + str(rawDelay)); +if isinstance(upperBound,float): + delay = min(upperBound, rawDelay); +elif upperBound is None: + delay = rawDelay; +logging.debug('DEBUG:delay(seconds) :' + str(delay)); # Sleep time.sleep(float(delay)); -- 2.30.2 From c5cfeb928ccdd6daeb9a45bc61917fd33479a0e7 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Wed, 11 Aug 2021 13:02:40 +0000 Subject: [PATCH 05/16] feat(unitproc/octave/invgaurnd.m):Add inverse gaussian generator - note: Is GNU octave function based on `normrnd.m` file from 'statistics' package (see https://gnu-octave.github.io/packages/statistics ). - Tested with GNU Octave 4.4.1 --- unitproc/octave/invgaurnd.m | 151 ++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 unitproc/octave/invgaurnd.m diff --git a/unitproc/octave/invgaurnd.m b/unitproc/octave/invgaurnd.m new file mode 100644 index 0000000..02d5628 --- /dev/null +++ b/unitproc/octave/invgaurnd.m @@ -0,0 +1,151 @@ +## Copyright (C) 2012 Rik Wehbring +## Copyright (C) 1995-2016 Kurt Hornik +## Copyright (C) 2021 Steven Baltakatei Sandoval +## +## This program is free software: you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation, either version 3 of the +## License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {} invgaurnd (@var{mu}, @var{lambda}) +## @deftypefnx {} {} invgaurnd (@var{mu}, @var{lambda}, @var{r}) +## @deftypefnx {} {} invgaurnd (@var{mu}, @var{lambda}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {} {} invgaurnd (@var{mu}, @var{lambda}, [@var{sz}]) +## Return a matrix of random samples from the inverse gaussian distribution with +## parameters mean @var{mu} and shape parameter @var{lambda}. +## +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{mu} and @var{lambda}. +## @end deftypefn + +## Author: Steven Sandoval +## Description: Random variates from the inverse gaussian distribution + +function rnd = invgaurnd (mu, lambda, varargin) + + if (nargin < 2) + print_usage (); + endif + + if (! isscalar (mu) || ! isscalar (lambda)) + [retval, mu, lambda] = common_size (mu, lambda); + if (retval > 0) + error ("invgaurnd: MU and LAMBDA must be of common size or scalars"); + endif + endif + + if (iscomplex (mu) || iscomplex (lambda)) + error ("invgaurnd: MU and LAMBDA must not be complex"); + endif + + if (nargin == 2) + sz = size (mu); + elseif (nargin == 3) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("invgaurnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 3) + if (any (cellfun (@(x) (! isscalar (x) || x < 0), varargin))) + error ("invgaurnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (! isscalar (mu) && ! isequal (size (mu), sz)) + error ("invgaurnd: MU and LAMBDA must be scalar or of size SZ"); + endif + + if (isa (mu, "single") || isa (lambda, "single")) + cls = "single"; + else + cls = "double"; + endif; + + # Convert mu and lambda from scalars into matrices since scalar multiplication used + if isscalar (mu) + mu = mu * ones(sz); + endif; + if isscalar (lambda) + lambda = lambda * ones(sz); + endif; + + # Generate random variates + # Ref/Attrib: Michael, John R., Generating Random Variates Using + # Transformations with Multiple Roots. The American Statistician, May 1976, + # Vol. 30, No. 2. https://doi.org/10.2307/2683801 + nu = randn(sz,cls); + y = nu .** 2; + x1 = mu; + x2 = mu .** 2 .* y ./ (2 .* lambda); + x3 = (- mu ./ (2 .* lambda)) .* sqrt(4 .* mu .* lambda .* y + mu .** 2 .* y .** 2); + x = x1 + x2 + x3; + z = rand(sz,cls); + valTest1 = (mu ./ (mu + x)); # calculate test 1 value + valTest2 = (mu ./ (mu + x)); # calculate test 2 value + posTest1 = find(z <= valTest1); # perform test 1, save positions where test 1 true + posTest2 = find(z > valTest2); # perform test 2, save positions where test 2 true + ## indposTest1 = transpose(posTest1) # debug: list positions + ## indposTest2 = transpose(posTest2) # debug: list positions + ## indTest1 = z <= valTest1 # debug: show test 1 truth table + ## indTest2 = z > valTest2 # debug: show test 2 truth table + rnd = NaN(sz); # Initialize return array + rnd(posTest1) = x(posTest1); # populate return matrix with corresp. elements of x that satisfy test 1 + rnd(posTest2) = (mu(posTest2) .** 2 ./ x(posTest2)); # populate return matrix with corresp. elements of x that satisfy test 2 + k = ! isfinite (mu) | !(lambda >= 0) | !(lambda < Inf); # store position matrix indicating which parts of output are invalid based on + # elements of the matrices: mu, lambda. + rnd(k) = NaN; # mark invalid positions of output matrix with NaN + +endfunction + + +%!assert (size (invgaurnd (1,2)), [1, 1]) +%!assert (size (invgaurnd (ones (2,1), 2)), [2, 1]) +%!assert (size (invgaurnd (ones (2,2), 2)), [2, 2]) +%!assert (size (invgaurnd (1, 2*ones (2,1))), [2, 1]) +%!assert (size (invgaurnd (1, 2*ones (2,2))), [2, 2]) +%!assert (size (invgaurnd (1, 2, 3)), [3, 3]) +%!assert (size (invgaurnd (1, 2, [4 1])), [4, 1]) +%!assert (size (invgaurnd (1, 2, 4, 1)), [4, 1]) + +## Test class of input preserved +%!assert (class (invgaurnd (1, 2)), "double") +%!assert (class (invgaurnd (single (1), 2)), "single") +%!assert (class (invgaurnd (single ([1 1]), 2)), "single") +%!assert (class (invgaurnd (1, single (2))), "single") +%!assert (class (invgaurnd (1, single ([2 2]))), "single") + +## Test input validation +%!error invgaurnd () +%!error invgaurnd (1) +%!error invgaurnd (ones (3), ones (2)) +%!error invgaurnd (ones (2), ones (3)) +%!error invgaurnd (i, 2) +%!error invgaurnd (2, i) +%!error invgaurnd (1,2, -1) +%!error invgaurnd (1,2, ones (2)) +%!error invgaurnd (1, 2, [2 -1 2]) +%!error invgaurnd (1,2, 1, ones (2)) +%!error invgaurnd (1,2, 1, -1) +%!error invgaurnd (ones (2,2), 2, 3) +%!error invgaurnd (ones (2,2), 2, [3, 2]) +%!error invgaurnd (ones (2,2), 2, 2, 3) -- 2.30.2 From e3cd181c3cc410cb52e0d7f9f9c01b5c75f38aa6 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Thu, 14 Oct 2021 01:00:20 +0000 Subject: [PATCH 06/16] feat(unitproc/bktemp-initGitRepo):Fetch remote branches after pull --- unitproc/bktemp-initGitRepo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unitproc/bktemp-initGitRepo b/unitproc/bktemp-initGitRepo index 3e4b566..911a63c 100644 --- a/unitproc/bktemp-initGitRepo +++ b/unitproc/bktemp-initGitRepo @@ -31,7 +31,7 @@ initGitRepo() { # arg2: repoDir # arg3: remoteName # arg4: branchName - # Version: 0.0.7 + # Version: 0.0.8 # Depends: checkURL() 0.0.2, yell(), Bash 5.0.3 # Ref/Attrib: [1]: Test for space-less alphanuemric string. https://unix.stackexchange.com/a/416120 # [2]: Test for argument count. https://stackoverflow.com/q/18568706 @@ -77,6 +77,7 @@ initGitRepo() { git remote add "$remoteName" "$repoURL"; yell "STATUS:Pulling branch $branchName from remote $remoteName"; git pull --ff-only "$remoteName" "$branchName"; + git fetch "$remoteName"; unset repoURL repoDir remoteName branchName; popd || exit 1; #==END create and populate git repository== -- 2.30.2 From 5113c9ac659baf9aa3612e31e4d0aaf7d39ea62d Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 03:41:31 +0000 Subject: [PATCH 07/16] feat(unitproc):Add PI loop updater --- unitproc/bktemp-updateLoopPI | 143 +++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 unitproc/bktemp-updateLoopPI diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI new file mode 100644 index 0000000..d01e6b4 --- /dev/null +++ b/unitproc/bktemp-updateLoopPI @@ -0,0 +1,143 @@ +#!/bin/bash + +#==BEGIN function definition== +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +update_pi() { + # Desc: Calculates control variable (CV) given setpoint (SP) and + # process variable (PV). Uses proportional integral (PI) + # control. + # Usage: update_pi arg1 arg2 arg3 arg4 arg5 + # Version: 0.0.1 + # Input: arg1: path_loop_name (control loop name path) + # arg2: var_pv (process variable) + # arg3: var_sp (set point) + # arg4: tune_p (proportional tuning factor) + # arg5: tune_i (integral tuning factor) + # Output: stdout: var_cv (control variable) + # file: path_var_pv + # file: path_var_sp + # file: path_tune_p + # file: path_tune_i + # file: path_sum (saves updated sum state) + # Example: update_pi /dev/shm/DC1.AC 1.0 3.0 2.0 3.0 + # Depends: bc, gnu coreutils 8.30, yell(), try() + local var_sp var_pv var_cv; + local tune_p tune_i; + local term_p term_i; + local error sum; + local path_sum path_var_sp path_var_pv path_tune_p path_tune_i; + + path_loop_name="$1"; + + path_var_pv="$path_loop_name".pv + var_pv="$2"; # read provided process variable + + path_var_sp="$path_loop_name".sp + if [[ -f "$path_var_sp" ]]; then + var_sp="$(cat "$path_var_sp" | head -n1)"; + else + var_sp="$3"; + fi; + + path_tune_p="$path_loop_name".tune_p + if [[ -f "$path_tune_p" ]]; then + tune_p="$(cat "$path_tune_p" | head -n1)"; + else + tune_p="$4"; + fi; + + path_tune_i="$path_loop_name".tune_i + if [[ -f "$path_tune_i" ]]; then + tune_i="$(cat "$path_tune_i" | head -n1)"; + else + tune_i="$5"; + fi; + + path_sum="$path_loop_name".sum + if [[ -f "$path_sum" ]]; then + sum="$(cat "$path_sum" | head -n1)"; + else + sum=0; + fi; + + #yell "DEBUG:path_loop_name:$path_loop_name"; + #yell "DEBUG:var_pv:$var_pv"; + #yell "DEBUG:var_sp:$var_sp"; + #yell "DEBUG:tune_p:$tune_p"; + #yell "DEBUG:tune_i:$tune_i"; + + error="$(try echo "$var_sp - $var_pv" | bc -l)"; + #yell "DEBUG:error:$error"; + sum="$(try echo "$sum + $error" | bc -l)"; + #yell "DEBUG:sum:$sum"; + term_p="$(try echo "$tune_p * $error" | bc -l)"; + #yell "DEBUG:term_p:$term_p"; + term_i="$(try echo "$tune_i * $sum" | bc -l)"; + #yell "DEBUG:term_i:$term_i"; + var_cv="$(try echo "$term_p + $term_i" | bc -l)"; + #yell "DEBUG:var_cv:$var_cv"; + + # Write variables to memory + echo "$sum" > "$path_sum"; + echo "$var_sp" > "$path_var_sp"; + echo "$var_pv" > "$path_var_pv"; + echo "$tune_p" > "$path_tune_p"; + echo "$tune_i" > "$path_tune_i"; + + # Output control variable to stdout + echo "$var_cv"; + + #yell "DEBUG:=============END_ROUND==============="; +} +#==END function definition== + +#==BEGIN Example code== +path_loop_name="/tmp/DC1.AC"; +var_pv=1.0; +var_sp=2.0; +tune_p=1.0; +tune_i=0.1; +try rm "$path_loop_name"* + +var_pv=4.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=4.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=4.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=4.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=4.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=1.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=1.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=1.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +var_pv=1.0; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; +yell "DEBUG:output:$output"; +#==END Example code== + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+ -- 2.30.2 From 77c52629945029642045e6ee132e063927400c10 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 04:08:05 +0000 Subject: [PATCH 08/16] feat(bktemp-updateLoopPI):Add argument for initial CV bias - note: Additinoal argument helps prevent initial jerk caused by high initial error if set to correct value. --- unitproc/bktemp-updateLoopPI | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI index d01e6b4..84adb77 100644 --- a/unitproc/bktemp-updateLoopPI +++ b/unitproc/bktemp-updateLoopPI @@ -8,18 +8,20 @@ update_pi() { # Desc: Calculates control variable (CV) given setpoint (SP) and # process variable (PV). Uses proportional integral (PI) # control. - # Usage: update_pi arg1 arg2 arg3 arg4 arg5 - # Version: 0.0.1 + # Usage: update_pi arg1 arg2 arg3 arg4 arg5 arg6 + # Version: 0.1.0 # Input: arg1: path_loop_name (control loop name path) # arg2: var_pv (process variable) # arg3: var_sp (set point) # arg4: tune_p (proportional tuning factor) # arg5: tune_i (integral tuning factor) + # arg6: var_cv_bias (control variable bias; prevents initial jerk) # Output: stdout: var_cv (control variable) # file: path_var_pv # file: path_var_sp # file: path_tune_p # file: path_tune_i + # file: path_var_cv # file: path_sum (saves updated sum state) # Example: update_pi /dev/shm/DC1.AC 1.0 3.0 2.0 3.0 # Depends: bc, gnu coreutils 8.30, yell(), try() @@ -55,6 +57,10 @@ update_pi() { tune_i="$5"; fi; + path_var_cv="$path_loop_name".cv + + var_cv_bias="$6"; + path_sum="$path_loop_name".sum if [[ -f "$path_sum" ]]; then sum="$(cat "$path_sum" | head -n1)"; @@ -65,6 +71,7 @@ update_pi() { #yell "DEBUG:path_loop_name:$path_loop_name"; #yell "DEBUG:var_pv:$var_pv"; #yell "DEBUG:var_sp:$var_sp"; + #yell "DEBUG:var_cv:$var_cv"; #yell "DEBUG:tune_p:$tune_p"; #yell "DEBUG:tune_i:$tune_i"; @@ -76,7 +83,7 @@ update_pi() { #yell "DEBUG:term_p:$term_p"; term_i="$(try echo "$tune_i * $sum" | bc -l)"; #yell "DEBUG:term_i:$term_i"; - var_cv="$(try echo "$term_p + $term_i" | bc -l)"; + var_cv="$(try echo "$term_p + $term_i + $var_cv_bias" | bc -l)"; #yell "DEBUG:var_cv:$var_cv"; # Write variables to memory @@ -85,6 +92,7 @@ update_pi() { echo "$var_pv" > "$path_var_pv"; echo "$tune_p" > "$path_tune_p"; echo "$tune_i" > "$path_tune_i"; + echo "$var_cv" > "$path_var_cv"; # Output control variable to stdout echo "$var_cv"; @@ -99,42 +107,43 @@ var_pv=1.0; var_sp=2.0; tune_p=1.0; tune_i=0.1; +var_cv_init=1000; try rm "$path_loop_name"* var_pv=4.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=4.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=4.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=4.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=4.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=1.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=1.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=1.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; var_pv=1.0; -output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" | tail -n1)"; +output="$(update_pi "$path_loop_name" "$var_pv" "$var_sp" "$tune_p" "$tune_i" "$var_cv_init" | tail -n1)"; yell "DEBUG:sum:$(cat "$path_loop_name".sum | head -n1)"; yell "DEBUG:output:$output"; #==END Example code== -- 2.30.2 From 37bc30fd8a2e3e3ee3a1dadcfad6fecc9345a53c Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 04:10:40 +0000 Subject: [PATCH 09/16] style(bktemp-updateLoopPI):add function comment --- unitproc/bktemp-updateLoopPI | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI index 84adb77..2c345ab 100644 --- a/unitproc/bktemp-updateLoopPI +++ b/unitproc/bktemp-updateLoopPI @@ -9,7 +9,7 @@ update_pi() { # process variable (PV). Uses proportional integral (PI) # control. # Usage: update_pi arg1 arg2 arg3 arg4 arg5 arg6 - # Version: 0.1.0 + # Version: 0.1.1 # Input: arg1: path_loop_name (control loop name path) # arg2: var_pv (process variable) # arg3: var_sp (set point) @@ -98,7 +98,7 @@ update_pi() { echo "$var_cv"; #yell "DEBUG:=============END_ROUND==============="; -} +} # update specified PI loop #==END function definition== #==BEGIN Example code== -- 2.30.2 From a47be58ab25177aadd9f65ac3379509b6da52309 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 04:16:27 +0000 Subject: [PATCH 10/16] feat(bktemp-updateLoopPI):write cv bias to tmpdir --- unitproc/bktemp-updateLoopPI | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI index 2c345ab..bda89ee 100644 --- a/unitproc/bktemp-updateLoopPI +++ b/unitproc/bktemp-updateLoopPI @@ -59,6 +59,7 @@ update_pi() { path_var_cv="$path_loop_name".cv + path_var_cv_bias="$path_loop_name".cv_bias var_cv_bias="$6"; path_sum="$path_loop_name".sum @@ -72,6 +73,7 @@ update_pi() { #yell "DEBUG:var_pv:$var_pv"; #yell "DEBUG:var_sp:$var_sp"; #yell "DEBUG:var_cv:$var_cv"; + #yell "DEBUG:var_cv_bias:$var_cv_bias"; #yell "DEBUG:tune_p:$tune_p"; #yell "DEBUG:tune_i:$tune_i"; @@ -93,6 +95,7 @@ update_pi() { echo "$tune_p" > "$path_tune_p"; echo "$tune_i" > "$path_tune_i"; echo "$var_cv" > "$path_var_cv"; + echo "$var_cv_bias" > "$path_var_cv_bias"; # Output control variable to stdout echo "$var_cv"; -- 2.30.2 From 8be2ec95ab4fc9c14541bebc6a4b70cf074bc5c6 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 22:16:49 +0000 Subject: [PATCH 11/16] fix(bktemp-updateloopPI):Add integral sum spike dampener --- unitproc/bktemp-updateLoopPI | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI index bda89ee..61f7e8d 100644 --- a/unitproc/bktemp-updateLoopPI +++ b/unitproc/bktemp-updateLoopPI @@ -9,7 +9,7 @@ update_pi() { # process variable (PV). Uses proportional integral (PI) # control. # Usage: update_pi arg1 arg2 arg3 arg4 arg5 arg6 - # Version: 0.1.1 + # Version: 0.1.2 # Input: arg1: path_loop_name (control loop name path) # arg2: var_pv (process variable) # arg3: var_sp (set point) @@ -28,7 +28,7 @@ update_pi() { local var_sp var_pv var_cv; local tune_p tune_i; local term_p term_i; - local error sum; + local error sum sum_cand; local path_sum path_var_sp path_var_pv path_tune_p path_tune_i; path_loop_name="$1"; @@ -79,8 +79,13 @@ update_pi() { error="$(try echo "$var_sp - $var_pv" | bc -l)"; #yell "DEBUG:error:$error"; - sum="$(try echo "$sum + $error" | bc -l)"; + sum_cand="$(try echo "$sum + $error" | bc -l)"; #yell "DEBUG:sum:$sum"; + if [[ "$(try echo "$sum_cand > 2 * $sum " | bc -l)" -eq 1 ]]; then + sum="$(try echo "$sum + l($error)" | bc -l)"; # dampen integral sum spikes + else + sum="$sum_cand"; + fi; term_p="$(try echo "$tune_p * $error" | bc -l)"; #yell "DEBUG:term_p:$term_p"; term_i="$(try echo "$tune_i * $sum" | bc -l)"; -- 2.30.2 From 12674731c5848a1a69f9fbe1124de73545bf9cbd Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sun, 31 Oct 2021 22:28:08 +0000 Subject: [PATCH 12/16] fix(bktemp-updateLoopPI):Fix log function used in sum dampener --- unitproc/bktemp-updateLoopPI | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unitproc/bktemp-updateLoopPI b/unitproc/bktemp-updateLoopPI index 61f7e8d..9054b90 100644 --- a/unitproc/bktemp-updateLoopPI +++ b/unitproc/bktemp-updateLoopPI @@ -9,7 +9,7 @@ update_pi() { # process variable (PV). Uses proportional integral (PI) # control. # Usage: update_pi arg1 arg2 arg3 arg4 arg5 arg6 - # Version: 0.1.2 + # Version: 0.1.3 # Input: arg1: path_loop_name (control loop name path) # arg2: var_pv (process variable) # arg3: var_sp (set point) @@ -82,7 +82,7 @@ update_pi() { sum_cand="$(try echo "$sum + $error" | bc -l)"; #yell "DEBUG:sum:$sum"; if [[ "$(try echo "$sum_cand > 2 * $sum " | bc -l)" -eq 1 ]]; then - sum="$(try echo "$sum + l($error)" | bc -l)"; # dampen integral sum spikes + sum="$(try echo "$sum + l($error + 1)" | bc -l)"; # dampen integral sum spikes else sum="$sum_cand"; fi; -- 2.30.2 From 1eb63ec23b162c8f094e08bbb3706349389c1dd5 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Tue, 2 Nov 2021 22:37:37 +0000 Subject: [PATCH 13/16] feat(u/bktemp-checkFlt):Add bash function to check for floats --- unitproc/bktemp-checkFlt | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 unitproc/bktemp-checkFlt diff --git a/unitproc/bktemp-checkFlt b/unitproc/bktemp-checkFlt new file mode 100644 index 0000000..530ff0e --- /dev/null +++ b/unitproc/bktemp-checkFlt @@ -0,0 +1,80 @@ +#!/bin/bash +# Desc: Checks if arg is a float + +#==BEGIN Define script parameters== +#===BEGIN Declare local script functions=== +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +checkFlt() { + # Desc: Checks if arg is a float + # Usage: checkInt arg + # Input: arg: float + # Output: - return code 0 (if arg is float) + # - return code 1 (if arg is not float) + # Example: if ! checkInt $arg; then echo "not flt"; fi; + # Version: 0.0.1 + # Depends: yell(), die(), bash 5.0.3 + # Ref/Attrib: JDB https://stackoverflow.com/a/12643073 float regex + local returnState + + #===Process Arg=== + if [[ $# -ne 1 ]]; then + die "ERROR:Invalid number of arguments:$#"; + fi; + + RETEST1='^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$'; # Regular Expression to test + if [[ ! $1 =~ $RETEST1 ]] ; then + returnState="false"; + else + returnState="true"; + fi; + + #===Determine function return code=== + if [ "$returnState" = "true" ]; then + return 0; + else + return 1; + fi; +} # Checks if arg is integer + +#===END Declare local script functions=== +#==END Define script parameters== + +#==BEGIN test code== +myVar1="4" ; echo "Test 1:Should succeed because int is float without decimal places or decimal."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="4.0" ; echo "Test 2:Should succeed because \"4.0\" is a float."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1=".0" ; echo "Test 3:Should succeed even if float lack whole numbers left of decimal."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="4." ; echo "Test 4:Should succeed even if float lacks decimal places right of decimal."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="14.0" ; echo "Test 5:Should succeed with multiple whole numbers to left of decimal." +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="." ; echo "Test 6:Should fail because neither whole numbers nor decimal places are present."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="4"; myVar2="5"; echo "Test 7:Should fail because multiple numbers are provided."; +(if checkFlt "$myVar1" "$myVar2"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="4 5"; echo "Test 8:Should fail because multiple numbers are provided."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="4.4.4"; echo "Test 9:Should fail because a float should contain only one decimal."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="foo"; echo "Test 10:Should fail because floats should only contain numbers and decimal characters." +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1="foo"; myVar2="bar"; myVar3="baz"; echo "Test 11: Should fail because multiple arguments provided."; +(if checkFlt "$myVar1" "$myVar2" "$myVar3"; then yell "success"; else yell "fail"; fi;) & sleep 1; +#==END test code== + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+ -- 2.30.2 From 0201a83dacb71cf75a8311ed69cc103441e2c969 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Tue, 2 Nov 2021 22:41:09 +0000 Subject: [PATCH 14/16] fix(u/bktemp-checkFlt):Update copypasta comments (int -> flt) --- unitproc/bktemp-checkFlt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unitproc/bktemp-checkFlt b/unitproc/bktemp-checkFlt index 530ff0e..affc94f 100644 --- a/unitproc/bktemp-checkFlt +++ b/unitproc/bktemp-checkFlt @@ -8,12 +8,12 @@ die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails checkFlt() { # Desc: Checks if arg is a float - # Usage: checkInt arg + # Usage: checkFlt arg # Input: arg: float # Output: - return code 0 (if arg is float) # - return code 1 (if arg is not float) - # Example: if ! checkInt $arg; then echo "not flt"; fi; - # Version: 0.0.1 + # Example: if ! checkFlt $arg; then echo "not flt"; fi; + # Version: 0.0.2 # Depends: yell(), die(), bash 5.0.3 # Ref/Attrib: JDB https://stackoverflow.com/a/12643073 float regex local returnState @@ -36,7 +36,7 @@ checkFlt() { else return 1; fi; -} # Checks if arg is integer +} # Checks if arg is float #===END Declare local script functions=== #==END Define script parameters== -- 2.30.2 From b2cb5f6a32afb8631641bba98b6fa6ad38e16f59 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Tue, 2 Nov 2021 22:46:06 +0000 Subject: [PATCH 15/16] feat(u/bktemp-checkFlt):Add empty string test --- unitproc/bktemp-checkFlt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unitproc/bktemp-checkFlt b/unitproc/bktemp-checkFlt index affc94f..0a0d6e4 100644 --- a/unitproc/bktemp-checkFlt +++ b/unitproc/bktemp-checkFlt @@ -74,6 +74,9 @@ myVar1="foo"; echo "Test 10:Should fail because floats should only contain numbe myVar1="foo"; myVar2="bar"; myVar3="baz"; echo "Test 11: Should fail because multiple arguments provided."; (if checkFlt "$myVar1" "$myVar2" "$myVar3"; then yell "success"; else yell "fail"; fi;) & sleep 1; + +myVar1=""; echo "Test 12: Should fil because empty string."; +(if checkFlt "$myVar1"; then yell "success"; else yell "fail"; fi;) & sleep 1; #==END test code== # Author: Steven Baltakatei Sandoval -- 2.30.2 From b700f6fff42bf497967a7fc33feb6db95e76ef5c Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sat, 8 Jan 2022 02:43:47 +0000 Subject: [PATCH 16/16] fix(u/bktemp-checkAppFileDir:checkdir()):handle blank arg case --- unitproc/bktemp-checkAppFileDir | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/unitproc/bktemp-checkAppFileDir b/unitproc/bktemp-checkAppFileDir index d5a620b..6059be6 100644 --- a/unitproc/bktemp-checkAppFileDir +++ b/unitproc/bktemp-checkAppFileDir @@ -65,16 +65,18 @@ checkfile() { checkdir() { # Desc: If arg is a dir path, save result in assoc array 'dirRollCall' # Usage: checkdir arg1 arg2 arg3 ... - # Version 0.1.1 + # Version 0.1.2 # Input: global assoc. array 'dirRollCall' # Output: adds/updates key(value) to global assoc array 'dirRollCall'; - # Output: returns 0 if app found, 1 otherwise + # Output: returns 0 if all args are dirs; 1 otherwise # Depends: Bash 5.0.3 local returnState #===Process Args=== for arg in "$@"; do - if [ -d "$arg" ]; then + if [ -z "$arg" ]; then + dirRollCall["(Unspecified Dirname(s))"]="false"; returnState="false"; + elif [ -d "$arg" ]; then dirRollCall["$arg"]="true"; if ! [ "$returnState" = "false" ]; then returnState="true"; fi else -- 2.30.2