Heat

Heat Seal

Quick Start

Heat sealing is much used in the packaging industry. Here we can simulate a jaw heat seal system with (up to) 3 layers on each side. It takes into account thermal contact resistance and allows you to cool the seal afterwards.

Credits

This is an update to a version in Practical Webhandling written a long time ago using a less elegant computational infrastructure.

Heat Sealing

T Jaws °C
T Seal °C
Seal Time s
Cooling time s
Air velocity
Pressure MPa
Substrate μm
Substrate K W/mK
Polymer μm
Polymer K W/mK
Seal μm
Seal K W/mK
hStep μm
tStep μs
Show Layers
Do Cooling
tSeal : Tmax
Tend tcross
//One universal basic required here to get things going once loaded
window.onload = function () {
    //restoreDefaultValues(); //Un-comment this if you want to start with defaults
    Main();
};

//Main() is hard wired as THE place to start calculating when inputs change
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
    //Save settings every time you calculate, so they're always ready on a reload
    saveSettings();
    //Send all the inputs as a structured object
    //If you need to convert to, say, SI units, do it here!
    const inputs = {
        TJaws: sliders.SlideTJaws.value,
        TSeal: sliders.SlideTSeal.value,
        tMax: sliders.SlidetMax.value,
        hSubstrate: sliders.SlidehSubstrate.value,
        hPolymer: sliders.SlidehPolymer.value,
        hSeal: sliders.SlidehSeal.value,
        Pressure: sliders.SlidePressure.value,
        hStep: sliders.SlidehStep.value,
        tStepFact: sliders.SlidetStep.value,
        SealK: sliders.SlideSealK.value,
        SubstrateK: sliders.SlideSubstrateK.value,
        PolymerK: sliders.SlidePolymerK.value,
        showLayers: document.getElementById('showLayers').checked,
        doCooling: document.getElementById('doCooling').checked,
        tCool: sliders.SlidetCool.value,
        vAir: sliders.SlidevAir.value,
    };

    //Send inputs off to CalcIt where the names are instantly available
    //Get all the resonses as an object, result
    console.time("time")
    const result = CalcIt(inputs);

    //Set all the text box outputs
    document.getElementById('Info').value = result.Info;
    document.getElementById('Tend').value = result.Tend;
    //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //plotIt is part of the app infrastructure in app.new.js
    if (result.plots) {
        for (let i = 0; i < result.plots.length; i++) {
            plotIt(result.plots[i], result.canvas[i]);
        }
    }
    console.timeEnd("time")
    //You might have some other stuff to do here, but for most apps that's it for Main!
}

