
To calculate the glideslope deviation we must first transfer the point of reference (from which we determine the aircraft's position) from the localiser to the point of touchdown. This is to determine the distance 'x' which is the aircraft's effective distance out along the extended runway centre line.
We then switch to the vertical view and use 'x' and the aircraft's height to find the aircraft's current angle-of-approach to the point of touchdown. We then compare this with the runway's prescribed glideslope angle to find the glideslope error.
The glide slope transmitter near the runway touch-down point sends up a pair of radio beams at angles such that they have equal strength along the plane of the approach glide slope. The plane of the glide slope tilts upwards at an appropriate glide slope angle 't->GS' from the point of touch-down on the runway:

The glide slope error, GsErr is the angular difference (a - t->GS) by which the aircraft is above or below the glide-slope plane. This glideslope error signal is received by the NAV receiver when it is within 30km of the glideslope transmitter.
To be able automatically to bring the aircraft on to the glide slope smoothly we must calculate the 'required angle of descent' as shown in the above diagram:
double ReqDes(struct TxData *t, struct RxData *r) {
#define FlairHeight .0000015 //~9.55 metres in Earth radians
double
Hdev, //aircraft's angular displacement from runway centre line
ReqDes, //Required angle of descent
gs, //runway's glideslope angle
GsErr, //linear version of glideslope error
RunLen = t->Len; //runway length
if(Air.Ht < FlairHeight) { //If aircraft now below flairout height, advance touchdown
RunLen *= .75; gs = 0; //point 1/4 way down runway and set glideslope angle to 0
} else gs = t->GS; //use runway's actual glideslope angle
Hdev = BipAng( t->Brg - r->ISR ); //aircraft's angular displacement from runway centre line
/*If the aircraft's distance along the extended runway centre
line from the current point of touchdown is non-zero... */
if((double x = (double D = t->Dst) * cos(Hdev)) - RunLen) != 0 ) {
/*Compute the glide slope error both as a linear angular
quantity and stored in RxData as an appropriately scaled
instrument needle deviation. */
r->GsErr = GetDev(GsErr = BipAng(double a = atan(Air.Ht / x)) - gs));
double y = D * sin(Hdev); //Compute perpendicular distance to runway line
r->DstTD = sqrt(x * x + y * y); //Computer distance to the touchdown point
ReqDes = BipAng(a + GsErr); //required angle of descent
}
else {
r->GsErr = 0; //glideslope error indication
r->DstTD = 0; //distance to touchdown point
ReqDes = 0; //required angle of descent
}
return(ReqDes); //return required angle of descent
}
When the aircraft is only a few metres above the runway, it ceases to descend at the normal fixed glideslope angle, gradually reducing its angle of descent to zero in order to make a smooth landing. This is called 'flair-out'.

The function ReqDes() performs this flair-out by shifting the touchdown point a quarter of the way down the runway and changing the glideslope angle to zero once the aircraft has gone below the critical height 'FlairHeight'. The damping effect of the way GsErr is computed causes the aircraft to make a smooth curved intercept with the surface of the runway.

Assuming automatic trim etc., the angle of descent is mainly a function of the aircraft's pitch and air speed. For the most part, airspeed would not be used to actually control the angle of descent. To control the angle of descent, we are therefore concerned only with changing pitch by a small amount 'dPitch' to counter the 'error' in angle of descent, DesErr = ReqDes - Air.Des. We shall make the amount by which we change the pitch proportional to DesErr:
dPitch = K1 * ( ReqDes - Air.Des );
Because the aircraft is a large finite object with physical limitations, we must impose an upper limit, RopLim, on the rate at which we can safely change the pitch. RopLim is the limit for the rate of change of pitch and is in radians per second. The limit to which we can change pitch during the elapsed time between program passes is therefore RopLim * et radians. Therefore in response to a given angle of descent error, we update the aircraft's pitch as follows to bring the aircraft smoothly on to its correct descent path:
Air.Pitch += LimAng(K1 * BipAng(ReqDes - Air.Des), RopLim * et);
But there must be an upper limit, PitchLim, to the actual pitch itself. We must therefore split the above statement into two as follows:
dPitch = LimAng(K1 * BipAng(ReqDes - Air.Des), RopLim * et);
Air.Pitch = LimAng(BipAng(Air.Pitch + dPitch), MaxPitch);
The change in angle of descent is proportional to the change in pitch. We can therefore return a change in angle of descent as PitchDes * dPitch. The complete function for determining the change in angle of descent effected by the airframe and flight control systems in response to a given the angle of descent error is:
double GetdDes(double et, double DesErr) {
#define PitchDesErr .03 //change in pitch per unit angle of descent error
#define RopLim .01 //rate of change of pitch limit in radians per second
#define MaxPitch .5 //maximum permitted pitch in radians
#define DesPitch 1.00 //change in Air.Des per unit change in Air.Pitch
dPitch = LimAng(K1 * BipAng(ReqDes(t, r) - Air.Des), RopLim * et);
Air.Pitch = LimAng(BipAng(Air.Pitch + dPitch), MaxPitch);
return(DesPitch * dPitch);
}
This function is our 'dummy' standing in place of a complete airframe simulation which would compute the change in angle of descent from pitch, trim, thrust, and the many other variables affecting the result in a real aircraft.
The whole vertical steering task is managed by the following function which from the required angle of descent and the actual angle of descent updates the aircraft's current height and angle of descent:
VertSteer(struct TxData *t, struct RxData, *r, double et) {
//Compute angle of descent error. Store it also as a non-linear instrument deviation.
r->DesErr = GetDev(double DesErr = BipAng(ReqDes(t, r) - Air.Des));
/*Compute required incremental change in angle of descent
since previous pass, then update aircraft's angle of
descent and hence its height since previous pass. Note
that Air.Spd is the aircraft's horizontal ground track
speed. Hence tan(). */
Air.Ht -= Air.Spd * et * tan(Air.Des = RatAng(Air.Des + GetdDes(et, DesErr)));
}