There is no need for integrals, if you think about it a little, although it may be faster with them.
I'll write out a breif explination of how I'd do this, as I haven't had time to work it out completely yet:
Modify an equation for a circle such that the bottom of the circle is tangent to x=0. The x values are equal to height of the liquid, which is the same as depth. Knowing depth allows one to find the Y values that the circle crosses at the given depth. Once this is accomplished, it is possible to find the angle of the arc from the center point of the cylinder. Finding this area is now quite simple, as it's simply a fraction of a circle. If the Y values are greater than half the depth, simply subtract half the depth and add half the volume of the cylinder to the end result. Once you have the area of the arc of the circle, subtract the area of the triangle to the top of the water. This also isn't hard to find, as you know the width and height of the triangle. Now, multiply by the length of the cylinder to find the volume.
Code and equations will come later if there is a desire to see them.
: As promised, here's the formula.
:
: Taking pi=3.142, the volume of fluid in the tank when the depth reading is d is:
:
V = (1000*(arcsin(d)+d.sqrt(1-d^2))+1570) liters
: where
: d = ((depth sensor reading)-2048)/2048
:
: Now you have to calculate an arcsin and a square root without a math package or a lookup table, and do it without rounding errors to 12 bits of resolution. Solution later.
:
: For those wishing to follow the math, the full derivation is given below.
:
: When the tank is partly filled, a certain D-shaped area of the end wall is covered by liquid. If we know this area, the area multiplied by the length of the tank gives us the volume of liquid.
:
: To simplify the math a little, the D-shaped area could be considered a fraction of the total end area, pi.R^2.
: So,
:
(area fraction) = (area D)/(pi.R^2)
: and
: (liquid volume) = (tank volume) * (area fraction)
: or
: (liquid volume) = (tank volume) * (area of D)/(pi.R^2)
: But (tank volume) is a constant, and so is (pi.R^2), so
:
(liquid volume) = (constant K) * (area of D)
: This makes things easier, because we can take considerable liberties to simplify the expression for the area, and take care of it at the end by selecting the constant.
:
: To find area, we have to integrate the equation for a circle between the edge and the liquid surface. The standard equation for a circle is:
:
(X/R)^2 + (Y/R)^2 = 1
: If you plot this on graph paper you get a circle of radius R, centered on the origin. So it covers X values from -R to +R. The first simplification I'm going to make is to set R=1.
: Now
:
X^2 + Y^2 = 1
: or
: Y = sqrt(1-X^2)
: and the area to the liquid surface, say depth d, is
:
A = integral{sqrt(1-X^2) dX}
: between the limits {X=-1,X=d}
: (Actually that's only half the area, because sqrt(1-X^2) has two roots, one positive and one negative, and the circle is half above and half below the X axis. But we take care of the constant 2 later.)
:
: This is an impossible integral as it stands, so make a substitution
:
X=sin(Q)
: where Q is in Radians.
: Now
:
sin^2(Q) + cos^2(Q) = 1
: so
:
sqrt(1-sin^2(Q)) = cos(Q)
: And the formula becomes
:
A = integral{cos(Q) dX}
: But we can't integrate Q by dX, so we have to multiply by dQ/dX
: Since
:
X = sin(Q)
: then
:
dQ/dX = cos(Q)
: So
:
A = integral{cos(Q) dQ/dX.dX}
: Therefore the final formula is
:
A = integral{cos^2(Q) dQ}
: Now
:
cos^2(Q) = (1+cos(2Q))/2 = 1/2 + 1/2.(cos(2Q))
: You can integrate this one term at a time, thus:
:
integral{1/2 dQ} = Q/2
: and
:
integral{1/2(cos(2Q)) dQ} = 1/2.1/2.sin(2Q)
: = 1/2.sin(Q).cos(Q)
: So
:
A = 1/2.(Q + sin(Q).cos(Q))
: and reversing the substitution to get back into X,
:
A = 1/2.(arcsin(X) + X.sqrt(1-X^2))
: To get a definite integral, or the area between two points, we evaluate the function at each point and subtract one from the other. In this case we evaluate at some variable point X, and subtract the (constant) value when the tank is empty at X=-1.
:
: The value when X=-1 is:
:
1/2.(-pi + -1.(1-1))
: = -pi/2
: Next thing is to express X in terms of d, the depth of fluid.
:
: Because at the start we decided to find A as a fraction (0..1) of the total area, we want X as a fraction of the total diameter. Further, because our original circle formula is centered on the origin, we want X to vary between -1 and +1. Further, we arbitrarily declared that the radius of the tank is 1, so the diameter is 2 * radius, or 2.
:
: So if our depth reading is d,
:
X = (d-radius)/radius
: = (d-1)
: and as d varies from 0..1 diameters, or 0..2 radii,
: when d=0, X=-1
: when d=2, X=+1
:
: Therefore the D-shaped area covered at depth d is:
:
A = 1/2.(arcsin(d-1)+(d-1).sqrt(1-(d-1)^2))-(pi/2)
: What we actually want is the total volume, so let's work out that
: constant K I mentioned at the beginning and put in some real numbers.
:
: Total tank volume is pi cubic meters, or pi*1000 liters.
: Output from sensor is in range (0..4095)
: So
:
d = ((sensor output) - 2048)/2048
: Liquid volume when half full (sensor reads 2048) is (pi/2)*1000 liters.
: So
:
(pi/2)*1000 = K*(arcsin(0)+(0).sqrt(1)-(-pi/2))
: = K*pi/2
: so
K = 1000
:
: Checking,
: Liquid volume when full (sensor reads 4096) is (pi)*1000 liters.
: So
:
(pi)*1000 = K*(arcsin(1)+(1).sqrt(0)-(-pi/2))
: = K*(pi/2 + pi/2)
: Confirmed,
K = 1000
:
: Hence our full formula is this:
:
Volume = 1000*(arcsin(d) + d.sqrt(1-d^2)) + 1570
: where
: d = ((sensor reading)-2048)/2048
:
: