classdef class_REVS_engine_legacy
	%UNTITLED6 Summary of this class goes here
	%   Detailed explanation goes here
	
    
    properties( Constant = true)
         model_type = enum_engine_model_type.legacy;	
	end
		    
	properties
		matrix_vintage = enum_matrix_vintage.present;
        name = '';
        doc;                                                    % documentation struct or class
		
        combustion_type;										% Combustion type specified via enum_engine_combustion_type
		
        displacement_L;											% Engine displacement [liters]
        bore_mm = [];                                           % cylinder bore [mm]
        stroke_mm = [];                                         % piston stroke [mm]
        num_cylinders = 4;                                      % number of engine cylinders
		compression_ratio = [];									% geometric compression ratio
		configuration = [];										% engine physical configuration ( I4, V6, etc.)
        
		inertia_kgm2 = [];                                      % Engine rotational inertia [kg*m^2]
				
		fuel;													% Structure Containing map fuel properties
				
		full_throttle_speed_radps;								% Maximum torque curve speed breakpoints [rad/sec]
		full_throttle_torque_Nm;								% Maximum torque curve [Nm]
		
		naturally_aspirated_speed_radps;						% Maximum torque curve without boost speed breakpoints [rad/sec]
		naturally_aspirated_torque_Nm;							% Maximum torque curve without boost [Nm]
		
		closed_throttle_speed_radps;							% Closed throttle (Motoring) torque curve speed breakpoints [rad/sec]
		closed_throttle_torque_Nm ;								% Closed throttle (Motoring) torque curve [Nm]
		
		throttle_duration_secs = 0.2;							% Torque response rate limiter [sec]
		boost_time_constant_secs = 0.5;							% RC time constant associated with turbocharger boost response [sec]

