fast-nuclear-sim/src/electric/generator.cpp

140 lines
3.7 KiB
C++

#include "generator.hpp"
#include "../util/math.hpp"
#include "../util/streams.hpp"
#include <cmath>
#include <iostream>
using namespace Sim::Electric;
Generator::Generator(Turbine* turbine, Grid* grid, double length, double diameter, double mass) :
length(length), diameter(diameter), mass(mass), turbine(turbine), grid(grid)
{
}
Generator::Generator(const Json::Value& node, Turbine* turbine, Grid* grid) :
length(node["length"].asDouble()),
diameter(node["diameter"].asDouble()),
friction(node["friction"].asDouble()),
mass(node["mass"].asDouble()),
turbine(turbine),
grid(grid)
{
velocity = node["velocity"].asDouble();
phase = node["phase"].asDouble();
breaker_closed = node["breaker_closed"].asBool();
energy_generated = node["energy_generated"].asDouble();
}
void Generator::update(double dt)
{
double energy_input = turbine->extract_energy();
double energy_friction = get_rpm() / 60 * dt * friction;
double work = Util::Math::j_to_ms2(energy_input - energy_friction, mass);
phase = std::fmod(phase + Util::Math::map( get_rpm(), 0, 3600, 0, 120 * M_PI ) * dt, 2 * M_PI);
// do energy transfer stuff here
if(breaker_closed)
{
double a = get_phase_diff();
double dist_extra = 0.1;
if(is_stable || (a < 1e-5 && std::abs(get_rpm() - 60 * grid->frequency) < 1e-3))
{
is_stable = true;
energy_generated = (energy_input - energy_friction) / dt;
grid->pull_energy(energy_friction - energy_input);
phase -= a;
set_rpm(grid->frequency * 60);
return;
}
glm::vec<2, double> point(std::cos(a), std::sin(a));
glm::vec<2, double> diff1 = point - glm::vec<2, double>(dist_extra + 1, 0);
glm::vec<2, double> diff2 = point - glm::vec<2, double>(-dist_extra - 1, 0);
double strength = 1e10;
double dist1 = glm::length(diff1);
double dist2 = glm::length(diff2);
double force1_len = -strength / (4 * M_PI * dist1 * dist1);
double force2_len = strength / (4 * M_PI * dist2 * dist2);
glm::vec<2, double> force1 = diff1 / dist1 * force1_len;
glm::vec<2, double> force2 = diff2 / dist2 * force2_len;
// calc the projected force vector
double t1 = std::tan(a);
double t2 = std::tan(a + M_PI/2);
glm::vec<2, double> proj1, proj2;
proj1.x = ((point.x + force1.x) * t1 - point.x * t2 - force1.y) / (t1 - t2);
proj2.x = ((point.x + force2.x) * t1 - point.x * t2 - force2.y) / (t1 - t2);
proj1.y = (proj1.x - point.x) * t2 + point.y;
proj2.y = (proj2.x - point.x) * t2 + point.y;
glm::mat<2, 2, double> rot_mat = {
point.x, -point.y,
point.y, point.x,
};
double eddy = (get_rpm() - 60 * grid->frequency) * dt * 1e5;
// calc the amount of actual work (in change in m/s) done
glm::vec<2, double> proj = rot_mat * (proj1 + proj2) * 0.5;
double work_done = proj.y / (mass * 0.001) * dt - eddy;
work += work_done;
double e = Util::Math::ms2_to_j(work_done / dt, mass);
energy_generated = -e / dt;
grid->pull_energy(e);
if(grid->is_above_limit())
{
breaker_closed = false;
}
}
else
{
energy_generated = 0;
is_stable = false;
}
velocity = std::max(velocity + work, 0.0);
}
double Generator::get_rpm() const
{
return velocity / (M_PI * mass * 0.001 * diameter * diameter * 0.25);
}
void Generator::set_rpm(double rpm)
{
velocity = rpm * (M_PI * mass * 0.001 * diameter * diameter * 0.25);
}
double Generator::get_phase_diff() const
{
return Util::Math::mod(phase - grid->get_phase() + M_PI, 2*M_PI) - M_PI;
}
Generator::operator Json::Value() const
{
Json::Value node;
node["length"] = length;
node["diameter"] = diameter;
node["velocity"] = velocity;
node["friction"] = friction;
node["breaker_closed"] = breaker_closed;
node["energy_generated"] = energy_generated;
node["phase"] = phase;
node["mass"] = mass;
return node;
}