Scott Mobley
11 years ago
2 changed files with 290 additions and 0 deletions
@ -0,0 +1,289 @@
@@ -0,0 +1,289 @@
|
||||
function TurkeyLayer( name, layerNumber1, turkeyModel, ovenModel ){ |
||||
var that = this; |
||||
|
||||
this.name = name; |
||||
this.layerNumber=layerNumber1; |
||||
this.waterLost = 0; |
||||
this.finalTemperature = 20; |
||||
this.cookCondition = "Raw"; |
||||
|
||||
return { |
||||
updateTemperatureTick: function(){ |
||||
that.finalTemperature = turkeyModel.globTemp[that.layerNumber] |
||||
console.log(turkeyModel.globTemp) |
||||
that.waterLost = that.waterLost + UtilityFunctions.waterLoss( that.finalTemperature ); |
||||
that.cookCondition = UtilityFunctions.cookCondition(that.waterLost); |
||||
if(DEBUG) console.log( that.name + ": "+ that.waterLost + " " + that.cookCondition + " " + that.finalTemperature + " C" ); |
||||
}, |
||||
getCondition: function(){ |
||||
return that.cookCondition; |
||||
}, |
||||
getTemperature: function(){ |
||||
return that.finalTemperature; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
function TurkeyModel( weight, ovenModel ){ |
||||
this.density = 700; // kg/m3 Assuming Density of Water 1000 kg/m3
|
||||
this.cp = 2810; // 2810 J/kg K for Turkey. Extra is to semi-account for water evaporation energy
|
||||
this.heatConvection = 9; // W/m2 K Some Reasonable estimate for natural Convection. Change as needed. 5-25
|
||||
this.thermalConduct = 0.412; // W/m K // Chicken
|
||||
this.skin = {}; |
||||
this.body = {}; |
||||
this.core = {}; |
||||
this.splitsNum = 20; |
||||
console.log(UtilityFunctions.lbs2kgs(weight)) |
||||
this.totalRadius = UtilityFunctions.calculateRadius( UtilityFunctions.lbs2kgs(weight), this.density ); |
||||
|
||||
|
||||
this.totalLayers = [ new TurkeyLayer("Skin", this.splitsNum-1, this, ovenModel ), |
||||
new TurkeyLayer("Body", this.splitsNum-4, this, ovenModel ), |
||||
new TurkeyLayer("Core", 0, this, ovenModel ) ]; |
||||
|
||||
// Whenever temperature is changed
|
||||
this.updateLayerTemps = function() { |
||||
this.globTemp = UtilityFunctions.transientSphereSeries( this.density, |
||||
this.thermalConduct, |
||||
this.heatConvection, |
||||
this.cp, |
||||
this.totalRadius, |
||||
ovenModel.tempInfini, |
||||
this.splitsNum, |
||||
this.deltar, |
||||
this.globTemp, |
||||
this.pointRadius |
||||
); |
||||
for (var i in this.totalLayers ){ |
||||
this.totalLayers[i].updateTemperatureTick(); |
||||
} |
||||
}; |
||||
|
||||
this.resetLayerTemps = function() { |
||||
for (var i in this.totalLayers ) { |
||||
this.totalLayers[i].resetLayerTemps(); |
||||
} |
||||
}; |
||||
|
||||
//Sheen Model Stuff
|
||||
this.globTemp=[]; |
||||
this.pointRadius = [] |
||||
this.splitsNum = 20; |
||||
this.deltar = this.totalRadius/this.splitsNum; //20 Data Points
|
||||
|
||||
this.initializePoints = function() { |
||||
var step = ( this.totalRadius - this.deltar ) / ( this.splitsNum - 1 ); |
||||
for (var i = 0; i<this.splitsNum ; i++ ) { |
||||
this.pointRadius.push(step*i+this.deltar); |
||||
this.globTemp.push(20+step*i); //Starts at 20 C for initilizating
|
||||
}
|
||||
}; |
||||
this.initializePoints() |
||||
|
||||
|
||||
} |
||||
|
||||
function OvenModel( turkeyWeight, gameState ) { |
||||
var that = this; |
||||
this.tempInfini=20; //C
|
||||
this.setTemp = 20; |
||||
this.globalTime = 0; |
||||
|
||||
var turkey = new TurkeyModel(turkeyWeight, this ); |
||||
var proportional = 0.004; // This value is arbitrary to how fast you want the temperatures to converge. (Or oscillate, which could be realistic as well)
|
||||
var errorTolerance = 10; //Stove is accurate to 1 degree Celcius Should hopefully oscillate below that value.
|
||||
// Equalize temp will need to be sent each time iteration
|
||||
this.equalizeTemp= function(){ |
||||
var error = Math.abs(this.setTemp-this.tempInfini); |
||||
if( this.setTemp>this.tempInfini ){ |
||||
this.tempInfini = this.tempInfini + error*proportional; |
||||
} |
||||
else if( this.setTemp<this.tempInfini ){ |
||||
this.tempInfini = this.tempInfini - error*proportional; |
||||
} |
||||
|
||||
if( error>errorTolerance ) { |
||||
return(true); |
||||
} |
||||
} |
||||
return { |
||||
getTurkeyState: function(){ |
||||
return { |
||||
"skin" : { |
||||
"temp": turkey.totalLayers[0].getTemperature(), |
||||
"cond": turkey.totalLayers[0].getCondition() |
||||
}, |
||||
"body" : { |
||||
"temp": turkey.totalLayers[1].getTemperature(), |
||||
"cond": turkey.totalLayers[1].getCondition() |
||||
}, |
||||
"core" : { |
||||
"temp": turkey.totalLayers[2].getTemperature(), |
||||
"cond": turkey.totalLayers[2].getCondition() |
||||
} |
||||
}; |
||||
}, |
||||
changeTemp: function(setTemp){ |
||||
if(DEBUG) console.log("temp changed to " + setTemp); |
||||
that.setTemp = setTemp; |
||||
}, |
||||
// set the tempInfini
|
||||
setRawTemp: function(newTemp){ |
||||
if(DEBUG) console.log("raw temp changed to" + that.tempInfini); |
||||
that.tempInfini = newTemp; |
||||
}, |
||||
getRawTemp: function(){ |
||||
return that.tempInfini; |
||||
}, |
||||
getCookTime: function(){ |
||||
return that.globalTime; |
||||
}, |
||||
secondTick: function(){ |
||||
that.globalTime = that.globalTime + 1; |
||||
if ( that.equalizeTemp() ) { |
||||
|
||||
// Turn on oven light
|
||||
gameState.pubsub.publish( "OvenLight", "On" ); |
||||
} |
||||
else { |
||||
// Turn off oven light
|
||||
gameState.pubsub.publish( "OvenLight", "Off" ); |
||||
} |
||||
if(DEBUG) console.log("Oven Temp " + that.tempInfini ) |
||||
turkey.updateLayerTemps(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
UtilityFunctions = { |
||||
|
||||
// Cache the lambda if the Biot number does not change, to avoid expensive root-finding operations
|
||||
cachedBiot: null, |
||||
cachedLambda: null, |
||||
|
||||
// Using Ratios for a rectangular Box Turkey
|
||||
calculateRadius: function(weight, density) { |
||||
|
||||
var ratioLvG=1.4; //1.4, Turkey length vs shoulder girth
|
||||
var ratioLvH=2; //2, Turkey length vs height from resting position
|
||||
|
||||
var length = Math.pow(weight/((1/ratioLvG)*(1/ratioLvH)*density),(1/3)) |
||||
var depth = 1/(ratioLvG /length); |
||||
var height = 1/(ratioLvH /length); |
||||
var simpleRadius = length/2; //Doesn't take into account equal Volume
|
||||
|
||||
var rectangleVolume = depth*height*length; //m^3 Multiple by 1/4 to account for triangular shape and empty Space
|
||||
var complexRadius = Math.pow(rectangleVolume/((4/3)*Math.PI), 1/3); //Volume of 3D Box = 3D Sphere
|
||||
|
||||
//if(DEBUG) console.log("Simple Radius " + simpleRadius + " Meters")
|
||||
//if(DEBUG) console.log("Complex Radius " + complexRadius + " Meters")
|
||||
return complexRadius; |
||||
}, |
||||
|
||||
sphereVolume: function(radius) { |
||||
return((4/3)*Math.PI*Math.pow(radius,3)) |
||||
}, |
||||
|
||||
waterLoss: function(temperature) { |
||||
return (Math.pow(10,(temperature-20)/80)-1) |
||||
}, |
||||
|
||||
transientSphereSeries: function( density, thermalConduct, heatConvection, cp, rTotal, tempInfinity, splitsNum, deltar, globTemp,pointRadius) { |
||||
|
||||
//Not Global Stuff
|
||||
var r0 = rTotal; |
||||
var deltat = 0.1 |
||||
|
||||
var alpha = thermalConduct/(density*cp) |
||||
var h=heatConvection;
|
||||
|
||||
for (var j=0; j<(1/deltat); j++ ) { |
||||
var dTdr=[] |
||||
// globTemp[splitsNum-1] should be last entry in globtemp
|
||||
for (var k=0; k<splitsNum; k++){ |
||||
if (k==0) { |
||||
dTdr.push((globTemp[1] - globTemp[0])/deltar) } |
||||
else if (k==splitsNum-1) { |
||||
dTdr.push((globTemp[splitsNum-1] - globTemp[splitsNum-2])/deltar)} |
||||
else { |
||||
dTdr.push((globTemp[k+1] - globTemp[k-1])/(2*deltar))} |
||||
} |
||||
dTdr[splitsNum-1] = heatConvection*(tempInfinity-globTemp[splitsNum-1])/thermalConduct |
||||
|
||||
var parenthesis = [] |
||||
for (var k=0; k<splitsNum; k++){ |
||||
parenthesis.push(dTdr[k]*pointRadius[k]) |
||||
} |
||||
|
||||
dPdr = [] |
||||
for (var k=0; k<splitsNum; k++){ |
||||
if (k==0) { |
||||
dPdr.push((parenthesis[1] - parenthesis[0])/deltar) } |
||||
else if (k==splitsNum-1) { |
||||
dPdr.push((parenthesis[splitsNum-1] - parenthesis[splitsNum-2])/deltar)} |
||||
else { |
||||
dPdr.push((parenthesis[k+1] - parenthesis[k-1])/(2*deltar))} |
||||
} |
||||
|
||||
for (var k=0; k<splitsNum; k++){ |
||||
globTemp[k]=alpha*dPdr[k]/Math.pow(pointRadius[k],2)*deltat + globTemp[k] //dTdr * deltaT in one loop
|
||||
} |
||||
//dTdt(1)=dTdt(1)/2;
|
||||
} |
||||
console.log("dPdr" + dPdr) |
||||
return(globTemp) |
||||
}, |
||||
|
||||
/* Utility Functions */ |
||||
C2F: function( celsius ){ |
||||
return ( (celsius*(9/5)) + 32 ); |
||||
}, |
||||
F2C: function( farenheit ) { |
||||
return ( (farenheit-32) *(5/9) ); |
||||
}, |
||||
lbs2kgs: function(pounds){ |
||||
return pounds * 0.453592 |
||||
}, |
||||
randRange: function(min, max){ |
||||
return Math.floor(Math.random()*(max-min+1))+min; |
||||
}, |
||||
cookCondition: function(cookValue,volume){ |
||||
var multiplier = 1; |
||||
if (cookValue>=multiplier*600000) { |
||||
return ["Fire", (cookValue-600000)/(multiplier*600000),"fire"]; |
||||
} |
||||
else if(cookValue>=multiplier*250000) { |
||||
return ["Burnt", (cookValue-250000)/(multiplier*600000), "burnt"]; |
||||
} |
||||
else if (cookValue>=multiplier*150000) { |
||||
return ["Dry", (cookValue-150000)/(multiplier*250000), "dry"]; |
||||
} |
||||
else if (cookValue>=multiplier*85000){ |
||||
return ["Cooked", (cookValue-12000)/(multiplier*150000), "overcooked"]; |
||||
} |
||||
else if (cookValue>=multiplier*12000) { |
||||
return ["Cooked", (cookValue-12000)/(multiplier*150000), "cooked"]; |
||||
} |
||||
else if (cookValue>=multiplier*10000){ |
||||
return ["Undercooked", (cookValue-5000)/(multiplier*12000), "slightly cooked"]; |
||||
} |
||||
else if (cookValue>=multiplier*5000) { |
||||
return ["Undercooked", (cookValue-5000)/(multiplier*12000), "undercooked"]; |
||||
} |
||||
else { |
||||
return ["Raw", 1, "raw"]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
//Running the Program Stuff
|
||||
/* |
||||
var ovenObject = new OvenModel(); |
||||
var turkey = new TurkeyModel(9, ovenObject); |
||||
|
||||
globalTime=0; |
||||
setInterval(function(){ovenObject.secondTick();},1000); |
||||
*/ |
Loading…
Reference in new issue