I used the Schreiner equations but just deriving the gas rates from the intended start and finish values and the time.

I felt that as the one thing a rebreather doesn't do well is track the mix on ascent and descent that was near enough.

I wondered about trying to model the real behaviour but as I tend to manually interfere to get it nearer it was pointless.

// Process an CCR ascent or descent

static double ccrtransition(double startDepth, double endDepth, double descentRate, double ppO2)

{

double segTime = (endDepth - startDepth)/descentRate; // time taken

runTime += segTime;

double startPressure = startDepth*m2b + atm;

// OK so we need the pp

double ppInert = startPressure-ppO2-ppWaterVapour;

double rHe=gas[gtable[0].mix].he, rN2=gas[gtable[0].mix].n2(); // fractions

// initial pressures

double ppiHe=rHe*ppInert/(rHe+rN2);

double ppiN2=rN2*ppInert/(rHe+rN2);

// do that again for the end pressures

double endPressure = endDepth*m2b + atm;

double ppI = endPressure-ppO2-ppWaterVapour;

double ppeHe=rHe*ppI/(rHe+rN2);

double ppeN2=rN2*ppI/(rHe+rN2);

double heliumRate = (ppeHe - ppiHe)/segTime; // rate in meters/min

double nitrogenRate = (ppeN2 - ppiN2)/segTime;

// now add it to the compartments using the Schreiner equation

for(int i=0; i<COMPARTMENTS; i++){

comp[i].he = ppiHe + heliumRate*(segTime - 1.0/helium[i].k) - (ppiHe - comp[i].he - heliumRate/helium[i].k)*exp(-helium[i].k*segTime);

comp[i].n2 = ppiN2 + nitrogenRate*(segTime - 1.0/nitrogen[i].k) - (ppiN2 - comp[i].n2 - nitrogenRate/nitrogen[i].k)*exp(-nitrogen[i].k*segTime);

}

return segTime;

}