MDDP-Cableship/maths/power_model.m
2020-11-30 18:59:47 +00:00

290 lines
8.0 KiB
Matlab

%% power_model.m
%%
%% Vessel power model
close all;clear all;clc;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Flags
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CUMULATIVE_ERRORS = false;
ITERATE = ~true;
SAVE = ~true;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ITERATIONS = 5;
% SIMULATION_DAYS = 1; % days
CELL_TOTAL = 159201; % from battery script
% CELL_TOTAL = 500000;
MIN_P_IN = 0; % W, max power from fuel cells
MAX_P_IN = 8e6; % W, max power from fuel cells
P_IN_LOAD = 0.3; % most efficient load percent
%%%%% DP (SS7)
% MAX_P_OUT = 3842e3; % W
% MIN_P_OUT = 362e3; % W
% TITLE = 'Dyn. Pos. Sea State 7';
% SIMULATION_DAYS = 2; % days
%%%%% Outbound
% MAX_P_OUT = 1600e3; % W
% MIN_P_OUT = 600e3; % W
% TITLE = 'Outbound Steaming';
% SIMULATION_DAYS = 3; % days
%
%%%%% Manouvering
% MAX_P_OUT = 800e3; % W
% MIN_P_OUT = 200e3; % W
% TITLE = 'Manouvering';
% SIMULATION_DAYS = 1; % days
%
% %%%%% Home
% MAX_P_OUT = 800e3; % W
% MIN_P_OUT = 200e3; % W
% TITLE = 'Homebound';
% SIMULATION_DAYS = 3; % days
P_IN_INTERVAL = ( 200e3/(5*60) ) * 0.75; % W amount that gen power increases when required
P_OUT_INTERVAL = 1e4; % W amount that load can varies by randomly
BATT_INIT_LEVEL = 0.5;
BATT_FULL_LEVEL = 0.9; % battery level at which the power input decreases
BATT_WARN_LEVEL = 0.3; % battery level at which the power input increases
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Specs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cell_voltage = 3.6; % V
cell_capacity = 2850; % mAh
cell_dis_c = 1; % 1/h
cell_charge_c = 0.5; % 1/h
cell_dis_i = cell_capacity * cell_dis_c / 1e3; % A
cell_charge_i = cell_capacity * cell_charge_c / 1e3; % A
batt_dis_p = cell_dis_i * cell_voltage * CELL_TOTAL; % W
batt_charge_p = cell_charge_i * cell_voltage * CELL_TOTAL; % W
batt_capacity = CELL_TOTAL * cell_capacity * cell_voltage / 1e3; % Wh
% P_IN = MAX_P_IN * P_IN_LOAD; % W, efficient load
P_IN = (MIN_P_OUT + MAX_P_OUT) / 2; % W, Average power out
sim_seconds = SIMULATION_DAYS * 24 * 60 * 60;
%%%%%%% unit conversions
batt_capacity = batt_capacity * 3600; % J
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Simulate
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ITERATE; iter_range = ITERATIONS; else; iter_range = 1; end
for I=(1:iter_range)
% Arrays for time varying values
power_in = zeros(1, sim_seconds);
battery_level = zeros(1, sim_seconds);
power_out = zeros(1, sim_seconds);
unused_energy = zeros(1, sim_seconds);
unavailable_energy = zeros(1, sim_seconds);
% 'cursor' values that change throughout sim
current_p_in = P_IN;
current_p_out = (MAX_P_OUT + MIN_P_OUT) / 2;
% Set initial value
power_in(1) = current_p_in;
battery_level(1)= batt_capacity * BATT_INIT_LEVEL;
power_out(1) = current_p_out;
% loop through day
for SECOND=1:sim_seconds
battery_net = current_p_in - current_p_out; % net power this second
% get last energy value at the battery
% set cumulative values
if SECOND == 1
battery_last = battery_level(1);
if CUMULATIVE_ERRORS
unused_energy(SECOND) = unused_energy(1); % cumulative
unavailable_energy(SECOND) = unavailable_energy(1); % cumulative
end
else
battery_last = battery_level(SECOND - 1);
if CUMULATIVE_ERRORS
unused_energy(SECOND) = unused_energy(SECOND - 1); % cumulative
unavailable_energy(SECOND) = unavailable_energy(SECOND - 1); % cumulative
end
end
% CHARGING
if battery_net > 0
curr_battery = battery_last + min(battery_net, batt_charge_p);
% TOO MUCH FOR BATTERY CAPACITY
if batt_capacity < curr_battery
unused_energy(SECOND) = unused_energy(SECOND) + abs(batt_capacity - curr_battery);
end
% TOO MUCH CURRENT FOR BATTERY
if battery_net > batt_charge_p
unused_energy(SECOND) = unused_energy(SECOND) + battery_net - batt_charge_p;
end
% DISCHARGING
else
discharge_p = min(abs(battery_net), batt_dis_p);
curr_battery = battery_last - discharge_p;
% BATTERY EMPTY
if curr_battery < 0
unavailable_energy(SECOND) = unavailable_energy(SECOND) + abs(curr_battery);
end
% TOO MUCH CURRENT FOR BATTERY
if abs(battery_net) > batt_dis_p
unavailable_energy(SECOND) = unavailable_energy(SECOND) + abs(battery_net) - batt_dis_p;
end
end
% STORE VALUES
power_in(SECOND) = current_p_in;
battery_level(SECOND) = max(min(curr_battery, batt_capacity), 0);
power_out(SECOND) = current_p_out;
% CHANGE LOAD
power_out_delta = (rand - 0.5) * 2 * P_OUT_INTERVAL;
current_p_out = min(max(current_p_out + power_out_delta, MIN_P_OUT), MAX_P_OUT);
% BATTERY LOW, INCREASE POWER IN
% if battery_net < 0 && (battery_level(SECOND)/batt_capacity) < BATT_WARN_LEVEL
if (battery_level(SECOND)/batt_capacity) < BATT_WARN_LEVEL
current_p_in = min(current_p_in + P_IN_INTERVAL, MAX_P_IN);
% BATTERY HIGH, DECREASE POWER IN
elseif (battery_level(SECOND)/batt_capacity) > BATT_FULL_LEVEL
current_p_in = max(current_p_in - P_IN_INTERVAL, MIN_P_IN);
% NEITHER, RELAX TO EFFICIENT STATE
else
delta_to_efficiency = P_IN - current_p_in;
if delta_to_efficiency > 0
current_p_in = min(current_p_in + P_IN_INTERVAL, P_IN);
else
current_p_in = max(current_p_in - P_IN_INTERVAL, P_IN);
end
end
end
x = (1:sim_seconds) / (60 * 60);
x_ticks = (1: sim_seconds / (60 * 60));
if SIMULATION_DAYS > 1
if SIMULATION_DAYS < 4
x_ticks = (1: sim_seconds / (60 * 60));
else
% x_ticks = (1: sim_seconds / (60 * 60 * 24));
end
x = x / 24;
end
% figure(I)
figure('Renderer', 'painters', 'Position', [10 10 1000 800])
% t = tiledlayout(1,1,'Padding','none');
% t.Units = 'inches';
% t.OuterPosition = [0.25 0.25 5 5];
% nexttile;
line_width = 1;
subplot(3, 1, 1);
sgtitle(TITLE);
hold on;
grid on;
plot(x, power_in / 1e6, 'g', 'LineWidth', 2);
plot(x, power_out / 1e6, 'r', 'LineWidth', 1);
max_line = yline(MAX_P_OUT / 1e6, '-c', 'LineWidth', line_width * 0.75);
min_line = yline(MIN_P_OUT / 1e6, '-c', 'LineWidth', line_width * 0.75);
max_line.Alpha = 0.5;
min_line.Alpha = 0.5;
yline(P_IN / 1e6, '--m', 'LineWidth', line_width * 0.5);
legend('P In', 'P Out', 'Max P Out', 'Min P Out', 'Ideal P In');
ylabel('Power (MW)')
xlim([0 inf])
ylim([0 ceil(max(max(power_in/1e6), max(power_out/1e6)))])
xticks(x_ticks)
if SIMULATION_DAYS > 1
xlabel('Time (Days)')
else
xlabel('Time (Hours)')
end
hold off;
% figure(2)
subplot(3, 1, 2);
hold on;
grid on;
plot(x, battery_level * 100 / batt_capacity, 'LineWidth', 2);
legend('Battery Level');
ylabel('Capacity (%)')
xlim([0 inf])
ylim([0 100])
xticks(x_ticks)
if SIMULATION_DAYS > 1
xlabel('Time (Days)')
else
xlabel('Time (Hours)')
end
hold off;
subplot(3, 1, 3);
hold on;
grid on;
plot(x, unused_energy, 'g', 'LineWidth', line_width);
plot(x, unavailable_energy, 'r', 'LineWidth', line_width);
legend('Unused', 'Unavailable');
if CUMULATIVE_ERRORS
ylabel('Energy (J)')
else
ylabel('Power (W)')
end
xlim([0 inf])
ylim([0 inf])
xticks(x_ticks)
if SIMULATION_DAYS > 1
xlabel('Time (Days)')
else
xlabel('Time (Hours)')
end
hold off;
if SAVE
exportgraphics(gcf, sprintf('%s-%i.png', TITLE, I), 'Resolution', '250')
end
end
% FINAL STATS
if ~CUMULATIVE_ERRORS
fprintf('%.f MJ/day of unused power\n', unused_energy(end) / (1e6 * SIMULATION_DAYS));
fprintf('%.f MJ/day of unavailable power\n\n', unavailable_energy(end) / (1e6 * SIMULATION_DAYS));
fprintf('%.f MJ of unused power\n', unused_energy(end) / 1e6);
fprintf('%.f MJ of unavailable power\n', unavailable_energy(end) / 1e6);
end