lab6: add javadoc comments and polish the code

This commit is contained in:
dymik739 2023-06-20 19:39:06 +03:00
parent bd6a285f8f
commit d2535d233f
6 changed files with 774 additions and 59 deletions

View File

@ -1,33 +1,145 @@
public class Appliance { /*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Class representing a general appliance and containing basic methods
* that are used in multiple child classes. Supposed to be extended by
* other classes and not to be used as a standalone class.
*
* @author Dymik739
* @since 0.3
*/
public class Appliance implements Comparable<Appliance> {
/** Indicates if this device is drawing power from the power network. */
private boolean powerConnected; private boolean powerConnected;
/** Defines the type of this device */
private String type;
/**
* Constructor for this class. Should be called only from within
* constructors of other classes which inherit this one.
*
* @param connected defines if the device is connected to the network
* at the start
*/
public Appliance(boolean connected) { public Appliance(boolean connected) {
this.powerConnected = connected; this.powerConnected = connected;
} }
/**
* Getter for checking the power connection.
*
* @return true if connected and false otherwise
*/
public boolean getPowerState() { public boolean getPowerState() {
return powerConnected; return powerConnected;
} }
/**
* Getter for the device type variable.
*
* @return device type string
*/
public String getType() {
return type;
}
/**
* Setter for setting the device type string.
* Should be used only from the constructors of the classes
* which inherit this one!
*
* @param type type of the device
*/
public void setType(String type) {
this.type = type;
}
/**
* Method for connecting power to the device.
*/
public void plug() { public void plug() {
powerConnected = true; powerConnected = true;
} }
/**
* Method for disconnecting power from the device.
*/
public void unplug() { public void unplug() {
powerConnected = false; powerConnected = false;
} }
/**
* Method for getting the smaller value out of two.
*
* @param v1 first value
* @param v2 second value
*
* @return smaller value of the two given
*/
public float min(float v1, float v2) { public float min(float v1, float v2) {
return v1 <= v2 ? v1 : v2; return v1 <= v2 ? v1 : v2;
} }
/**
* Method for getting the bigger value out of two.
*
* @param v1 first value
* @param v2 second value
*
* @return bigger value of the two given
*/
public float max(float v1, float v2) { public float max(float v1, float v2) {
return v1 >= v2 ? v1 : v2; return v1 >= v2 ? v1 : v2;
} }
/**
* Dummy method for getting the power consumption of the device.
* Should be overridden by the child class!
*
* @return current power consumption.
*/
public float getPowerConsumption() { public float getPowerConsumption() {
return 0f; return 0f;
} }
/**
* Dummy method for performing the simulation.
* Should be overridden by the child class!
*
* @param seconds delta time for the correct simulation step
* @param ventRPM air flow created by the vent
*/
public void step(float seconds, float ventRPM) {} public void step(float seconds, float ventRPM) {}
/**
* Method for comparing this appliance's power consumption to another
* one. Part os the Comparable implementation.
*
* @param o another appliance to compare to
*
* @return difference between power consumption values
*/
@Override
public int compareTo(Appliance o) {
return (int) (getPowerConsumption() - o.getPowerConsumption());
}
} }

View File