//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ TJaws, TSeal, tMax, hSubstrate, hPolymer, hSeal, hStep, Pressure, tStepFact, SealK, SubstrateK, PolymerK, showLayers,doCooling,tCool,vAir }) {

    //Key values
    const ThermCond = { Substrate: SubstrateK, Polymer: PolymerK, Seal:SealK } //W/m.K
    const HeatCapacity = { Substrate: 2000, Polymer: 1800, Seal: 1700 } //J/kg.K
    const MeltPt = { Substrate: 999, Polymer: 999, Seal: TSeal }
    const MPtHt = { Substrate: 999, Polymer: 999, Seal: 4000 }
    const MPtWidth = { Substrate: 999, Polymer: 999, Seal: 15 }
    const Density = { Substrate: 1000, Polymer: 920, Seal: 1000 }

    const xThick = (20 - 20 * Math.min(1,Pressure)) * ThermCond.Substrate / 0.05 //Centred around 0.5MPa and maxes at 1MPa
    let Thick = [hSubstrate + xThick, hPolymer, hSeal, hSeal, hPolymer, hSubstrate + xThick]
    let TC = [ThermCond.Substrate, ThermCond.Polymer, ThermCond.Seal, ThermCond.Seal, ThermCond.Polymer, ThermCond.Substrate]
    let HC = [HeatCapacity.Substrate, HeatCapacity.Polymer, HeatCapacity.Seal, HeatCapacity.Seal, HeatCapacity.Polymer, HeatCapacity.Substrate]
    let Dens = [Density.Substrate, Density.Polymer, Density.Seal, Density.Seal, Density.Polymer, Density.Substrate]
    let MPt = [MeltPt.Substrate, MeltPt.Polymer, MeltPt.Seal, MeltPt.Seal, MeltPt.Polymer, MeltPt.Substrate]
    let MHt = [MPtHt.Substrate, MPtHt.Polymer, MPtHt.Seal, MPtHt.Seal, MPtHt.Polymer, MPtHt.Substrate]
    let MWidth = [MPtWidth.Substrate, MPtWidth.Polymer, MPtWidth.Seal, MPtWidth.Seal, MPtWidth.Polymer, MPtWidth.Substrate]
    const Step = hStep, SealLayer = 2

    let HCT = Create2DArray(Thick.length)
    let HCTC = Create2DArray(Thick.length)
    let LThick = [], NLayers = 0, TotThick = 0, SumThick = [], LTC = [], LHC = []
    let plotData = [], lineLabels = [], myColors = [], borderWidth = [], dottedLine = []
    for (var i = 0; i < Thick.length; i++) {
        if (Thick[i] > 0.99) {
            LThick[NLayers] = Thick[i]
            TotThick += Thick[i]
            SumThick[NLayers] = TotThick
            LTC[NLayers] = TC[i]
            LHC[NLayers] = HC[i] * Dens[i] * 1e-18 //Convert from cubic microns
            for (var j = 25; j <= 300; j++) {
                HCT[NLayers][j] = (HC[i] * (1 + (j - 25) / 300) + MHt[i] * Math.exp(-Math.pow((j - MPt[i]) / MWidth[i], 2))) * Dens[i] * 1e-18
                //Heat capacity is - T offset by 30deg
                HCTC[NLayers][j] = (HC[i] * (1 + (j - 25) / 300) + MHt[i] * Math.exp(-Math.pow((j - (MPt[i] - 30)) / MWidth[i], 2))) * Dens[i] * 1e-18
            }
            NLayers += 1
        };
    };
    //Let's make 1um steps and see what happens
    var GSteps = Math.floor(TotThick / Step)
    var GTC = [], GHC = [], GT = [], TmpT = [], ThisLayer = 0, Seal = 0
    for (var i = 0; i < GSteps; i++) {
        if (i * Step >= SumThick[ThisLayer]) { ThisLayer += 1; if (ThisLayer == SealLayer) Seal = i }
        GTC[i] = LTC[ThisLayer]
        GHC[i] = ThisLayer
        GT[i] = 25;
        TmpT[i] = GT[i]
    };
    GT[0] = TJaws;
    GT[GSteps - 1] = TJaws
    GT[GSteps] = TJaws

    //Now do things in small steps and report them every 0.01s
    let tNow = 0, TShow = 0.01, TStep = 0.000001 * tStepFact, TNext = TShow
    let PPts = [{ x: 0, y: 25 }]
    let JFact = 1e-6 / (Step * Step) //*TStep//Each slice is in microns but units are in m and convert from Watts to J
    let tSeal=0
    while (tNow <= tMax) {
        for (let i = 1; i < GSteps - 1; i++) {
            //This is the logic
            //Flow = ((GT[i - 1] - GT[i]) * GTC[i] - (GT[i] - GT[i + 1]) * GTC[i + 1]) * JFact * TStep
            // TRise = Flow / HCT[GHC[i]][Math.floor(GT[i])]
            // TmpT[i] = GT[i] + TRise
            //This is faster but less obvious
            TmpT[i]= GT[i] + (((GT[i - 1] - GT[i]) * GTC[i] - (GT[i] - GT[i + 1]) * GTC[i + 1]) * JFact * TStep) / HCT[GHC[i]][Math.floor(GT[i])]
       };
        for (let i = 1; i < GSteps - 1; i++) {
            GT[i] = TmpT[i]
        };
        if (GT[Seal]>=TSeal && tSeal==0) tSeal=tNow

        if (tNow >= TNext) {
            let tPts = []
            tPts.push({ x: GT[Math.floor(xThick/Step)], y: 0 })
            for (var i = 1; i < GSteps - 1; i++) {
                iStep = i * Step
                if (iStep > xThick && iStep < TotThick - xThick) {
                    tPts.push({ x: GT[i], y: iStep - xThick })
                }
            };

            PPts.push({ x: tNow, y: GT[Seal] })
            rbow = Rainbow(tNow / tMax); Col = "rgb(" + rbow.r + "," + rbow.g + "," + rbow.b + ")"
            plotData.push(tPts)
            lineLabels.push(tNow.toFixed(2) + "s")
            myColors.push(Col)
            borderWidth.push(2)
            dottedLine.push(false)
            TNext += TShow
        }
         tNow += TStep
    } //Big While
    if (tSeal==0) {tSeal="n/a"} else {tSeal=tSeal.toFixed(3)+"s"}
    // //Just in case didn't reach TMax step
    PPts.push({ x: tMax, y: GT[Seal] })
    if (showLayers) {
        //Dotted lines
        const theTop = 0
        yPos = Thick[0] - xThick + Thick[1] + Thick[2]
        makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, "Seal")
        yPos = Thick[0] - xThick
        makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, "SubstratePoly")
        yPos = Thick[0] - xThick + 2 * Thick[1] + 2 * Thick[2]
        makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, "SubstratePoly")
        yPos = Thick[0] - xThick + Thick[1]
        makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, "PolySeal")
        yPos = Thick[0] - xThick + Thick[1] + 2 * Thick[2]
        makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, "PolySeal")
    }
    const sealMax=GT[Seal]
    let tCross=0
    tCool=doCooling?tCool:0
    if (doCooling) {
    	var TC0 = 1.103110087, TC1 = 0.14739637, TC2 = -0.000958993, TC3 = 2.34e-06
    	var BC0 = TC0, BC1 = TC1, BC2 = TC2, BC3 = TC3
    	var AirFact = vAir/3*0.000025 / Step
        TStep = 0.00004
    	while (tNow <= tMax+tCool) {
    		for (var i = 1 ; i < GSteps - 1; i++) {
                //The condensed version for speed
    			TmpT[i] = GT[i] + ((GT[i - 1] - GT[i]) * GTC[i] - (GT[i] - GT[i + 1]) * GTC[i + 1]) * JFact * TStep / HCTC[GHC[i]][Math.floor(GT[i])]
    		};
    		//Now the top and bottom layers
    		Flow = (-(GT[0] - GT[ 1]) * GTC[1] - AirFact * (TC0 + TC1 * GT[0] + TC2 * GT[[0]] * GT[[0]] + TC3 * GT[[0]] * GT[[0]] * GT[[0]]) * (GT[[0]] - 25)) * JFact * TStep
    		TRise = Flow / HCTC[GHC[[0]]][Math.floor(GT[[0]])]
    		TmpT[[0]] = GT[[0]] + TRise
    		Flow = ((GT[GSteps-2] - GT[GSteps-1]) * GTC[GSteps-1] - AirFact * (BC0 + BC1 * GT[GSteps-1] + BC2 * GT[GSteps-1] * GT[GSteps-1] + BC3 * GT[GSteps-1] * GT[GSteps-1] * GT[GSteps-1]) * (GT[GSteps-1] - 25)) * JFact * TStep
    		TRise = Flow / HCTC[GHC[GSteps-1]][Math.floor(GT[GSteps-1])]
    		TmpT[GSteps-1] = GT[GSteps-1] + TRise

    		for (var i = 0; i < GSteps; i++) {
    			GT[i] = TmpT[i]
            };
            if (GT[Seal]<=TSeal && tSeal!="n/a" && tCross==0) tCross=tNow-tMax //Relative to start of cooling
    		if (tNow >= TNext) {
                PPts.push({ x: tNow, y: GT[Seal] })
                TNext += TShow
    		}
    		tNow += TStep
    	} //Big While
    	//Just in case didn't reach TMax step
        PPts.push({ x: tMax+tCool, y: GT[Seal] })
        if (tCross==0) {tCross="n/a"} else {tCross=tCross.toFixed(2)+"s"}

    }//End of cooling
    const PPtsSeal=[{x:0,y:TSeal},{x:tMax+tCool,y:TSeal}]

    //Now set up all the graphing data.
    //We use the amazing Open Source Chart.js, https://www.chartjs.org/
    //A lot of the sophistication is addressed directly here
    //But if you need something more, read the Chart.js documentation or search Stack Overflow

    //Now set up all the graphing data detail by detail.
    const prmap = {
        plotData: plotData, //An array of 1 or more datasets
        lineLabels: lineLabels, //An array of labels for each dataset
        colors: myColors, //An array of colors for each dataset
        dottedLine: dottedLine,
        borderWidth: borderWidth,
        hideLegend: true,
        xLabel: 'T&°C', //Label for the x axis, with an & to separate the units
        yLabel: 'z&μm', //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [,Math.ceil(TotThick-2*xThick)], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'F0', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'F0', //F for Fixed, P for Precision, E for exponential
    };
    const prmap1 = {
        plotData: [PPts,PPtsSeal], //An array of 1 or more datasets
        lineLabels: ["T @ Seal","Seal T"], //An array of labels for each dataset
        dottedLine: [false,true],
        hideLegend: true,
        xLabel: 't&s', //Label for the x axis, with an & to separate the units
        yLabel: 'T&°C', //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [0, tMax+tCool], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [20,TJaws], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'F3', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'F0', //F for Fixed, P for Precision, E for exponential
    };


    //Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot
    return {
        Info: tSeal+ " : "+ sealMax.toFixed(0) + "°",
        Tend: doCooling ? GT[Seal].toFixed(0) + "°  " + tCross:"-",
        plots: [prmap, prmap1],
        canvas: ['canvas', 'canvas1'],
    };
}
function makeDotted(plotData, lineLabels, myColors, borderWidth, dottedLine, yPos, TJaws, hStep, theTop, theLabel) {
    let tPts = []
    yPos-=hStep
    tPts.push({ x: 20, y: yPos }, { x: TJaws, y: yPos })
    plotData.push(tPts)
    lineLabels.push(theLabel)
    myColors.push("rgba(2,100,100,0.5)")
    borderWidth.push(1)
    dottedLine.push(true)
}

