1
0
Fork 0

공간벡터제어 적용

This commit is contained in:
Sangbum Kim 2017-09-07 01:21:33 +09:00
parent ec0c7112b1
commit 08e83afe52
3 changed files with 211 additions and 17 deletions

50
main.go
View File

@ -15,6 +15,7 @@ import (
"sync" "sync"
"syscall" "syscall"
"time" "time"
"amuz.es/src/infra/cpu_ctrl/pid"
"github.com/coreos/go-systemd/daemon" "github.com/coreos/go-systemd/daemon"
"github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/cpu"
@ -92,10 +93,10 @@ func ReadTempeture(path string, senseChan chan<- float64, errorChan chan<- error
} }
} }
func CpuTempetureMonitoring(info *Processor, notifier chan<- TempetureChange, errorChan chan<- error, ctx context.Context, waiter *sync.WaitGroup) { func CpuTempetureMonitoring(info *Processor,sampleDuration time.Duration, notifier chan<- TempetureChange, errorChan chan<- error, ctx context.Context, waiter *sync.WaitGroup) {
defer waiter.Done() defer waiter.Done()
tempeturePathGlob := path.Join(info.TempeturePath, "temp?_input") tempeturePathGlob := path.Join(info.TempeturePath, "temp?_input")
ticker := time.Tick(3 * time.Second) ticker := time.Tick(sampleDuration)
for { for {
select { select {
case <-ticker: case <-ticker:
@ -129,31 +130,47 @@ func CpuTempetureMonitoring(info *Processor, notifier chan<- TempetureChange, er
} }
func CpuTempetureScraper(processorCount int, notifier <-chan TempetureChange, errorChan chan<- error, ctx context.Context, waiter *sync.WaitGroup) { func CpuTempetureScraper(processorCount int, notifier <-chan TempetureChange, errorChan chan<- error, ctx context.Context, waiter *sync.WaitGroup) {
defer waiter.Done() defer waiter.Done()
pastFan := make([]int, processorCount) var (
P,I,D=1.5, 0.4, 2.0
SetPoint=40.0
SampleTime=time.Second
WindupGuard=96.0
maxNoob,minNoob=0x64,0x4
)
noobs := make([]int,processorCount)
controllers := make([]pid.Controller, 0,processorCount)
for i:=0 ;i<processorCount;i++{
controller:=pid.New(PID)
controller.SetSetPoint(SetPoint)
controller.SetSampleTime(SampleTime)
controller.SetWindupGuard(WindupGuard)
controllers := append(controllers,controller)
}
for { for {
select { select {
case change := <-notifier: case change := <-notifier:
delta := int(change.Tempeture) - 33 controller:=controllers[change.Id]
fan := 0x4 + (delta - delta%0x4) resp:=controller.Update(change)
if fan < 0x4 {
fan = 0x4 adj_noob := -resp + minNoob
} else if fan > 0x50 { if adj_noob > maxNoob{
fan = 0x0 adj_noob=maxNoob
} }
if pastFan[change.Id] != fan { if noobs[change.Id]== adj_noob{
pastFan[change.Id] = fan
} else {
continue continue
} }
noobs[change.Id]=adj_noob
fmt.Printf("cpu %d fan 0x%x\n", change.Id, adj_noob)
fmt.Printf("cpu %d fan 0x%x\n", change.Id, fan)
args := make([]string, 0) args := make([]string, 0)
args = append(args, args = append(args,
"raw", "raw",
"0x3a", "0x01", "0x3a", "0x01",
) )
for _, item := range pastFan { for _, item := range noobs {
args = append(args, fmt.Sprintf("0x%x", item)) args = append(args, fmt.Sprintf("0x%x", item))
} }
args = append(args, args = append(args,
@ -172,12 +189,13 @@ func CpuTempetureScraper(processorCount int, notifier <-chan TempetureChange, er
func main() { func main() {
var ( var (
processorCount = 0 //getProcessorCount() processorCount = getProcessorCount()
ctx, canceled = context.WithCancel(context.Background()) ctx, canceled = context.WithCancel(context.Background())
waiter = &sync.WaitGroup{} waiter = &sync.WaitGroup{}
exitSignal = make(chan os.Signal, 1) exitSignal = make(chan os.Signal, 1)
errorChan = make(chan error, 1) errorChan = make(chan error, 1)
tempetureChange = make(chan TempetureChange) tempetureChange = make(chan TempetureChange)
sampleDuration = time.Second
) )
if processorCount == 0 { if processorCount == 0 {
@ -188,7 +206,7 @@ func main() {
errorChan <- err errorChan <- err
} else { } else {
waiter.Add(1) waiter.Add(1)
go CpuTempetureMonitoring(info, tempetureChange, errorChan, ctx, waiter) go CpuTempetureMonitoring(info,sampleDuration, tempetureChange, errorChan, ctx, waiter)
} }
} }
waiter.Add(1) waiter.Add(1)

126
pid/pid.go Normal file
View File

@ -0,0 +1,126 @@
package pid
import (
"time"
)
type controller struct {
Kp float64
Ki float64
Kd float64
lastTime time.Time
SetPoint float64
SampleTime time.Duration
WindupGuard float64
Output float64
pTerm float64
iTerm float64
dTerm float64
lastError float64
}
/*
PID Controller
*/
type Controller interface {
GetKp() float64
GetKi() float64
GetKd() float64
GetSetPoint() float64
GetSampleTime() time.Duration
GetWindupGuard() float64
GetOutput() float64
SetKp(float64)
SetKi(float64)
SetKd(float64)
SetSetPoint(float64)
SetSampleTime(time.Duration)
SetWindupGuard(float64)
SetOutput(float64)
Clear()
Update(float64) float64
}
/*
create PID Controller
*/
func New(proportionalGain float64, integralGain float64, derivativeGain float64) Controller {
return &controller{
Kp: proportionalGain,
Ki: integralGain,
Kd: derivativeGain,
WindupGuard: 20.0,
lastTime: time.Now(),
}
}
/*
Clears PID computations and coefficients
*/
func (c *controller) Clear() {
c.SetPoint = 0.0
c.pTerm = 0.0
c.iTerm = 0.0
c.dTerm = 0.0
c.lastError = 0.0
c.WindupGuard = 20.0
c.Output = 0.0
}
/*
Calculates PID value for given reference feedback
.. math::
u(t) = K_p e(t) + K_i \int_{0}^{t} e(t)dt + K_d {de}/{dt}
.. figure:: images/pid_1.png
:align: center
Test PID with Kp=1.2, Ki=1, Kd=0.001 (test_pid.py)
*/
func (c *controller) Update(feedbackValue float64) float64 {
var (
errorValue = c.SetPoint - feedbackValue
currentTime = time.Now()
deltaTime, deltaError = currentTime.Sub(c.lastTime), errorValue - c.lastError
)
if deltaTime >= c.SampleTime {
c.pTerm = c.Kp * errorValue
c.iTerm += errorValue * deltaTime.Seconds()
if c.iTerm < -c.WindupGuard {
c.iTerm = -c.WindupGuard
} else if c.iTerm > c.WindupGuard {
c.iTerm = c.WindupGuard
}
c.dTerm = 0.0
if deltaTime.Seconds() > 0.0 {
c.dTerm = deltaError / deltaTime.Seconds()
}
c.lastTime = currentTime
c.lastError = errorValue
c.Output = c.pTerm + (c.Ki * c.iTerm) + (c.Kd * c.dTerm)
}
return c.Output
}
func (c *controller) GetKp() float64 { return c.Kp }
func (c *controller) GetKi() float64 { return c.Ki }
func (c *controller) GetKd() float64 { return c.Kd }
func (c *controller) GetSetPoint() float64 { return c.SetPoint }
func (c *controller) GetSampleTime() time.Duration { return c.SampleTime }
func (c *controller) GetWindupGuard() float64 { return c.WindupGuard }
func (c *controller) GetOutput() float64 { return c.Output }
func (c *controller) SetKp(v float64) { c.Kp = v }
func (c *controller) SetKi(v float64) { c.Ki = v }
func (c *controller) SetKd(v float64) { c.Kd = v }
func (c *controller) SetSetPoint(v float64) { c.SetPoint = v }
func (c *controller) SetSampleTime(v time.Duration) { c.SampleTime = v }
func (c *controller) SetWindupGuard(v float64) { c.WindupGuard = v }
func (c *controller) SetOutput(v float64) { c.Output = v }

50
test/test.go Normal file
View File

@ -0,0 +1,50 @@
package main
import (
"fmt"
"time"
"amuz.es/src/infra/cpu_ctrl/pid"
)
// 실제 CPU온도환경 모델링
func test_pid(P float64, I float64, D float64, L int) {
pid := pid.New(P, I, D)
pid.SetSetPoint(40.0)
pid.SetSampleTime(time.Second)
pid.SetWindupGuard(96.0)
END := L
feedback := 60.0
minTemp := 28.0
for i := 0; i < END; i++ {
output := pid.Update((feedback * 1000.0) / 1000.0)
adj := output
if output > 0 {
adj = 0.0
} else if output < -96.0 {
adj = -96.0
}
adj_noob := int(-adj + 4)
adj /= 10.0
adj += 1.1
fmt.Printf("feedback: %0.17f output: %0.17f adj: %0.17f noob: 0x%x\n", feedback, output, adj, adj_noob)
feedback += adj
if feedback < minTemp {
feedback = minTemp
}
time.Sleep(time.Second)
}
}
func main() {
test_pid(1.5, 0.4, 2.0, 500)
}