@ -1,13 +1,58 @@
/*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Class which represents the behaviour of a dishwasher.
*
* @author Dymik739
* @since 0.3
*/
public class Dishwasher extends Appliance { public class Dishwasher extends Appliance {
private float basePower = 160.0f; /** Defines power usage at different stages of washing dishes. */
private float[] powerStates = {400f, 60f, 130f, 350f}; private float[] powerStates = {400f, 60f, 130f, 350f};
/** Shows how much time should pass before switching to the next stage */
private float nextPowerStateIn = 20f; private float nextPowerStateIn = 20f;
/** Shows current stage the dishwasher is performing, -1 for none */
private int currentState = -1; private int currentState = -1;
/**
* Constructor for this class.
*
* @param plugged sets the starting power state of this device
*/
public Dishwasher(boolean plugged) { public Dishwasher(boolean plugged) {
super(plugged); super(plugged);
super.setType("Dishwasher");
} }
/**
* Method for simulating the devices' behaviour.
* Once started, it goes through every stage until it finishes washing
* the dishes (every stage has it's own power usage level. After that,
* it resets the device and turns it off automatically.
*
* @param seconds delta time to simulate for
* @param ventRPM air flow created by the vent
*/
public void step(float seconds, float ventRPM) { public void step(float seconds, float ventRPM) {
if (!super.getPowerState()) { if (!super.getPowerState()) {
return; return;
@ -25,6 +70,10 @@ public class Dishwasher extends Appliance {
} }
} }
/**
* Overridden method for turning on this device.
* It automatically sets it to the correct stage and delay.
*/
@Override @Override
public void plug() { public void plug() {
super.plug(); super.plug();
@ -33,6 +82,10 @@ public class Dishwasher extends Appliance {
nextPowerStateIn = 20f; nextPowerStateIn = 20f;
} }
/**
* Overridden method for turning this device off.
* It automatically resets the current washing stage to -1.
*/
@Override @Override
public void unplug() { public void unplug() {
super.unplug(); super.unplug();
@ -40,6 +93,12 @@ public class Dishwasher extends Appliance {
currentState = -1; currentState = -1;
} }
/**
* Method for calculating the power consumption of this device.
* Power usage depends on the current washing stage.
*
* @return float showing current power consumption
*/
public float getPowerConsumption() { public float getPowerConsumption() {
if (super.getPowerState()) { if (super.getPowerState()) {
return powerStates[currentState]; return powerStates[currentState];
@ -47,4 +106,18 @@ public class Dishwasher extends Appliance {
return 0f; return 0f;
} }
} }
/**
* Method for printing this devices' object in a nice way.
*
* @return String containing text description of this devices' state
*/
@Override
public String toString() {
return String.format("Dishwasher(%s, %4.1fW, %2.1fs)",
super.getPowerState() ? "on" : "off", getPowerConsumption(),
super.getPowerState()
? (3 - currentState) * 20 + nextPowerStateIn
: 0f);
}
} }

View File

@ -1,8 +1,82 @@
import java.util.concurrent.TimeUnit; /*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
import java.util.Arrays;
/**
* Main class that controls all the devices and regulates vent power.
*
* @author Dymik739
* @since 0.3
*/
public class Main { public class Main {
/**
* Defines the ServerRack power consumption at which the vent
* power is enabled.
*/
private static final float VENT_START_POWER = 240f;
/**
* Defines the ServerRack power consumption at which the vent
* power is disabled.
*/
private static final float VENT_STOP_POWER = 185f;
/** Defines magic number for real-time TTY output mode */
private static final int TTY_LIVE_MONITORING_MODE = 0;
/**
* Defines magic number for raw graph output mode for current
* power consumption and vent RPM
*/
private static final int POWER_RPM_GRAPH_MODE = 1;
/** Defines magic number for raw graph output mode for total consumption */
private static final int TOTAL_CONSUMPTION_GRAPH_MODE = 2;
/**
* Defines magic number for raw graph output mode for vent rpm and
* power consumption relation
*/
private static final int VENT_POWER_RPM_GRAPH_MODE = 3;
/** Defines the amount of simulation samples to get per every second */
private static final int TICKS_PER_SECOND = 720;
/** Defines the time simulation will run for (in seconds) */
private static final int SIMULATION_TIME = 240;
/**
* Main method for containing the devices, performing all
* checks and plugging the devices in and out.
*
* @param args accepts CLI arguments.
*/
public static void main(String[] args) { public static void main(String[] args) {
Vent vent = new Vent(true); float ventConsumed = 0f;
float totalPowerConsumed = 0f;
int outputMode = parseMode(args);
int liveStatsOutputDelay = parseOutputDelay(args);
Vent vent = new Vent(false); // defining vent as a special appliance
Appliance[] devices = { Appliance[] devices = {
new ServerRack(false), new ServerRack(false),
@ -11,53 +85,174 @@ public class Main {
new Dishwasher(false) new Dishwasher(false)
}; };
devices[0].plug(); devices[2].plug(); // turning on RPI right away
devices[2].plug(); // (RPI stands for Raspberry Pi)
int i = 0; // letting the simulation run
float ventConsumed = 0f; for (int i = 1; i <= SIMULATION_TIME*TICKS_PER_SECOND; i++) {
float totalPowerConsumed = 0f; step(vent, devices, (float) 1/TICKS_PER_SECOND); // stepping time
//for (int i = 0; i < 180*10; i++) {
while (true) { // performing accounting
step(vent, devices, 0.1f); ventConsumed += vent.getPowerConsumption() / TICKS_PER_SECOND;
ventConsumed += vent.getPowerConsumption() * 0.1; totalPowerConsumed += getTotalPowerConsumption(vent, devices)
totalPowerConsumed += getTotalPowerConsumption(vent, devices) * 0.1 / 3600; / TICKS_PER_SECOND / 3600;
//System.out.print(String.format("Time: %02.1f; ", (float) i/10)
System.out.print("Time: " + floatFormat((float)i/10, 2, 1) + "; " // outputting the data in the desired format
+ getStats(vent, devices) + "; vent avg = " if (outputMode == TTY_LIVE_MONITORING_MODE) {
+ floatFormat(ventConsumed*10/i, 3, 1) System.out.print("Time: " + floatFormat((float)i/TICKS_PER_SECOND, 2, 2)
+ "W; total = " + "; " + getStats(vent, devices) + "; vent avg = "
+ floatFormat(totalPowerConsumed, 3, 3) + "W\r"); + floatFormat(ventConsumed/TICKS_PER_SECOND/i, 4, 1)
if (devices[0].getPowerConsumption() > 205) { + "W; total = "
vent.plug(); + floatFormat(totalPowerConsumed, 4, 3) + "W\r");
} else if (outputMode == POWER_RPM_GRAPH_MODE) {
System.out.println(getTotalPowerConsumption(vent, devices)
+ " " + vent.getRPM()/10);
} else if (outputMode == TOTAL_CONSUMPTION_GRAPH_MODE) {
System.out.println(totalPowerConsumed);
} else if (outputMode == VENT_POWER_RPM_GRAPH_MODE) {
System.out.println(vent.getRPM()/10 + " "
+ vent.getPowerConsumption());
} }
if (devices[0].getPowerConsumption() < 190) { adjustVentPower(devices, vent);
vent.unplug();
managePower(i, devices);
if ((outputMode == TTY_LIVE_MONITORING_MODE)
&& (liveStatsOutputDelay != 0)) {
try {
Thread.sleep(liveStatsOutputDelay);
} catch (Exception e) {
System.exit(0);
}
}
}
if (outputMode == TTY_LIVE_MONITORING_MODE) {
Appliance[] totalDevices = new Appliance[devices.length + 1];
for (int i = 0; i < devices.length; i++) {
totalDevices[i] = devices[i];
} }
if (i == 150) { totalDevices[devices.length] = vent;
devices[1].plug();
} else if (i == 300) {
devices[0].unplug();
} else if (i == 400) {
devices[3].plug();
} else if (i == 700) {
devices[0].plug();
}
try { System.out.println("\nCurrently devices draw "
//TimeUnit.SECONDS.sleep(1); + floatFormat(getTotalPowerConsumption(totalDevices), 4, 2)
Thread.sleep(2); + "W from the power lines.");
} catch (Exception e) {
System.exit(0);
}
i++; Arrays.sort(totalDevices);
printAppliances(totalDevices);
} }
} }
/**
* Method which decides on how to manage the vent power supply.
* It looks at power consumption of every ServerRack device
* and:
* - turns the vent on if ANY of them meet the VENT_START_POWER threshold
* - turns the vent off if ALL of them meet the VENT_STOP_POWER threshold
*
* @param devices list of devices to look at.
* @param vent vent to manage power for.
*/
public static void adjustVentPower(Appliance[] devices, Vent vent) {
for (Appliance i : devices) {
if ("ServerRack".equals(i.getType())
&& (i.getPowerConsumption() > VENT_START_POWER)) {
vent.plug();
return;
}
}
for (Appliance i : devices) {
if ("ServerRack".equals(i.getType())
&& !(i.getPowerConsumption() < VENT_STOP_POWER)) {
return;
}
}
vent.unplug();
}
/**
* Method that plugs in and out the devices in a predefined manner.
*
* @param i current simulation time.
* @param devices device list to control.
*/
public static void managePower(int i, Appliance[] devices) {
if (i == 25 * TICKS_PER_SECOND) {
devices[1].plug();
} else if (i == 35 * TICKS_PER_SECOND) {
devices[0].plug();
} else if (i == 50 * TICKS_PER_SECOND) {
devices[0].unplug();
} else if (i == 60 * TICKS_PER_SECOND) {
devices[3].plug();
} else if (i == 130 * TICKS_PER_SECOND) {
devices[0].plug();
}
}
/**
* Method for printing out a gives array of appliances.
*
* @param devices appliance array to print out.
*/
public static void printAppliances(Appliance[] devices) {
for (Appliance i : devices) {
System.out.println(i);
}
}
/**
* Method for extracting output mode setting set from CLI.
*
* @param args CLI args array to use.
*
* @return int representing requested mode.
*/
public static int parseMode(String[] args) {
for (String i : args) {
if ("--power-rpm-graph".equals(i)) {
return POWER_RPM_GRAPH_MODE;
} else if ("--total-consumption-graph".equals(i)) {
return TOTAL_CONSUMPTION_GRAPH_MODE;
} else if ("--vent-monitoring-graph".equals(i)) {
return VENT_POWER_RPM_GRAPH_MODE;
}
}
return TTY_LIVE_MONITORING_MODE;
}
/**
* Method for extracting output delay setting set from CLI.
*
* @param args CLI args array to use.
*
* @return delay in miliseconds.
*/
public static int parseOutputDelay(String[] args) {
for (int i = 0; i < args.length; i++) {
if ("--output-delay".equals(args[i])) {
return Integer.parseInt(args[i+1]);
}
}
return 90;
}
/**
* Method for performing the simulation. Runs the respective .step()
* methods on all of the given appliances.
*
* @param vent vent object to process
* @param devices devices array to process
* @param seconds delta time to move forward.
*/
public static void step(Vent vent, Appliance[] devices, float seconds) { public static void step(Vent vent, Appliance[] devices, float seconds) {
vent.step(seconds); vent.step(seconds);
for (Appliance i : devices) { for (Appliance i : devices) {
@ -65,6 +260,15 @@ public class Main {
} }
} }
/**
* Method for collecting the overall usage statistics to make it
* easy to output status line during TTY mode execution.
*
* @param vent vent object to track
* @param devices devices array to track
*
* @return String containing current stats for all the devices
*/
public static String getStats(Vent vent, Appliance[] devices) { public static String getStats(Vent vent, Appliance[] devices) {
float[] powerConsumption = new float[devices.length]; float[] powerConsumption = new float[devices.length];
float totalPowerConsumption = 0; float totalPowerConsumption = 0;
@ -77,25 +281,29 @@ public class Main {
String result = "PPD: "; String result = "PPD: ";
for (float i : powerConsumption) { for (float i : powerConsumption) {
//result += String.format("%03.1fW ", i);
result += String.format(floatFormat(i, 3, 1) + "W "); result += String.format(floatFormat(i, 3, 1) + "W ");
} }
float powerLinesDraw = totalPowerConsumption float powerLinesDraw = totalPowerConsumption
+ vent.getPowerConsumption(); + vent.getPowerConsumption();
//result += String.format("; Vent: %03.1fW, %05.0f RPM; Total power: %04.1fW",
result += "; Vent: " + floatFormat(vent.getPowerConsumption(), 3, 1) result += "; Vent: " + floatFormat(vent.getPowerConsumption(), 3, 1)
+ "W, " + floatFormat(vent.getRPM(), 5, 0) + "W, " + floatFormat(vent.getRPM(), 5, 0)
+ " RPM; Total power: " + floatFormat(powerLinesDraw, 4, 1) + " RPM; Total power: " + floatFormat(powerLinesDraw, 4, 1)
+ "W"; + "W";
//vent.getPowerConsumption(), vent.getRPM(),
//totalPowerConsumption + vent.getPowerConsumption());
return result; return result;
} }
/**
* Overloaded method for calculating the total power consumption
* (devices + the vent).
*
* @param vent vent to account
* @param devices array of devices to account
*
* @return sum of all the .getPowerConsumption() returned from devices
*/
public static float getTotalPowerConsumption(Vent vent, public static float getTotalPowerConsumption(Vent vent,
Appliance[] devices) { Appliance[] devices) {
float result = vent.getPowerConsumption(); float result = vent.getPowerConsumption();
@ -107,6 +315,34 @@ public class Main {
return result; return result;
} }
/**
* Overloaded method for calculating the total power consumption
* (devices only).
*
* @param devices array of devices to account
*
* @return sum of all the .getPowerConsumption() returned from devices
*/
public static float getTotalPowerConsumption(Appliance[] devices) {
float result = 0;
for (Appliance a : devices) {
result += a.getPowerConsumption();
}
return result;
}
/**
* Custom method which adds the support for arbitrary formatting of float
* numbers.
*
* @param num value to format
* @param leading amount of digits before period to print
* @param trailing amount of digits after perio to print
*
* @return String with formatted result
*/
public static String floatFormat(float num, int leading, int trailing) { public static String floatFormat(float num, int leading, int trailing) {
String newNum = String.format("%0" + leading + "." + trailing + "f", num); String newNum = String.format("%0" + leading + "." + trailing + "f", num);

View File

@ -1,11 +1,59 @@
/*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Class which represents the RPI (Raspberry Pi) microcomputer.
*
* @author Dymik739
* @since 0.3
*/
public class RPI extends Appliance { public class RPI extends Appliance {
/** Contains current power draw from the power supply. */
private float power = 15.0f; private float power = 15.0f;
/**
* Defines the delay after the startup when the power usage starts to drop
* to it's lowest value.
*/
private float postBootDecreaseIn = 10.0f; private float postBootDecreaseIn = 10.0f;
/**
* Constructor for this class.
*
* @param plugged sets the power state on the beginning
*/
public RPI(boolean plugged) { public RPI(boolean plugged) {
super(plugged); super(plugged);
super.setType("RPI");
} }
/**
* Method which is used to simulate the device's behaviour.
* The device draws it's maximum power for postBootDecreaseIn
* seconds and gradually drops to it's lowest level, after that
* it always stays on the lowest power usage level until a
* reboot happens.
*
* @param seconds delta time to simulate for
* @param ventRPM air flow generated by the vent
*/
public void step(float seconds, float ventRPM) { public void step(float seconds, float ventRPM) {
postBootDecreaseIn -= seconds; postBootDecreaseIn -= seconds;
@ -18,6 +66,24 @@ public class RPI extends Appliance {
} }
} }
/**
* Custom method for unplugging the device.
* Adds the automatic resetting to the default values right after
* turning the device off.
*/
@Override
public void unplug() {
super.unplug();
power = 15f;
postBootDecreaseIn = 10f;
}
/**
* Method for getting the power draw of this device.
*
* @return current power consumption
*/
public float getPowerConsumption() { public float getPowerConsumption() {
if (super.getPowerState()) { if (super.getPowerState()) {
return power; return power;
@ -25,4 +91,15 @@ public class RPI extends Appliance {
return 0f; return 0f;
} }
} }
/**
* Method for printing this devices' object in a nice way.
*
* @return String containing text description of this devices' state
*/
@Override
public String toString() {
return String.format("RPI(%s, %4.1fW)",
super.getPowerState() ? "on" : "off", getPowerConsumption());
}
} }

View File

@ -1,28 +1,124 @@
/*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Class which represents a server rack.
*
* @author Dymik739
* @since 0.3
*/
public class ServerRack extends Appliance { public class ServerRack extends Appliance {
private String type = "ServerRack"; /** Defines power used by the rack at lowest temperature. */
private float basePower = 160.0f; private float basePower = 160.0f;
/** Defines power limit for this rack */
private float maxPower = 350.0f; private float maxPower = 350.0f;
/** Contains the inner temperature of this rack */
private float temperature = 20f; private float temperature = 20f;
/** Defines current usage of this device */
private float currentLoad = 0.2f;
/** Predicts the future change of the load */
private float loadVector = +1f;
/**
* Constructor for this class.
*
* @param plugged defines if the device is plugged in at the start
*/
public ServerRack(boolean plugged) { public ServerRack(boolean plugged) {
super(plugged); super(plugged);
super.setType("ServerRack");
} }
/**
* Method for simulating this device behaviour.
* This rack processes video segments for the streaming platform and
* serves them to the public in different qualities. Every device requires
* the fragments to be encoded in it's respective format in order to play
* the stream. As such, the load rises when new fragment arrives and falls
* as it converts it into all the formats required.
*
* Temperature depends on many factors. Firstly, the device heats up while
* performing tasks and the rate is affected by:
* - current temperature (hotter = more power drawn);
* - load on the CPU (more load = more heat);
*
* Of course, the temperature can be reduced using the vent installed in
* the house. The rate of reduction is calculated using:
* - current temperature (the bigger the difference compared to the outside
* temperature, the larger impact the vent has on it);
* - air flow, created by the vent (the faster the air moves, the more
* heat it takes away from the system);
*
* This device can also cool itself down while standing still as the heat
* slowly transfers to the air even when the vent doesn't force it.
* The rate is calculated by only the temperature difference between inner
* and outer temperatures.
*
* @param seconds delta time to simulate for
* @param ventRPM air flow created by the vent
*/
public void step(float seconds, float ventRPM) { public void step(float seconds, float ventRPM) {
if (super.getPowerState()) { currentLoad += loadVector/10 * seconds;
temperature += min(basePower + (temperature - 20f) * 1.8f, maxPower)
* seconds * 0.024f; if (currentLoad >= 1) {
loadVector = -1f;
} else if (currentLoad <= 0.2) {
loadVector = +1f;
} }
temperature -= (temperature - 20f) * ventRPM*0.0003f * seconds; if (super.getPowerState()) {
temperature -= 0.006f * (temperature - 20f) * seconds; temperature += min(basePower + (temperature - 20f) * 1.8f
* max(min(currentLoad, 1), 0), maxPower) * seconds
* 0.024f;
}
temperature -= (temperature - 20f) * ventRPM * 0.00013f * seconds;
temperature -= 0.002f * (temperature - 20f) * seconds;
} }
/**
* Method which calculates power consumption if this device.
*
* @return power consumption of this device
*/
public float getPowerConsumption() { public float getPowerConsumption() {
if (super.getPowerState()) { if (super.getPowerState()) {
return min(basePower + (temperature - 20f) * 1.8f, maxPower); return min(basePower + (temperature - 20f) * 1.8f * max(min(currentLoad, 1), 0), maxPower);
} else { } else {
return 0f; return 0f;
} }
} }
/**
* Overridden toString() method for printing the state of this device.
*
* @return String representing current state of this device
*/
@Override
public String toString() {
return String.format("ServerRack(%s, %4.1fW, %3.1f℃C, %3.1f%%)",
super.getPowerState() ? "on" : "off", getPowerConsumption(),
temperature, currentLoad * 100);
}
} }

View File

@ -1,13 +1,111 @@
public class Vent extends Appliance { /*
private float maxPower = 90.0f; * %W% %E% Dymik739
private float rpm = 0.0f; * Email: dymik739@109.86.70.81
private final float rotorInertia = 7.0f; *
private final float maxRPM = 6500.0f; * Copyright (C) 2023 FIOT Dev Team
*
* 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. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Class that represents a vent installed in the house.
* This device acts as a reactive load.
*
* @author Dymik739
* @since 0.3
*/
public class Vent extends Appliance {
/**
* Power draw limit set by the digital controller, designed by a KPI
* student. Built with the JK-triggers, may malfunction sometimes.
* Exceeding this limit may damage the engine, so it's hard limited.
*/
private float maxPower = 80.0f;
/**
* Current rotor revolutions per minute.
* Can also be defined as angular velocity or kinetic energy
* accumulated in the device.
*/
private float rpm = 0.0f;
/**
* Defines inertia of the rotor.
* Allows the rotor to withstand forces changing it's angular speed.
*/
private final float rotorInertia = 2.0f;
/**
* Target RPM the vent is tuned to maintain.
* Rotor draws full power until it reaches this speed, after that it
* draws only as much power as needed to maintain this speed.
*
* Might be tweaked up to match the exact RPM required, as the target
* RPM is more than actual RPM while running due to additional forces
* and failures in design of the microcontroller (it was also designed
* using JK-triggers as they were the ones that student used in their
* coursework last year).
*/
private final float maxRPM = 2013.0f;
/**
* Constructor for this class.
*
* @param plugged defines if the device is plugged into the power
* network right away
*/
public Vent(boolean plugged) { public Vent(boolean plugged) {
super(plugged); super(plugged);
super.setType("Vent");
} }
/**
* Method for simulating the device behaviour.
* As was stated before in the class docs, this device has reactive
* properties when it comes to loading the network. This means, it
* doesn't only change it's power usage during operation, but also
* follows some real-world physics laws while running.
*
* First, it uses the power, limited by a device microcontroller,
* to gain angular velocity, measured in RPM. Right before it reaches
* it's target RPM, the power draw falls with the exponential decrement
* law (can be seen from the graph in --vent-monitoring-graph mode).
*
* Once it meets the target RPM, it draws power to only maintain it's
* speed (the power goes to withstand air forces trying to slow the
* fan - and the attached rotor - down).
*
* After the power cuts off, the fan keeps rotating due to it's inertia
* and, when plugged back in, starts getting back up to it's target speed
* according to it's current RPM. The power draw from the network always
* meets the power used to gain angular velocity of the rotor.
*
* Also, as this vent is forcing the air through, the blades experience
* the air drag - it always tries to slow the fan down. As such, the
* air rag force is always calculated and depends of the RPM, which
* is proportional to the force being put on the blades.
*
* And the engineering level is kind of weird: on one hand, they
* engineer a smark device that can manage the RPM and limit the power
* to the rotor, but on the other hand they're unable to deal with
* reverse polarity the rotor generates while running, so they've
* just soldered a single diode on the wire and thus limited possible
* power down to just 80W! At least, the vent is still functional, so
* I guess it's good enough...
*
* @param seconds delta time to simulate for
*/
public void step(float seconds) { public void step(float seconds) {
// electric current usage // electric current usage
if (super.getPowerState()) { if (super.getPowerState()) {
@ -16,9 +114,15 @@ public class Vent extends Appliance {
} }
// air drag (always present) // air drag (always present)
rpm -= (rpm / 200) / rotorInertia; rpm -= (rpm / 20) / rotorInertia * seconds;
} }
/**
* Method for calculating current power consumption of this device.
* Calculations are similar to the step() method above.
*
* @return current power consumption of this device
*/
public float getPowerConsumption() { public float getPowerConsumption() {
if (super.getPowerState()) { if (super.getPowerState()) {
return max(min(rotorInertia*(maxRPM - rpm), maxPower), 0); return max(min(rotorInertia*(maxRPM - rpm), maxPower), 0);
@ -27,7 +131,24 @@ public class Vent extends Appliance {
} }
} }
/**
* Getter for RPM.
*
* @return current RPM
*/
public float getRPM() { public float getRPM() {
return rpm; return rpm;
} }
/**
* Method for ptinting out this device state in a nice way.
*
* @return string representation of this device state
*/
@Override
public String toString() {
return String.format("Vent(%s, %4.1fW, %4.0f RPM)",
super.getPowerState() ? "on" : "off", getPowerConsumption(),
rpm);
}
} }