#!/usr/bin/perl -w

# quick hack to calculate req_fuel and starting tables

print '# You must understand what you are doing '
. "\n\# (and know your engine and ECM), this is NO magic tool.\n";

# Marcell Gal 2003

# injector flowrate:
$ccpermin = 220;	#cm3 permin
$fueldens = 0.9;	#g/cm3
$airdens=1.2;	# kg/m3 same as gram/liter
$targetafr = 14.7;
$volume = 1.8/4; # of 1 cylinder, in liter
$kpatrim = 100;	# above this reading is nonsense (value should be in config_t)
# set this to 100 .. 200, it will mean the VE=1 entry in the vetable, and downscale reqfuel: *vebase/100
$vebase = 200;
$bsfc = 0.44;	# pound per horsepower*hour :-(

# stoich below, enrichen linearly above [Watt]:
$StoichThreshold = 22000;	
$EnrichperP = 0.15 / 50000;

# MAP enrichment above:
$MAPThreshold = 30;
$EnrichMAP = 0.12 / 70;

# Ignition advance parameters

$ignadvres = 0.25;	# [1/4 degrees resolution]
$ignadvmax = 40;	# degrees

# $advmin = 6;			# see the $ignadvmin array reference
# zzzzz $ignadvperrpm = 40; # see the $ignadvmin array reference

$ignadvpermap = 8 / 30;	# Vacuum advance: eg.: 8 degrees / 30 kPa

# this is in grams per cycle:
$req_fuel_mass = $volume * $airdens/$targetafr ;

$gram_per_sec = ($ccpermin*$fueldens) / 60;

# the time (100usec) required for this is:
$req_fuel = 10000 * $req_fuel_mass / $gram_per_sec  ; # 1sec / 100 usec = 10000

# print "req_fuel= $req_fuel\n";

printf ("for ve=100: req_fuel=%d, 0x%02x\n", $req_fuel, $req_fuel);
$req_fuel *= 100 / $vebase;
printf ("for ve=$vebase: req_fuel=%d, 0x%02x\n", $req_fuel, $req_fuel);

$req_fuel_sec = $req_fuel / 10000;

# kpa values (ADCcount? No, I think real kpa, but almost same for 2.5bar sensor) 
$kpa	=	[ 0, 1, 2, 3,  20, 80, 100, 255 ]; 

$rpm 	= 	[ 500, 1000, 1500, 2000,   3000, 4000, 5000, 7000 ];
$ignadvmin =[ 5,	10,	  15,	20,		25,	 30, 	32,	  34 ]; # ignadv at max MAP
$ignadvmap =[ 30,	40,	  50,	55,		58,	 60,	62,	  64 ];	# below this MAP advancing happens

# torque is for max measured kpa, which we usually don't know! Assuming 100 kPa
# also it is not output torque, but breathed in air !! ( no losses)
# BE careful!!
# this is in Nm units (TODO: fix multiplier!!!!!!!!!)
$torque =	[ 70, 80,  100,  120,       128, 120, 100, 50 ];


hexarr('k[0]=', $kpa, 1.00); # what the heck is wrong ???

hexarr('r[0]=', $rpm, 0.01);

my $i;
my $nmfact = Nm2time(100.00 / $req_fuel_sec ); # 0.01 (not 1 :-) would be needed to backscale kpa, see later

# print "nmfact = $nmfact \n";

foreach $i (0..7){
	$map = $kpa->[$i]; # exported global
	my $mul = 1.0;
	
	# for nonsense high kpa readings, downscale ve (will be right in fuelcalc)
	if ($map > $kpatrim){
		$mul = $kpatrim / $map; # we downscale !!!
		$map = $kpatrim;
	}
	hexarr("j[$i]=", $torque, $nmfact * $mul);
	$igntable .= "\nn[$i]=" . ignadvline();
}

print "\n\# ignadv in 1/4 degree, higher means higher advance\n$igntable\n";

# prints the array in hexa
sub hexarr
{
	my $str = shift;
	my $arr = shift; # the array reference
	my $mult = shift;
	my $i; my $v;

	print $str;
	$i = 0;

	
	while( defined ($v = $arr->[$i])){
		if($str =~ /^j/){ # what a hack :-)
			$enrich = Penrich(Power($rpm->[$i], $v, $map)) * MAPenrich($map);
		} else {
			$enrich = 1.0; # no "enrichment" for kpa or rpm arrays, just table 'j' (vetable)
		}
		printf ("%02x ", $v * $mult * $enrich);
		$i++;
	}
	print "\n";
}

# return ignadv for a loadsite
sub ignadv
{
	my $advmin = shift;
	my $mapthres = shift;
	
	return $advmin if $map > $mapthres;
	my $ignadv = $advmin + ($mapthres - $map) * $ignadvpermap;
	return $ignadvmax if $ignadv > $ignadvmax;	# clipping
	return $ignadv;
}

# returns the ignition advance for a kpa line (taken from $map)
sub ignadvline
{
	my $rpmline = shift;
	my $i; my $advmin; my $str;

	$i = 0;
	while( defined ($advmin = ($ignadvmin->[$i]))){
		my $aadv = ignadv($advmin, $ignadvmap->[$i]); 
		# print "adv = $aadv ";
		$str .= sprintf ("%02x ", $aadv / $ignadvres );
		$i++;
	}
	return $str;
}

# calculates injectorpulsewidth time (sec) from torque
# is this broken ??
sub Nm2time
{
	my $nm = shift;
# let's assume 10 msec period, which is 100 cycles/sec,( 3000RPM ?? => 50 turns / sec)
	my $power = Power(3000, $nm, 100);	# Watt
	my $bsfc_kg_per_kWh = $bsfc * 0.450 / 0.741;	# from pound, and horsepower units
	my $fuel = $power * $bsfc_kg_per_kWh / 3600 ;	# gram per sec
	$fuel = $fuel / 100;				# gram per cycle
	return $fuel / $gram_per_sec   ; 		# opentime: sec per cycle
}

# enrichment due to MAP
sub MAPenrich
{
	my $p = shift;
	return 1.0 if ($p < $MAPThreshold);
	return 1.0 + $EnrichMAP * ($p - $MAPThreshold);
}

# enrichment due to power
sub Penrich
{
	my $P = shift;	# power in Watts
	return 1.0 if $P < $StoichThreshold;
	return 1.0 + $EnrichperP * ($P - $StoichThreshold); 
}

# Power (in Watt) at given rpm and torque
# map is a simple scaler, use 100 for scaling factor of 1.00
sub Power
{
	my $rpm = shift;	# 1/min
	my $torque = shift; # Nm
	my $map = shift;	# kPa
	
	return $rpm / 60 * 3.14 * 2 * $torque * $map * 0.01; 
}