function Create2DArray(rows) {
    var arr = [];
    for (var i = 0; i < rows; i++) {
        arr[i] = [];
    }
    return arr;
}
var RB = [[0, 48, 245], [0, 52, 242], [0, 55, 238], [0, 59, 235], [3, 62, 231], [9, 66, 228], [14, 69, 225], [18, 72, 221], [20, 74, 218], [22, 77, 214], [23, 80, 211], [24, 82, 207], [25, 85, 204], [25, 87, 200], [25, 90, 197], [25, 92, 193], [25, 94, 190], [25, 96, 187], [24, 99, 183], [24, 101, 180], [24, 103, 177], [23, 105, 173], [23, 106, 170], [24, 108, 167], [24, 110, 164], [25, 112, 160], [27, 113, 157], [28, 115, 154], [30, 117, 151], [32, 118, 148], [34, 120, 145], [36, 121, 142], [39, 122, 139], [41, 124, 136], [43, 125, 133], [45, 126, 130], [47, 128, 127], [49, 129, 124], [51, 130, 121], [53, 132, 118], [54, 133, 115], [56, 134, 112], [57, 136, 109], [58, 137, 106], [59, 138, 103], [60, 139, 99], [61, 141, 96], [62, 142, 93], [62, 143, 90], [63, 145, 87], [63, 146, 83], [64, 147, 80], [64, 149, 77], [64, 150, 74], [65, 151, 70], [65, 153, 67], [65, 154, 63], [65, 155, 60], [66, 156, 56], [66, 158, 53], [67, 159, 50], [68, 160, 46], [69, 161, 43], [70, 162, 40], [71, 163, 37], [73, 164, 34], [75, 165, 31], [77, 166, 28], [79, 167, 26], [82, 168, 24], [84, 169, 22], [87, 170, 20], [90, 171, 19], [93, 172, 18], [96, 173, 17], [99, 173, 17], [102, 174, 16], [105, 175, 16], [108, 176, 16], [111, 176, 16], [114, 177, 17], [117, 178, 17], [121, 179, 17], [124, 179, 18], [127, 180, 18], [130, 181, 19], [132, 182, 19], [135, 182, 20], [138, 183, 20], [141, 184, 20], [144, 184, 21], [147, 185, 21], [150, 186, 22], [153, 186, 22], [155, 187, 23], [158, 188, 23], [161, 188, 24], [164, 189, 24], [166, 190, 25], [169, 190, 25], [172, 191, 25], [175, 192, 26], [177, 192, 26], [180, 193, 27], [183, 194, 27], [186, 194, 28], [188, 195, 28], [191, 195, 29], [194, 196, 29], [196, 197, 30], [199, 197, 30], [202, 198, 30], [204, 199, 31], [207, 199, 31], [210, 200, 32], [212, 200, 32], [215, 201, 33], [217, 201, 33], [220, 202, 34], [223, 202, 34], [225, 202, 34], [227, 203, 35], [230, 203, 35], [232, 203, 35], [234, 203, 36], [236, 203, 36], [238, 203, 36], [240, 203, 36], [241, 202, 36], [243, 202, 36], [244, 201, 36], [245, 200, 36], [246, 200, 36], [247, 199, 36], [248, 197, 36], [248, 196, 36], [249, 195, 36], [249, 194, 35], [249, 192, 35], [250, 191, 35], [250, 190, 35], [250, 188, 34], [250, 187, 34], [250, 185, 34], [250, 184, 33], [250, 182, 33], [250, 180, 33], [250, 179, 32], [249, 177, 32], [249, 176, 32], [249, 174, 31], [249, 173, 31], [249, 171, 31], [249, 169, 30], [249, 168, 30], [249, 166, 30], [248, 165, 29], [248, 163, 29], [248, 161, 29], [248, 160, 29], [248, 158, 28], [248, 157, 28], [248, 155, 28], [247, 153, 27], [247, 152, 27], [247, 150, 27], [247, 148, 26], [247, 147, 26], [246, 145, 26], [246, 143, 26], [246, 142, 25], [246, 140, 25], [246, 138, 25], [245, 137, 24], [245, 135, 24], [245, 133, 24], [245, 132, 24], [244, 130, 23], [244, 128, 23], [244, 127, 23], [244, 125, 23], [244, 123, 22], [243, 121, 22], [243, 119, 22], [243, 118, 22], [243, 116, 21], [242, 114, 21], [242, 112, 21], [242, 110, 21], [241, 109, 21], [241, 107, 21], [241, 105, 21], [241, 103, 21], [240, 101, 21], [240, 100, 22], [240, 98, 22], [240, 96, 23], [240, 95, 24], [240, 93, 26], [240, 92, 27], [240, 90, 29], [240, 89, 31], [240, 88, 33], [240, 87, 36], [240, 87, 38], [241, 86, 41], [241, 86, 44], [242, 86, 47], [242, 86, 51], [243, 86, 54], [243, 87, 58], [244, 88, 62], [245, 88, 65], [245, 89, 69], [246, 90, 73], [247, 91, 77], [247, 92, 82], [248, 94, 86], [249, 95, 90], [249, 96, 94], [250, 97, 98], [251, 99, 102], [251, 100, 106], [252, 101, 111], [252, 103, 115], [253, 104, 119], [253, 105, 123], [254, 107, 128], [254, 108, 132], [255, 109, 136], [255, 111, 140], [255, 112, 145], [255, 114, 149], [255, 115, 153], [255, 116, 157], [255, 118, 162], [255, 119, 166], [255, 120, 170], [255, 122, 175], [255, 123, 179], [255, 125, 183], [255, 126, 188], [255, 127, 192], [255, 129, 196], [255, 130, 201], [255, 132, 205], [255, 133, 210], [255, 134, 214], [255, 136, 219], [255, 137, 223], [255, 139, 227], [255, 140, 232], [255, 141, 236], [254, 143, 241], [254, 144, 245], [253, 146, 250]]
function Rainbow(v) {
    var i = Math.floor((Math.min(v, 1), Math.max(v, 0)) * 255)
    r = RB[i][0]
    g = RB[i][1]
    b = RB[i][2]
    return { r: r, g: g, b: b }
}
                

