Попробовал решить задачу измерения объёма в усечённом конусе двумя способами:
1. Выразил объём прямого (полного) конуса через высоту конуса и угол между основанием и образующей (т.е. выразил радиус через высоту и подставил в формулу объёма). Далее взял три точки - начало отсчёта датчика, середину конуса и верхнюю часть конуса - для них известны и уровень и объём. Получил систему из двух уравнений относительно двух переменных - высота конуса до нижней точки измерения датчика и угол между основанием и образующей. Получил квадратное уравнение, решил.
2. Взял точки и при помощи метода наименьших квадратов нашёл полином второй степени. Тут всё просто - в институте на чисметах делал, осталась программка на Pascal. Думаю, что для тех, кто чисметы не изучал - существуют онлайн сервисы аппроксимации МНК.
Какие результаты.
Очень удивился, что лобовое решение при помощи интерполяции по 3 точкам (1-й способ) дал неудовлетворительные результаты - вместо параболы получилась функция гиперболы с перегибом.
А вот аппроксимация дала весьма хорошие результаты.
У меня нет MS Office - работаю в Libre Office, поэтому исходники прикладывать нет смысла, покажу распечатки в pdf - и вывод формулы (как оказалось не нужной) и результаты вычислений по формуле и МНК.
Итого. Как бы поступил лично я.
Нет ничего универсального и эта программа пишется не для всех конусных и не только бункеров, а для конкретного. А для конкретного бункера на диапазоне 35-60 см хорошо применим полином второй степени, коэффициенты для которого получены МНК. Поэтому решение такое:
1. на диапазоне измерений от 35 до 60 см объём вычисляется по аппроксимационному полиному.
2. на диапазоне 60 см и более - по линейной формуле для цилиндра (может придётся разбить на несколько участков)
В примере программы не стал усердствовать с точностью вычислений для цилиндрической части, просто для примера показал с каким-то коэффициентом.
Код:
function BunkerVolume: real;
var_input
rLevel: real;
end_var
var
a: array [0..2] of real := [7.8577289377217835E-002, -3.0897496947466449E-003, 1.4868742368739197E-004];
rVolumeMin: real := 0.152;
rVolumeMax: real := 0.429;
rResult: real;
i: udint;
end_var
if rLevel < 35.0 then
rResult := rVolumeMin;
elsif rLevel <=60.0 then
rResult := 0;
for i := 0 to 2 do
rResult := rResult * rLevel + a[2-i];
end_for;
elsif rLevel <= 200.0 then
rResult := rVolumeMax + 0.0348 * (rLevel - 60.0);
end_if;
BunkerVolume := rResult;
end_function