github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/bltcomfrt.go (about) 1 //This file is part of EESLISM. 2 // 3 //Foobar is free software : you can redistribute itand /or modify 4 //it under the terms of the GNU General Public License as published by 5 //the Free Software Foundation, either version 3 of the License, or 6 //(at your option) any later version. 7 // 8 //Foobar is distributed in the hope that it will be useful, 9 //but WITHOUT ANY WARRANTY; without even the implied warranty of 10 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 11 //GNU General Public License for more details. 12 // 13 //You should have received a copy of the GNU General Public License 14 //along with Foobar.If not, see < https://www.gnu.org/licenses/>. 15 16 /* tcomfrt.c */ 17 18 package eeslism 19 20 import "math" 21 22 /* 作用温度制御時の設定室内空気温度 */ 23 24 var __Rmotset_Pint int 25 26 func Rmotset(_Room []*ROOM) { 27 Fotinit(_Room) 28 29 for i := range _Room { 30 Room := _Room[i] 31 32 Eo := Room.cmp.Elouts[0] 33 if Eo.Control == LOAD_SW { 34 rmld := Room.rmld 35 36 if rmld.tropt == 'o' { 37 Fotf(Room) 38 39 OT := rmld.Tset 40 a := OT - rmld.FOC 41 42 for j := 0; j < Room.Ntr; j++ { 43 trnx := Room.trnx[j] 44 a -= rmld.FOTN[j] * trnx.nextroom.Tr 45 } 46 47 for j := 0; j < Room.Nrp; j++ { 48 rmpnl := Room.rmpnl[j] 49 50 var Twi float64 51 if __Rmotset_Pint == 0 { 52 Twi = rmpnl.sd.mw.Tw[rmpnl.sd.mw.mp] 53 __Rmotset_Pint = 1 54 } else { 55 Twi = rmpnl.pnl.Tpi 56 } 57 58 a -= rmld.FOPL[j] * Twi 59 } 60 61 Trset := a / rmld.FOTr 62 Eo.Sysv = Trset 63 Room.Tr = Trset 64 65 if rmld.loadx != nil { 66 Eo = Room.cmp.Elouts[1] 67 if Eo.Control == LOAD_SW && rmld.hmopt == 'r' { 68 Eo.Sysv = FNXtr(Trset, rmld.Xset) 69 } 70 } 71 } 72 } 73 } 74 } 75 76 /* -------------------------------------- */ 77 78 var __Fotinit_init int = 'i' 79 80 func Fotinit(_Room []*ROOM) { 81 if __Fotinit_init == 'i' { 82 for i := range _Room { 83 Room := _Room[i] 84 if Room.rmld != nil { 85 Room.rmld.FOTN = nil 86 Room.rmld.FOPL = nil 87 88 Room.rmld.FOTN = make([]float64, Room.Ntr) 89 Room.rmld.FOPL = make([]float64, Room.Nrp) 90 } 91 } 92 __Fotinit_init = 'x' 93 } 94 } 95 96 /* -------------------------------------- */ 97 func Fotf(Room *ROOM) { 98 var r float64 99 if Room.OTsetCwgt == nil || *(Room.OTsetCwgt) < 0.0 || *(Room.OTsetCwgt) > 1.0 { 100 r = 0.5 101 } else { 102 r = *(Room.OTsetCwgt) 103 } 104 105 { 106 var a, C float64 107 for i := 0; i < Room.N; i++ { 108 Sd := Room.rsrf[i] 109 a += Sd.A * Sd.WSR 110 C += Sd.A * Sd.WSC 111 } 112 Room.rmld.FOTr = r + (1.0-r)*a/Room.Area 113 Room.rmld.FOC = (1.0 - r) * C / Room.Area 114 } 115 116 for k := 0; k < Room.Ntr; k++ { 117 ft := &Room.rmld.FOTN[k] 118 119 var a float64 120 for i := 0; i < Room.N; i++ { 121 Sd := Room.rsrf[i] 122 a += Sd.A * Sd.WSRN[k] 123 } 124 125 *ft = (1.0 - r) * a / Room.Area 126 } 127 128 for k := 0; k < Room.Nrp; k++ { 129 ft := &Room.rmld.FOPL[k] 130 131 var a float64 132 for i := 0; i < Room.N; i++ { 133 Sd := Room.rsrf[i] 134 a += Sd.A * Sd.WSPL[k] 135 } 136 137 *ft = (1.0 - r) * a / Room.Area 138 } 139 } 140 141 /* -------------------------------------- */ 142 143 /* 各室の温熱環境指標計算 */ 144 145 func Rmcomfrt(_Room []*ROOM) { 146 met := 0.0 147 Icl := 0.0 148 v := 0.0 149 150 for i := range _Room { 151 id := 0 152 Room := _Room[i] 153 if Room.Metsch != nil && *Room.Metsch > 0.0 { 154 met = *Room.Metsch 155 id++ 156 } 157 if Room.Closch != nil && *Room.Closch > 0.0 { 158 Icl = *Room.Closch 159 id++ 160 } 161 if Room.Wvsch != nil && *Room.Wvsch > 0.0 { 162 v = *Room.Wvsch 163 id++ 164 } 165 166 if id == 3 { 167 Room.PMV = Pmv0(met, Icl, Room.Tr, Room.xr, Room.Tsav, v) 168 Room.SET = SET_star(Room.Tr, Room.Tsav, v, Room.RH, met, Icl, 0.0, 101.3) 169 } else { 170 Room.PMV = -999.0 171 } 172 /******************* 173 fmt.Printf("**** Rmcomfrt met=%.1f Icl=%.1f v=%.2f Tr=%.1f xr=%.4f Tmrt=%.1f PMV=%.2f\n", 174 met, Icl, v, Room.Tr, Room.xr, Room.Tsav, Room.PMV) 175 *******************/ 176 } 177 } 178 179 /* ----------------------------------------------------- */ 180 181 /* PMVの計算 */ 182 183 func Pmv0(met, Icl, Tr, xr, Tmrt, v float64) float64 { 184 /* m [kcal.m2h] */ 185 186 Po := 760.0 187 eta := 0.0 188 189 m := met * 50.0 190 Pa := xr * Po / (xr + 0.62198) 191 hc := 10.4 * math.Sqrt(v) 192 Tm := 0.5*(37.0+0.5*(Tr+Tmrt)) + 273.15 193 hr := 13.6e-8 * Tm * Tm * Tm 194 fcl := 1.0 195 if Icl < 0.5 { 196 fcl = 1.0 + 0.2*Icl 197 } else { 198 fcl = 1.05 + 0.1*Icl 199 } 200 Ifcl := 0.18 * Icl * fcl 201 202 tcl := (35.7 - 0.032*m*(1.0-eta) + Ifcl*(hr*Tmrt+hc*Tr)) / (1.0 + Ifcl*(hr+hc)) 203 204 L := m*(0.60135-0.0023*(44.0-Pa)-0.0014*(34.0-Tr)) + 0.35*Pa + 5.95 - 0.6013*eta - fcl*(hr*(tcl-Tmrt)+hc*(tcl-Tr)) 205 206 return (0.352*math.Exp(-0.042*m) + 0.032) * L 207 } 208 209 // SET*の計算 210 func SET_star(TA, TR, VEL, RH, MET, CLO, WME, PATM float64) float64 { 211 //Input doubleiables ? TA (air temperature): °C, TR (mean radiant temperature): °C, VEL (air velocity): m/s, 212 //RH (relative humidity): %, MET: met unit, CLO: clo unit, WME (external work): W/m2, PATM (atmospheric pressure): kPa 213 const KCLO = 0.25 214 const BODYWEIGHT = 69.9 //kg 215 const BODYSURFACEAREA = 1.8258 //m2 216 const METFACTOR = 58.2 //W/m2 217 const SBC = 0.000000056697 //Stefan-Boltzmann constant (W/m2K4) 218 const CSW = 170.0 219 const CDIL = 120.0 220 const CSTR = 0.5 221 const LTIME = 60 222 var PS = FindSaturatedVaporPressureTorr(TA) 223 var VaporPressure = RH * PS / 100.0 224 var AirVelocity = math.Max(VEL, 0.1) 225 const TempSkinNeutral = 33.7 226 const TempCoreNeutral = 36.49 227 const TempBodyNeutral = 36.49 228 const SkinBloodFlowNeutral = 6.3 229 var TempSkin = TempSkinNeutral //Initial values 230 var TempCore = TempCoreNeutral 231 var SkinBloodFlow = SkinBloodFlowNeutral 232 var MSHIV = 0.0 233 var ALFA = 0.1 234 var ESK = 0.1 * MET 235 // 桁落ちによる誤差を避けるため換算係数を変更 236 //double PressureInAtmospheres = PATM * 0.009869; 237 var PressureInAtmospheres = PATM / 101.3 238 var RCL = 0.155 * CLO 239 var FACL = 1.0 + 0.15*CLO 240 var LR = 2.2 / PressureInAtmospheres //Lewis Relation is 2.2 at sea level 241 var RM = MET * METFACTOR 242 var M = MET * METFACTOR 243 var ICL, WCRIT float64 244 if CLO <= 0 { 245 WCRIT = 0.38 * math.Pow(AirVelocity, -0.29) 246 ICL = 1.0 247 } else { 248 WCRIT = 0.59 * math.Pow(AirVelocity, -0.08) 249 ICL = 0.45 250 } 251 var CHC = 3.0 * math.Pow(PressureInAtmospheres, 0.53) 252 var CHCV = 8.600001 * math.Pow((AirVelocity*PressureInAtmospheres), 0.53) 253 CHC = math.Max(CHC, CHCV) 254 var CHR = 4.7 255 var CTC = CHR + CHC 256 var RA = 1.0 / (FACL * CTC) //Resistance of air layer to dry heat transfer 257 var TOP = (CHR*TR + CHC*TA) / CTC 258 var TCL = TOP + (TempSkin-TOP)/(CTC*(RA+RCL)) 259 //TCL and CHR are solved iteratively using: H(Tsk - TOP) = CTC(TCL - TOP), 260 //where H = 1/(RA + RCL) and RA = 1/FACL*CTC 261 var TCL_OLD = TCL 262 var flag = true 263 var DRY, HFCS, ERES, CRES, SCR, SSK, TCSK, TCCR, DTSK, DTCR, TB, SKSIG, WARMS, COLDS, CRSIG, WARMC, 264 COLDC, BDSIG, WARMB, REGSW, EMAX float64 265 var PWET = 0.0 266 267 //Begin iteration 268 for TIM := 1; TIM <= LTIME; TIM++ { 269 for i := 0; i < 100; i++ { 270 if flag { 271 TCL_OLD = TCL 272 CHR = 4.0 * SBC * math.Pow(((TCL+TR)/2.0+273.15), 3.0) * 0.72 273 CTC = CHR + CHC 274 RA = 1.0 / (FACL * CTC) //Resistance of air layer to dry heat transfer 275 TOP = (CHR*TR + CHC*TA) / CTC 276 } 277 TCL = (RA*TempSkin + RCL*TOP) / (RA + RCL) 278 flag = true 279 if math.Abs(TCL-TCL_OLD) <= 0.01 { 280 break 281 } 282 } 283 flag = false 284 DRY = (TempSkin - TOP) / (RA + RCL) 285 HFCS = (TempCore - TempSkin) * (5.28 + 1.163*SkinBloodFlow) 286 ERES = 0.0023 * M * (44.0 - VaporPressure) 287 CRES = 0.0014 * M * (34.0 - TA) 288 SCR = M - HFCS - ERES - CRES - WME 289 SSK = HFCS - DRY - ESK 290 TCSK = 0.97 * ALFA * BODYWEIGHT 291 TCCR = 0.97 * (1. - ALFA) * BODYWEIGHT 292 DTSK = (SSK * BODYSURFACEAREA) / (TCSK * 60.0) //°C/min 293 DTCR = SCR * BODYSURFACEAREA / (TCCR * 60.0) //°C/min 294 TempSkin = TempSkin + DTSK 295 TempCore = TempCore + DTCR 296 TB = ALFA*TempSkin + (1.-ALFA)*TempCore 297 SKSIG = TempSkin - TempSkinNeutral 298 if SKSIG > 0 { 299 WARMS = SKSIG 300 } else { 301 WARMS = 0 302 } 303 if (-1.0 * SKSIG) > 0 { 304 COLDS = (-1.0 * SKSIG) 305 } else { 306 COLDS = 0 307 } 308 CRSIG = (TempCore - TempCoreNeutral) 309 if CRSIG > 0 { 310 WARMC = CRSIG 311 } else { 312 WARMC = 0 313 } 314 if (-1.0 * CRSIG) > 0 { 315 COLDC = (-1.0 * CRSIG) 316 } else { 317 COLDC = 0 318 } 319 BDSIG = TB - TempBodyNeutral 320 if BDSIG > 0 { 321 WARMB = BDSIG 322 } else { 323 WARMB = 0 324 } 325 SkinBloodFlow = (SkinBloodFlowNeutral + CDIL*WARMC) / (1. + CSTR*COLDS) 326 SkinBloodFlow = math.Max(0.5, math.Min(90.0, SkinBloodFlow)) 327 REGSW = CSW * WARMB * math.Exp(WARMS/10.7) 328 REGSW = math.Min(REGSW, 500.0) 329 var ERSW = 0.68 * REGSW 330 var REA = 1.0 / (LR * FACL * CHC) //Evaporative resistance of air layer 331 var RECL = RCL / (LR * ICL) //Evaporative resistance of clothing (icl=.45) 332 EMAX = (FindSaturatedVaporPressureTorr(TempSkin) - VaporPressure) / (REA + RECL) 333 var PRSW = ERSW / EMAX 334 PWET = 0.06 + 0.94*PRSW 335 var EDIF = PWET*EMAX - ERSW 336 ESK = ERSW + EDIF 337 //if (TIM == 60) 338 // printf("aqa\n"); 339 if PWET > WCRIT { 340 PWET = WCRIT 341 PRSW = WCRIT / 0.94 342 ERSW = PRSW * EMAX 343 EDIF = 0.06 * (1.0 - PRSW) * EMAX 344 ESK = ERSW + EDIF 345 } 346 if EMAX < 0 { 347 EDIF = 0 348 ERSW = 0 349 PWET = WCRIT 350 PRSW = WCRIT 351 ESK = EMAX 352 } 353 ESK = ERSW + EDIF 354 //printf("%d\t%f\n", TIM, ESK); 355 MSHIV = 19.4 * COLDS * COLDC 356 M = RM + MSHIV 357 ALFA = 0.0417737 + 0.7451833/(SkinBloodFlow+0.585417) 358 } //End iteration 359 360 var HSK = DRY + ESK //Total heat loss from skin 361 var RN = M - WME //Net metabolic heat production 362 var ECOMF = 0.42 * (RN - (1. * METFACTOR)) 363 if ECOMF < 0.0 { 364 ECOMF = 0.0 //From Fanger 365 } 366 EMAX = EMAX * WCRIT 367 var W = PWET 368 var PSSK = FindSaturatedVaporPressureTorr(TempSkin) 369 var CHRS = CHR //Definition of ASHRAE standard environment 370 //... denoted “S” 371 var CHCS float64 372 if MET < 0.85 { 373 CHCS = 3.0 374 } else { 375 CHCS = 5.66 * math.Pow((MET-0.85), 0.39) 376 CHCS = math.Max(CHCS, 3.0) 377 } 378 var CTCS = CHCS + CHRS 379 var RCLOS = 1.52/((MET-WME/METFACTOR)+0.6944) - 0.1835 380 var RCLS = 0.155 * RCLOS 381 var FACLS = 1.0 + KCLO*RCLOS 382 var FCLS = 1.0 / (1.0 + 0.155*FACLS*CTCS*RCLOS) 383 const IMS = 0.45 384 var ICLS = IMS * CHCS / CTCS * (1. - FCLS) / (CHCS/CTCS - FCLS*IMS) 385 var RAS = 1.0 / (FACLS * CTCS) 386 var REAS = 1.0 / (LR * FACLS * CHCS) 387 var RECLS = RCLS / (LR * ICLS) 388 var HD_S = 1.0 / (RAS + RCLS) 389 var HE_S = 1.0 / (REAS + RECLS) 390 //SET determined using Newton’s iterative solution 391 const DELTA = .0001 392 var dx = 100.0 393 var SET, ERR1, ERR2 float64 394 var SET_OLD = TempSkin - HSK/HD_S //Lower bound for SET 395 for math.Abs(dx) > .01 { 396 ERR1 = (HSK - HD_S*(TempSkin-SET_OLD) - W*HE_S*(PSSK-0.5* 397 FindSaturatedVaporPressureTorr(SET_OLD))) 398 ERR2 = (HSK - HD_S*(TempSkin-(SET_OLD+DELTA)) - W*HE_S*(PSSK-0.5* 399 FindSaturatedVaporPressureTorr((SET_OLD+DELTA)))) 400 SET = SET_OLD - DELTA*ERR1/(ERR2-ERR1) 401 dx = SET - SET_OLD 402 SET_OLD = SET 403 } 404 return SET 405 } 406 407 func FindSaturatedVaporPressureTorr(T float64) float64 { 408 //Helper function for pierceSET calculates Saturated Vapor Pressure (Torr) at Temperature T (°C) 409 return math.Exp(18.6686 - 4030.183/(T+235.0)) 410 }