The basic calculation takes your chosen jaws temperature (assumed equal top and bottom) T Jaws, Seal temperature T Seal, and the thicknesses μm of substrate (which might be a paper or heat-resistant polymer), intermediate polymer (set to 0 if you have a 2-layer system) and the seal polymer itself, then calculates the temperature distribution over timesteps up to your chosen Seal Time. The thermal conductivities W/m.K are also required. Heat capacities are assumed to be "normal".

These models need to cut the stack into individual layers of thickness hStep and divide time into small slices of size tStep. Bigger h slices are faster to calculate but potentially less accurate. Smaller t slices are slower. The combination of big h and big t can lead the calculations to "blow up" (large temperature gradients can also blow up) so find a pair of settings that are fast enough and accurate enough for your specific setup.

The main graph uses rainbow colours (blue-->red) to show the different timesteps, the x axis is temperature and y is your stack. Moving the mouse gives you time, position and temperature information. You also get a graph of the temperature at the point where the two seal layers meet. Your chosen seal temperature is shown as a dotted line and the time taken to reach it is included in the information box, along with maximum temperature.

If you select the Layers option, dotted lines show the intersections between substrate/polymer, polymer/seal and seal/seal.

The jaws make imperfect contact with the substrate surface, resulting in a "thermal contact resistance". The resistance depends on the applied pressure, currently simulated via the Pressure slider with 1 being low pressure, poor contact, to 10 being high pressure, good contact. The internal calculations translate the resistance into an extra thickness of substrate which is then assumed to make perfect contact with the jaws. This is an elegant trick found in the literature.

Cooling

Air cooling is very inefficient and the seal can remain above the seal temperature for a long time, risking damage from stresses after exiting the sealing zone. Turning on the Cooling option lets you see the cooling in the graph and providing the final temperature at the seal and also, if relevant, the time (from release of the jaws) taken to cross back over the seal temperature. Given the many uncertainties of air cooling, a "standard" rate is assumed at an air "velocity" set to 3, with cooling 3x slower at 1 and 3x faster at 9.

Numerics, accuracy, convenience

As mentioned above with all numerical simulations there is a trade-off of speed and accuracy along with the possibility of the numerics blowing up, the result being either no graph or obvious graph artefacts. The hStep slider controls the thickness of individual computed layers. Thinner is slower, more accurate and more likely to blow up. The tStep slider alters the time steps (μs), with smaller being slower, more accurate and less likely to blow up.

The best approach is to start with hStep as 2 or 3μm and tStep as 5 to 10 μs while you set up your system and explore the effects of large changes. When you are more interested in details, reduce hStep and, if neccesary tStep. If you see any changes then decrease either/both till there are no more obvious changes.

Visit my YouTube Logo channel for more Practical Science videos