#!/usr/bin/perl use Time::HiRes qw(usleep); use POSIX; $0 = "fan_t420s"; my $fan_min = 1; my $fan_max = 7; my $temp_max = 65; my $setpoint = 48; my $interval = 1; my $integral = 0; my $kc = 2; #my $ti = 8; my $td = 1; my $kp = $kc; #my $ki = 1 / $ti; my $kd = 1 / $td; my $i = 0; my $output_max = $kc * ($temp_max - $setpoint) + ($kd * 2) / $interval; my $last_error = $setpoint - &getTemp; while (1) { my $temp = &getTemp; my $e = $setpoint - $temp; #$i = $i + $e * $interval; my $d = ($e - $last_error)/$interval; #my $out = $kp * $e + $ki * $i + $kd * $d; my $out = $kp * $e + $kd * $d; $last_error = $e; $level = &getLevel($out); if ($e < 0) { &setFanSpeed($level); } else { &setFanSpeed($fan_min); } #print "e:".$e."-->"; #print "i:".$i."\(".($ki*$i)."\)-->"; #print "d:".$d."\(".($kd*$d)."\)-->"; #print "o:".$out."-->"; #print $level."\n"; sleep $interval; } sub getLevel { my $result = $fan_min; my $output = shift; if ($output < 0) { $result = floor(abs($fan_max * $output / $output_max)); if ($fan_max < $result) { $result = "full-speed"; } elsif ($result < $fan_min) { $result = $fan_min; } } return $result; } sub getTemp { my $sensor = `sensors | grep °C`; my ($temp) = ($sensor =~ m/temp\d:\s+\+(\d+)\.\d°C.*/); return $temp; } sub setFanSpeed { my $level = shift; `echo level $level > /proc/acpi/ibm/fan`; }