def implicitEuler(self, tend, step=None): if step is None: step = (tend - self.t0) / 1e3 from ArrayTable import ArrayTable result = ArrayTable(2, 0) result.setTableHeader(["$t$", "y(t) solved with implicit euler"]) result.setTableUnit(["/", "/"]) result.append([self.t0, self.y0]) t = self.t0 while t < tend: temp = self.fun(t, result.table[1].data[-1]) ynextinit = result.table[1].data[-1] + step / 2. * ( temp + self.fun(t + step, result.table[1].data[-1] + temp * step)) def func(w): return result.table[1].data[-1] + step * self.fun(t + step, w) - w ynext = ynextinit h = step / 10. while func(ynext) > 1.e-5: ynext -= func(ynext) / ( (func(ynext + h) - func(ynext - h)) / 2. / h) result.append([t + step, ynext]) t += step return result
def __init__(self, valveDiameter, open_timing_angle, close_timing_angle, _valve_lift, sigma=0, rock=1, _valve_flow_coeff=None): self.valve_diameter = valveDiameter self.open_timing_angle = open_timing_angle self.close_timing_angle = close_timing_angle self.sigma = sigma * math.pi / 180. open = _valve_lift.table[0].data[0] close = _valve_lift.table[0].data[-1] temp = (close_timing_angle - open_timing_angle) / (close - open) self.valve_lift = ArrayTable(2, 0) self.valve_lift.setTableUnit(["CA", "m"]) self.valve_lift.setTableHeader(["Crank angle", "Valve lift"]) for i in range(_valve_lift.row): self.valve_lift.append([ self.open_timing_angle + temp * (_valve_lift.table[0].data[i] - _valve_lift.table[0].data[0]), _valve_lift.table[1].data[i] * rock ]) self.flow_coeff = _valve_flow_coeff if _valve_flow_coeff is None: self.flow_coeff = ArrayTable(2, 0) self.flow_coeff.setTableHeader(["Crank angle", "Flow coefficient"]) self.flow_coeff.setTableUnit(["CA", "/"]) maxlift = self.valve_lift.findMaxValue(1) import numpy as np for i in np.arange(0, maxlift, 0.001): self.flow_coeff.append([i, self.__flowcoefficient(i)])
def __init__(self, _flowArea=1.): from ArrayTable import ArrayTable self.flowArea = _flowArea self.data = ArrayTable(2, 0) self.data.setTableHeader(["Pressure ratio", "Mass flow rate"]) self.data.setTableUnit(["/", "kg/s"]) # 连接关系 self.next = None self.last = None
def __init__(self, L0=14.3): self.L0 = L0 # self.gf = gf from ArrayTable import ArrayTable self.data = ArrayTable(8, 0) self.data.setTableHeader([ "已燃百分比", "缸内气体总质量", "空气质量", "废气质量", "已喷燃油量", "广义过量空气系数", "残余废气系数", "气体常数" ]) self.data.setTableUnit( ["Fraction", "kg", "kg", "kg", "kg", "", "", "J/(kg·k)"])
def eulersolver(self, tend, step=None): if step is None: step = (tend - self.t0) / 1e3 from ArrayTable import ArrayTable result = ArrayTable(2, 0) result.setTableHeader(["$t$", "y(t) solved with explicit euler"]) result.setTableUnit(["/", "/"]) result.append([self.t0, self.y0]) t = self.t0 while t < tend: ynext = result.table[1].data[-1] + self.fun( t, result.table[1].data[-1]) * step result.append([t + step, ynext]) t += step return result
def forecastCorrection(self, tend, step=None): if step is None: step = (tend - self.t0) / 1e3 from ArrayTable import ArrayTable result = ArrayTable(2, 0) result.setTableHeader(["$t$", "y(t) solved with forecast correction"]) result.setTableUnit(["/", "/"]) result.append([self.t0, self.y0]) t = self.t0 while t < tend: dydt = self.fun(t, result.table[1].data[-1]) ynextpridict = result.table[1].data[-1] + dydt * step ynext = result.table[1].data[-1] + step / 2. * ( dydt + self.fun(t + step, ynextpridict)) result.append([t + step, ynext]) t += step return result
def analyze(self, speed=1500,plot=False): from ArrayTable import ArrayTable from Cylinder import MeEff PV = ArrayTable(3, 0) self.data.doQuickSort(0) for i in range(self.data.row): PV.append( [self.data.table[0].data[i], self.CylGeo.V(self.data.table[0].data[i]), self.data.table[1].data[i]]) PV.plot(2, 1) work = PV.integrate(2, _colx=1) power=work/(30*4/speed) BMEP=work / self.CylGeo.displacedVolume() etam = MeEff(self.CylGeo.bore, self.CylGeo.stroke * speed / 30, BMEP) etait=work / (self.mix.gf * 42700e3) print(work/(self.Hu*etam)/(self.mix.M_air(0)/self.L0/self.alpha)) print("Injected fuel {} mg".format(self.mix.gf * 1.e6)) print("Brake power {} kW".format(power/1.e3*self.CylGeo.num_of_cylinders*etam)) print("Mechanical efficiency {}".format(etam)) print("BMEP={} bar".format(BMEP/1.e5)) print("thermal efficiency {}".format(etait)) if plot: self.plot() return work
def Rungekutta4(self, tend, step=None): if step is None: step = (tend - self.t0) / 1e3 from ArrayTable import ArrayTable result = ArrayTable(2, 0) result.setTableHeader(["$t$", "y(t) solved with runge kutta 4"]) result.setTableUnit(["/", "/"]) result.append([self.t0, self.y0]) t = self.t0 while t < tend: s1 = self.fun(t, result.table[1].data[-1]) s2 = self.fun(t + step / 2., result.table[1].data[-1] + step / 2. * s1) s3 = self.fun(t + step / 2., result.table[1].data[-1] + step / 2. * s2) s4 = self.fun(t + step, result.table[1].data[-1] + step * s3) ynext = result.table[1].data[-1] + step / 6. * (s1 + 2 * s2 + 2 * s3 + s4) result.append([t + step, ynext]) t += step return result
class ValveSimple: def __init__(self, _flowArea=1.): from ArrayTable import ArrayTable self.flowArea = _flowArea self.data = ArrayTable(2, 0) self.data.setTableHeader(["Pressure ratio", "Mass flow rate"]) self.data.setTableUnit(["/", "kg/s"]) # 连接关系 self.next = None self.last = None def __massFlowRate(self, p1, T1, R1, k1, p2, T2=0, R2=0, k2=0): return self.flowArea * flowUnitArea(p1, T1, R1, k1, p2, T2, R2, k2) def connect_to(self, last, next): self.last = last self.last.next = self self.next = next self.next.last = self def update(self): self.dm_record = self.__massFlowRate(self.last.p, self.last.T, self.last.Rg, self.last.k, self.next.p, self.next.T, self.next.Rg, self.next.k) # return self.dm_record def airFlowExample(self, p1, T1, p2=None, T2=None, K2=None): from GasProperty import Rg, k_Justi R1 = Rg(T1) R2 = Rg(T2) k1 = k_Justi(T1) k2 = k_Justi(T2) step = 1.e-3 * p1 import numpy as np for i in np.arange(0, p1, step): self.data.append([i / p1, self.__massFlowRate(p1, T1, R1, k1, i)]) if p2 is not None and T2 is not None: step2 = 0.01 * p2 for i in np.arange(0.5 * p2, p2, step): self.data.append([ p2 / i, self.__massFlowRate(i, T1, R1, k1, p2, T2, R2, K2) ]) return self.data
def __init__(self, CylGeo, ValveTiming=None): from ArrayTable import ArrayTable self.CompressData = ArrayTable(5, 0) self.ExpanseData = ArrayTable(5, 0) self.Rpressure = ArrayTable(2, 0) self.GasExchange = ArrayTable(2, 0) self.CompressData.setTableHeader(["Crank angle", "V", "p", "T", "m"]) self.CompressData.setTableUnit(["°CA", "m^3", "Pa", "K", "kg"]) self.ExpanseData.setTableHeader(["Crank angle", "V", "p", "T", "m"]) self.ExpanseData.setTableUnit(["°CA", "m^3", "Pa", "K", "kg"]) self.data = ArrayTable(2, 0) self.data.setTableHeader(["Crank angle", "Cylinder pressure"]) self.data.setTableUnit(["°CA", "Pa"]) self.CylGeo = CylGeo from Valve import ValveDesign if ValveTiming is None: self.ValveTiming = ValveDesign() else: self.ValveTiming = ValveTiming
def AnalyticalSolution(t, left=[], right=[], xlim=None): import math u1 = left[0] u2 = right[0] # r1 = left[1]; # r2 = right[1] T1 = left[1] T2 = right[1] p1 = left[2] p2 = right[2] # T1 = p1 / r1 / Rg(); # T2 = p2 / r2 / Rg() r1 = p1 / Rg() / T1 r2 = p2 / Rg() / T2 k1 = k_Justi(T1) k2 = k_Justi(T2) a1 = math.sqrt(k1 * p1 / r1) a2 = math.sqrt(k2 * p2 / r2) # print("-" * 100) # print("{0:^50}|{1:^50}".format("ul=%.5gm/s" % u1, "ur=%.5gm/s" % u2)) # print("{0:^50}|{1:^50}".format("rhol=%.5gkg/m^3" % r1, "rhor=%.5gkg/m^3" % r2)) # print("{0:^50}|{1:^50}".format("pl=%sPa" % p1, "pr=%sPa" % p2)) # print("{0:^50}|{1:^50}".format("Tl=%sK" % T1, "Tr=%sK" % T2)) # print("-" * 100) def function(pbar, pj, rhoj, gamma=1.4): if pbar == pj: return 0 elif pbar > pj: import math aj = math.sqrt(gamma * pj / rhoj) return (pbar - pj) / rhoj / aj / math.sqrt( (gamma + 1) / 2. / gamma * pbar / pj + (gamma - 1) / 2. / gamma) elif pbar < pj: import math aj = math.sqrt(gamma * pj / rhoj) return 2. * aj / (gamma - 1.) * (pow(pbar / pj, (gamma - 1) / 2. / gamma) - 1) def F(p): return function(p, p1, r1, k1) + function(p, p2, r2, k2) pbar = (p1 + p2) / 2 h = 10. while abs(u1 - u2 - F(pbar)) > 1.e-5: pbar -= (u1 - u2 - F(pbar)) / ((-F(pbar + h) + F(pbar - h)) / 2. / h) # print(pbar) ubar = (u1 + u2 - function(pbar, p1, r1, k1) + function(pbar, p2, r2, k2)) / 2. # print(ubar) A1 = r1 * a1 * math.sqrt((k1 + 1.) / (2. * k1) * pbar / p1 + (k1 - 1) / 2. / k1) A2 = r2 * a2 * math.sqrt((k2 + 1.) / (2. * k2) * pbar / p2 + (k2 - 1) / 2. / k2) if pbar >= p1: Z1 = u1 - A1 / r1 else: Z1 = u1 - a1 if pbar >= p2: Z2 = u2 + A2 / r2 else: Z2 = u2 + a2 if pbar >= p1: Z1star = Z1 elif pbar > 0: a1star = a1 + (k1 - 1) / 2. * (u1 - ubar) Z1star = ubar - a1star else: Z1star = u1 - 2. * a1 / (k1 - 1) if pbar >= p2: Z2star = Z2 elif pbar > 0: a2star = a2 - (k2 - 1) / 2. * (u2 - ubar) Z2star = ubar + a2star else: Z2star = u2 + 2 * a2 / (k2 - 1) r1bar = r1 * A1 / (A1 - r1 * (u1 - ubar)) r2bar = r2 * A2 / (A2 + r2 * (u2 - ubar)) # print("Z1=", Z1) # print("Z1star=", Z1star) # print("ubar=", ubar) # print("Z2star=", Z2star) # print("Z2=", Z2) if xlim is None: Zlaggest = abs(Z1) if abs(Z1) > abs(Z2) else abs(Z2) xlim = [-1.5 * t * Zlaggest, 1.5 * t * Zlaggest] # print("Will draw air state between [{},{}]".format(xlim[0],xlim[1])) def fun(t, x): if x / t > Z2: return u2, r2, p2 elif x / t < Z1: return u1, r1, p1 elif Z1star < x / t < ubar: return ubar, r1bar, pbar elif ubar < x / t < Z2star: return ubar, r2bar, pbar elif Z1 < x / t < Z1star: a = (k1 - 1) / (k1 + 1) * (u1 - x / t) + 2 * a1 / (k1 + 1) u = x / t + a p = p1 * pow(a / a1, 2 * k1 / (k1 - 1)) r = k1 * p / a / a return u, r, p elif Z2star < x / t < Z2: a = (k2 - 1) / (k2 + 1) * (x / t - u2) + 2 * a2 / (k2 - 1) u = x / t - a p = p2 * pow(a / a2, 2 * k2 / (k2 - 1)) r = k2 * p / a / a return u, r, p result = ArrayTable(5, 0) result.setTableHeader( ["x", "Velocity", "Density", "Pressure", "Temperature"]) result.setTableUnit(["m", "m/s", "kg/m^3", "Pa", "K"]) import numpy as np step = (xlim[1] - xlim[0]) / 1000. xx = np.arange(xlim[0], xlim[1], step) for each in xx: u, r, p = fun(t, each) result.append([each, u, r, p, p / r / Rg()]) return result
def laxWendroff1step(t, left=[], right=[], xlim=None, numberOfNode=500, A=1): import numpy as np init = ArrayTable(2, 0) solution = AnalyticalSolution(t, left, right) if xlim is None: mindata = [min(solution.table[i].data) for i in range(solution.col)] maxdata = [max(solution.table[i].data) for i in range(solution.col)] xlim = [1.5 * mindata[0], 1.5 * maxdata[0]] print(xlim) deltax = (xlim[1] - xlim[0]) / numberOfNode for i in np.arange(xlim[0], xlim[1], deltax): Nodeex = Node() if i < 0: Nodeex.Uinit(left[0], left[2], left[1]) else: Nodeex.Uinit(right[0], right[2], right[1]) Nodeex.Jaccobi() Nodeex.F() init.append([i, Nodeex]) thisstep = init tnow = 0 Corant = 0.9 while tnow < t: laststep = thisstep mm = 0 for i in range(laststep.row): if max(abs(laststep.table[1].data[i].Jeigenvalue)) > mm: mm = max(abs(laststep.table[1].data[i].Jeigenvalue)) deltat = deltax * Corant / mm print(deltat) thisstep = ArrayTable(2, 0) thisstep.append([laststep.table[0].data[0], laststep.table[1].data[0]]) for i in range(1, laststep.row - 1): Aright = 1. / 2. * (laststep.table[1].data[i].J + laststep.table[1].data[i + 1].J) Aleft = 1. / 2. * (laststep.table[1].data[i].J + laststep.table[1].data[i - 1].J) Uthis = laststep.table[1].data[i].U\ - deltat /2./ deltax * (laststep.table[1].data[i + 1].F - laststep.table[1].data[i-1].F)\ + deltat**2 /2./ deltax**2*(np.dot(Aright,(laststep.table[1].data[i+1].F - laststep.table[1].data[i].F)) -np.dot(Aleft,(laststep.table[1].data[i].F - laststep.table[1].data[i-1].F))) Nodethis = Node() Nodethis.solve(Uthis) Nodethis.Jaccobi() Nodethis.F() thisstep.append([laststep.table[0].data[i], Nodethis]) thisstep.append( [laststep.table[0].data[-1], laststep.table[1].data[-1]]) tnow += deltat print("tnow={}".format(tnow)) print("Row of table {}".format(thisstep.row)) result = ArrayTable(5, 0) result.setTableHeader( ["x", "Velocity", "Density", "Pressure", "Temperature"]) result.setTableUnit(["m", "m/s", "kg/m^3", "Pa", "K"]) for i in range(thisstep.row): result.append([ thisstep.table[0].data[i], thisstep.table[1].data[i].u, thisstep.table[1].data[i].rho, thisstep.table[1].data[i].p, thisstep.table[1].data[i].T ]) return result
class IdealCylcle: def __init__(self, CylGeo, ValveTiming=None): from ArrayTable import ArrayTable self.CompressData = ArrayTable(5, 0) self.ExpanseData = ArrayTable(5, 0) self.Rpressure = ArrayTable(2, 0) self.GasExchange = ArrayTable(2, 0) self.CompressData.setTableHeader(["Crank angle", "V", "p", "T", "m"]) self.CompressData.setTableUnit(["°CA", "m^3", "Pa", "K", "kg"]) self.ExpanseData.setTableHeader(["Crank angle", "V", "p", "T", "m"]) self.ExpanseData.setTableUnit(["°CA", "m^3", "Pa", "K", "kg"]) self.data = ArrayTable(2, 0) self.data.setTableHeader(["Crank angle", "Cylinder pressure"]) self.data.setTableUnit(["°CA", "Pa"]) self.CylGeo = CylGeo from Valve import ValveDesign if ValveTiming is None: self.ValveTiming = ValveDesign() else: self.ValveTiming = ValveTiming def compress(self, pim=1.e5, Tim=300, Tr=800, xr=0.0, kc=1.3, phic=1): self.kc=kc from GasProperty import DieselMixture, Rg ivc = self.ValveTiming.IVC self.pim = pivc = pim Tim = 313. + 5. / 6. * (Tim - 273.15) # 新鲜充量温度 self.Tim = Tivc = Tim * (1 - xr) + xr * Tr # 新鲜充量质量 mivc = phic * pivc * self.CylGeo.V(180) / Rg() / Tivc self.mix = DieselMixture() self.mix.init_With_Mc_r(mivc, xr, mivc / 14.3 / 1.1) print("Intake air mass {} mg".format(mivc * 1.e6)) print("Tivc=", Tivc) Vivc = self.CylGeo.V(ivc) for i in range(ivc, ivc + 720): V = self.CylGeo.V(i) T = Tivc * pow(Vivc / V, kc - 1) p = pivc * pow(Vivc / V, kc) m = p * V / self.mix.Rg_gas(0) / T self.CompressData.append([i, V, p, T, m]) from Valve import mod for i in range(self.CompressData.row): self.CompressData.table[0].data[i] = mod(self.CompressData.table[0].data[i]) self.CompressData.doQuickSort(0) def Burn(self, Rp, SOC=-5, alpha=1, Hu=42700e3, L0=14.3): self.Hu=Hu from numpy import arange for i in arange(self.ValveTiming.IVC, SOC): self.data.append([i, self.CompressData.linearInterpolate(i, 2)]) if Rp < 0 or Rp > 1: raise Exception("premixed burn fraction value error!!") self.Rp = Rp self.L0 = L0 self.alpha = alpha self.SOC = SOC self.mix.gf = self.mix.M_air(0) / L0 / alpha def fun(x, T): return (Hu - self.mix.u(x, T)) / (alpha * L0 + x) / self.mix.cv(x, T) x = 0 self.T2 = T = self.CompressData.linearInterpolate(SOC, 3) self.p2 = self.CompressData.linearInterpolate(SOC, 2) step = Rp / 50. while x < Rp: T += fun(x, T) * step x += step print("Temperature after premixed burn {}".format(T)) Ttemp = T self.p3 = self.p2 * T / self.T2 print("Pressure after premixed burn {}".format(self.p3)) def fun2(x, T): return (Hu - self.mix.h(x, T)) / (self.mix.cp(x, T) * (self.alpha * self.L0 + x)) step2 = (1 - self.Rp) / 100. while x < 1: T += fun2(x, T) * step2 x += step2 print("Temperature after disfusion burn {}".format(T)) self.V3 = self.CylGeo.V(0) * T / Ttemp self.EOC = self.CylGeo.getFi(self.V3) print("End of combustion {}".format(self.EOC)) self.T3 = T # self.p3=self.mix.M_total(1)*self.mix.Rg_gas(1)*self.T3/self.V3 # print("Pressure after burned {}".format(self.p3)) return T def Expense(self, ke=1.33): self.ke=ke from numpy import arange for i in arange(self.SOC, self.SOC + 360): V = self.CylGeo.V(i) p = self.p3 * pow(self.V3 / V, ke) T = self.T3 * pow(self.V3 / V, ke - 1) self.ExpanseData.append([i, V, p, T, self.mix.M_total(1)]) from Valve import mod for i in range(self.ExpanseData.row): self.ExpanseData.table[0].data[i] = mod(self.ExpanseData.table[0].data[i]) self.ExpanseData.doQuickSort(0) from numpy import arange for i in arange(self.EOC, self.ValveTiming.EVO): self.data.append([i, self.ExpanseData.linearInterpolate(i, 2)]) def pressureReconstruct(self, m=1): from Cylinder import WibeFunction from numpy import arange for i in arange(self.SOC, self.EOC): temp = WibeFunction(i, self.SOC, self.EOC - self.SOC, m=m) p = (1 - temp) * self.CompressData.linearInterpolate(i, 2) + temp * self.ExpanseData.linearInterpolate(i, 2) self.Rpressure.append([i, p]) from numpy import arange for i in arange(self.SOC, self.EOC): self.data.append([i, self.Rpressure.linearInterpolate(i, 1)]) def pit(self, pik=2, p0e=1.e5, T0=273.15 + 20, etaTK=0.56): from Compressor import piT from GasProperty import k_exhaust_gu # 计算排气门打开时的压力和温度 pevo = self.ExpanseData.linearInterpolate(self.ValveTiming.EVO, 2) Tevo = self.ExpanseData.linearInterpolate(self.ValveTiming.EVO, 3) # pevo = self.ExpanseData.linearInterpolate(180, 2) # Tevo = self.ExpanseData.linearInterpolate(180, 3) print("Temperature at EVO {}".format(Tevo)) def fun(x): k = k_exhaust_gu(500) def Ttfun(kk): Tt0=Tevo * pow(x * p0e / pevo, (kk - 1) / kk) return k_exhaust_gu(Tt0)-kk h=0.01 while abs(Ttfun(k))>1.e-5: k-=Ttfun(k)/((Ttfun(k+h)-Ttfun(k-h))/2./h) Tt = Tevo * pow(x * p0e / pevo, (k - 1) / k) return piT(pik, etaTK, Tt, T0, self.alpha * 14.7) - x def fun2(x): Tt=p0e*x/pevo*Tevo return piT(pik, etaTK, Tt, T0, self.alpha * 14.7) - x x = 2.0 h = 0.01 # while abs(fun(x)) > 1.e-5: # x -= fun(x) / ((fun(x + h) - fun(x - h)) / 2. / h) while abs(fun2(x)) > 1.e-5: x -= fun2(x) / ((fun2(x + h) - fun2(x - h)) / 2. / h) print("Pressure ratio of turbine {}".format(x)) print("pressure before turbine {} bar".format(x * p0e / 1.e5)) print("Temperature before turbine {} K".format(Tevo * pow(x * p0e / pevo, (1.33 - 1) / 1.33))) self.pem = x * p0e return x * p0e def gasExchange(self): pem = self.pem from numpy import arange evc = self.ValveTiming.EVC int = self.ValveTiming.int = (self.ValveTiming.EVC + self.ValveTiming.IVC) / 2. for i in arange(self.ValveTiming.EVC, int): self.data.append([i, self.pim]) for i in arange(int, self.ValveTiming.IVC): temp = xi(i, int, self.ValveTiming.IVC) p = self.pim * (1 - temp) + self.CompressData.linearInterpolate(i, 2) * temp self.data.append([i, p]) exh = self.ValveTiming.exh = (self.ValveTiming.EVO + self.ValveTiming.IVO) / 2. for i in arange(self.ValveTiming.EVO, exh): temp = xi(i, self.ValveTiming.EVO, exh) p = self.ExpanseData.linearInterpolate(i, 2) * (1 - temp) + pem * temp self.data.append([i, p]) for i in arange(exh, self.ValveTiming.IVO): self.data.append([i, pem]) from Valve import mod for i in arange(self.ValveTiming.IVO, self.ValveTiming.EVC + 720): temp = xi(i, self.ValveTiming.IVO, self.ValveTiming.EVC + 720) p = pem * (1 - temp) + self.pim * temp self.data.append([mod(i), p]) # from numpy import arange # for i in arange(self.ValveTiming.EVC, self.ValveTiming.IVC): # self.data.append([i, self.GasExchange.linearInterpolate(i, 1)]) def plot(self): self.data.doQuickSort(0) import matplotlib.pyplot as plt fig, ax = plt.subplots(1, figsize=(10, 5)) ax.plot(self.data.table[0].data, self.data.table[1].data) plt.xlabel(self.data.table[0].ColName + "(" + self.data.table[0].ColUnit + ")") plt.ylabel(self.data.table[1].ColName + "(" + self.data.table[1].ColUnit + ")") ax.scatter(self.EOC, self.data.linearInterpolate(self.EOC, 1)) ax.annotate('EOC %.3g $^\circ$CA' % self.EOC, xy=(self.EOC, self.data.linearInterpolate(self.EOC, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) index = self.data.findMaxValueIndex(1) maxpreCA = self.data.table[0].data[index] ax.scatter(maxpreCA, self.data.linearInterpolate(maxpreCA, 1)) ax.annotate('maxium pressure %.5g bar' % (self.data.linearInterpolate(maxpreCA, 1) / 1.e5), xy=(maxpreCA, self.data.linearInterpolate(maxpreCA, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.ValveTiming.IVC, self.data.linearInterpolate(self.ValveTiming.IVC, 1)) ax.annotate('IVC %.3g $^\circ$CA' % self.ValveTiming.IVC, xy=(self.ValveTiming.IVC, self.data.linearInterpolate(self.ValveTiming.IVC, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.ValveTiming.EVO, self.data.linearInterpolate(self.ValveTiming.EVO, 1)) ax.annotate('EVO %.3g $^\circ$CA' % self.ValveTiming.EVO, xy=(self.ValveTiming.EVO, self.data.linearInterpolate(self.ValveTiming.EVO, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.ValveTiming.EVC, self.data.linearInterpolate(self.ValveTiming.EVC, 1)) ax.annotate('EVC %.3g $^\circ$CA' % self.ValveTiming.EVC, xy=(self.ValveTiming.EVC, self.data.linearInterpolate(self.ValveTiming.EVC, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.ValveTiming.IVO, self.data.linearInterpolate(self.ValveTiming.IVO, 1)) ax.annotate('IVO %.3g $^\circ$CA' % self.ValveTiming.IVO, xy=(self.ValveTiming.IVO, self.data.linearInterpolate(self.ValveTiming.IVO, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) # ax.scatter(self.ValveTiming.int, self.data.linearInterpolate(self.ValveTiming.int, 1)) ax.annotate('$p_{im}$ %.4g bar' % (self.pim / 1.e5), xy=(self.ValveTiming.int, self.data.linearInterpolate(self.ValveTiming.int, 1)), xycoords='data', xytext=(-28, 40), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.annotate('$p_{em}$ %.4g bar' % (self.pem / 1.e5), xy=(self.ValveTiming.exh, self.data.linearInterpolate(self.ValveTiming.exh, 1)), xycoords='data', xytext=(-0, 40), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.SOC, self.data.linearInterpolate(self.SOC, 1)) ax.annotate('SOC %.3g $^\circ$CA' % self.SOC, xy=(self.SOC, self.data.linearInterpolate(self.SOC, 1)), xycoords='data', xytext=(-80, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) # # ax.scatter(self.EVC, table.linearInterpolate(self.EVC, 1)) # ax.annotate('EVC %.3g $^\circ$CA' % self.EVC, # xy=(self.EVC, table.linearInterpolate(self.EVC, 1)), xycoords='data', # xytext=(0, 10), textcoords='offset points', # arrowprops=dict(arrowstyle="->")) plt.xticks([-360, -180, 0, 180, 360], ["-360\nTDC", "-180\nBDC", "0\nTDCF", "180\nBDC", "360\nTDC"]) # ax.axhline(y=0, color='r', linestyle="-.") ax.axvline(x=0, color='g', linestyle=":") ax.axvline(x=180, color='g', linestyle=":") ax.axvline(x=-180, color='g', linestyle=":") ax.axvline(x=360, color='g', linestyle=":") ax.axvline(x=-360, color='g', linestyle=":") plt.tight_layout() plt.show() def analyze(self, speed=1500,plot=False): from ArrayTable import ArrayTable from Cylinder import MeEff PV = ArrayTable(3, 0) self.data.doQuickSort(0) for i in range(self.data.row): PV.append( [self.data.table[0].data[i], self.CylGeo.V(self.data.table[0].data[i]), self.data.table[1].data[i]]) PV.plot(2, 1) work = PV.integrate(2, _colx=1) power=work/(30*4/speed) BMEP=work / self.CylGeo.displacedVolume() etam = MeEff(self.CylGeo.bore, self.CylGeo.stroke * speed / 30, BMEP) etait=work / (self.mix.gf * 42700e3) print(work/(self.Hu*etam)/(self.mix.M_air(0)/self.L0/self.alpha)) print("Injected fuel {} mg".format(self.mix.gf * 1.e6)) print("Brake power {} kW".format(power/1.e3*self.CylGeo.num_of_cylinders*etam)) print("Mechanical efficiency {}".format(etam)) print("BMEP={} bar".format(BMEP/1.e5)) print("thermal efficiency {}".format(etait)) if plot: self.plot() return work def loop(self): pass
class DieselMixture: def __init__(self, L0=14.3): self.L0 = L0 # self.gf = gf from ArrayTable import ArrayTable self.data = ArrayTable(8, 0) self.data.setTableHeader([ "已燃百分比", "缸内气体总质量", "空气质量", "废气质量", "已喷燃油量", "广义过量空气系数", "残余废气系数", "气体常数" ]) self.data.setTableUnit( ["Fraction", "kg", "kg", "kg", "kg", "", "", "J/(kg·k)"]) def init_With_Ma_r(self, ma, r, gf): self.ma = ma self.r = r self.gf = gf if ma < self.L0 * self.gf: print("Charged air is too few to burn all the fuel!!") raise Exception( "There are must at least {}(kg) air but {} is provided".format( self.L0 * self.gf, ma)) if r < 0 or r > 1: raise Exception( "residual gas fraction can not less than 0 and greater than 1!!" ) self.xr = ma * r / (1 - r) / (1 + self.L0) / self.gf self.__initPropertyTable() def init_With_Mc_r(self, mc, r, gf): self.init_With_Ma_r((1 - r) * mc, r, gf) def init_With_Mc_AFA(self, mc, afa, gf): self.gf = gf if afa < 1: raise Exception( "Excess air fuel ratio must be greater than or equal to 1") mr = (1 + self.L0) / (self.L0 * afa + 1) * mc self.ma = self.L0 * (afa - 1) / (self.L0 * afa + 1) * mc if self.ma < self.L0 * gf: print("Charged air is too few to burn all the fuel!!") raise Exception( "There are must at least {}(kg) air but {} is provided".format( self.L0 * self.gf, self.ma)) self.r = mr / mc self.xr = self.ma * self.r / (1 - self.r) / (1 + self.L0) / self.gf self.__initPropertyTable() def AFAK(self, x): if x < 0: x = 0 if (self.xr + x) < 1.e-8: return 1.e8 return (self.L0 * self.gf * self.xr + self.ma) / (self.L0 * self.gf * (self.xr + x)) def M_total(self, x): if x < 0: x = 0 if (self.xr + x) < 1.e-8: return self.ma return self.gf * (self.xr + x) * (1 + self.AFAK(x) * self.L0) def M_exhaust(self, x): return self.M_total(x) * (1 + self.L0) / (self.L0 * self.AFAK(x) + 1) def M_air(self, x): return self.M_total(x) - self.M_exhaust(x) def Xk(self, x): return self.M_total(x) / (1 + self.L0 * self.AFAK(x)) / self.gf def cv(self, x, T): return cv_Justi(T, self.AFAK(x)) def cp(self, x, T): return cp_Justi(T, self.AFAK(x)) def u(self, x, T): return u_Justi(T, self.AFAK(x)) def h(self, x, T): return h_Justi(T, self.AFAK(x)) def U(self, x, T): return self.M_total(x) * u_Justi(T, self.AFAK(x)) def Rg_gas(self, x): return Rg(self.AFAK(x)) def k(self, x, T): return k_Justi(T, self.AFAK(x)) def __initPropertyTable(self): from numpy import arange for i in arange(0, 1, 0.01): self.data.append([ i, self.M_total(i), self.M_air(i), self.M_exhaust(i), self.gf * i, self.AFAK(i), self.M_exhaust(i) / self.M_total(i), self.Rg_gas(i) ])
def plot(self): from ArrayTable import ArrayTable table = ArrayTable() table.readSQLiteTable("EngineDB.db", "`Cylinder pressure GT example`") for i in range(table.row): table.table[0].data[i] = mod(table.table[0].data[i], TDC=self.TDC) table.doQuickSort() import matplotlib.pyplot as plt fig, ax = plt.subplots(1, figsize=(10, 5)) ax.plot(table.table[0].data, table.table[1].data) plt.xlabel(table.table[0].ColName + "(" + table.table[0].ColUnit + ")") plt.ylabel(table.table[1].ColName + "(" + table.table[1].ColUnit + ")") ax.scatter(self.IVC, table.linearInterpolate(self.IVC, 1)) ax.annotate('IVC %.3g $^\circ$CA' % self.IVC, xy=(self.IVC, table.linearInterpolate(self.IVC, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.IVO, table.linearInterpolate(self.IVO, 1)) ax.annotate('IVO %.3g $^\circ$CA' % self.IVO, xy=(self.IVO, table.linearInterpolate(self.IVO, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.EVO, table.linearInterpolate(self.EVO, 1)) ax.annotate('EVO %.3g $^\circ$CA' % self.EVO, xy=(self.EVO, table.linearInterpolate(self.EVO, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) ax.scatter(self.EVC, table.linearInterpolate(self.EVC, 1)) ax.annotate('EVC %.3g $^\circ$CA' % self.EVC, xy=(self.EVC, table.linearInterpolate(self.EVC, 1)), xycoords='data', xytext=(0, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->")) plt.xticks( [-360, -180, 0, 180, 360], ["-360\nTDC", "-180\nBDC", "0\nTDCF", "180\nBDC", "360\nTDC"]) # ax.axhline(y=0, color='r', linestyle="-.") ax.axvline(x=0, color='g', linestyle=":") ax.axvline(x=180, color='g', linestyle=":") ax.axvline(x=-180, color='g', linestyle=":") ax.axvline(x=360, color='g', linestyle=":") ax.axvline(x=-360, color='g', linestyle=":") plt.tight_layout() plt.show()