/* * %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 . */ /** * 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) { 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 * 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) { // electric current usage if (super.getPowerState()) { rpm += max(min(((int) (maxRPM - rpm) * rotorInertia), maxPower), 0) * 10 / rotorInertia * seconds; } // air drag (always present) 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() { if (super.getPowerState()) { return max(min(rotorInertia*(maxRPM - rpm), maxPower), 0); } else { return 0f; } } /** * Getter for RPM. * * @return current RPM */ public float getRPM() { 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); } }