initial commit
This commit is contained in:
342
tcl/drivers/piloop.tcl
Normal file
342
tcl/drivers/piloop.tcl
Normal file
@@ -0,0 +1,342 @@
|
||||
# software pi loop
|
||||
# new version (old version has strange parameters)
|
||||
|
||||
namespace eval piloop {
|
||||
}
|
||||
|
||||
if {![namespace exists trun]} {
|
||||
source drivers/trun.tcl
|
||||
}
|
||||
|
||||
proc stdConfig::piloop args {
|
||||
variable name
|
||||
variable path
|
||||
variable node
|
||||
|
||||
scanargs $args var -invar -outvar -outmin 0 -outmax 1 -prop 1 -int 10 \
|
||||
-maxdelta 60 -precision 0.001 -inpfunc 0 -outfunc 0 -title $name \
|
||||
-custinp log -custout log -span 0 -deadband 0 \
|
||||
-outlinear 1e-6 -inplinear 1e-3 -ramptime 0 -smoothtime 0 -ramptol 0.05
|
||||
|
||||
# custinp, custout:
|
||||
# custom input / output function
|
||||
# log: allow choice between linear and logarithmic
|
||||
# none: only linear
|
||||
# else: a custom function. the last arguments are either
|
||||
# <value> forward conversion
|
||||
# inv <value> inverted conversion
|
||||
|
||||
variable hostport none
|
||||
controller dumprot
|
||||
|
||||
if {$span == 0} {
|
||||
if {$custout eq "none"} {
|
||||
set span [expr $outmax - $outmin]
|
||||
}
|
||||
}
|
||||
|
||||
obj loop -drive out
|
||||
prop lastinput 0
|
||||
prop label setpoint
|
||||
prop custinp $custinp
|
||||
prop custout $custout
|
||||
prop span [expr double($span)]
|
||||
|
||||
kids "$title control parameters" {
|
||||
node mode -int out
|
||||
default 0
|
||||
prop enum off,on
|
||||
prop check piloop::checkmode
|
||||
prop write stdSct::completeUpdate
|
||||
|
||||
node reg upd
|
||||
prop geterror "off"
|
||||
|
||||
node output out
|
||||
default $outmin
|
||||
prop check piloop::checkoutput
|
||||
prop write stdSct::completeUpdate
|
||||
|
||||
node ramptime par $ramptime
|
||||
prop help {time for ramping [sec] deltax = 1 or a factor 10}
|
||||
|
||||
node ramptol par $ramptol
|
||||
prop help {log of max. deviation when ramping}
|
||||
|
||||
node smoothtime par $smoothtime
|
||||
prop help {time for smoothing ramp near setpoint}
|
||||
|
||||
node invar -text out
|
||||
default 0
|
||||
prop check piloop::setinvar
|
||||
prop write stdSct::completeUpdate
|
||||
prop visible false
|
||||
|
||||
node outvar -text par $outvar
|
||||
prop visible false
|
||||
|
||||
node prop par $prop
|
||||
prop help {smaller means more sensitive. a change of 'prop' on input\
|
||||
-> a change of 100 % or a factor 10 on output}
|
||||
|
||||
node int par $int
|
||||
prop help "integration time (sec)"
|
||||
|
||||
node outmin par $outmin
|
||||
prop help "output for maximal decrease of input var."
|
||||
|
||||
node outmax par $outmax
|
||||
prop help "output for maximal increase of input var."
|
||||
|
||||
if {$custinp eq "log"} {
|
||||
node inpfunction par -int $inpfunc
|
||||
prop label "input function"
|
||||
prop enum linear,logarithmic
|
||||
|
||||
node inplinear par $inplinear
|
||||
prop help "function gets linear below about this value"
|
||||
}
|
||||
|
||||
if {$custout eq "log"} {
|
||||
node outfunction par -int $outfunc
|
||||
prop label "output function"
|
||||
prop enum linear,exponential
|
||||
|
||||
node outlinear par $outlinear
|
||||
prop help "function gets linear below about this value"
|
||||
}
|
||||
|
||||
node precision par $precision
|
||||
prop label "output precision"
|
||||
|
||||
node deadband par $deadband
|
||||
|
||||
node maxdelta par $maxdelta
|
||||
}
|
||||
stdConfig::tdrive "$name control parameters" self piloop::settarget
|
||||
# hset $path/setcmd piloop::settarget
|
||||
hset $path/invar $invar
|
||||
}
|
||||
|
||||
proc piloop::checkmode {} {
|
||||
if {[sct target] == 0} {
|
||||
set outmin [hvali [sct parent]/outmin]
|
||||
set effoutput [silent $outmin eval "result [hvali [sct parent]/outvar]"]
|
||||
if {$effoutput > $outmin} {
|
||||
hset [sct parent]/output $outmin
|
||||
}
|
||||
updateerror [sct parent]/reg off
|
||||
} elseif {[hvali [sct]] == 0} {
|
||||
hupdate [sct parent]/reg [hvali [sct parent]]
|
||||
set outvar_start [silent "" sct @outvar_start]
|
||||
if {$outvar_start ne ""} {
|
||||
eval $outvar_start
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc piloop::updateinput {value} {
|
||||
|
||||
set maxdelta [hvali [sct]/maxdelta]
|
||||
set now [DoubleTime]
|
||||
if {[sct lastinput] == 0} {
|
||||
set deltat 1
|
||||
} else {
|
||||
set deltat [expr $now - [sct lastinput]]
|
||||
if {$deltat > $maxdelta} {
|
||||
set deltat $maxdelta
|
||||
}
|
||||
}
|
||||
set timestep [silent 1 sct timestep]
|
||||
if {$deltat < $timestep * 0.9 && $timestep > 0.01} {
|
||||
set timestep [expr $timestep * 0.9]
|
||||
} else {
|
||||
set timestep $deltat
|
||||
}
|
||||
sct timestep $timestep
|
||||
sct lastinput $now
|
||||
if {[hvali [sct]/mode] == 0} {
|
||||
return idle
|
||||
}
|
||||
|
||||
set prop [hvali [sct]/prop]
|
||||
set int [hvali [sct]/int]
|
||||
set outmin [hvali [sct]/outmin]
|
||||
set outmax [hvali [sct]/outmax]
|
||||
set precision [hvali [sct]/precision]
|
||||
set ramptime [hvali [sct]/ramptime]
|
||||
set smoothtime [hvali [sct]/smoothtime]
|
||||
set reg [hvali [sct]/reg]
|
||||
set input $value
|
||||
set soll [hvali [sct]/set]
|
||||
set deadband [hvali [sct]/deadband]
|
||||
if {abs($soll - $input) <= $deadband} {
|
||||
return idle
|
||||
}
|
||||
|
||||
set effoutput [eval "result [hvali [sct]/outvar]"]
|
||||
set output [hvali [sct]/output]
|
||||
set span [sct span]
|
||||
if {[sct custout] eq "log"} {
|
||||
set outlinear [hvali [sct]/outlinear]
|
||||
set outfunction [hvali [sct]/outfunction]
|
||||
if {$outfunction == 1} {
|
||||
set output [expr log10($output + $outlinear)]
|
||||
set effoutput [expr log10($effoutput + $outlinear)]
|
||||
if {$span == 0} {
|
||||
set span 1.0
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} elseif {[sct custout] ne "none"} {
|
||||
set output [eval [sct custout] inv $output]
|
||||
set effoutput [eval [sct custout] inv $effoutput]
|
||||
}
|
||||
set lastdif [silent 0 sct lastdif]
|
||||
if {$span == 0} {
|
||||
set span [expr double($outmax - $outmin)]
|
||||
}
|
||||
|
||||
set otol [silent $precision sct otol]
|
||||
if {$output > $effoutput + $otol} {
|
||||
#clientput "$otol [expr $output - $effoutput + $otol]"
|
||||
set output [expr $effoutput + $otol]
|
||||
} elseif {$output < $effoutput - $otol} {
|
||||
#clientput "$otol [expr $output - ($effoutput - $otol)]"
|
||||
set output [expr $effoutput - $otol]
|
||||
}
|
||||
|
||||
if {[sct custinp] eq "log"} {
|
||||
set inplinear [hvali [sct]/inplinear]
|
||||
set inpfunction [hvali [sct]/inpfunction]
|
||||
if {$inpfunction == 1} {
|
||||
set soll [expr log10($soll + $inplinear)]
|
||||
set input [expr log10($input + $inplinear)]
|
||||
set reg [expr log10($reg + $inplinear)]
|
||||
}
|
||||
} elseif {[sct custinp] ne "none"} {
|
||||
set soll [eval [sct custinp] $soll]
|
||||
set input [eval [sct custinp] $input]
|
||||
set reg [eval [sct custinp] $reg]
|
||||
|
||||
}
|
||||
|
||||
if {$ramptime == 0} {
|
||||
set reg $soll
|
||||
} else {
|
||||
set step [expr $deltat / double($ramptime)]
|
||||
set dist [expr abs($reg - $soll)]
|
||||
if {$dist * $ramptime < $smoothtime } {
|
||||
set step [expr $step * sqrt($dist * $ramptime / $smoothtime)]
|
||||
}
|
||||
set tol [hvali [sct]/ramptol]
|
||||
if {$tol * $ramptime < $timestep} {
|
||||
set tol [expr $timestep/double($ramptime)]
|
||||
}
|
||||
if {$soll > $input} {
|
||||
set newreg [expr $reg + $step]
|
||||
if {$newreg > $input + $tol} {
|
||||
set newreg [expr $input + $tol]
|
||||
}
|
||||
if {$newreg > $soll} {
|
||||
set reg $soll
|
||||
} elseif {$newreg > $reg} {
|
||||
set reg $newreg
|
||||
}
|
||||
} else {
|
||||
set newreg [expr $reg - $step]
|
||||
if {$newreg < $input - $tol} {
|
||||
set newreg [expr $input - $tol]
|
||||
}
|
||||
if {$newreg < $soll} {
|
||||
set reg $soll
|
||||
} elseif {$newreg < $reg} {
|
||||
set reg $newreg
|
||||
}
|
||||
}
|
||||
}
|
||||
set dif [expr double($reg - $input)]
|
||||
set l [llength $lastdif]
|
||||
set difdif [expr ($dif - [lindex $lastdif 0]) / $l]
|
||||
lappend lastdif $dif
|
||||
sct lastdif [lrange $lastdif end-5 end]
|
||||
|
||||
set do [expr $span/double($prop) * ($difdif + $deltat * $dif / double($int))]
|
||||
set output [expr $output + $do]
|
||||
#clientput [format "out %12.5g dd %12.5g dtd %12.5g s/p %12.5g" $output $difdif [expr $deltat * $dif / double($int)] [expr $span/double($prop)]]
|
||||
|
||||
sct otol [expr 2 * abs($do) + $precision]
|
||||
|
||||
if {[sct custinp] eq "log"} {
|
||||
if {$inpfunction == 1} {
|
||||
set reg [expr pow(10, $reg) - $inplinear]
|
||||
}
|
||||
} elseif {[sct custinp] ne "none"} {
|
||||
set reg [eval [sct custinp] inv $reg]
|
||||
}
|
||||
updateval [sct]/reg $reg
|
||||
if {[sct custout] eq "log"} {
|
||||
if {$outfunction == 1} {
|
||||
set output [expr pow(10, $output) - $outlinear]
|
||||
#clientput $output
|
||||
}
|
||||
} elseif {[sct custout] ne "none"} {
|
||||
set output [eval [sct custout] $output]
|
||||
}
|
||||
if {$outmax > $outmin} {
|
||||
if {$output > $outmax} {
|
||||
set output $outmax
|
||||
} elseif {$output < $outmin} {
|
||||
set output $outmin
|
||||
}
|
||||
} else {
|
||||
if {$output > $outmin} {
|
||||
set output $outmin
|
||||
} elseif {$output < $outmax} {
|
||||
set output $outmax
|
||||
}
|
||||
}
|
||||
if {[catch {hset [sct]/output $output} msg]} {
|
||||
hsetprop [sct]/reg geterror $msg
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
# updatescript on the remote input node
|
||||
proc piloop::updateinput1 {value} {
|
||||
set loopobj [sct loopobj]
|
||||
if {[silent 0 sct geterror] eq "0"} {
|
||||
updateval $loopobj $value
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
proc piloop::setinvar {} {
|
||||
catch {
|
||||
[sct controllerName] killupdatescript [hval [sct]] piloop::updateinput1
|
||||
}
|
||||
[sct controllerName] updatescript [sct target] piloop::updateinput1
|
||||
[sct controllerName] updatescript [sct parent] piloop::updateinput
|
||||
hsetprop [sct target] loopobj [sct parent]
|
||||
return
|
||||
}
|
||||
|
||||
proc piloop::settarget {target} {
|
||||
# clientput "settarget $target == [silent 0 sct @offvalue]"
|
||||
if {$target == [silent 0 sct @offvalue]} {
|
||||
hset [sct]/mode 0
|
||||
} else {
|
||||
hset [sct]/mode 1
|
||||
}
|
||||
sct print "[sct]/set = $target"
|
||||
return idle
|
||||
}
|
||||
|
||||
proc piloop::updtarget {} {
|
||||
sct print "[sct]/set = [sct target]"
|
||||
return idle
|
||||
}
|
||||
|
||||
proc piloop::checkoutput {} {
|
||||
eval "[hvali [sct parent]/outvar] [sct target]"
|
||||
}
|
||||
Reference in New Issue
Block a user