Inkjet Trajectories
Quick Start
This is a basic simulation of inkjet drop trajectories from a moving head (or a moving substrate) and how they depend on velocity, drop size and working distance.
Credits
The app is based on core papers by Rodriguez-Rivero et. al. 1 and Ivan Arango et. al.2
Trajectories
//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 = {
H: sliders.SlideH.value * 1e-3, //mm to m
D: sliders.SlideD.value * 1e-6, //μm to m
DV: sliders.SlideDV.value,
HV: sliders.SlideHV.value,
Vflow: sliders.SlideVflow.value,
rho: sliders.Sliderho.value * 1000, //g/cc to kg/m3
theta: sliders.Slidetheta.value * Math.PI / 180, //deg to radians
Invert: document.getElementById('Invert').checked,
Remove: document.getElementById('Remove').checked,
};
//Send inputs off to CalcIt where the names are instantly available
//Get all the resonses as an object, result
const result = CalcIt(inputs);
document.getElementById('Data').value = result.Data;
if (result.plots) {
for (let i = 0; i < result.plots.length; i++) {
plotIt(result.plots[i], result.canvas[i]);
}
}
//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({ H, D, DV, HV,Vflow, rho, theta ,Invert,Remove}) {
const AF = 0.1806, BF = 0.6459, CF = 0.4251, DF = 6880.95 //For drag coeff calc
const rhoair = 1.2 //kg/m3 of drop then air
const g = 9.81, dt = 0.00002 //Timestep seems OK
let t = 0, PH = 0, PV = H, VH = 0, VV = DV
const r = D / 2
const pl = 4 / 3 * Math.PI * Math.pow(r, 3) * 1e15
const ReP = 2 * r / 1.8e-5 //Pre-reynolds number - Diameter/Air Viscosity
const m = 4 / 3 * Math.PI * Math.pow(r, 3) * rho //Mass of the drop
const mgh = m * g * Math.sin(theta), mgv = m * g * Math.cos(theta)
const A = Math.PI * r * r, Afact = A / 2 * rhoair //Cross sectional area and drag factor
let Dxy = [{ x: 0 * 1000, y: H * 1000 }], Hav = 0, HVnet,VVnet, Re
if (Invert) {VH=HV;Hav=VH} else {Remove=false} //Don't allow Remove if not Invert
//An alternative formula for CD is
//CDv = 24 / Re * Math.pow(1 + 0.27 * Re, 0.43) + 0.47 * (1 - Math.exp(-0.04 * Math.pow(Re, 0.38)))
//The results were found to be very similar
while (t < 1 && PV > 0) {
//Horizontal component
HVnet = (Hav - VH)
Re = Math.max(0.0001, Math.abs(ReP * HVnet))
CDv = 24 / Re * (1 + AF * Math.pow(Re, BF)) + CF / (1 + DF / Re)
FH = Afact * CDv * HVnet * HVnet + mgh
dHdt = FH / m * dt
VH += Math.sign(Hav) * dHdt
PH += VH * dt
//Vertical component
Re = Math.max(0.0001, Math.abs(ReP * VV))
CDv = 24 / Re * (1 + AF * Math.pow(Re, BF)) + CF / (1 + DF / Re)
VVnet=VV-Vflow
FV = -Afact * CDv * VVnet * VVnet + mgv
dVdt = FV / m * dt
VV += dVdt
PV -= VV * dt
t += dt
if (Remove){
Dxy.push({ x: (PH-HV*t) * 1000, y: PV * 1000 })
} else {
Dxy.push({ x: PH * 1000, y: PV * 1000 })
}
if (Invert){
Hav = Math.pow(PV / H, 1) * HV
} else {
Hav = Math.pow((H - PV) / H, 1) * HV
}
}
const offs=Dxy[Dxy.length-1].x
//Now set up all the graphing data detail by detail.
let plotData = [Dxy], lineLabels = ["Drops"]
const prmap = {
plotData: plotData, //An array of 1 or more datasets
lineLabels: lineLabels, //An array of labels for each dataset
hideLegend: true, //Set to true if you don't want to see any labels/legnds.
xLabel: 'x&mm', //Label for the x axis, with an & to separate the units
yLabel: 'y&mm', //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,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
yMinMax: [0,], //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
};
//Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot
return {
Data: "Vol=" + pl.toFixed(0) + "pl, t=" + (t * 1e6).toFixed(0) + "μs, V=" + (VV.toFixed(1)) + "m/s, Offs="+offs.toPrecision(3)+"mm",
plots: [prmap],
canvas: ['canvas'],
};
}
An inkjet drop of diameter D exits a nozzle at velocity DV, printing across a gap H at a head velocity HV. The coordinate system defines the head vertically above the substrate, so gravity is set via an angle input (hint, head orientation makes almost no difference).
Although the head is moving relative to the substrate, it's more normal to think of a stationary head and a moving substrate.
The drop is slowed down by drag in the vertical direction and shifted horizontally by the Couette flow (linear increase in velocity) from the moving substrate. The final horizontal displacement is seen in the graph and the data output provides the time taken, the final (vertical) drop velocity and the volume of the drop for reference.
The calculation proceeds in time steps to determine the drag forces in each direction. For cross sectional area A in air of density ρ, velocity V, the Force, F is given by:
`F=CD(Aρ)/2V^2`
The acceleration of the particle of mass m (from `m=(4π)/3r^3ρ_"drop"`) is simply:
`"δV"/"δt"=F/m`
For each time step δt the velocity increases by `"δV"/"δt""δt"`.
Drag coefficient
The drag coefficient, CD, is often assumed to be the typical constant used for a sphere, 0.5. In fact it depends strongly on the Reynolds number and smaller particles experience much more relative drag than larger ones. For a particle of diameter D, velocity U in air with viscosity η, the Reynolds number is:
`Re=(UD)/η`
The drag coefficient implemented here depends on Re and four coefficients: A=0.1806, B=0.6459, C=0.4251, D=6880.95:
`CD=24/(Re)(1+A.(Re)^B)+C/(1+D/(Re))`
Other equations are available but give similar results over the relevant range.
Head versus Substrate motion
Some like to study a fixed head with a moving substrate (the default here because of the Rodriguez-Rivero approach) and others the "Inverted" option of moving head and fixed substrate. In the Inverted case, a drop that travelled "straight" would go in a diagonal line relative to the substrate so the plot is dominated by the relative head velocity. In Fig 9 of the Arango paper, a large 150pl drop travels in almost a straight line, while the 6pl drop is highly curved. If you select the "Remove relative head" option you can see the "real" flight of the drop. Both views have their uses.
VFlow
If a vertical air flow can be created from the head down to substrate then the effective air resistance decreases and drop offset is reduced. This is one of many possible fixes for the problems caused by the head motion, but each "fix" adds extra problems as air flows interact in complex manners.
Rodriguez-Rivero, C., Castrejon-Pita, J.R., Hutchings, I.M., Aerodynamic effects in industrial inkjet printing. J. Imaging Sci. Technol. 59(4), 40401–1 (2015)
Ivan Arango, Leonardo Bonil, David Posada, Javier Arcila, Prediction of a flying droplet landing over a non‑flat substrates for ink‑jet applications, IJIDeM,2019, 13:967–980