% 		throttle_duration_sec = [];                             % REMOVE WHEN NEW MATRIX EXECUTABLES MADE
%		boost_time_constant_sec = [];							% REMOVE WHEN NEW MATRIX EXECUTABLES MADE
        
		idle_speed_radps@class_REVS_dynamic_lookup;				% Target idle speed Dynamic Lookup - can be set to scalar value [rad/sec]
		idle_control_Kp = 15;									% Idle Speed Control PID Proportional Term
		idle_control_Ki = 65;									% Idle Speed Control PID Integral Term
		idle_control_Kd = 0;									% Idle Speed Control PID Derivative Term
		idle_control_ramp_radps = 100 * convert.rpm2radps;      % Idle Speed Control Idle Ramp Speed [rad/s]
        idle_control_ramp_time_secs = 2;                        % Idle Speed Control Idle Ramp Time [sec]

		idle_control_activation_speed_radps = 1;				% Speed above which idle speed control PID activates [rad/sec]
		idle_control_deactivation_speed_radps = 0;				% Speed below which idle speed control deactivates ( engine stall ) [rad/sec]
		
		pedal_map_type;											% Generic or custom accelerator pedal to torque mapping
		pedal_map_speed_radps;									% Accelerator pedal to torque map speed breakpoints [radians/sec]
		pedal_map_pedal_norm;									% Accelerator pedal to torque map pedal breakpoints [0 - 1]
		pedal_map_Nm;											% Accelerator pedal to torque map [Nm]
		
		fuel_map_speed_radps;									% Fuel consumption map speed breakpoints [rad/sec]
		fuel_map_torque_Nm										% Fuel consumption map torque breakpoints [Nm]
		fuel_map_gps;											% Fuel consumption map [g/sec]
				
		deac_fuel_map_gps;										% Fuel consumption map with cylinder deac active [g/sec]
		deac_strategy;											% Structure / Class defining type and calibration for cylinder deactivation logic
				
		fast_torque_fuel_adjust_norm;							% Portion of fuel cut associated with fast torque reduction [0 - 1] generally 0 for gasoline 1 for diesel
		
		refuel_profile_mult = [1.0 1.0];						% Defuel -> Refuel penalty fuel multiplier profile
		refuel_profile_time_secs = [0.0, 1.0];					% Defuel -> Refuel penalty fuel multiplier profile time [sec]
		refuel_limit_gps = 0.0;									% Defuel -> Refuel penalty additional fuel limit [grams/sec]
		refuel_min_defuel_duration_secs = inf; 					% Defuel -> Refuel penalty defueled duration before triggering penalty
		
		acceleration_penalty_gpradps2 = 0.0;					% Acceleration Penalty fuel rate [g/(rad/sec^2)]
		acceleration_penalty_squelch_gps = 0.0;					% Acceleration Penalty squelch limit [g/sec]
		
		decel_fuel_shutoff_disabled = false;					% Continue fueling engine when operating on closed throttle curve
		decel_fuel_shutoff_condition = '1';						% Conditions to allow decel fuel cutoff when operating on closed throttle curve [DYNAMIC EXPRESSION]
		
    end
	
	properties ( Dependent = true, SetAccess = immutable, Transient = true)
		full_throttle_power_W;
		
		max_torque_Nm;
		min_torque_Nm;
		max_power_W;
				
		max_power_min_radps;
		max_power_max_radps;
		max_power_avg_radps;
		max_test_speed_radps;
	end
	
	methods
		
		%% Constructor
		
		function obj = class_REVS_engine_legacy
			
		obj.idle_speed_radps = class_REVS_dynamic_lookup;
			
		end
		
		
		%% Setters
		
		
		%% Getters
		
		function val = get.naturally_aspirated_speed_radps( obj )
			val = REVS_class_default( obj.naturally_aspirated_speed_radps, obj.full_throttle_speed_radps );
		end
		
		function val = get.naturally_aspirated_torque_Nm( obj )
			val = REVS_class_default( obj.naturally_aspirated_torque_Nm, obj.full_throttle_torque_Nm );
		end
		
		function val = get.full_throttle_power_W(obj)
			val = obj.full_throttle_speed_radps .* obj.full_throttle_torque_Nm;
		end
		
		function val = get.fast_torque_fuel_adjust_norm(obj)
			val = REVS_class_default( obj.fast_torque_fuel_adjust_norm, obj.combustion_type == enum_engine_combustion_type.compression_ignition );
		end
		
		function val = get.pedal_map_Nm(obj)
			if isempty(obj.pedal_map_type) || obj.pedal_map_type == enum_engine_pedal_map_type.lookup_table
				val = obj.pedal_map_Nm ;
			else
				
				zero_pedal_torque_Nm = zeros(length(obj.full_throttle_speed_radps),1);
				full_pedal_torque_Nm = obj.full_throttle_torque_Nm(:) - min(0, interp1(obj.closed_throttle_speed_radps(:), obj.closed_throttle_torque_Nm(:), obj.full_throttle_speed_radps(:),'linear','extrap'));
				
				obj.pedal_map_pedal_norm =  [0 1];
				%obj.pedal_map_speed_radps = obj.full_throttle_speed_radps;
				
				switch( obj.pedal_map_type)
					
					case  enum_engine_pedal_map_type.linear_WOT
						val = [zero_pedal_torque_Nm, full_pedal_torque_Nm]';
						
					case enum_engine_pedal_map_type.linear_max_engine_torque
						val = [zero_pedal_torque_Nm, max(full_pedal_torque_Nm)*ones(size(full_pedal_torque_Nm))]';
						
					case enum_engine_pedal_map_type.max_engine_power
						closed_throttle_power_W = obj.closed_throttle_speed_radps .* obj.closed_throttle_torque_Nm;
						val = [zero_pedal_torque_Nm, (obj.max_power_W - min(closed_throttle_power_W)) ./ max(min(obj.idle_speed_radps.table(:)), obj.full_throttle_speed_radps(:))]';
						
					case enum_engine_pedal_map_type.linear_enhanced_WOT
						val = [zero_pedal_torque_Nm, 1.1 * full_pedal_torque_Nm]';
						
					case enum_engine_pedal_map_type.linear_enhanced_max_engine_torque
						val = [zero_pedal_torque_Nm, 1.1 * max(full_pedal_torque_Nm)*ones(size(full_pedal_torque_Nm))]';
						
					otherwise
						val = [];
				end
			end
		end
		
		
		function val = get.pedal_map_pedal_norm(obj)
			
			if isempty(obj.pedal_map_type) || obj.pedal_map_type == enum_engine_pedal_map_type.lookup_table;
				val = obj.pedal_map_pedal_norm;
			else
				val =  [0 1];
			end
			% Handle undefined pedal map types
			
		end
		
		function val = get.pedal_map_speed_radps(obj)
			
			if isempty(obj.pedal_map_type) || obj.pedal_map_type == enum_engine_pedal_map_type.lookup_table ;
				val = obj.pedal_map_speed_radps;
			else
				val =  obj.full_throttle_speed_radps;
			end
			% Handle undefined pedal map types
			
		end
		
		function val = get.deac_fuel_map_gps( obj)
			
			if isempty( obj.deac_fuel_map_gps)
				val = nan * ones( size( obj.fuel_map_gps));
			else
				val = obj.deac_fuel_map_gps;
			end
			
			
		end
		
		function [trq, spd] = full_throttle_hires_torque( obj)
			spd = 0:0.1:obj.full_throttle_speed_radps(end);
			trq = interp1( obj.full_throttle_speed_radps, obj.full_throttle_torque_Nm, spd );
		end
		
		function val = get.max_torque_Nm(obj)
			val = max( obj.full_throttle_torque_Nm );
		end
		
		function val = 	get.min_torque_Nm(obj)
			val = min( obj.closed_throttle_torque_Nm );
		end
		
		
		function val = get.max_power_W(obj)
			[trq, spd] = obj.full_throttle_hires_torque;
			val = max( spd .* trq );
		end
		
		function val = get.max_power_max_radps(obj)
			[trq, spd] = obj.full_throttle_hires_torque;
			
			power_W = spd .* trq ;
			idx =  find( power_W > max(power_W) * 0.98,1,'last');
			val = spd(idx);
		end
		
		
		function val = get.max_power_min_radps(obj)
			[trq, spd] = obj.full_throttle_hires_torque;
			
			power_W = spd .* trq ;
			idx =  find( power_W > max(power_W) * 0.98,1,'first');
			val = spd(idx);
		end
		
		function val = get.max_power_avg_radps(obj)
			[trq, spd] = obj.full_throttle_hires_torque;
			power_W = spd .* trq;
			
			idx1 =  find( power_W > max(power_W) * 0.98,1,'last');
			idx2 =  find( power_W > max(power_W) * 0.98,1,'first');
			val = mean(spd([idx1,idx2]));
		end
		
		function val = get.max_test_speed_radps(obj)
			[trq, spd] = obj.full_throttle_hires_torque;
			power_W = spd .* trq ;
			
			% calculations following 1065.510 to find Maximum Test Speed (MTS)
			P_normi                    = power_W ./ obj.max_power_W;
			f_normi                    = spd ./ obj.max_power_avg_radps;
			sum_squares                = f_normi.^2 + P_normi.^2;
			max_test_speed_min_radps   = spd( find(sum_squares >= 0.98 * max(sum_squares), 1, 'first') );
			max_test_speed_radps       = spd( find(sum_squares >= 0.98 * max(sum_squares), 1, 'last') );
			val                        = mean( [max_test_speed_radps max_test_speed_min_radps] );
		end
		
		%% Regular Methods
		
		function val = max_power_max_rpm(obj)
			val = obj.max_power_max_radps .* convert.radps2rpm;
		end
		
		function val = max_power_min_rpm(obj)
			val = obj.max_power_min_radps .* convert.radps2rpm;
		end
		
		function val = max_power_avg_rpm(obj)
			val = obj.max_power_avg_radps .* convert.radps2rpm;
		end
		
		function val = max_test_speed_rpm(obj)
			val = obj.max_test_speed_radps * convert.radps2rpm;
        end
				
        function val = fuel_map_output_power_W(obj)
            val = kron(obj.fuel_map_speed_radps(:)', obj.fuel_map_torque_Nm(:));
        end

        function val = fuel_map_fuel_power_W(obj)
            val = obj.fuel_map_gps * obj.fuel.energy_density_MJpkg;
        end
        
        function val = bsfc_map_gpkWh(obj)
            val = obj.fuel_map_gps ./ (obj.fuel_map_output_power_W / 1000 / 3600);
            % remove spurious points, if necessary            
            val(val <= 0 | val >= 500) = NaN;
        end
        
        function val = efficiency_map_norm(obj)
            val = max(0, obj.fuel_map_output_power_W / 1000) ./ obj.fuel_map_fuel_power_W;
            % remove spurious points, if necessary
            val( val > 1 | val < 0 ) = NaN;
		end
        
		function val = fuel_map_gpi(obj)           
			val = obj.fuel_map_gps ./ (repmat(obj.fuel_map_speed_radps(:)' ,length(obj.fuel_map_torque_Nm),1))*4*pi/ obj.num_cylinders;           
            % remove spurious points, if necessary
            val(isinf(val)) = NaN;
		end
				
        function val = max_efficiency_norm(obj)
            efficiency_map_norm = obj.efficiency_map_norm;
            val = max(efficiency_map_norm(:));
        end
        
        function val = min_bsfc_gpkWh(obj)
            bsfc_map_gpkWh = obj.bsfc_map_gpkWh;
            val = min(bsfc_map_gpkWh(:));
        end
        
	end
	

	
end

